<AttributeUsage(AttributeTargets.Method)> _ Public Class TraceExtensionAttribute Inherits SoapExtensionAttribute Private TracePriority As Integer Public Overrides ReadOnly Property ExtensionType() As Type Get Return GetType(TraceExtension) End Get End Property Public Overrides Property Priority() As Integer Get Return TracePriority End Get Set(ByVal value As Integer) TracePriority = value End Set End Property End Class Public Class TraceExtension Inherits SoapExtension Private OldStream As Stream Private NewStream As Stream Private Shared cXmlRequest As String = "" Private Shared cXmlResponse As String = "" Public ReadOnly Property XmlRequest As String Get Return cXmlRequest End Get End Property Public ReadOnly Property XmlResponse As String Get Return cXmlResponse End Get End Property Public Overloads Overrides Function GetInitializer(ByVal methodInfo As LogicalMethodInfo, _ ByVal attribute As SoapExtensionAttribute) As Object Return Nothing End Function Public Overloads Overrides Function GetInitializer(ByVal WebServiceType As Type) As Object Return Nothing End Function Public Overrides Sub Initialize(ByVal initializer As Object) Return End Sub ' The ProcessMessage method is where the real work is done. ProcessMessage is invoked before and after ' an input message is deserialized to input parameters and before and after output parameters are ' serialized to an output message. After an input message is deserialized, the extension rewinds ' the HTTP input stream so a method can read it (the stream's cursor advances during deserialization) ' and creates a new memory stream for the method to write an output message to. This output stream, ' appOutputStream, is the second output stream required to make this scheme work. (The first output ' stream, chainedOutputStream, is created when ChainStream is called the second time.) ' References to both streams are stored in the current HTTP context's Items collection, with the ' keys "SoapInputStream" and "SoapOutputStream," respectively. After an output message is serialized, ' ProcessMessage copies the contents of the second output stream, appOutputStream, to the HTTP output ' stream—httpOutputStream. (Most SOAP extensions would copy the contents of their chained output stream ' to the HTTP output stream at this point.) Public Overrides Sub ProcessMessage(ByVal message As SoapMessage) Dim loStreamReader As StreamReader = Nothing Select Case message.Stage Case SoapMessageStage.BeforeSerialize Case SoapMessageStage.AfterSerialize ' Retrieve the SOAP Message from the Output Stream message.Stream.Position = 0 loStreamReader = New StreamReader(message.Stream) cXmlRequest = loStreamReader.ReadToEnd() WriteOutput(message) Case SoapMessageStage.BeforeDeserialize WriteInput(message) ' Retrieve the SOAP Message from the Input Stream loStreamReader = New StreamReader(message.Stream) cXmlResponse = loStreamReader.ReadToEnd() message.Stream.Position = 0 Case SoapMessageStage.AfterDeserialize End Select End Sub ' ChainStream replaces original stream with extension's stream Public Overrides Function ChainStream(ByVal toStream As Stream) As Stream OldStream = toStream NewStream = New MemoryStream() Return NewStream End Function Public Sub WriteOutput(ByVal message As SoapMessage) NewStream.Position = 0 Copy(NewStream, OldStream) End Sub Public Sub WriteInput(ByVal message As SoapMessage) Copy(OldStream, NewStream) NewStream.Position = 0 End Sub ' CopyStream copies the contents of a source stream to a destination stream Private Function Copy(ByVal toFromStream As Stream, ByVal toStream As Stream) As Boolean Dim loReader As New StreamReader(toFromStream) Dim loWriter As New StreamWriter(toStream) loWriter.WriteLine(loReader.ReadToEnd()) loWriter.Flush() Return True End Function End ClassThen, from the application:
Private oTraceExtension As TraceExtension = New TraceExtension() loShipmentResponse = loShipService.ProcessShipment(loShipmentRequest) cXmlResponse = oTraceExtension.XmlResponseAnd, in the app.config:
<system.web> <webServices> <soapExtensionTypes> <add type="Framework.TraceExtension,Framework" priority="1" group="0"/> </soapExtensionTypes> </webServices> </system.web>...just before the /configuration tag.