Похоже, что решение Тима Картера не работает, если обращение к веб-ссылке вызывает исключение. Я пытался получить необработанный веб-резонанс, чтобы я мог изучить его (в коде) в обработчике ошибок после того, как возникнет исключение. Однако я обнаружил, что журнал ответов, записанный методом Тима, остается пустым, когда вызов вызывает исключение. Я не совсем понимаю код, но похоже, что метод Тима врезается в процесс после того момента, когда .Net уже аннулировал и отбросил веб-ответ.
Я работаю с клиентом, который вручную разрабатывает веб-службу с помощью низкоуровневого кодирования. На этом этапе они добавляют свои собственные сообщения об ошибках внутреннего процесса в виде сообщений в формате HTML в ответ ПЕРЕД ответом в формате SOAP. Конечно, автоматическая веб-ссылка .Net взрывается по этому поводу. Если бы я мог получить необработанный HTTP-ответ после создания исключения, я мог бы искать и анализировать любой SOAP-ответ в смешанном возвращающемся HTTP-ответе и знать, получили ли они мои данные нормально или нет.
Потом ...
Вот решение, которое работает даже после выполнения (обратите внимание, что я только после ответа - тоже могу получить запрос):
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;
}
}
}
Вот как вы настраиваете это в файле конфигурации:
<configuration>
...
<system.web>
<webServices>
<soapExtensionTypes>
<add type="ChuckBevitt.GetRawResponseSoapExtension, TestCallWebService"
priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
«TestCallWebService» следует заменить на имя библиотеки (это оказалось именем тестового консольного приложения, в котором я работал).
Вам действительно не нужно переходить на ChainStream; вы сможете сделать это проще из ProcessMessage как:
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
}
}
Если вы посмотрите на SoapMessage.Stream, это должен быть поток только для чтения, который вы можете использовать для проверки данных на этом этапе. Это ошибка, потому что, если вы читаете поток, последующая обработка приводит к ошибкам без обнаруженных данных (поток был в конце), и вы не можете сбросить позицию в начало.
Интересно, что если вы используете оба метода, ChainStream и ProcessMessage, метод ProcessMessage будет работать, потому что вы изменили тип потока с ConnectStream на MemoryStream в ChainStream, а MemoryStream разрешает операции поиска. (Я пробовал преобразовать ConnectStream в MemoryStream - не разрешено.)
Итак ... Microsoft должна либо разрешить операции поиска для типа ChainStream, либо сделать SoapMessage.Stream действительно доступной только для чтения копией, как и должно быть. (Напишите своему конгрессмену и т. Д.)
Еще один момент. После создания способа получить необработанный HTTP-ответ после исключения я все еще не получил полного ответа (как определено анализатором HTTP). Это произошло потому, что, когда веб-служба разработки добавляла сообщения об ошибках HTML в начало ответа, она не настраивала заголовок Content-Length, поэтому значение Content-Length было меньше размера фактического тела ответа. Все, что я получил, это количество символов в значении Content-Length - остальные отсутствовали. Очевидно, что когда .Net читает поток ответа, он просто считывает количество символов Content-Length и не допускает, чтобы значение Content-Length могло быть ошибочным. Это так и должно быть; но если значение заголовка Content-Length неверно, единственный способ получить все тело ответа - это использовать сниффер HTTP (я использую HTTP Analyzer изhttp://www.ieinspector.com ).