2010-02-05 71 views
0

我有一個WCF服務,並且無法使用DataContracts,因爲我需要更多地控制接收到的XML並將其發送到此服務。因此,我使用XmlRoot和XmlElement ...我現在遇到的問題是我的類接收xml被反序列化並且序列化的響應都需要具有相同的根名稱,並且當我嘗試設置這兩個類與:WCF,XmlRoot和可選參數

[XmlRoot(ElementName = "myRoot")] 

我得到一個錯誤,說已經使用了根名稱。有這個簡單的解決方法嗎?我試圖把我的響應類放在一個單獨的命名空間中,但似乎沒有工作。

如果一些變量沒有在我的響應類中被設置爲序列化,那麼我不會讓它們被序列化並返回響應中...有沒有一個選項我錯過了這麼做.. 。我可以用DataContract做到這一點,但不能用XmlElements來解決它。

+0

同樣的問題,必須有辦法做到這一點.. – 2010-07-28 14:28:37

+0

有類似的問題「不能做」回答:http://stackoverflow.com/questions/2417721/wcf-contracts-namespaces-and-serializationexceptions – 2010-07-28 14:31:29

回答

0

實現此目的的一種方法是攔截XML響應,並在反序列化之前將根元素名稱更改爲唯一。這可以通過自定義的IClientMessageFormatter和操作的關聯屬性輕鬆完成。

我只寫了這件事,所以「油漆未乾」和所有的,但在這裏是什麼樣子:

/// <summary> 
/// An operation attribute that changes the XML root name in responses 
/// </summary> 
/// <example> 
///  
/// [ServiceContract] 
/// [XmlSerializerFormat] 
/// public interface IRedBlueServiceApi 
/// { 
///  [OperationContract] 
///  [WebGet(...)] 
///  [XmlChangeRoot("RedResponse")] 
///  RedResponse GetRed(); 
/// 
///  [OperationContract] 
///  [WebGet(...)] 
///  [XmlChangeRoot("BlueResponse")] 
///  BlueResponse GetBlue(); 
/// } 
/// 
/// [XmlRoot("RedResponse")] 
/// public class RedResponse 
/// {...} 
/// 
/// [XmlRoot("BlueResponse")] 
/// public class BlueResponse 
/// {...} 
/// </example> 
[DefaultProperty("NewRootElementName")] 
public class XmlChangeRootAttribute : Attribute, IOperationBehavior 
{ 
    public XmlChangeRootAttribute(string newRootElementName) 
    { 
     NewRootElementName = newRootElementName; 
    } 

    public string NewRootElementName { get; set; } 

    #region IOperationBehavior Members 

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) 
    { 
     // Inject our xml root changer into the client request/response pipeline 
     clientOperation.Formatter = new XmlRootChangeFormatter(clientOperation.Formatter, NewRootElementName); 
    } 

    #endregion 

    #region Unrelated Overrides 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 
    { 
    } 

    public void AddBindingParameters(OperationDescription operationDescription, 
            BindingParameterCollection bindingParameters) 
    { 
    } 

    public void Validate(OperationDescription operationDescription) 
    { 
    } 

    #endregion 
} 

/// <summary> 
/// A simple wrapper around an existing IClientMessageFormatter 
/// that alters the XML root name before passing it along 
/// </summary> 
public class XmlRootChangeFormatter : IClientMessageFormatter 
{ 
    private readonly IClientMessageFormatter _innerFormatter; 
    private readonly string _newRootElementName; 

    public XmlRootChangeFormatter(IClientMessageFormatter innerFormatter, string newRootElementName) 
    { 
     if (innerFormatter == null) 
      throw new ArgumentNullException("innerFormatter"); 

     if (String.IsNullOrEmpty(newRootElementName)) 
      throw new ArgumentException("newRootElementName is null or empty"); 

     _innerFormatter = innerFormatter; 
     _newRootElementName = newRootElementName; 
    } 

    #region IClientMessageFormatter Members 

    public Message SerializeRequest(MessageVersion messageVersion, object[] parameters) 
    { 
     return _innerFormatter.SerializeRequest(messageVersion, parameters); 
    } 

    public object DeserializeReply(Message message, object[] parameters) 
    { 
     if (!message.IsEmpty) 
     { 
      var doc = XDocument.Load(message.GetReaderAtBodyContents()); 

      if (doc.Root == null) 
       throw new SerializationException("Could not find root in WCF messasge " + message); 

      // Change the root element name 
      doc.Root.Name = _newRootElementName; 

      // Create a new 'duplicate' message with the modified XML 
      var modifiedReply = Message.CreateMessage(message.Version, null, doc.CreateReader()); 
      modifiedReply.Headers.CopyHeadersFrom(message.Headers); 
      modifiedReply.Properties.CopyProperties(message.Properties); 

      message = modifiedReply; 
     } 

     return _innerFormatter.DeserializeReply(message, parameters); 
    } 

    #endregion 
} 
這裏