Wygląda na to, że rozwiązanie Tima Cartera nie działa, jeśli wywołanie odwołania internetowego zgłasza wyjątek. Próbowałem uzyskać odpowiedź nieprzetworzoną, aby móc ją zbadać (w kodzie) w programie obsługi błędów po wyrzuceniu wyjątku. Jednak stwierdzam, że dziennik odpowiedzi napisany przez metodę Tima jest pusty, gdy wywołanie zgłasza wyjątek. Nie rozumiem do końca kodu, ale wydaje się, że metoda Tima przerywa proces po punkcie, w którym .Net już unieważnił i odrzucił odpowiedź sieciową.
Pracuję z klientem, który ręcznie opracowuje usługę internetową z kodowaniem niskiego poziomu. W tym momencie dodają swoje własne wewnętrzne komunikaty o błędach procesu jako komunikaty w formacie HTML do odpowiedzi PRZED odpowiedzią w formacie SOAP. Oczywiście, pojawia się tutaj odniesienie do automagic .Net. Gdybym mógł uzyskać nieprzetworzoną odpowiedź HTTP po wyrzuceniu wyjątku, mógłbym poszukać i przeanalizować każdą odpowiedź SOAP w mieszanej zwrotnej odpowiedzi HTTP i wiedzieć, że otrzymali moje dane w porządku, czy nie.
Później ...
Oto rozwiązanie, które działa, nawet po wykonaniu (zwróć uwagę, że jestem dopiero po odpowiedzi - również mogę uzyskać żądanie):
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;
}
}
}
Oto jak możesz to skonfigurować w pliku konfiguracyjnym:
<configuration>
...
<system.web>
<webServices>
<soapExtensionTypes>
<add type="ChuckBevitt.GetRawResponseSoapExtension, TestCallWebService"
priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
„TestCallWebService” należy zastąpić nazwą biblioteki (była to nazwa aplikacji konsoli testowej, w której pracowałem).
Naprawdę nie powinieneś iść do ChainStream; powinieneś być w stanie zrobić to prościej z ProcessMessage, ponieważ:
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
}
}
Jeśli spojrzysz na SoapMessage.Stream, powinien to być strumień tylko do odczytu, którego możesz użyć do sprawdzenia danych w tym momencie. Jest to błąd, ponieważ jeśli odczytujesz strumień, kolejne przetwarzanie bomb bez błędów znalezionych danych (strumień był na końcu) i nie możesz zresetować pozycji do początku.
Co ciekawe, jeśli wykonasz obie metody, ChainStream i ProcessMessage, metoda ProcessMessage będzie działać, ponieważ zmieniono typ strumienia z ConnectStream na MemoryStream w ChainStream, a MemoryStream zezwala na operacje wyszukiwania. (Próbowałem rzucić ConnectStream na MemoryStream - nie było dozwolone.)
Więc ..... Microsoft powinien albo zezwolić na operacje wyszukiwania na typie ChainStream, albo uczynić SoapMessage.Stream prawdziwie kopią tylko do odczytu, tak jak powinna. (Napisz kongresmana itp.)
Jeszcze jeden punkt. Po utworzeniu sposobu na odzyskanie nieprzetworzonej odpowiedzi HTTP po wyjątku nadal nie otrzymałem pełnej odpowiedzi (określonej przez sniffer HTTP). Dzieje się tak, ponieważ gdy programistyczna usługa sieciowa dodawała komunikaty o błędach HTML na początku odpowiedzi, nie dostosowywała nagłówka Content-Length, więc wartość Content-Length była mniejsza niż rozmiar rzeczywistej treści odpowiedzi. Wszystko, co otrzymałem, to liczba znaków wartości Content-Length - reszty brakowało. Oczywiście, kiedy .Net czyta strumień odpowiedzi, po prostu czyta liczbę znaków Content-Length i nie pozwala na to, aby wartość Content-Length była błędna. Tak powinno być; ale jeśli wartość nagłówka Content-Length jest nieprawidłowa, jedynym sposobem, w jaki kiedykolwiek otrzymasz całą treść odpowiedzi, jest sniffer HTTP (używam analizatora HTTP zhttp://www.ieinspector.com ).