我只想用某些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
,并且BeforeSendRequest
和AfterReceiveReply
都可以使用它。例如。...
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,但是可以防止无关的代码访问您存储在其中的敏感数据。