title: Logging SOAP request and response on server side
body: <p>I'm trying to create a logging service for all SOAP method calls to my ASP.NET webservice. I've been looking at 
  <a href="https://stackoverflow.com/questions/17620228/log-soap-messages-from-a-console-application">Log SOAP messages from a console application</a> and the walkthrough for SOAP extensions at MSDN (<a href="http://msdn.microsoft.com/en-us/library/s25h0swd%28v=vs.100%29.aspx" rel="nofollow noreferrer">http://msdn.microsoft.com/en-us/library/s25h0swd%28v=vs.100%29.aspx</a>) but they don't seem to cover it completely.</p>
  
  <p>I don't want to alter the SOAP message, just log it to a database table.
  What I'm trying to do is read the SOAP message stream, parse it as an XML, log the XML and the let the call be on its merry way. But when I read the stream it is spent/disposed. I've tried copying the stream contents to not interrupt the flow.</p>
  
  <p>According to the walkthrough the <code>ProcessMessage</code> method should look something like this:</p>
  
  <pre><code>public override void ProcessMessage(SoapMessage message) 
  {
     switch (message.Stage) 
     {
     case SoapMessageStage.BeforeSerialize:
         break;
     case SoapMessageStage.AfterSerialize:
         // Write the SOAP message out to a file.
         WriteOutput( message );
         break;
     case SoapMessageStage.BeforeDeserialize:
         // Write the SOAP message out to a file.
         WriteInput( message );
         break;
     case SoapMessageStage.AfterDeserialize:
         break;
     default:
         throw new Exception("invalid stage");
     }
  }
  </code></pre>
  
  <p>I've managed to parse the stream without problems during the <code>BeforeDeserialize</code> stage, but then <code>ProcessMessage</code> is called again in the <code>AfterSerialize</code> stage and by then the stream is used and no longer contains any data.</p>
  
  <p>According to SOAP Message Modification Using SOAP Extensions (<a href="http://msdn.microsoft.com/en-us/library/esw638yk%28v=vs.100%29.aspx" rel="nofollow noreferrer">http://msdn.microsoft.com/en-us/library/esw638yk%28v=vs.100%29.aspx</a>) the SOAP call goes through the following steps:</p>
  
  <blockquote>
    <h2>Server Side Receives a Request Message and Prepares a Response</h2>
    
    <ol>
    <li>ASP.NET on the Web server receives the SOAP message.</li>
    <li>A new instance of the SOAP extension is created on the Web server.</li>
    <li>On the Web server, if this is the first time this SOAP extension has executed with this Web service on the server side, the GetInitializer method is invoked on the SOAP extension running on the server.</li>
    <li>The Initialize method is invoked.</li>
    <li>The ChainStream method is invoked.</li>
    <li>The ProcessMessage method is invoked with SoapMessageStage set to <strong>BeforeDeserialize</strong>.</li>
    <li>ASP.NET deserializes the arguments within the XML.</li>
    <li>The ProcessMessage method is invoked with SoapMessageStage set to <strong>AfterDeserialize</strong>.</li>
    <li>ASP.NET creates a new instance of the class implementing the Web service and invokes the Web service method, passing in the deserialized arguments. This object resides on the same computer as the Web server.</li>
    <li>The Web service method executes its code, eventually setting the return value and any out parameters.</li>
    <li>The ProcessMessage method is invoked with SoapMessageStage set to <strong>BeforeSerialize.</strong></li>
    <li>ASP.NET on the Web server serializes the return value and out parameters into XML.</li>
    <li>The ProcessMessage method is invoked with SoapMessageStage set to <strong>AfterSerialize</strong>.</li>
    <li>ASP.NET sends the SOAP response message over the network back to the Web service client.</li>
    </ol>
  </blockquote>
  
  <p>Step 6 is performed correctly and the SOAP XML is logged. Then it shouldn't do anything more until after the server has processed the call, done what it needs (step 10), and returned a response (step 13). Instead it immediately calls <code>ProcessMessage</code> again in the <code>AfterSerialize</code> stage, but this time the stream is already spent and throws an exception when I try to log it.</p>
  
  <p>According to the walkthrough I should use the <code>ChainStream</code> method, and it should be run in step 5 above. When I make the call it is run <em>twice</em>, once before <code>BeforeDeserialize</code> and once before <code>AfterSerialize</code>.</p>
  
  <p>I've tried copying the message stream to a separate stream and use that for the logging, also to set some kind of status if <code>BeforeDeserialize</code> already have run, but problem still persists.</p>
  
  <p>I still need the code in <code>AfterSerialize</code> to handle the response that is sent back to the client. But if I try to remove my code in <code>AfterSerialize</code> and only run the code in <code>BeforeDeserialize' I get a</code>HTTP 400: Bad Request`.</p>
  
  <p>This all happens before the actual method call, so I never even get to the code inside the method (step 10).</p>