如何在WCF服务中使用IDispatchMessageInspector?
我试图在WCF服务实现中使用IDispatchMessageInspector来访问自定义标头值。
就像是:
public class MyService : IMyService { public List GetNames() { var headerInspector = new CustomHeaderInspector(); // Where do request & client channel come from? var values = headerInspector.AfterReceiveRequest(ref request, clientChannel, OperationContext.Current.InstanceContext); } }
我已经实现了自己的IDispatchMessageInspector类。
public class CustomHeaderInspector : IDispatchMessageInspector { public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) { var prop = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]; var userName = prop.Headers["Username"]; return userName; } }
我怎么通过
-
System.ServiceModel.Channels。 消息和
-
System.ServiceModel。 IClientChannel
从服务实现调用AfterReceiveRequest ?
编辑:
许多像这样或者这样的文章给出了如何实现自己的ServiceBehavior
示例。 所以你的服务实现如下:
[MyCustomBehavior] public class MyService : IMyService { public List GetNames() { // Can you use 'MyCustomBehavior' here to access the header properties? } }
因此,我可以在服务操作方法中以某种方式访问MyCustomBehavior
以访问自定义标头值吗?
你必须配置
然后,扩展将在您的WCF堆栈中处理。 服务本身没有serviceInterceptors
概念,你不必像在第一个代码块中那样做。 WCF堆栈将为您注入Inspector。
MSDN:system.servicemodel.dispatcher.idispatchmessageinspector
我正在使用IClientMessageInspector达到同样的目标。 以下是如何从代码中应用它们:
var serviceClient = new ServiceClientClass(binding, endpointAddress); serviceClient.Endpoint.Behaviors.Add( new MessageInspectorEndpointBehavior()); /// /// Represents a run-time behavior extension for a client endpoint. /// public class MessageInspectorEndpointBehavior : IEndpointBehavior where T: IClientMessageInspector, new() { /// /// Implements a modification or extension of the client across an endpoint. /// /// The endpoint that is to be customized. /// The client runtime to be customized. public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(new T()); } /// /// Implement to pass data at runtime to bindings to support custom behavior. /// /// The endpoint to modify. /// The objects that binding elements require to support the behavior. public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { // Nothing special here } /// /// Implements a modification or extension of the service across an endpoint. /// /// The endpoint that exposes the contract. /// The endpoint dispatcher to be modified or extended. public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { // Nothing special here } /// /// Implement to confirm that the endpoint meets some intended criteria. /// /// The endpoint to validate. public void Validate(ServiceEndpoint endpoint) { // Nothing special here } }
这里是MessageInspector的示例实现,我用它将客户端版本传递给服务器,并在自定义头文件中检索服务器版本:
/// /// Represents a message inspector object that can be added to the MessageInspectors collection to view or modify messages. /// public class VersionCheckMessageInspector : IClientMessageInspector { /// /// Enables inspection or modification of a message before a request message is sent to a service. /// /// The message to be sent to the service. /// The WCF client object channel. /// /// The object that is returned as the argument of /// the method. /// This is null if no correlation state is used.The best practice is to make this a to ensure that no two /// objects are the same. /// public object BeforeSendRequest(ref Message request, IClientChannel channel) { request.Headers.Add(new VersionMessageHeader()); return null; } /// /// Enables inspection or modification of a message after a reply message is received but prior to passing it back to the client application. /// /// The message to be transformed into types and handed back to the client application. /// Correlation state data. public void AfterReceiveReply(ref Message reply, object correlationState) { var serverVersion = string.Empty; var idx = reply.Headers.FindHeader(VersionMessageHeader.HeaderName, VersionMessageHeader.HeaderNamespace); if (idx >= 0) { var versionReader = reply.Headers.GetReaderAtHeader(idx); while (versionReader.Name != "ServerVersion" && versionReader.Read()) { serverVersion = versionReader.ReadInnerXml(); break; } } ValidateServerVersion(serverVersion); } private static void ValidateServerVersion(string serverVersion) { // TODO... } } public class VersionMessageHeader : MessageHeader { public const string HeaderName = "VersionSoapHeader"; public const string HeaderNamespace = ""; private const string VersionElementName = "ClientVersion"; public override string Name { get { return HeaderName; } } public override string Namespace { get { return HeaderNamespace; } } protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion) { writer.WriteElementString( VersionElementName, Assembly.GetExecutingAssembly().GetName().Version.ToString()); } }
我相信您不需要实现自定义IDispatchMessageInspector来检索自定义标头,可以通过以下服务操作方法完成:
var mp = OperationContext.Current.IncomingMessageProperties; var property = (HttpRequestMessageProperty)mp[HttpRequestMessageProperty.Name]; var userName = property.Headers["Username"];
如果要中止消息处理,则实现自定义调度消息检查器是有意义的,例如,如果缺少凭据 – 在这种情况下您可以抛出FaultException。
但是如果你仍然希望将值从调度消息检查器传递给服务操作方法 – 可能它可以通过一些单例与调用标识符(会话标识)一起传递,稍后通过方法或使用wcf扩展来提取
我做了什么来访问我在IDispatchMessageInspector.AfterReceiveRequest
设置以下内容的详细信息
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(username, "Membership Provider"), roles);
我已经省略了这个validation码。
要从服务方法访问值,您可以调用
Thread.CurrentPrincipal.Identity.Name
在您链接到的MSDN页面上,还有一个描述如何插入检查器的说明以及一个示例。 报价:
通常,消息检查器由服务行为,端点行为或合同行为插入。 然后,该行为将消息检查器添加到DispatchRuntime.MessageInspectors集合。
稍后您将获得以下示例:
- 实现自定义IDispatchMessageInspector
- 实现将检查器添加到运行时的自定义IServiceBehavior。
- 通过.config文件配置行为。
这应该足以让你开始。 否则随便问:)
如果您只想从服务中访问标头,可以尝试OperationContext.Current.IncomingMessageHeaders
。