如何将参数(id)传递给 WCF 中的消息检查器?
Posted
技术标签:
【中文标题】如何将参数(id)传递给 WCF 中的消息检查器?【英文标题】:How to pass parameter (id) to message inspector in WCF? 【发布时间】:2013-03-14 13:37:58 【问题描述】:我只想用一些 id 绑定 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;
【问题讨论】:
mattgemmell.com/2008/12/08/what-have-you-tried @SonerGönül 事实上,我什至不知道如何开始解决这个问题 :) 每个 WCF 调用都有与之关联的唯一 ID:OperationContext.Current.IncomingMessageHeaders.MessageId @Alexander 我想定义自己的自定义 ID,与 DB 中的其他实体相关联。 您能否至少发布服务接口以及您计划如何生成该 ID? 【参考方案1】:如果我理解正确,您想使用 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
更新
问题是如何将参数传递给 BeforeSendRequest 方法。
在这种情况下,如果您的请求消息中没有您需要的所有信息,显而易见的解决方案是给我们一个 ThreadStatic 字段,以便将来自您的呼叫者的信息传达给 BeforeSendRequest
。
在调用服务之前设置字段,然后提取并使用BeforeSendRequest
中的值。
更新 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
,它对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 并不是绝对必要的,但可以防止无关代码访问您存储在那里的可能敏感数据。
【讨论】:
正如您在我的代码示例中看到的那样,我已经这样做了。问题是如何将参数传递给BeforeSendRequest
方法。
我可以使用的另一个选项是将参数设置为消息本身,但是如何在BeforeSendRequest
的request
参数中访问它?【参考方案2】:
我认为最简单的解决方案是将线程静态变量放入LogMessageInspector
。在BeforeSendRequest
中设置值并在AfterReceiveReply
中再次使用它。
如果您使用异步操作,我会变得更复杂一些,但您所要做的就是密切关注您如何访问和传递这个本地 var。
MessageInspectors 旨在处理 Message 本身,因此最好的解决方案是在消息中包含一些相关的内容,例如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 以关联请求和响应。
【讨论】:
能否请您给我一些有关 RequestID 或 OrderID 的样本。找不到此类属性。 貌似不错但是没有机会在BeforeSendRequest
得到RequestID
以上是关于如何将参数(id)传递给 WCF 中的消息检查器?的主要内容,如果未能解决你的问题,请参考以下文章