为具有属性的方法添加Message Inspector

时间:2013-04-08 19:50:56

标签: .net wcf idispatchmessageinspector

是否可以在某些服务方法上只有一个消息检查器,这些服务方法应用了自定义属性?我在网上看到的所有示例都添加了一个消息检查器作为行为扩展,它将应用于服务上的每个方法。

2 个答案:

答案 0 :(得分:1)

我不确定是否可以将检查器仅应用于一组有限的方法,但是您可以尝试创建一个常规的消息检查器来检查目标方法是否应用了自定义属性:

public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
        string actionName = request.Headers.Action.Substring(request.Headers.Action.LastIndexOf('/') + 1);
        if (!string.IsNullOrEmpty(actionName))
        {
            var methodInfo = instanceContext.Host.Description.ServiceType.GetMethod(actionName);
            if (methodInfo != null)
            {
                var customAttributes = methodInfo.GetCustomAttributes(false);
                if (customAttributes.Any(ca => ca.GetType().Equals(typeof(MyCustomAttribute))))
                { 

                }
            }
        }
        ...

这只是一个快速而又脏的实现,你可能想要重构一下。您可能还想在检查器本身之外抽象出过滤过程,可能还有某种责任链来处理它。希望有所帮助。

答案 1 :(得分:0)

是的,你可以这样做。您需要一个继承自soapextension的类,而另一个继承自soapexstensionattribute的类。然后使用soapextensionattribute类在Web服务方法上设置属性。

例如

