如何访问用于在 WCF 服务(服务器端)上实现 IDispatchMessageInspector 的类中的属性?
我正在使用 WCF IClientMessageInspector 将标头中的信息发送到 WCF 服务 (wsHTTP)。我正在使用 IDispatchMessageInspector 来接收信息并填充 String 属性。
当我在特定方法中使用 FindHeader 时,我验证了标头正在正确发送信息,但我宁愿只访问具有 Token 属性的自定义类并从那里获取令牌,而不必在单独的方法中执行 FindHeader所有其他方法都调用以获取标头值。
所以我的问题是,从服务器端(我认为是 OperationContext)如何访问具有填充了标头信息的 Token 属性的类实例?
下面是整个类的代码:
Region " IMPORTS "
Imports System.ServiceModel
Imports System.ServiceModel.Dispatcher
Imports System.ServiceModel.Description
Imports System.ServiceModel.Channels
Imports System.ServiceModel.Configuration
End Region
Public Class MessageInspector
Inherits BehaviorExtensionElement
Implements IClientMessageInspector, IDispatchMessageInspector, IEndpointBehavior
Private Const headerName As String = "HeaderToken"
Private Const headerNamespace As String = "urn:com.nc-software.services:v1"
Private _token As String
Public Property Token() As String
Get
Return _token
End Get
Set(ByVal Value As String)
_token = Value
End Set
End Property
Public Overrides ReadOnly Property BehaviorType() As System.Type
Get
Return GetType(MessageInspector)
End Get
End Property
Protected Overrides Function CreateBehavior() As Object
Return New MessageInspector
End Function
Region " IEndpointBehavior "
Public Sub AddBindingParameters(ByVal endpoint As System.ServiceModel.Description.ServiceEndpoint, ByVal bindingParameters As System.ServiceModel.Channels.BindingParameterCollection) Implements System.ServiceModel.Description.IEndpointBehavior.AddBindingParameters
End Sub
Public Sub ApplyClientBehavior(ByVal endpoint As System.ServiceModel.Description.ServiceEndpoint, ByVal clientRuntime As System.ServiceModel.Dispatcher.ClientRuntime) Implements System.ServiceModel.Description.IEndpointBehavior.ApplyClientBehavior
clientRuntime.MessageInspectors.Add(Me)
End Sub
Public Sub ApplyDispatchBehavior(ByVal endpoint As System.ServiceModel.Description.ServiceEndpoint, ByVal endpointDispatcher As System.ServiceModel.Dispatcher.EndpointDispatcher) Implements System.ServiceModel.Description.IEndpointBehavior.ApplyDispatchBehavior
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(Me)
End Sub
Public Sub Validate(ByVal endpoint As System.ServiceModel.Description.ServiceEndpoint) Implements System.ServiceModel.Description.IEndpointBehavior.Validate
End Sub
End Region
Region " IClientMessageInspector "
Public Sub AfterReceiveReply(ByRef reply As System.ServiceModel.Channels.Message, ByVal correlationState As Object) Implements System.ServiceModel.Dispatcher.IClientMessageInspector.AfterReceiveReply
End Sub
Public Function BeforeSendRequest(ByRef request As System.ServiceModel.Channels.Message, ByVal channel As System.ServiceModel.IClientChannel) As Object Implements System.ServiceModel.Dispatcher.IClientMessageInspector.BeforeSendRequest
Dim header As New MessageHeader(Of String)(Token)
Dim untypedHeader As MessageHeader = header.GetUntypedHeader(headerName, headerNamespace)
request.Headers.Add(untypedHeader)
Return Nothing
End Function
End Region
Region " IDispatchMessageInspector "
Public Function AfterReceiveRequest(ByRef request As System.ServiceModel.Channels.Message, ByVal channel As System.ServiceModel.IClientChannel, ByVal instanceContext As System.ServiceModel.InstanceContext) As Object Implements System.ServiceModel.Dispatcher.IDispatchMessageInspector.AfterReceiveRequest
Try
Dim headers As MessageHeaders = OperationContext.Current.IncomingMessageHeaders
Dim headerIndex As Integer = headers.FindHeader(headerName, headerNamespace)
If headerIndex >= 0 Then
Token = headers.GetHeader(Of String)(headerIndex)
End If
Catch
End Try
Return Nothing
End Function
Public Sub BeforeSendReply(ByRef reply As System.ServiceModel.Channels.Message, ByVal correlationState As Object) Implements System.ServiceModel.Dispatcher.IDispatchMessageInspector.BeforeSendReply
End Sub
End Region
End Class
I am using the WCF IClientMessageInspector to send information in a header to a WCF service (wsHTTP). I am using the IDispatchMessageInspector to receive the information and populate a String property.
I verified the header is sending the information properly as I use the FindHeader within my specific method but I'd rather just access the custom class that has the Token property and GET the Token from there rather than having to do FindHeader in a separate method that all other methods call to get the header value.
So my question is, from the server side (OperationContext I presume) how do I access this class instance that has the Token property populated with the header info?
Here is the code from the entire class below:
Region " IMPORTS "
Imports System.ServiceModel
Imports System.ServiceModel.Dispatcher
Imports System.ServiceModel.Description
Imports System.ServiceModel.Channels
Imports System.ServiceModel.Configuration
End Region
Public Class MessageInspector
Inherits BehaviorExtensionElement
Implements IClientMessageInspector, IDispatchMessageInspector, IEndpointBehavior
Private Const headerName As String = "HeaderToken"
Private Const headerNamespace As String = "urn:com.nc-software.services:v1"
Private _token As String
Public Property Token() As String
Get
Return _token
End Get
Set(ByVal Value As String)
_token = Value
End Set
End Property
Public Overrides ReadOnly Property BehaviorType() As System.Type
Get
Return GetType(MessageInspector)
End Get
End Property
Protected Overrides Function CreateBehavior() As Object
Return New MessageInspector
End Function
Region " IEndpointBehavior "
Public Sub AddBindingParameters(ByVal endpoint As System.ServiceModel.Description.ServiceEndpoint, ByVal bindingParameters As System.ServiceModel.Channels.BindingParameterCollection) Implements System.ServiceModel.Description.IEndpointBehavior.AddBindingParameters
End Sub
Public Sub ApplyClientBehavior(ByVal endpoint As System.ServiceModel.Description.ServiceEndpoint, ByVal clientRuntime As System.ServiceModel.Dispatcher.ClientRuntime) Implements System.ServiceModel.Description.IEndpointBehavior.ApplyClientBehavior
clientRuntime.MessageInspectors.Add(Me)
End Sub
Public Sub ApplyDispatchBehavior(ByVal endpoint As System.ServiceModel.Description.ServiceEndpoint, ByVal endpointDispatcher As System.ServiceModel.Dispatcher.EndpointDispatcher) Implements System.ServiceModel.Description.IEndpointBehavior.ApplyDispatchBehavior
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(Me)
End Sub
Public Sub Validate(ByVal endpoint As System.ServiceModel.Description.ServiceEndpoint) Implements System.ServiceModel.Description.IEndpointBehavior.Validate
End Sub
End Region
Region " IClientMessageInspector "
Public Sub AfterReceiveReply(ByRef reply As System.ServiceModel.Channels.Message, ByVal correlationState As Object) Implements System.ServiceModel.Dispatcher.IClientMessageInspector.AfterReceiveReply
End Sub
Public Function BeforeSendRequest(ByRef request As System.ServiceModel.Channels.Message, ByVal channel As System.ServiceModel.IClientChannel) As Object Implements System.ServiceModel.Dispatcher.IClientMessageInspector.BeforeSendRequest
Dim header As New MessageHeader(Of String)(Token)
Dim untypedHeader As MessageHeader = header.GetUntypedHeader(headerName, headerNamespace)
request.Headers.Add(untypedHeader)
Return Nothing
End Function
End Region
Region " IDispatchMessageInspector "
Public Function AfterReceiveRequest(ByRef request As System.ServiceModel.Channels.Message, ByVal channel As System.ServiceModel.IClientChannel, ByVal instanceContext As System.ServiceModel.InstanceContext) As Object Implements System.ServiceModel.Dispatcher.IDispatchMessageInspector.AfterReceiveRequest
Try
Dim headers As MessageHeaders = OperationContext.Current.IncomingMessageHeaders
Dim headerIndex As Integer = headers.FindHeader(headerName, headerNamespace)
If headerIndex >= 0 Then
Token = headers.GetHeader(Of String)(headerIndex)
End If
Catch
End Try
Return Nothing
End Function
Public Sub BeforeSendReply(ByRef reply As System.ServiceModel.Channels.Message, ByVal correlationState As Object) Implements System.ServiceModel.Dispatcher.IDispatchMessageInspector.BeforeSendReply
End Sub
End Region
End Class
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
根据我看到 WCF 团队建立的模式,我的建议是让 IDispatchMessageInspector 将标头的值推送到当前的 OperationContext 的 IncomingMessageProperties 字典。通过这样做,该值将与当前操作上下文相关联,并由 WCF 运行时正确地完成执行的所有阶段。
至于如何进一步读取堆栈中的值,您可以做两件事。 ,您可以公开将用于在静态只读字符串上的属性集合中读取/写入值的字符串键,其他代码可以使用它从 OperationContext.Current 本身检索值,如下所示:
首先 仍然需要所有需要读取该值的人进行大量编码。获取当前上下文,使用键索引到字典并将结果转换为正确的类型(我使用 int 作为上面的示例)。如果您想变得更奇特,下一步可以采取的方法是通过您自己的上下文类公开这些属性,以便人们可以像普通的强类型 CLR 属性一样访问它们。这可能看起来有点像这样:
首先,在名为 MyOperationContext 的类上实现静态访问器属性:
现在,在需要读取此标头的各种实现中,他们只需执行以下操作:
Based on patterns I see the WCF team themsevles establishing, my suggestion would be to have your IDispatchMessageInspector shove the value of the header into the current OperationContext's IncomingMessageProperties dictionary. By doing this, the value will be tied to the current operation context and carried through all stages of execution properly for you by the WCF runtime.
As far as how to read that value further down the stack out you can do two things. First, you can expose the string key you will be using to read/write the value to the properties collection on a static readonly string somewhere that other code can use it to retrieve the value from the OperationContext.Current themselves like so:
Now, this still requires a lot of coding on the part of all the people who need to read the value. Getting the current context, indexing into the dictionary with the key and casting the result to the proper type (I used int as a sample above). If you want to get fancy, the next step you can take is to instead just expose these properties via your own context class so people can just access them like normal, strongly typed CLR properties. That might look a little something like this:
First, implement a static accessor property on a class called MyOperationContext:
Now in your various implementations that need to read this header they would simply do: