Похоже, что решение Тима Картера не сработает, если при обращении к веб-ссылке возникнет исключение. Я пытался получить чистый веб-резонанс, чтобы я мог исследовать его (в коде) в обработчике ошибок после того, как возникнет исключение. Однако я обнаружил, что журнал ответов, написанный методом Тима, пуст, когда вызов вызывает исключение. Я не совсем понимаю код, но похоже, что метод Тима включается в процесс после того, как .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).