SoapHttpClientProtocolからクエリテキストを取得する

.NETには、SOAPクライアントを作成するためのいくつかのオプションがあり、その1つはwsdl.exeを使用して生成することです。 出力はファイルです(C#で記述しているため、それぞれcsを生成しました)。その基礎は、SoapHttpClientProtocolから継承されたクラスです。 詳細はこちら



私の観点から、これはかなり便利な方法です。さらに、クライアント自体はsgen.exeを使用して細分化できます( 非常に良い例 )。 それにもかかわらず、彼には1つの非常に深刻な欠点があります-要求/応答のテキストを受信するための定期的な能力の欠如。 そしてこれは、サービスの初期デバッグ、エラーの分析、そして最も重要なこととして、これらのサービスを提供する側からの訴訟の際に非常に便利です。



ただし、本当にしたい場合は、それを行う必要があります。



主なアイデア



何らかの方法でSoapHttpClientProtocolをオーバーライドするのは良い方法であり、このログ機能を追加します。 ここに提示されクライアントリクエストを受信するためのオプションは基礎として採用され、その後、ログ記録とサーバーの応答の可能性がそれに「ねじ込まれ」ました。



SoapHttpClientProtocolをオーバーライドする



クラスをリリースします。SoapHttpClientProtocolからそれぞれ継承したSoapHttpClientProtocolSpyとします。 クライアントリクエストをインターセプトするには、GetWriterForMessageメソッドをオーバーライドし、サーバーレスポンス-GetReaderForMessageをインターセプトします。 最初はXmlWriterを返し、2番目はXmlReaderを返します。 代わりに、独自の実装を返します。これにより、XMlがそれらを通過できるようになります。



次のクラスを取得します。



SoapHttpClientProtocolSpy
public class SoapHttpClientProtocolSpy: SoapHttpClientProtocol { private XmlWriterSpy writer; private XmlReaderSpy reader; public SoapHttpClientProtocolSpy() : base(){} protected override XmlWriter GetWriterForMessage(SoapClientMessage message, int bufferSize) { writer = new XmlWriterSpy(base.GetWriterForMessage(message, bufferSize)); return writer; } protected override XmlReader GetReaderForMessage(SoapClientMessage message, int bufferSize) { reader = new XmlReaderSpy(base.GetReaderForMessage(message, bufferSize)); return reader; } public string XmlRequest => reader?.Xml; public string XmlResponce => writer?.Xml; }
      
      







XmlWriterSpyとXmlReaderSpyは、XmlWriterとXmlReaderのデコレータです。



XmlWriterSpy



基本的に、実装自体はStringWriterを追加することであり、処理された要求テキストをそこに格納します。 つまり、すべての記録メソッドを再定義して、通常のハンドラーを呼び出して結果をStringWriterに渡す必要があります。



実装
  public class XmlWriterSpy : XmlWriter { //  ,     ,   private XmlWriter _me; private XmlTextWriter _bu; private StringWriter _sw; public XmlWriterSpy(XmlWriter implementation) { _me = implementation; _sw = new StringWriter(); _bu = new XmlTextWriter(_sw); _bu.Formatting = Formatting.Indented; } public override void Flush() { _me.Flush(); _bu.Flush(); _sw.Flush(); } public string Xml => _sw?.ToString(); public override void Close() { _me.Close(); _bu.Close(); } public override string LookupPrefix(string ns) { return _me.LookupPrefix(ns); } public override void WriteBase64(byte[] buffer, int index, int count) { _me.WriteBase64(buffer, index, count); _bu.WriteBase64(buffer, index, count); } public override void WriteCData(string text) { _me.WriteCData(text); _bu.WriteCData(text); } //  ,     }
      
      







この記事を再度ありがとう。



XmlWriterSpy



ここでの考え方はまったく同じです。 しかし、実装を行うだけで、少し手を加える必要があります。 一方では、たった1つのメソッド(読み取り)に入るだけで十分です。他方では、ストリームからの読み取りがあり、それを破るのはそれほど簡単ではありません。 ここからアイデアを取りました。



実装
  public class XmlReaderSpy : XmlReader { //  ,     ,   private XmlReader _baseXmlReader; StringWriter _sw; public string Xml => _sw?.ToString(); public XmlReaderSpy(XmlReader xmlReader) { _sw = new StringWriter(); _baseXmlReader = xmlReader; } public override bool Read() { //   var res = _baseXmlReader.Read(); //      - switch (_baseXmlReader.NodeType) { case XmlNodeType.Element: _sw.Write("<" + _baseXmlReader.Name); while (_baseXmlReader.MoveToNextAttribute()) _sw.Write(" " + _baseXmlReader.Name + "='" + _baseXmlReader.Value + "'"); _sw.Write(_baseXmlReader.HasValue || _baseXmlReader.IsEmptyElement ? "/>" : ">"); //    ,     _baseXmlReader.MoveToElement(); break; case XmlNodeType.Text: _sw.Write(_baseXmlReader.Value); break; case XmlNodeType.CDATA: _sw.Write(_baseXmlReader.Value); break; case XmlNodeType.ProcessingInstruction: _sw.Write("<?" + _baseXmlReader.Name + " " + _baseXmlReader.Value + "?>"); break; case XmlNodeType.Comment: _sw.Write("<!--" + _baseXmlReader.Value + "-->"); break; case XmlNodeType.Document: _sw.Write("<?xml version='1.0'?>"); break; case XmlNodeType.Whitespace: _sw.Write(_baseXmlReader.Value); break; case XmlNodeType.SignificantWhitespace: _sw.Write(_baseXmlReader.Value); break; case XmlNodeType.EndElement: _sw.Write("</" + _baseXmlReader.Name + ">"); break; } return res; } }
      
      







_baseXmlReaderを使用して同じメソッドを呼び出すだけで、他のすべてのメソッドをオーバーライドします。



使用する



生成されたクラスを思い出してください。SoapHttpClientProtocolSpyから継承するだけです。 このような実装は、サーバーがエラーを返した場合でも機能する(つまり、セキュリティで保護されている)と言ってもいいでしょう。 それでは、メソッド呼び出しは次のようになります。



 using (var worker = new Service()) { try { res = worker.Metod(....); Log.Info((worker?.XmlRequest ?? "")+(worker?.XmlResponce ?? "")); } catch (System.Exception ex) { Log.Error((worker?.XmlRequest ?? "")+(worker?.XmlResponce ?? "")); throw ex; } }
      
      





PS。 私の観点からは、これをすべて別個のlibにすると便利です。 常に緊張する唯一のことは、クライアントを更新した後にファイルに登り、そこでSoapHttpClientProtocolを置き換える必要があることですが、これらは些細なことです。



All Articles