C# 替换WCF客户端代理中未知DataContract的属性值

C# 替换WCF客户端代理中未知DataContract的属性值,c#,wcf,datacontract,C#,Wcf,Datacontract,可能重复: 我有一个通用的WCF代理,对于那些不熟悉它的人来说,它是一个具有以下OperationContract方法的类 [OperationContract(Action = "*", ReplyAction = "*")] void Proxy(Message requestMessage); 最近出现的一个要求是,我需要将消息中所有类型为IPAddress的属性替换为提供请求消息的属性的IPAddress值 比如说 public void Proxy(Message requestM

可能重复:

我有一个通用的WCF代理,对于那些不熟悉它的人来说,它是一个具有以下OperationContract方法的类

[OperationContract(Action = "*", ReplyAction = "*")]
void Proxy(Message requestMessage);
最近出现的一个要求是,我需要将消息中所有类型为IPAddress的属性替换为提供请求消息的属性的IPAddress值

比如说

public void Proxy(Message requestMessage)
{
    try
    {
        // Client IP address, not currently used!
        IPAddress clientIP = IPAddress.Parse((requestMessage
            .Properties[RemoteEndpointMessageProperty.Name] 
            as RemoteEndpointMessageProperty).Address);
        var factory = new ChannelFactory<IDmzProxy>("client");
        IDmzProxy dmzProxy = factory.CreateChannel();
        dmzProxy.Proxy(requestMessage);
        factory.Close();
    }

    // No leakage of data!  Any exceptions still return void!
    catch (Exception exception)
    {
        Log.Fatal(
            "Exception occurred on proxying the request",
            exception);
        return;
    }
}
编辑2

一种方法似乎是替换MessageBody的XML。对我来说,这似乎太过分了。那么WCF有什么意义呢

这也不是特别容易,因为MessageBody需要通过属性名而不是元素名来匹配元素

  <ipAddress xmlns:a="http://schemas.datacontract.org/2004/07/System.Net" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <a:m_Address>3772007081</a:m_Address>
    <a:m_Family>InterNetwork</a:m_Family>
    <a:m_HashCode>0</a:m_HashCode>
    <a:m_Numbers xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
      <b:unsignedShort>0</b:unsignedShort>
      <b:unsignedShort>0</b:unsignedShort>
      <b:unsignedShort>0</b:unsignedShort>
      <b:unsignedShort>0</b:unsignedShort>
      <b:unsignedShort>0</b:unsignedShort>
      <b:unsignedShort>0</b:unsignedShort>
      <b:unsignedShort>0</b:unsignedShort>
      <b:unsignedShort>0</b:unsignedShort>
    </a:m_Numbers>
    <a:m_ScopeId>0</a:m_ScopeId>
  </ipAddress>
编辑3

