Схоже, рішення Тіма Картера не працює, якщо виклик веб-посилання викликає виняток. Я намагався отримати неопрацьований веб-резонанс, щоб я міг перевірити його (у коді) в обробнику помилок, коли буде вилучено виняток. Однак я виявляю, що журнал відповідей, написаний методом Тіма, порожній, коли виклик викликає виняток. Я не повністю розумію код, але, схоже, метод Тіма врізається в процес після того моменту, коли .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 sniffer). Це було тому, що коли веб-служба розробки додала повідомлення про помилки HTML на початок відповіді, вона не відрегулювала заголовок Content-Length, тому значення Content-Length було менше розміру фактичного тіла відповіді. Все, що я отримав, - це кількість знаків Content-Length, кількість інших символів відсутня. Очевидно, що коли .Net читає потік відповідей, він просто зчитує кількість символів Content-Length і не допускає помилки значення Content-Length. Це як слід; але якщо значення заголовка Content-Length неправильне, єдиний спосіб, яким ви коли-небудь отримаєте все тіло відповіді, - це HTTP-sniffer (I user HTTP Analyzer fromhttp://www.ieinspector.com ).