是否可以仅对某些应用了自定义属性的服务方法设置消息检查器?我在网上看到的所有示例都添加了一个消息检查器作为行为扩展,它应用于服务上的每个方法。
2 回答
我不确定是否可以将检查器仅应用于一组有限的方法,但是您可以尝试创建一个常规消息检查器,该检查器将检查目标方法是否应用了自定义属性:
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 的类和另一个继承自soapexstension 属性的类。然后,您可以使用 soapextensionattribute 类来设置 Web 服务方法的属性。
例如
' 为应用 SOAP 扩展的 XML Web 服务方法定义跟踪 SOAP 请求和 SOAP 响应的 SOAP 扩展。' //blog.encoresystems.net/articles/how-to-capture-soap-envelopes-when-sumption-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)
... 标准 DB 插入代码
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
然后在您的网络服务中,该方法看起来像这样
<WebMethod(Description:="Some web method"), _
SOAPDatabaseTrace(method:="MyFunction")> _
Public Function MyFunction(ByVal Param1 As String) as object
...
您将 SOAPDatabaseTrace 属性放在要跟踪的任何方法上