目的
Webサービスで呼び出されたWebメソッドを自動で記録する必要があり、後付けで行わなければならない場合の簡易的な方法について記載します。
概要
SoapExtension
を継承したクラスを作成し、ProcessMessage
関数でSystem.Web.Services.Protocols.SoapMessage.Stage
がSoapMessageStage.AfterSerialize
の場合に処理を行うようにします。
さらに、Web.Configで作成したクラスが、自動で呼び出されるように設定します。
実装
SoapExtension
を継承したクラス
CustomSoapExtension.vb
Public Class CustomSoapExtension
Inherits SoapExtension
Public Overrides Function GetInitializer(ByVal serviceType As System.Type) As Object
Return Nothing
End Function
Public Overrides Function GetInitializer(ByVal methodInfo As System.Web.Services.Protocols.LogicalMethodInfo, ByVal attribute As System.Web.Services.Protocols.SoapExtensionAttribute) As Object
Return Nothing
End Function
Public Overrides Sub Initialize(ByVal initializer As Object)
End Sub
Public Overrides Sub ProcessMessage(ByVal message As System.Web.Services.Protocols.SoapMessage)
Select Case message.Stage
Case SoapMessageStage.BeforeDeserialize
Case SoapMessageStage.AfterDeserialize
'関数をを記録する場合はここで行う。
LogInfoForWebServicesStart()
Case SoapMessageStage.BeforeSerialize
Case SoapMessageStage.AfterSerialize
If message.Exception IsNot Nothing Then
Dim mesEx As Exception = message.Exception
'エラーを記録する場合はここで行う。
End If
Case Else
Throw New ApplicationException
End Select
End Sub
''' <summary>
''' Webサービスメソッドのスタート時にログ情報を出力する
''' </summary>
Private Sub LogInfoForWebServicesStart()
If System.Web.HttpContext.Current Is Nothing Then
Return
End If
Dim message As String = GetWebServiceInfos()
'ログを記録する(log4Netなど)
(log4Netなどを使用する)
End Sub
''' <summary>
''' メソッド名などの情報を取得
''' </summary>
Private Function GetWebServiceInfos() As String
'' ガード条件
If Web.HttpContext.Current Is Nothing Then Return Nothing
Dim strInfo As New System.Text.StringBuilder
strInfo.Length = 0
Dim request As Web.HttpRequest = Web.HttpContext.Current.Request
If request IsNot Nothing Then
'URLを取得
Dim queryKEYOfURL = From el In request.ServerVariables.AllKeys
Where el?.ToString = "URL"
If queryKEYOfURL Is Nothing Then Return Nothing
If queryKEYOfURL.Count = 0 Then Return Nothing
Dim url = ""
url = request.ServerVariables(queryKEYOfURL.First)
Dim ip = request.UserHostAddress
Dim methodName = GetMethodName()
strInfo.Append($"IP={ip}")
strInfo.Append($",URL={url}/{methodName}")
End If
Return strInfo.ToString
End Function
''' <summary>
''' Webメソッド名の取得
''' </summary>
''' <remarks>
''' サンプル
'''<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
''' <s:Body>
''' <TryLogin xmlns = "http://tempuri.org/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
''' <userid>00020001</userid>
''' </TryLogin>
''' </s:Body>
'''</s:Envelope>
''' </remarks>
Private Function GetMethodName() As String
Dim request As Web.HttpRequest = Web.HttpContext.Current.Request
If request.ServerVariables("HTTP_SOAPACTION") Is Nothing Then Return Nothing
Dim savedPosition As Long = request.InputStream.Position
Try
Dim inputStream(request.ContentLength) As Byte
Dim strSOAP As New Text.StringBuilder
'読み込み
request.InputStream.Position = 0
request.InputStream.Read(inputStream, 0, request.ContentLength)
strSOAP.Length = 0
strSOAP.Append(request.ContentEncoding.GetString(inputStream))
'NullCharを削除
strSOAP = strSOAP.Replace(vbNullChar, "")
Dim xDocument As XmlDocument = New XmlDocument
Call xDocument.Load(New IO.StringReader(strSOAP.ToString)) 'XMLファイルをロード
Dim xRoot = xDocument.DocumentElement 'XMLドキュメントからルート要素を取り出す
Dim xDataList = xRoot.GetElementsByTagName("soap:Body") 'ルート要素から親リストを取得する
If xDataList?.Count = 0 Then
xDataList = xRoot.GetElementsByTagName("s:Body") 'ルート要素から親リストを取得する
End If
Return GetMethodNameSub1(xDataList)
Finally
'読出しのために移動した位置をもとに戻す
request.InputStream.Position = savedPosition
End Try
End Sub
Private Function GetMethodNameSub1(xDataList As XmlNodeList) As String
If xDataList Is Nothing Then Return Nothing
If xDataList.Count = 0 Then Return Nothing
Return GetMethodNameSub2(xDataList(0).ChildNodes)
End Sub
Private Function GetMethodNameSub2(node As XmlNodeList) As String
If node Is Nothing Then Return Nothing
'XML Elementのみ取得
Dim query = From el In node
Where TypeOf (el) Is XmlElement
Select xmlEl = CType(el, XmlElement)
Return query.First?.Name
End Sub
End Class
Web.Configで作成したクラスを呼び出すための設定
web.config
<system.web>
<webServices>
<soapExtensionTypes>
<add type="(名前空間).CustomSoapExtension, (アセンブリ名)"/>
</soapExtensionTypes>
</webServices>
</system.web>