替换WCF消息的内容

tom*_*ich 6 xml wcf

我正在尝试设置一个路由服务,该服务将位于我的网络的DMZ中,并允许外部人员访问一些内部托管的WCF服务.我已经设置好所有工作,但是当我转发MEX服务时,它会将我们的外部客户端指向我们的内部地址,这显然是他们无法访问的.

微软似乎建议制作wsdl的副本,这可能会起作用,但是每次服务定义发生变化时都需要我制作wsdl的新副本,而这些副本经常发生,而且看起来有些过分.唯一需要改变的是mex消息中的地址.

       <endpoint address="http://appsrv1:8781/ProcessManagementService/"
            binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IProcessManagementService"
            contract="IProcessManagementService" name="WSHttpBinding_IProcessManagementService" />
Run Code Online (Sandbox Code Playgroud)

好像使用了一个IDispatchMessageInspector,我应该能够拦截mex消息并用外部服务器名称替换内部服务器名称,然后我只需要在需要添加或删除服务时触摸路由服务,而不是比每次我做出任何改变.

我对XML阅读器,编写器等没有太多经验,所以我正在寻找有关如何继续的一些指导.如果我可以将xml内容读入字符串,我可以执行替换操作来替换内部地址的外部地址,然后用我的修改版本替换回复的消息内容.我该如何去做,或者有更好的方法来修改WCF消息的内容?

编辑:所以这就是我到目前为止拼凑的东西.

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 && bodyReader.LocalName != "Body" && 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;    
    }
}
Run Code Online (Sandbox Code Playgroud)

它似乎主要起作用.但是,XMLReader抛出异常"根级别的数据无效.第1行,位置1".当我尝试创建消息时.我不知道从那里开始.

编辑2:

好的,现在我有一个方法将消息提取到xdocument中,然后将其发送到字符串,然后编辑它,然后将其拉回到xdocument中,当我发回一个时,我得到一个"强制关闭连接"包含该已编辑邮件的邮件.可怕.

编辑3:

在测试之后,简单地从回复到xdoc中提取消息然后将其加载到新消息中就足以导致"连接强制关闭"问题.这绝不是编辑邮件的正确方法.我正在寻找有关如何最好地解决这个问题的示例或经验.

tom*_*ich 10

我从MSDN论坛得到了答案.我的问题是我正在改变字符串的长度,但没有重置MemoryStream的长度,这意味着最后的字节没有被报告.

这是一个有效的替换功能.

 public Message ChangeString(Message oldMessage, string from, string to)
        {
            MemoryStream ms = new MemoryStream();
            XmlWriter xw = XmlWriter.Create(ms);
            oldMessage.WriteMessage(xw);
            xw.Flush();
            string body = Encoding.UTF8.GetString(ms.ToArray());
            xw.Close();

            body = body.Replace(from, to);

            ms = new MemoryStream(Encoding.UTF8.GetBytes(body));
            XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(ms, new XmlDictionaryReaderQuotas());
            Message newMessage = Message.CreateMessage(xdr, int.MaxValue, oldMessage.Version);
            newMessage.Properties.CopyProperties(oldMessage.Properties);
            return newMessage; 
       }
Run Code Online (Sandbox Code Playgroud)