web-dev-qa-db-ja.com

WCFサービスで生の要求をログに記録する方法

いくつかの方法でWCFサービスを利用しています。送信方法に関係なく、クライアントからの生のリクエストをログに記録したいと思います。 1つのメソッドは、次を使用してログに記録できるクエリ文字列(厳密にはレガシーサポート用)としてデータを受け入れます。

OperationContext.Current.IncomingMessageHeaders.To.AbsoluteUri

そのシナリオではこれで十分ですが、他のメソッドを使用すると、クライアントはsvcutil.exeによって生成されたプロキシクラスを使用してデータをXMLとして送信できます。このシナリオでは、次のs:Bodyで必要なデータを見つけました。

OperationContext.Current.RequestContext.RequestMessage

残念ながら、何を試しても、メッセージを読み取る前に、バッファリングされたメッセージのコピーを作成することはできません。次に例を示します。

public CascadeResponse SendCustomer(Customer c)
    {
        Message msg = OperationContext.Current.RequestContext.RequestMessage.CreateBufferedCopy(Int32.MaxValue).CreateMessage();
        LogMessage(msg);
        // Now that the request is logged, get on with the rest
    }

ただし、SendCustomerの最初の行で、次のエラーが発生します。

このメッセージは読み取られているため、操作をサポートできません。

これが私がバッファリングされたコピーを作成するポイントですよね?私はここで要素的に間違ったことをしていると思います。

編集:

さて、メソッドは次のようになりました。

public CascadeResponse SendCustomer(Message requestMessage)
    {
        Message msg = OperationContext.Current.RequestContext.RequestMessage.CreateBufferedCopy(Int32.MaxValue).CreateMessage();
        LogMessage(msg);
        // Now that the request is logged, get on with the rest        
        Customer c = msg.GetBody<Customer>();
        string clientKey = "1111"; // This should be the clientKey string passed to the function along with the customer 
        return SendLead(c, clientKey);
    }

私の問題は、CustomerとClientKeyを別々のエンティティとして送信する方法がわからないことです。 clientKeyをCustomerのプロパティにすることもできます(または、データを渡すためだけに、CustomerとClientKeyを属性として含むカスタムオブジェクトを作成することもできます)が、これはレガシーシステムのアップグレードであるため、可能であれば避けたいと思います。すでにこのように機能します。

また、svcUtil.exeを使用してプロキシクラスを作成するのに問題があります-上記のメソッドシグネチャがあると、サービスがリクエストを送信するための正しいシグネチャをアドバタイズしなくなると思いますか?それが十分に明確であるかどうかはわかりません-私の唯一の入力メソッドがMessageオブジェクトを受け入れる場合、クライアントはどのようにしてCustomerとClientKeyを送信することを知っていますか?

12
Maloric

私は他の人も役立つかもしれない解決策を見つけました。 MessageInspectorを作成すると、次のように、「AfterReceiveRequest」イベントと「BeforeSendReply」イベントにコードを添付できます。

public class MessageInspector : IDispatchMessageInspector
{
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
    {
        MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
        request = buffer.CreateMessage();
        LogMessage("Received:\n{0}", buffer.CreateMessage().ToString());
        return null;
    }

    public void BeforeSendReply(ref Message reply, object correlationState)
    {
        MessageBuffer buffer = reply.CreateBufferedCopy(Int32.MaxValue);
        reply = buffer.CreateMessage();
        LogMessage("Sending:\n{0}", buffer.CreateMessage().ToString());
    }
}

ここにwcfのメッセージインスペクターを設定するための完全なチュートリアル があります。 app.config/web.configに動作拡張機能を追加するときは、完全修飾アセンブリ名を注意深く確認してください。

他の誰かがこれが役に立つと思うことを願っています。

18
Maloric

...ToString()メソッドを使用できると思います。その方法は、メッセージを内部的に書き直すことです。

_string soap = OperationContext.Current.RequestContext.RequestMessage.ToString();
_

ToString()メソッドの内部を見てください...;)

2
Ostati

上記を達成するには、以下に示すようにメソッドを変更する必要があります。

public CascadeResponse SendCustomer(Message requestMessage)
    {
        Message msg = OperationContext.Current.RequestContext.RequestMessage.CreateBufferedCopy(Int32.MaxValue).CreateMessage();
        LogMessage(msg);
        // Now that the request is logged, get on with the rest        
        Customer c = msg.GetBody<Customer>();
    }

メッセージクラスの使用 に関する詳細情報

2
Rajesh

WCFサービスプロジェクトのVS2015では、web.configを右クリックしてWCF構成を編集できます。ここから、診断を有効にして生のメッセージをログに記録できます。

0
Mustafa Temiz