[WCF] 使用Xml來Request WCF Service需注意Xml Element順序

[WCF] 使用Xml來Request WCF Service需注意Xml Element順序

前言

這兩天同事在寫Wcf REST Service的時候,遇到一個很奇怪的問題,

需求是這樣的,Request的資料型別為Xml,而Response為Json,

但在Request Xml資料時卻發現透過Wcf Deserialize之後,

Data Class的Property有些是Null的,但可以確認XML是完整送到Service端,

沒有遺漏任何訊息。

 

實際演練

接下來讓我們來重現當時的場景,

首先我們先定義一個Wcf REST Service 如下,

他可以透過Post來存取GetData Function


[ServiceContract]
public interface IService
{
    [OperationContract]    
    [WebInvoke(ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare)]    
    string GetData(Comment value);
}

並定義好Function參數的Data Class

 


[DataContract(Namespace = "")]
public class Comment
{
    [DataMember]
    public string Name { get; set; }

    [DataMember]    
    public string Body { get; set; }
}

我們使用Fiddler2來測試Post資料到Service

2011-05-09_190506

同時在Visual Studio裡面設Break point可以發現Body是Null的

2011-05-09_173607

但我們透過OperationContext.Current.RequestContext.RequestMessage可以看見,訊息是有完整收到的。

2011-05-09_190927

但如果我們改變Request Xml的順序,改成

 


<Comment>
    <Body>123</Body>
    <Name>kirk</Name>
</Comment>

再次查看可以發現,這次Property理面的資料都存在了

2011-05-09_174118 

這是因為Wcf預設的DataContractSerializer 在解析Xml時會按照字母順序塞值,

而且不是每次都從頭尋找 (像已經塞值到Name時,就不會回頭塞Body,因為N的字母順序在B之後),

若我們希望按照自己想要的順序來排放XML的話,則需要在DataMember屬性加上Order如下


[DataContract(Namespace = "")]
public class Comment
{
    [DataMember(Order=0)]
    public string Name { get; set; }

    [DataMember(Order = 1)]    
    public string Body { get; set; }
}

這樣我們就可以使用第一組XML來Request,並正確取得資料了。

 

備註:

  1. 若request和response都使用xml,我們可以在Class或Function加上XmlSerializeFormatAttribute,就可以不用擔心Xml的順序問題。
  2. 若request和response都使用json,也不需要擔心順序的問題


參考資料:

http://msdn.microsoft.com/en-us/library/ms729813.aspx

http://www.pluralsight-training.net/community/blogs/aaron/archive/2006/04/18/21950.aspx

http://stackoverflow.com/questions/2250111/does-order-matter-in-the-xml-read-by-the-datacontractserializer