如何在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