是否可能仅对某些应用了自定义属性的服务方法使用消息检查器?我在网上看到的所有例子都添加了一个消息检查器作为行为扩展,它应用于服务上的每个方法。
我不确定是否可以将检查器仅应用于有限的方法集,但是您可以尝试创建一个常规消息检查器,该检查器将检查目标方法是否应用了自定义属性:
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属性放到任何想要跟踪的方法上