Il semble que la solution de Tim Carter ne fonctionne pas si l'appel à la référence Web lève une exception. J'ai essayé d'obtenir la réponse Web brute afin de pouvoir l'examiner (dans le code) dans le gestionnaire d'erreurs une fois l'exception levée. Cependant, je trouve que le journal des réponses écrit par la méthode de Tim est vide lorsque l'appel lève une exception. Je ne comprends pas complètement le code, mais il semble que la méthode de Tim entre dans le processus après le point où .Net a déjà invalidé et ignoré la réponse Web.
Je travaille avec un client qui développe manuellement un service Web avec un codage de bas niveau. À ce stade, ils ajoutent leurs propres messages d'erreur de processus internes sous forme de messages au format HTML dans la réponse AVANT la réponse au format SOAP. Bien sûr, la référence Web automagic .Net explose à ce sujet. Si je pouvais obtenir la réponse HTTP brute après qu'une exception a été lancée, je pourrais rechercher et analyser toute réponse SOAP dans la réponse HTTP de retour mixte et savoir qu'ils ont reçu mes données OK ou non.
Plus tard ...
Voici une solution qui fonctionne, même après une exécution (notez que je ne suis qu'après la réponse - je pourrais aussi obtenir la demande):
namespace ChuckBevitt
{
class GetRawResponseSoapExtension : SoapExtension
{
//must override these three methods
public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
{
return null;
}
public override object GetInitializer(Type serviceType)
{
return null;
}
public override void Initialize(object initializer)
{
}
private bool IsResponse = false;
public override void ProcessMessage(SoapMessage message)
{
//Note that ProcessMessage gets called AFTER ChainStream.
//That's why I'm looking for AfterSerialize, rather than BeforeDeserialize
if (message.Stage == SoapMessageStage.AfterSerialize)
IsResponse = true;
else
IsResponse = false;
}
public override Stream ChainStream(Stream stream)
{
if (IsResponse)
{
StreamReader sr = new StreamReader(stream);
string response = sr.ReadToEnd();
sr.Close();
sr.Dispose();
File.WriteAllText(@"C:\test.txt", response);
byte[] ResponseBytes = Encoding.ASCII.GetBytes(response);
MemoryStream ms = new MemoryStream(ResponseBytes);
return ms;
}
else
return stream;
}
}
}
Voici comment vous le configurez dans le fichier de configuration:
<configuration>
...
<system.web>
<webServices>
<soapExtensionTypes>
<add type="ChuckBevitt.GetRawResponseSoapExtension, TestCallWebService"
priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
"TestCallWebService" doit être remplacé par le nom de la bibliothèque (qui s'est avéré être le nom de l'application de la console de test dans laquelle je travaillais).
Vous ne devriez vraiment pas avoir à accéder à ChainStream; vous devriez pouvoir le faire plus simplement à partir de ProcessMessage comme:
public override void ProcessMessage(SoapMessage message)
{
if (message.Stage == SoapMessageStage.BeforeDeserialize)
{
StreamReader sr = new StreamReader(message.Stream);
File.WriteAllText(@"C:\test.txt", sr.ReadToEnd());
message.Stream.Position = 0; //Will blow up 'cause type of stream ("ConnectStream") doesn't alow seek so can't reset position
}
}
Si vous recherchez SoapMessage.Stream, il est censé être un flux en lecture seule que vous pouvez utiliser pour inspecter les données à ce stade. C'est une mauvaise cause si vous lisez le flux, les bombes de traitement ultérieures sans données ont trouvé des erreurs (le flux était à la fin) et vous ne pouvez pas réinitialiser la position au début.
Fait intéressant, si vous utilisez les deux méthodes, ChainStream et ProcessMessage, la méthode ProcessMessage fonctionnera car vous avez changé le type de flux de ConnectStream en MemoryStream dans ChainStream, et MemoryStream autorise les opérations de recherche. (J'ai essayé de lancer ConnectStream sur MemoryStream - ce n'était pas autorisé.)
Donc ..... Microsoft devrait soit autoriser les opérations de recherche sur le type ChainStream, soit faire de SoapMessage.Stream une véritable copie en lecture seule comme il est censé l'être. (Écrivez à votre membre du Congrès, etc ...)
Un autre point. Après avoir créé un moyen de récupérer la réponse HTTP brute après une exception, je n'ai toujours pas obtenu la réponse complète (comme déterminé par un sniffer HTTP). En effet, lorsque le service Web de développement a ajouté les messages d'erreur HTML au début de la réponse, il n'a pas ajusté l'en-tête Content-Length, de sorte que la valeur Content-Length était inférieure à la taille du corps de la réponse réelle. Tout ce que j'ai obtenu était le nombre de caractères de la valeur Content-Length - le reste manquait. De toute évidence, lorsque .Net lit le flux de réponse, il lit simplement le nombre de caractères Content-Length et ne permet pas que la valeur Content-Length soit éventuellement fausse. C'est comme ça qu'il devrait être; mais si la valeur de l'en-tête Content-Length est fausse, la seule façon d'obtenir le corps de la réponse dans son intégralité est d'utiliser un sniffer HTTPhttp://www.ieinspector.com ).