我只想用某些ID绑定(bind)WCF传入和传出消息,然后将这些消息记录到数据库中。

由于计划在高多线程环境中使用它,因此出现了一些问题。

发布编辑

这是我要记录的方式:

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;
        }
    }

最佳答案

如果我理解正确,则希望使用ID作为correlationState将请求与回复链接起来。为此,请将您的ID作为对象从BeforeSendRequest返回,并将其作为参数传递给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
}

更新



在这种情况下,如果您的请求消息中没有所需的全部信息,则显而易见的解决方案是为我们提供ThreadStatic字段,以将信息从调用者传达到BeforeSendRequest

在调用服务之前设置字段,然后提取并使用BeforeSendRequest中的值。

更新2



我不明白这个问题。如果我理解正确,那么您希望能够将参数从调用方传递给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;
}

请注意,严格地不需要使用try/finally将CallerContext.State重置为null,但是可以防止无关的代码访问您存储在其中的敏感数据。

10-08 06:37