'定义跟踪SOAP请求和SOAP响应的SOAP扩展     '对于应用SOAP扩展的XML Web服务方法。     '//blog.encoresystems.net/articles/how-to-capture-soap-envelopes-when-consuming-a-web-service.aspx     '和//bytes.com/topic/net/answers/426481-how-log-soap-messages-client-side     '和//www.codeproject.com/KB/cpp/SerializationFun.aspx     朋友类SoapdbTraceExtension         继承SoapExtension

    Private _originalStream As Stream
    Private _newStream As Stream

    Private _methodname As String

    Sub New()
    End Sub

    ' Save the Stream representing the SOAP request (or SOAP response) into
    ' a local memory buffer.
    ' basically due to the nature of streams, this creates a copy so that 
    ' we have something that we can work on. This function is called automatically
    ' when this soapextension is invoked.
    ' see //msdn.microsoft.com/en-us/magazine/cc164007.aspx
    ' the goal here is to save the stream containing the SOAP message
    ' We also create a NewStream for holding a working copy of the message
    ' The stream passed into Chainstream creates a memory stream and passes it back to the caller
    ' the stream returned from chainstream contains the serialised SOAP message
    Public Overrides Function ChainStream(ByVal stream As Stream) As Stream

        ' this is called prior to BeforeDeserialize and BeforeSerialize 
        ' see http://hyperthink.net/blog/inside-of-chainstream/
        ' In the former case (i.e. the one we are interested in here
        ' oldstream contains the contents of the soap request and newstream will be empty

        _originalStream = stream
        _newStream = New MemoryStream()
        Return _newStream
    End Function

    ' When the SOAP extension is accessed for the first time, the XML Web
    ' service method it is applied to is accessed to store the parameter values
    ' passed in, using the corresponding SoapExtensionAttribute.  So in the case 
    ' of the database trace this might be the method name (as shown below)
    Public Overloads Overrides Function GetInitializer(ByVal methodInfo As  _
                                                          LogicalMethodInfo,
                                                       ByVal attribute As SoapExtensionAttribute) As Object
        ' We use this to establish
        ' the method name (though it could be any attribute from the
        ' SOAPDatabaseTrace class) i.e. any attribute that can be 
        ' passed from the use of the attribute on the web service method declaration

        ' here we store the name of the method in the property we have setup

            ' name of the calling method

            Me._methodname = CType(attribute, SOAPDatabaseTrace).Method

            Return _methodname

    End Function


    Public Overloads Overrides Function GetInitializer(ByVal webServiceType As  _
                                                          Type) As Object

        Return _methodname
    End Function

    ' Receive the method name stored by GetInitializer and store it in a
    ' member variable for this specific instance.
    Public Overrides Sub Initialize(ByVal initializer As Object)

        ' this is called once per soap request and is therefore the ideal place to add appropriate data

            _methodname = CStr(initializer)


    End Sub


    ' This is automatically called after the chainstream function.
    ' this is called multiple times
    Public Overrides Sub ProcessMessage(ByVal message As SoapMessage)
            Select Case message.Stage
                Case SoapMessageStage.BeforeSerialize
                    ' chainstream is called prior to BeforeSerialize
                Case SoapMessageStage.AfterSerialize
                    WriteOutput(message)

                Case SoapMessageStage.BeforeDeserialize
                    ' chainstream is called prior to BeforeDeserialize 
                    WriteInput(message)
                Case SoapMessageStage.AfterDeserialize
            End Select
    End Sub

    ' Write the SOAP response to the database
    Public Sub WriteOutput(ByVal message As SoapMessage)

            CopyAndKeepXMLStream(_newStream, _originalStream)
    End Sub

    ' Write the SOAP request message to the database

    Public Sub WriteInput(ByVal message As SoapMessage)

            CopyAndKeepXMLStream(oldStream:=_originalStream, cleanedUpStream:=_newStream)

    End Sub

    Private Sub CopyAndKeepXMLStream(ByVal oldStream As Stream, ByVal cleanedUpStream As Stream)

            ' from //google-api-adwords-dotnet.googlecode.com/svn-history/r50/trunk/src/lib/TraceExtension.cs
            Dim oldposition As Long
            If oldStream.CanSeek Then
                oldposition = oldStream.Position
                oldStream.Position = 0
            End If
            ' load the XML writer
            Dim xmlwriter As XmlTextWriter = New XmlTextWriter(cleanedUpStream, Encoding.UTF8)
            ' pretty it all up
            xmlwriter.Indentation = 2
            xmlwriter.IndentChar = Char.Parse(" ")
            xmlwriter.Formatting = Formatting.Indented

            ' load from old stream and write to the new cleaned up stream
            Dim xmlreader As XmlReader = New XmlTextReader(oldStream)
            Dim xml As XmlDocument = New XmlDocument
            xml.Load(xmlreader)
            xml.WriteTo(xmlwriter)
            xmlwriter.Flush()
            cleanedUpStream.Flush()

            If cleanedUpStream.CanSeek Then
                cleanedUpStream.Position = 0
            End If

            If oldStream.CanSeek Then
                oldStream.Position = oldposition
            End If
            'Dim result As String
            'result = xml.OuterXml

            ' now we have the string we can write to the database
            StoreSOAP(xml)
    End Sub

    ''' <summary>
    ''' Parse and store the soap message 
    ''' </summary>
    ''' <param name="xml">The SOAP message</param>
    ''' <remarks>Stores the SOAP message in a database</remarks>
    Private Sub StoreSOAP(ByVal xml As XmlDocument)

...标准数据库插入代码

  End Sub


    Private Sub Copy(ByVal fromStream As Stream, ByVal toStream As Stream)
        Dim reader As New StreamReader(fromStream)
        Dim writer As New StreamWriter(toStream)
        writer.WriteLine(reader.ReadToEnd())
        writer.Flush()
    End Sub
End Class

' Create a SoapExtensionAttribute for our SOAP Extension that can be
' applied to an XML Web service method.
' these are the attributes we have available
' they are available in the web service of interest
' and can be used here for logging etc.
<AttributeUsage(AttributeTargets.Method)>
Friend Class SOAPDatabaseTrace
    Inherits SoapExtensionAttribute

    Private _mPriority As Integer
    Private _mMethod As String = "Unknown"

    Public Overrides ReadOnly Property ExtensionType() As Type
        Get
            Return GetType(SoapdbTraceExtension)
        End Get
    End Property


    ''' <summary>
    '''     Priority
    ''' </summary>
    ''' <value>Integer</value>
    ''' <returns>
    '''     Indicates the priority in which the extension will be executed relative to other soapextensions.
    '''     1 is the highest priority
    ''' </returns>
    ''' <remarks>Required by the inheritance</remarks>
    Public Overrides Property Priority() As Integer
        Get
            Return _mPriority
        End Get
        Set(ByVal value As Integer)
            _mPriority = value
        End Set
    End Property

    Public Property Method() As String
        Get
            Return _mMethod
        End Get
        Set(ByVal value As String)
            _mMethod = value
        End Set
    End Property

End Class

然后在您的Web服务中,该方法看起来像这样

    <WebMethod(Description:="Some web method"), _
    SOAPDatabaseTrace(method:="MyFunction")> _
    Public Function MyFunction(ByVal Param1 As String) as object

...

将SOAPDatabaseTrace属性放在要跟踪的任何方法上