C# 如何在WCF中将参数(id)传递给消息检查器?

C# 如何在WCF中将参数(id)传递给消息检查器?,c#,.net,wcf,web-services,service,C#,.net,Wcf,Web Services,Service,我只想用一些id绑定WCF传入和传出的消息,这些id将被记录到数据库中 由于计划在高多线程环境中使用,因此出现了一些问题 后期编辑 以下是我想要记录的方式: public class LogMessageInspector : IClientMessageInspector { public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationS

我只想用一些id绑定WCF传入和传出的消息,这些id将被记录到数据库中

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


后期编辑

以下是我想要记录的方式:

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;
        }
    }
公共类LogMessageInspector:IClientMessageInspector
{
接收后公共无效(参考System.ServiceModel.Channel.Message reply,object correlationState)
{
Dictionary logParams=(Dictionary)correlationState;
logParams[“description”]=reply.ToString();
Logger log=LogManager.GetCurrentClassLogger();
log.InfoEx(String.Format(“response”{0})、logParams[“\u action”]、logParams);
}
发送请求前的公共对象(参考System.ServiceModel.Channels.Message request,System.ServiceModel.IClientChannel)
{            
字符串迭代_id=“”;
//这里来寻找自定义的、以前设置的id为的标题
for(int i=0;i
我认为最简单的解决方案是将threadstatic变量放入
LogMessageInspector
中。在发送请求之前的
中设置该值,并在接收方之后的
中再次使用该值

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
}
如果您使用异步操作,我会变得稍微复杂一点,但是您所要做的就是更加关注如何访问和传递这个本地变量

MessageInspector旨在处理消息本身,所以最好的解决方案是在消息中有一些相关的内容,例如requestId、OrderId等

编辑:

我可以想象服务合同是这样的:

[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以关联请求和响应。

如果我理解正确,您希望使用ID作为
correlationState
将请求与回复链接起来。为此,请将ID作为对象从
BeforeSendRequest
返回,它将作为参数传递给
afterreceiverply

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
}
更新

问题是如何将参数传递给BeforeSendRequest方法

在这种情况下,如果您的请求消息中没有您需要的所有信息,那么显而易见的解决方案是为我们提供一个字段,以便在发送请求之前将调用者的信息传递给

在调用服务之前设置该字段,然后在发送请求之前提取并使用
中的值

更新2


我可以使用的另一个选项是将参数设置为消息本身,但如何在BeforeSendRequest的请求参数中访问它

我不明白这个问题。如果我理解正确,您希望能够将一个参数从调用方传递到BeforeSendRequest
方法。您知道如何使用correlationState将它从发送请求之前的
传递到接收方之后的

方法是使用
ThreadStatic
字段。例如,您可以创建以下类:

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

    public static object State
    {
        get { return _state; }
        set { _state = value; }
    }
}
然后,调用方将在调用web服务之前设置
CallerContext.State
,并且在发送请求之前的
和接收之后的
都可以使用它。例如

...
try
{
    CallerContext.State = myId;

    ... call web service here ...
}
finally
{
    CallerContext.State = null;
}
这将在发送请求之前的
中提供:

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

    ... do your stuff here

    return correlationState;
}

请注意,严格来说,使用try/finally将调用方上下文.State
重置为null并不是必需的,但会阻止无关代码访问存储在那里的可能敏感数据。

@SonerGönül事实上,我甚至不知道如何开始解决这个问题:)每个WCF调用都有与之关联的唯一id:OperationContext.Current.IncomingMessageHeaders。MessageId@Alexander我想定义自己的自定义ID,与数据库中的其他实体关联。您是否可以至少发布服务接口,以及您计划如何生成该ID?您可以给我一些关于RequestID或OrderID的示例吗。找不到此类属性。看起来不错,但在发送请求之前的
中没有机会获取
RequestID
,正如您在我的代码示例中看到的,我已经这样做了。问题是如何将参数传递给BeforeSendRequest
方法。我可以使用的另一个选项是将参数设置为消息本身,但如何在
BeforeSendRequest
中的
请求
参数中访问它?