Es sieht so aus, als ob die Lösung von Tim Carter nicht funktioniert, wenn der Aufruf der Webreferenz eine Ausnahme auslöst. Ich habe versucht, auf die unformatierte Webantwort zuzugreifen, damit ich sie (im Code) im Fehlerhandler untersuchen kann, sobald die Ausnahme ausgelöst wird. Ich stelle jedoch fest, dass das von Tims Methode geschriebene Antwortprotokoll leer ist, wenn der Aufruf eine Ausnahme auslöst. Ich verstehe den Code nicht vollständig, aber es scheint, dass Tims Methode in den Prozess einschneidet, nachdem .Net die Webantwort bereits ungültig gemacht und verworfen hat.
Ich arbeite mit einem Client zusammen, der einen Webdienst manuell mit niedriger Codierung entwickelt. Zu diesem Zeitpunkt fügen sie der Antwort VOR der SOAP-formatierten Antwort ihre eigenen internen Prozessfehlermeldungen als HTML-formatierte Nachrichten hinzu. Natürlich sprengt die automagische .Net-Webreferenz dies. Wenn ich nach dem Auslösen einer Ausnahme auf die unformatierte HTTP-Antwort zugreifen könnte, könnte ich jede SOAP-Antwort in der gemischten HTTP-Antwort suchen und analysieren und wissen, ob meine Daten in Ordnung sind oder nicht.
Später ...
Hier ist eine Lösung, die auch nach einer Ausführung funktioniert (beachten Sie, dass ich erst nach der Antwort bin - könnte auch die Anfrage erhalten):
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;
}
}
}
So konfigurieren Sie es in der Konfigurationsdatei:
<configuration>
...
<system.web>
<webServices>
<soapExtensionTypes>
<add type="ChuckBevitt.GetRawResponseSoapExtension, TestCallWebService"
priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
"TestCallWebService" sollte durch den Namen der Bibliothek ersetzt werden (dies war zufällig der Name der Testkonsolen-App, in der ich gearbeitet habe).
Sie sollten wirklich nicht zu ChainStream gehen müssen; Sie sollten dies in ProcessMessage einfacher tun können als:
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
}
}
Wenn Sie nach SoapMessage.Stream suchen, sollte es sich um einen schreibgeschützten Stream handeln, mit dem Sie die Daten an dieser Stelle überprüfen können. Dies ist ein Fehler, denn wenn Sie den Stream lesen, nachfolgende Verarbeitungsbomben ohne Datenfehler gefunden haben (Stream war am Ende) und Sie die Position nicht auf den Anfang zurücksetzen können.
Interessanterweise funktioniert die ProcessMessage-Methode, wenn Sie beide Methoden ausführen, ChainStream und ProcessMessage, da Sie den Stream-Typ in ChainStream von ConnectStream in MemoryStream geändert haben und MemoryStream Suchvorgänge zulässt. (Ich habe versucht, den ConnectStream in MemoryStream zu übertragen - war nicht zulässig.)
Also ..... Microsoft sollte entweder Suchvorgänge für den ChainStream-Typ zulassen oder SoapMessage.Stream wirklich zu einer schreibgeschützten Kopie machen, wie sie sein soll. (Schreiben Sie Ihren Kongressabgeordneten usw.)
Ein weiterer Punkt. Nachdem ich eine Möglichkeit erstellt hatte, die unformatierte HTTP-Antwort nach einer Ausnahme abzurufen, erhielt ich immer noch nicht die vollständige Antwort (wie von einem HTTP-Sniffer ermittelt). Dies lag daran, dass der Entwicklungswebdienst beim Hinzufügen der HTML-Fehlermeldungen am Anfang der Antwort den Content-Length-Header nicht anpasste, sodass der Content-Length-Wert kleiner als die Größe des tatsächlichen Antwortkörpers war. Alles, was ich bekam, war die Anzahl der Zeichen für den Wert der Inhaltslänge - der Rest fehlte. Wenn .Net den Antwortstrom liest, liest es natürlich nur die Anzahl der Zeichen für die Inhaltslänge und lässt nicht zu, dass der Wert für die Inhaltslänge möglicherweise falsch ist. Das ist so wie es sein sollte; Wenn der Content-Length-Header-Wert jedoch falsch ist, erhalten Sie den gesamten Antworttext nur mit einem HTTP-Sniffer (ich benutze HTTP Analyzer vonhttp://www.ieinspector.com ).