2013-03-25 4 views
7

私はちょうどいくつかのIDを持つWCFの着信メッセージと発信メッセージをバインドすると、何がデータベースに記録されます。WCFのメッセージインスペクタにパラメータ(ID)を渡すにはどうすればよいですか?

高いマルチスレッド環境で使用する予定だったため、いくつかの問題が発生しました。


POSTのEDIT

は、ここで私がログインする方法である:

public class LogMessageInspector : IClientMessageInspector 
    { 
     public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState) 
     { 
      Dictionary<string, object> logParams = (Dictionary<string, object>)correlationState; 
      logParams["description"] = reply.ToString(); 

      Logger log = LogManager.GetCurrentClassLogger(); 
      log.InfoEx(String.Format("response_{0}", logParams["_action"]), logParams); 
     } 

     public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel) 
     {    
      string iteration_id = ""; 
// here comes seeking for custom, previously setted header with id 
      for (int i = 0; i < request.Headers.Count; i++) 
      { 
       if ((request.Headers[i].Name == "_IterationId") && (request.Headers[i].Namespace == "http://tempuri2.org")) 
       { 
        iteration_id = request.Headers.GetHeader<string>(i); 
        request.Headers.RemoveAt(i); 

        break; 
       } 
      } 

      string pair_id = StringGenerator.RandomString(10); 
      string action_name = request.Headers.Action.Substring(request.Headers.Action.LastIndexOf("/") + 1); 
      Dictionary<string, object> logParams = new Dictionary<string,object>() { {"iteration_id", iteration_id}, { "description", request.ToString() }, { "request_response_pair", pair_id }, { "_action", action_name } }; 

      Logger log = LogManager.GetCurrentClassLogger(); 
      log.InfoEx(String.Format("request_{0}", action_name), logParams);    

      return logParams; 
     } 
    } 
+2

http://mattgemmell.com/2008/12/08/what-have-you-tried/ –

+0

@SonerGönül実際、私はその問題を解決する方法も知らなかった: – kseen

+0

すべてのWCF呼び出しにはそれに関連付けられた一意のID:OperationContext.Current.IncomingMessageHeaders.MessageId – Alexander

答えて

4

私は最も簡単な解決策はLogMessageInspectorでthreadstatic変数を配置することだと思います。値をBeforeSendRequestに設定し、AfterReceiveReplyに再度使用してください。

非同期操作を使用している場合、少し複雑になりますが、このローカルvarにアクセスして渡す方法に細心の注意を払うだけです。

MessageInspectorsはMessage自体を処理することを目的としているため、メッセージに何かを関連付けておくことが最善の解決策です。 requestId、OrderIdで、など

EDIT:

私はこのような何かを探すようにサービス契約を想像

[ServiceContract] 
public interface IService1 
{ 
    [OperationContract] 
    ServiceResponse Process(ServiceRequest request); 
} 


class ServiceRequest 
{ 
    public Guid RequestID { get; set; } 
    public string RequestData { get; set; } 
} 

class ServiceResponse 
{ 
    public Guid RequestID { get; set; } 
    public string ResponseData { get; set; } 
} 

RequestIDクライアント側で生成されるだろう、と今は上のXPathを行うことができます要求と応答を関連付けるためのRequestIDを取得します。

+0

RequestIDまたはOrderIDでサンプルを教えてください。このようなプロパティを見つけることができませんでした。 – kseen

+0

@kseen私の更新を見てください。 – Enes

+0

良いと思われますが、 'BeforeSendRequest'に' RequestID'を得る機会はありません – kseen

4

私が正しく理解している場合は、correlationStateというIDを使用してリクエストと返信をリンクしたいとします。これを行うには、BeforeSendRequestからオブジェクトとしてあなたのIDを返し、それはAfterReceiveReplyへの引数として渡されます。

public object BeforeSendRequest(ref Message request, IClientChannel channel) 
{ 
    var correlationState = ... // for example, a new GUID, or in your case 
           // an id extracted from the message 

    ... do your stuff here 

    return correlationState; 
} 

public void AfterReceiveReply(ref Message reply, object correlationState) 
{ 
    // the correlationState parameter will contain the value you returned from 
    // BeforeSendRequests 
} 

UPDATE

問題がBeforeSendRequestメソッドにパラメータを渡す方法です。その場合

あなたがあなたの要求メッセージにすでに必要なすべての情報を持っていない場合は、明白な解決策は、私たちにBeforeSendRequestにあなたの発信者からの情報を通信するためThreadStaticフィールドです。

サービスを呼び出す前にフィールドを設定してから、BeforeSendRequestの値を抽出して使用してください。私が使用することができます

UPDATE 2

別のオプションは、メッセージ自体にパラメータを設定することですが、どのように私はBeforeSendRequestでリクエストパラメータにアクセスすることができますか?

私はこの質問を理解していません。私が正しく理解していれば、呼び出し側のパラメータをBeforeSendRequestメソッドに渡すことができます。 correlationStateを使用してBeforeSendRequestからAfterReceiveReplyに渡す方法を知っています。

これを行う方法は、ThreadStaticフィールドを使用することです。たとえば、次のようなクラスを作成することができます。

public static class CallerContext 
{ 
    [ThreadStatic] 
    private static object _state; 

    public static object State 
    { 
     get { return _state; } 
     set { _state = value; } 
    } 
} 

を次に、あなたの発信者は、Webサービスを呼び出す前にCallerContext.Stateを設定します、そして、それはBeforeSendRequestAfterReceiveReplyの両方に利用できるようになります。例えば。

... 
try 
{ 
    CallerContext.State = myId; 

    ... call web service here ... 
} 
finally 
{ 
    CallerContext.State = null; 
} 

、これはBeforeSendRequestで利用できるようになります:

public object BeforeSendRequest(ref Message request, IClientChannel channel) 
{ 
    var correlationState = CallerContext.State; 

    ... do your stuff here 

    return correlationState; 
} 

注nullにCallerContext.Stateをリセットする/ついに試みの使用は厳密には必要ではないが、その可能性が機密データにアクセスすることから無関係なコードを防ぐことあなたはそこに保管します。

+0

私のコードサンプルでわかるように、私はすでにそれを行っています。問題は、BeforeSendRequestメソッドにパラメータを渡す方法です。 – kseen

+0

私が使用できる別のオプションは、メッセージ自体にパラメータを設定することですが、 'BeforeSendRequest'の' request'パラメータでどのようにそれにアクセスできますか? – kseen

関連する問題