Sepertinya solusi Tim Carter tidak berfungsi jika panggilan ke referensi web melontarkan pengecualian. Saya telah mencoba untuk mendapatkan jawaban web mentah sehingga saya dapat memeriksanya (dalam kode) di penangan kesalahan setelah pengecualian dilemparkan. Namun, saya menemukan bahwa log respons yang ditulis oleh metode Tim kosong saat panggilan melontarkan pengecualian. Saya tidak sepenuhnya memahami kodenya, tetapi tampaknya metode Tim memotong proses setelah titik di mana .Net telah membatalkan dan membuang respons web.
Saya bekerja dengan klien yang mengembangkan layanan web secara manual dengan pengkodean tingkat rendah. Pada titik ini, mereka menambahkan pesan kesalahan proses internal mereka sendiri sebagai pesan berformat HTML ke dalam tanggapan SEBELUM tanggapan yang diformat SOAP. Tentu saja, referensi web .Net automagic meledak dalam hal ini. Jika saya bisa mendapatkan respons HTTP mentah setelah pengecualian dilemparkan, saya dapat mencari dan mengurai respons SOAP apa pun dalam respons HTTP campuran yang kembali dan tahu bahwa mereka menerima data saya dengan baik atau tidak.
Nanti ...
Berikut adalah solusi yang berhasil, bahkan setelah eksekusi (perhatikan bahwa saya hanya setelah respons - bisa mendapatkan permintaan juga):
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;
}
}
}
Berikut cara Anda mengkonfigurasinya di file konfigurasi:
<configuration>
...
<system.web>
<webServices>
<soapExtensionTypes>
<add type="ChuckBevitt.GetRawResponseSoapExtension, TestCallWebService"
priority="1" group="0" />
</soapExtensionTypes>
</webServices>
</system.web>
</configuration>
"TestCallWebService" harus diganti dengan nama pustaka (yang kebetulan adalah nama aplikasi konsol pengujian yang saya gunakan).
Anda benar-benar tidak harus pergi ke ChainStream; Anda seharusnya dapat melakukannya dengan lebih mudah dari ProcessMessage sebagai:
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
}
}
Jika Anda mencari SoapMessage.Stream, ini seharusnya menjadi aliran hanya-baca yang dapat Anda gunakan untuk memeriksa data pada saat ini. Ini adalah penyebab yang kacau jika Anda membaca aliran, pemrosesan selanjutnya membom tanpa kesalahan data yang ditemukan (aliran berada di akhir) dan Anda tidak dapat mengatur ulang posisi ke awal.
Menariknya, jika Anda melakukan kedua metode, cara ChainStream dan ProcessMessage, metode ProcessMessage akan berfungsi karena Anda mengubah jenis aliran dari ConnectStream ke MemoryStream di ChainStream, dan MemoryStream mengizinkan operasi pencarian. (Saya mencoba mentransmisikan ConnectStream ke MemoryStream - tidak diizinkan.)
Jadi ..... Microsoft harus mengizinkan operasi pencarian pada tipe ChainStream atau membuat SoapMessage.Stream benar-benar salinan hanya-baca sebagaimana mestinya. (Tulis anggota kongres Anda, dll ...)
Satu hal lagi. Setelah membuat cara untuk mengambil respons HTTP mentah setelah pengecualian, saya masih belum mendapatkan respons penuh (seperti yang ditentukan oleh sniffer HTTP). Ini karena ketika layanan web pengembangan menambahkan pesan kesalahan HTML ke awal respons, itu tidak menyesuaikan header Panjang Konten, sehingga nilai Panjang Konten kurang dari ukuran isi respons yang sebenarnya. Yang saya dapatkan hanyalah jumlah karakter nilai Panjang Konten - sisanya hilang. Jelas, ketika .Net membaca aliran respons, itu hanya membaca jumlah karakter Panjang Konten dan tidak memungkinkan nilai Panjang Konten mungkin salah. Ini sebagaimana mestinya; tetapi jika nilai header Panjang Konten salah, satu-satunya cara Anda akan mendapatkan seluruh isi respons adalah dengan sniffer HTTP (Saya pengguna HTTP Analyzer darihttp://www.ieinspector.com ).