2012-06-28 62 views
1

可能重复:
WCF: Data contract being converted to message contract在WCF客户端代理替换未知DataContract的属性值

我有一个通用的WCF代理,对于那些不熟悉,它是一类具有的方法与下面的OperationContract。

[OperationContract(Action = "*", ReplyAction = "*")] 
void Proxy(Message requestMessage); 

一个最近出现的要求,是我需要更换的消息,并且是类型的IPAddress的所有属性,那些提供的请求消息的ip地址值。

I.e.像,

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; 
    } 
} 

现在的问题是,如何在类ip地址的requestMessage设定的元素,我检索了clientIP?

编辑1件

事情我必须尝试和失败,

requestMessage.GetBodyAttribute("ipAddress", "http://schemas.datacontract.org/2004/07/System.Net") 

编辑2

一种方法似乎是更换消息体的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; 
} 
+0

使用'requestMessage.properties.OfType ()'而不是LINQ查询。 – abatishchev

+0

@abatishchev requestMessage属性实际上并不是消息属性btw。正如我所说的以上纯粹是由... –

+0

替换检索值从客户端,在服务方法,我知道调度员工作几乎完成!为什么?你需要信息检查员吗? – Beygi

回答

0

只需使用自定义寻址标题注释SOAP消息即可。

+0

这可以专门完成服务器端吗?没有更新DataContract,或生成消息的客户端正在更新?该消息毕竟拥有我们需要的所有信息。 –

+0

可以在服务端起诉IDispatchMessageInspector。 –

+0

不相关,我已经有消息,我可以很容易地覆盖它,因为它是一个BufferedMessage。如果需要,我也可以创建自己的。 –

0

在正常情况下,您不必这样做。您的留言已包含您正在查找的信息。

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

,其中客户端IP地址是在endpointProperty.Address财产的港口,是在endpointProperty.Port属性中找到。

+0

我提到过,但他真的很认真修改检索到的信息...... – Beygi

+0

但这是代理人所做的事情之一。我有一个位于DMZ中的“安全”WCF服务。客户端注入的客户端IP地址可能有很多,1.错误的(它是一个NAT的IP地址,这是无稽之谈),2.欺骗,其有人发送不良数据。该DMZ服务知道IP地址并将其替换。在我们网络边界的内部,我无法使用MessageProperty,在负载均衡器,代理和其他基础架构之间,这个值在内部也是无稽之谈,不同之处在于我信任客户端在我们的网络中发送的信息。 –

+0

那么在那种情况下,为什么知道IP地址并且应该替换它的DMZ服务不能在消息上添加基于DMZ安全策略的合适寻址标题?也许我错过了一些东西...... –