为带有属性的方法添加消息检查器



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

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

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))))
                { 
                }
            }
        }
        ...

这只是一个快速而肮脏的实现,您可能需要稍微重构一下。您可能还希望抽象出检查器本身之外的过滤过程,也许有某种责任链来处理它。

是的,你可以这样做。您需要一个继承自soapextension的类和另一个继承自soapextensionattribute的类。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属性放到任何想要跟踪的方法上

相关内容

  • 没有找到相关文章

最新更新