当然不是复制品,这是一个大致工作的东西,还需要一些工作来替换我要找的节点

    public void Proxy(Message requestMessage)
    {
        try
        {
            Log.Info("Received request");
            requestMessage = SourceNATMessage(requestMessage);

            // Check if there is an accepted action we have to catch
            // If the Accepted Action is set, and the action is not the same
            // then just return);)
            if (!String.IsNullOrEmpty(AcceptedAction) &&
                !requestMessage.Headers.Action.EndsWith(AcceptedAction))
            {
                Log.WarnFormat(
                    "Invalid request received with the following action {0}\n" +
                    "expected action ending with {1}",
                    requestMessage.Headers.Action,
                    AcceptedAction);
                return;
            }

            // otherwise, let's proxy the request
            Log.Debug("Proceeding with forwarding the request");
            var factory = new ChannelFactory<IDmzProxy>("client");
            IDmzProxy dmzProxy = factory.CreateChannel();
            dmzProxy.Proxy(requestMessage);
            factory.Close();
        }

        // No leakage of data!  Any exceptions still return void!
        catch (Exception exception)
        {
            Log.Fatal(
                "Exception occurred on proxying the request",
                exception);
            return;
        }
    }

    private static Message SourceNATMessage(Message message)
    {
        IPAddress clientIp =
                IPAddress.Parse(
                    ((RemoteEndpointMessageProperty)
                     message.Properties[
                         RemoteEndpointMessageProperty.Name]).Address);

        Log.DebugFormat("Retrieved client IP address {0}", clientIp);

        var stringBuilder = new StringBuilder();
        XDocument document;

        using (XmlWriter writer = XmlWriter.Create(stringBuilder))
        {
            message.WriteBody(writer);
            writer.Flush();
            document = XDocument.Parse(stringBuilder.ToString());
        }

        var deserializer = new DataContractSerializer(typeof(IPAddress));

        foreach (XElement element in
            from element in document.DescendantNodes().OfType<XElement>()
            let aNameSpace = element.GetNamespaceOfPrefix("a")
            let iNameSpace = element.GetNamespaceOfPrefix("i")
            where
                aNameSpace != null &&
                aNameSpace.NamespaceName.Equals(SystemNetNameSpace) &&
                iNameSpace != null &&
                iNameSpace.NamespaceName.Equals(XmlSchemaNameSpace) &&
                deserializer.ReadObject(element.CreateReader(), false) is IPAddress
            select element)
        {
            element.ReplaceWith(new XElement(element.Name, deserializer.WriteObject());
        }

        return Message.CreateMessage(message.Version,
                                     message.Headers.Action,
                                     document.CreateReader());
    }
编辑4

为感兴趣的人编写的工作代码,由于问题已关闭,无法作为答案发布

private static Message SourceNatMessage(Message message)
{
    IPAddress clientIp =
            IPAddress.Parse(
                ((RemoteEndpointMessageProperty)
                    message.Properties[
                        RemoteEndpointMessageProperty.Name]).Address);

    Log.DebugFormat("Retrieved client IP address {0}", clientIp);

    var stringBuilder = new StringBuilder();
    XDocument document;

    using (XmlWriter writer = XmlWriter.Create(stringBuilder))
    using (XmlDictionaryWriter dictionaryWriter =
        XmlDictionaryWriter.CreateDictionaryWriter(writer))
    {
        message.WriteBodyContents(dictionaryWriter);
        dictionaryWriter.Flush();
        document = XDocument.Parse(stringBuilder.ToString());
    }

    var deserializer = new DataContractSerializer(typeof(IPAddress));
    var clientIpXml = new StringBuilder();
    using (var xmlWriter = XmlWriter.Create(clientIpXml))
    {
        deserializer.WriteObject(xmlWriter, clientIp);
        xmlWriter.Flush();
    }

    var clientElement = XElement.Parse(clientIpXml.ToString());

    foreach (XElement element in
        from element in document.DescendantNodes().OfType<XElement>()
        let aNameSpace = element.GetNamespaceOfPrefix("a")
        let iNameSpace = element.GetNamespaceOfPrefix("i")
        where
            aNameSpace != null &&
            aNameSpace.NamespaceName.Equals(SystemNetNameSpace) &&
            iNameSpace != null &&
            iNameSpace.NamespaceName.Equals(XmlSchemaNameSpace) &&
            element.NodeType == XmlNodeType.Element
        select element)
    {
        try
        {
            deserializer.ReadObject(element.CreateReader(), false);
            element.ReplaceNodes(clientElement);
        }
        catch (SerializationException) { }
    }

    Message sourceNatMessage = Message.CreateMessage(message.Version,
                                    null,
                                    document.CreateReader());
    sourceNatMessage.Headers.CopyHeadersFrom(message);
    sourceNatMessage.Properties.CopyProperties(message.Properties);

    return sourceNatMessage;
}

只需使用自定义寻址头为SOAP消息添加注释。

在正常情况下,您不必执行类似操作。您的邮件已包含您要查找的信息

OperationContext context = OperationContext.Current;
MessageProperties messageProperties = context.IncomingMessageProperties;
RemoteEndpointMessageProperty endpointProperty = messageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;

其中客户端IP地址在endpointProperty.address属性上找到,端口在endpointProperty.port属性上找到。

使用requestMessage.properties.OfType而不是LINQ查询。@requestMessage上的abatishchev属性实际上不是消息属性。顺便说一句,上面所说的完全是虚构的…替换已检索来自客户端的值,在一个服务方法中,我知道调度程序的工作即将完成!为什么?你需要消息检查器吗?@Beygi是一种也可以收集IP地址的软件,对于某种类型的机器,我们不能完全信任它们的消息,需要用我们知道的值替换其中的一部分。@abatishchev的类型可以很好地工作。这可以由服务器端独占完成吗?没有更新DataContract,或者生成消息的客户端没有更新?该消息毕竟包含了我们所需的所有信息。可以在服务端起诉IDispatchMessageInspector来完成。不相关,我已经收到了该消息,并且我可以轻易地对其进行过度信任,因为它是一条缓冲消息。如果需要,我也可以创建自己的。那么如果您可以这样做,您还需要什么?如何将requestMessage中的属性ipAddress设置为客户端IP地址?Xml编辑是唯一的选择吗?我提到了这一点,但他真的很想修改检索到的消息……但这是代理所做的事情之一。我在DMZ有一个安全WCF服务。客户机注入的客户机IP地址可以是很多东西,1。不正确,它是一个NAT'ed IP地址,这是胡说八道,2。欺骗,是有人发送坏数据。此DMZ服务知道IP地址并替换它。在我们的网络外围内部,我不能使用MessageProperty,在负载平衡器、代理和其他ifnrastructure之间,该值在内部也是无意义的,区别在于我信任客户端在我们的网络中发送的内容。那么,在这种情况下,为什么知道IP地址并应该替换它的DMZ服务不能根据DMZ安全策略在消息中添加适当的寻址头?也许我错过了什么。。。
OperationContext context = OperationContext.Current;
MessageProperties messageProperties = context.IncomingMessageProperties;
RemoteEndpointMessageProperty endpointProperty = messageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;