Parece que la solución de Tim Carter no funciona si la llamada a la referencia web arroja una excepción. He estado tratando de acceder a la resonancia web sin procesar para poder examinarla (en código) en el controlador de errores una vez que se lanza la excepción. Sin embargo, encuentro que el registro de respuesta escrito por el método de Tim está en blanco cuando la llamada arroja una excepción. No entiendo completamente el código, pero parece que el método de Tim interviene en el proceso después del punto en el que .Net ya ha invalidado y descartado la respuesta web.
Estoy trabajando con un cliente que está desarrollando un servicio web manualmente con codificación de bajo nivel. En este punto, están agregando sus propios mensajes de error de proceso interno como mensajes con formato HTML en la respuesta ANTES de la respuesta con formato SOAP. Por supuesto, la referencia web de Automagic .Net explota sobre esto. Si pudiera obtener la respuesta HTTP sin procesar después de que se lanza una excepción, podría buscar y analizar cualquier respuesta SOAP dentro de la respuesta HTTP de retorno mixta y saber que recibieron mis datos bien o no.
Luego ...
Aquí hay una solución que funciona, incluso después de una ejecución (tenga en cuenta que solo estoy después de la respuesta, también podría obtener la solicitud):
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;
}
}
}
Así es como se configura en el archivo de configuración:
<configuration>
...
<system.web>
<webServices>
<soapExtensionTypes>
<add type="ChuckBevitt.GetRawResponseSoapExtension, TestCallWebService"
priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
"TestCallWebService" debe reemplazarse con el nombre de la biblioteca (que resultó ser el nombre de la aplicación de la consola de prueba en la que estaba trabajando).
Realmente no debería tener que ir a ChainStream; debería poder hacerlo de manera más simple desde ProcessMessage como:
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
}
}
Si busca SoapMessage.Stream, se supone que es un flujo de solo lectura que puede usar para inspeccionar los datos en este punto. Esto es un error porque si lee la transmisión, el procesamiento posterior de bombas sin errores de datos encontrados (la transmisión estaba al final) y no puede restablecer la posición al principio.
Curiosamente, si usa ambos métodos, ChainStream y ProcessMessage, el método ProcessMessage funcionará porque cambió el tipo de flujo de ConnectStream a MemoryStream en ChainStream, y MemoryStream sí permite operaciones de búsqueda. (Intenté transmitir ConnectStream a MemoryStream, no estaba permitido).
Entonces ... Microsoft debería permitir las operaciones de búsqueda en el tipo ChainStream o hacer que SoapMessage.Stream sea realmente una copia de solo lectura como se supone que es. (Escriba a su congresista, etc ...)
Un punto más. Después de crear una forma de recuperar la respuesta HTTP sin procesar después de una excepción, todavía no obtuve la respuesta completa (según lo determinado por un rastreador de HTTP). Esto se debió a que cuando el servicio web de desarrollo agregó los mensajes de error HTML al comienzo de la respuesta, no ajustó el encabezado Content-Length, por lo que el valor Content-Length era menor que el tamaño del cuerpo de la respuesta real. Todo lo que obtuve fue el número de caracteres del valor Content-Length; el resto faltaba. Obviamente, cuando .Net lee el flujo de respuesta, solo lee el número de caracteres Content-Length y no permite que el valor Content-Length posiblemente sea incorrecto. Esto es como debería ser; pero si el valor del encabezado Content-Length es incorrecto, la única forma de obtener el cuerpo de respuesta completo es con un rastreador HTTP (yo utilizo HTTP Analyzer dehttp://www.ieinspector.com ).