title: Replacing content of WCF Message
body: <p>I'm trying to set up a Routing Service that will sit in the DMZ of my network, and allow external people to access some internally hosted WCF services. I've got everything set up and working, but when I forward on the MEX services, it points our external clients to our internal address, which obviously they can not access. </p>
  
  <p><a href="http://social.msdn.microsoft.com/Forums/en/wcf/thread/b31891be-98d3-4440-a617-f584435b01aa" rel="noreferrer">Microsoft seems to recommend making a copy of the wsdl</a>, which would probably work, but would require me to make a new copy of the wsdl every time the service definitions change, which they do quite often, and seems like overkill. The only thing that needs to be changed is a address in the mex message.</p>
  
  <pre><code>       &lt;endpoint address="http://appsrv1:8781/ProcessManagementService/"
              binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IProcessManagementService"
              contract="IProcessManagementService" name="WSHttpBinding_IProcessManagementService" /&gt;
  </code></pre>
  
  <p>It seems as though using an <code>IDispatchMessageInspector</code>, I should be able to intercept the mex message and replace the internal server name with the external server name, and then I would only have to touch the Routing service when I need to add or remove a service, rather than every time I make any change. </p>
  
  <p>I don't have much experience with XML readers, writers, and so on, so I'm looking for some guidance on how to proceed. If I could just read the xml content into a string, I could perform a replace operation to substitute the external address for the internal one, then replace the message content of the reply with my modified version. How do I go about doing that, or is there a better way to modify the content of a WCF message? </p>
  
  <p>Edit: So this is what I've cobbled together so far. </p>
  
  <pre><code>public class EndpointReplacementInspector : IDispatchMessageInspector
  {
      public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
      {
          return null;
      }
  
      public void BeforeSendReply(ref Message reply, object correlationState)
      {           
          var ms = new MemoryStream();
          var w = XmlWriter.Create(ms, new XmlWriterSettings { Indent = true, IndentChars = "  ", OmitXmlDeclaration = true });
          var bodyReader = reply.GetReaderAtBodyContents();
          w.WriteStartElement("s", "Body", "http://schemas.xmlsoap.org/soap/envelope/");
          while (bodyReader.NodeType != XmlNodeType.EndElement &amp;&amp; bodyReader.LocalName != "Body" &amp;&amp; bodyReader.NamespaceURI != "http://schemas.xmlsoap.org/soap/envelope/")
          {
              if (bodyReader.NodeType != XmlNodeType.Whitespace)
              {
                  w.WriteNode(bodyReader, true);
              }
              else
              {
                  bodyReader.Read(); // ignore whitespace; maintain if you want
              }
          }
          w.WriteEndElement();
          w.Flush();
          var body = Encoding.UTF8.GetString(ms.ToArray());
          body = body.Replace("internalserver", "externalserver");            
          var replacedMessage = Message.CreateMessage(XmlReader.Create(new StringReader(body)), int.MaxValue, reply.Version);
          replacedMessage.Headers.CopyHeadersFrom(reply.Headers);
          replacedMessage.Properties.CopyProperties(reply.Properties);
          reply = replacedMessage;    
      }
  }
  </code></pre>
  
  <p>And it seems to <em>mostly</em> work. However, the <code>XMLReader</code> is throwing an exception "Data at the root level is invalid. Line 1, position 1." when I attempt to create the message. I don't know where to start on that one. </p>
  
  <p>Edit 2:</p>
  
  <p>Ok, Now I've got a method that extracts the message into an xdocument, then sends that to a string, then edits it, then pulls that back into an xdocument, and I get a "Connection Forcibly Closed" when I send back a message containing that edited message. Terrible.</p>
  
  <p>Edit 3: </p>
  
  <p>After testing, simply extracting the message from the reply to an xdoc and then loading it into a new message is enough to cause the "Connection Forcibly closed" issue. This must not be the right way to edit messages. I'm looking for examples or experience on how to best approach this. </p>