Sembra che la soluzione di Tim Carter non funzioni se la chiamata al riferimento Web genera un'eccezione. Ho cercato di ottenere la risposta web non elaborata in modo da poterla esaminare (nel codice) nel gestore degli errori una volta generata l'eccezione. Tuttavia, sto riscontrando che il registro delle risposte scritto dal metodo di Tim è vuoto quando la chiamata genera un'eccezione. Non capisco completamente il codice, ma sembra che il metodo di Tim si inserisca nel processo dopo il punto in cui .Net ha già invalidato e scartato la risposta web.
Sto lavorando con un cliente che sta sviluppando manualmente un servizio web con codifica di basso livello. A questo punto, stanno aggiungendo i propri messaggi di errore di processo interno come messaggi formattati HTML nella risposta PRIMA della risposta formattata SOAP. Naturalmente, il riferimento web di automagic .Net esplode su questo. Se potessi ottenere la risposta HTTP non elaborata dopo che è stata generata un'eccezione, potrei cercare e analizzare qualsiasi risposta SOAP all'interno della risposta HTTP di ritorno mista e sapere che hanno ricevuto i miei dati OK o meno.
Dopo ...
Ecco una soluzione che funziona, anche dopo un'esecuzione (nota che sto solo dopo la risposta - potrei anche ottenere la richiesta):
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;
}
}
}
Ecco come configurarlo nel file di configurazione:
<configuration>
...
<system.web>
<webServices>
<soapExtensionTypes>
<add type="ChuckBevitt.GetRawResponseSoapExtension, TestCallWebService"
priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
"TestCallWebService" dovrebbe essere sostituito con il nome della libreria (che era il nome dell'app della console di test su cui stavo lavorando).
Non dovresti davvero andare su ChainStream; dovresti essere in grado di farlo più semplicemente da ProcessMessage come:
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
}
}
Se cerchi SoapMessage.Stream, dovrebbe essere un flusso di sola lettura che puoi usare per ispezionare i dati a questo punto. Questo è un errore perché se leggi il flusso, le bombe di elaborazione successive senza dati trovati errori (il flusso era alla fine) e non puoi ripristinare la posizione all'inizio.
È interessante notare che, se si utilizzano entrambi i metodi, ChainStream e ProcessMessage, il metodo ProcessMessage funzionerà perché è stato modificato il tipo di flusso da ConnectStream a MemoryStream in ChainStream e MemoryStream consente le operazioni di ricerca. (Ho provato a trasmettere ConnectStream a MemoryStream - non era consentito.)
Quindi ..... Microsoft dovrebbe consentire le operazioni di ricerca sul tipo ChainStream o rendere SoapMessage.Stream veramente una copia di sola lettura come dovrebbe essere. (Scrivi il tuo membro del Congresso, ecc ...)
Un ulteriore punto. Dopo aver creato un modo per recuperare la risposta HTTP non elaborata dopo un'eccezione, non ho ancora ricevuto la risposta completa (come determinato da uno sniffer HTTP). Questo perché quando il servizio Web di sviluppo ha aggiunto i messaggi di errore HTML all'inizio della risposta, non ha modificato l'intestazione Content-Length, quindi il valore Content-Length era inferiore alla dimensione del corpo della risposta effettiva. Tutto quello che ho ottenuto è stato il numero di caratteri del valore Content-Length - il resto mancava. Ovviamente, quando .Net legge il flusso di risposta, legge solo il numero di caratteri Content-Length e non consente che il valore Content-Length sia errato. Questo è come dovrebbe essere; ma se il valore dell'intestazione Content-Length è sbagliato, l'unico modo per ottenere l'intero corpo della risposta è con uno sniffer HTTP (io utilizzo HTTP Analyzer dahttp://www.ieinspector.com ).