关于数据契约(DataContract)待续
前兩天做程序時(shí)建一個(gè)類(lèi)來(lái)要實(shí)例化一些數(shù)據(jù)的處理時(shí)遇到的一個(gè)問(wèn)題,
人懶了一下,就復(fù)制了以前的一部分代碼,由于漏掉了DataContract的服務(wù)契約,程序執(zhí)行時(shí)報(bào)錯(cuò)。
雖然找到錯(cuò)在哪,但對(duì)于DataContract不太懂,就在網(wǎng)上查了一下。
介紹的版本比較多暫時(shí)找了三個(gè)版本都復(fù)制過(guò)來(lái),表示能力確實(shí)不咋滴,就等我在研究透徹點(diǎn)在寫(xiě)讀書(shū)筆記(兩天時(shí)間內(nèi)會(huì)修改總結(jié))。
容我偷懶兩天
這是“在路上”微博的版本:
WCF第一要素就是契約:
服務(wù)契約用于聲明可用于遠(yuǎn)程訪問(wèn)的類(lèi)型。在Interface或class開(kāi)始處使用服務(wù)契約標(biāo)簽.
[ServiceContract]
Public interface Iservice
{
?
}
接口調(diào)用契約的好處:
1.???????同一服務(wù)類(lèi)型可以實(shí)現(xiàn)多個(gè)不相干的服務(wù)契約.
2.???????有利于版本升級(jí)
3.???????按照接口隔離原則,讓開(kāi)發(fā)人員可以隨時(shí)修改服務(wù)契約.
服務(wù)契約的屬性與作用:
Name/Namespace定義該服務(wù)契約的自定義名稱(chēng)和命名空間,它會(huì)反映到WSDL及客戶(hù)端的導(dǎo)出類(lèi)中
ConfigurationName設(shè)置信息在配置文件中的名稱(chēng)。默認(rèn)情況下為類(lèi)的全名(本例為“WCFDemo.IService”)。
SessionMode服務(wù)契約的會(huì)話(huà)方式,允許的值有Allowed、NotAllowed和Required。默認(rèn)為Allowed值。
CallbackContract設(shè)置雙工通信時(shí)(Duplex)的回調(diào)類(lèi)型。
ProtectionLevel指定消息保護(hù)模式,可以對(duì)通信的消息進(jìn)行加密及簽名。
使用參數(shù)時(shí),例如要指定自定義的Name和?Namespace,可以編寫(xiě)如下的代碼。
[ServiceContract(Name=”MyService”,Namespace=”http://microsoft.com/wcf/demo”)]
Interface IService{}
定義為服務(wù)契約的接口或類(lèi)的方法可以被聲明為OperationContract(操作契約),只有聲明為操?作契約的方法才可以被遠(yuǎn)程調(diào)用
[ServiceContract]
Public interface Iservice
{
?????? [OperationContract]
?????? String SayHello(string name);
}
?
錯(cuò)誤契約(FaultContract)
被標(biāo)識(shí)為FaultContract的方法必須同時(shí)已經(jīng)被聲明為OperationContract,否則就沒(méi)有什么意義。聲明一個(gè)方法為?FaultContract并指定了響應(yīng)的類(lèi)型參數(shù)以后,當(dāng)調(diào)用這個(gè)方法時(shí)產(chǎn)生錯(cuò)誤時(shí),就會(huì)有一個(gè)對(duì)應(yīng)SOAP格式的錯(cuò)誤消息返回給調(diào)用端
[DataContract]
public class UserFault //自定義錯(cuò)誤類(lèi)
{
??????? [DataMember]
??????? public string Message { get; set; }
??????? [DataMember]
??????? public int UserId { get; set; }
??????? public UserFault(int userId, string msg)
??????? {
??????????? this.UserId = userId;
??????????? this.Message = msg;
??????? }
}
? [ServiceContract]
? public interface IUserService
? {
??????? [OperationContract]
??????? [FaultContract(typeof(UserFault))]
??????? UserInfo GetUser(int id);
? }
? public UserInfo GetUser(int id)
? {
???? try{
??????????? UserInfo info = new UserInfo();
??????????? info.Age = 16;
??????????? info.UserName = "陳翔";
??????????? return info;
??????? }
??????? catch (Exception e)
??????? {
??????????? throw new FaultException<UserFault>(new UserFault(id, e.Message));
??????? }
? }
?
數(shù)據(jù)契約(DataContract)
[DataContract]
?????? public partial class Userinfo
?????? {????
????????????? private string _xsid = String.Empty;
?????????????
????????????? /// <summary>
????????????? ///?學(xué)生編號(hào)
????????????? /// </summary>
????????????? [DataMember(Name="xsid")]
????????????? public string Xsid
????????????? {
???????????????????? get { return _xsid; }
???????????????????? set { _xsid = value; }
????????????? }
???????}
服務(wù)契約定義了遠(yuǎn)程訪問(wèn)對(duì)象和可供調(diào)用的方法,數(shù)據(jù)契約則是服務(wù)端和客戶(hù)端之間要傳送的自定義數(shù)據(jù)類(lèi)型。
一個(gè)類(lèi)如果聲明了DataContract類(lèi)型,說(shuō)明類(lèi)是可以被傳送的,且只有成員屬性可以被傳送.支持Name/Namespace屬性[DataContract(Name=”Name”)]
每一個(gè)要傳送的成員聲明為DataMember類(lèi)型,同樣也可以包含Name,Namespace,IsRequired,Order,EmitDefaultvalue屬性
需要傳送SOAP消息時(shí)可以使用[MessageContract] eg:
[MessageContract]
?????? public partial class Userinfo
?????? {????
????????????? private string _xsid = String.Empty;
????????????? private string _njid = String.Empty;
????????????? /// <summary>
????????????? ///?學(xué)生編號(hào)
????????????? /// </summary>
????????????? [MessageBodyMember(
Name="xsid"
Namespace=”http://www.smodi.com”)]
????????????? public string Xsid
????????????? {
???????????????????? get { return _xsid; }
???????????????????? set { _xsid = value; }
????????????? }
?????????????
????????????? /// <summary>
????????????? ///?年級(jí)編號(hào)
????????????? /// </summary>
????????????? [MessageHeader(
Name="njid"
Namespace=”http://www.smodi.com”)]
????????????? public string Njid
????????????? {
???????????????????? get { return _njid; }
???????????????????? set { _njid = value; }
????????????? }
???????}
這個(gè)可以生成SOAP消息
<s:Envelope>
??? <s:Header>
??????? <a:Action s:mustUnderstand="1">http:// Userinfo /Action</a:Action>
??? ????<h:AuthKey s:mustUnderstand="1" xmlns:h="http://www.smodi.com">xxxx</h:AuthKey>
??? </s:Header>
??? <s:Body>
??????? <UserMessage xmlns="Microsoft.WCF.Documentation">
??? ?????????<User xmlns="http://www.smodi.com">abcd</User>
???????</UserMessage>
??? </s:Body>???
</s:Envelope>
?
?
?
這個(gè)是子夜微博的版本:
服務(wù)契約定義了遠(yuǎn)程訪問(wèn)對(duì)象和可供調(diào)用的方法,數(shù)據(jù)契約則是服務(wù)端和客戶(hù)端之間要傳送的自定義數(shù)據(jù)類(lèi)型。
一旦聲明一個(gè)類(lèi)型為DataContract,那么該類(lèi)型就可以被序列化在服務(wù)端和客戶(hù)端之間傳送,如下所示。
????? [DataContract]
???? public class UserInfo
???? {
????????? //….
}
只有聲明為DataContract的類(lèi)型的對(duì)象可以被傳送,且只有成員屬性會(huì)被傳遞,成員方法不會(huì)被傳遞。WCF對(duì)聲明為DataContract的類(lèi)型提供更加細(xì)節(jié)的控制,可以把一個(gè)成員排除在序列化范圍以外,也就是說(shuō),客戶(hù)端程序不會(huì)獲得被排除在外的成員的任何信息,包括定義和數(shù)據(jù)。默認(rèn)情況下,所有的成員屬性都被排除在外,因此需要把每一個(gè)要傳送的成員聲明為DataMember,如下所示。
??? [DataContract]
??? public class UserInfo
??? {
??????? [DataMember]
??????? public string UserName
??????? {
??????????? get;
??????????? set;
??????? }
??????? [DataMember]
??????? public int Age
??????? {
??? ????????get;
??????????? set;
??????? }
??????? [DataMember]
??????? public string Location
??????? {
??????????? get;
??????????? set;
??????? }
??????? public string Zodiac
??????? {
??????????? get;
??????????? set;
??????? }
}
上面這段代碼把UserInfo類(lèi)聲明為DataContract,將UserName、Age、Location這3個(gè)屬性聲明為DataMember(數(shù)據(jù)成員)。Zodiac成員沒(méi)有被聲明為DataMember,因此在交換數(shù)據(jù)時(shí),不會(huì)傳輸Zodiac的任何信息。
DataContract也支持Name/Namespace屬性,如同ServiceContract,Name和Namespace可以自定義名稱(chēng)和命名空間,客戶(hù)端將使用自定義的名稱(chēng)和命名空間對(duì)DataContract類(lèi)型進(jìn)行訪問(wèn)。
聲明為DataMember的成員也可以自定義客戶(hù)端可見(jiàn)的名稱(chēng),例如:
[DataMember(Name="Name")]
public string UserName
{
???? get;
???? set;
}
[DataMember(Name="Age")]
public int UserAge
{
????????? get;
????????? set;
}
除了Name和Namespace以外,DataMember還有以下參數(shù),它們的含義分別如下。
(1)IsRequired:值為true時(shí),要求序列化引擎檢查對(duì)象是否存在該值;若無(wú),則會(huì)有異常拋出。
(2)Order:bool類(lèi)型值,值為true時(shí),序列化和反序列化過(guò)程將會(huì)按成員定義的順序進(jìn)行,這對(duì)依賴(lài)于成員位置的反序列化過(guò)程無(wú)比重要。
(3)EmitDefaultvalue:為成員屬性設(shè)置一個(gè)默認(rèn)值。
一般情況下,將類(lèi)型聲明為DataContract就可以滿(mǎn)足傳送的需求了,不過(guò)特殊情況是難以避免的,這時(shí)就需要對(duì)要傳送的SOAP消息進(jìn)行更加精確的控制,MessageContract可以滿(mǎn)足這種需求。
把一個(gè)類(lèi)型聲明為MessageContract,意味著它可以被序列化為SOAP消息,可以聲明類(lèi)型的成員為SOAP消息的各個(gè)部分,如Header、Body等,如下所示。
?? ?[MessageContract]
??? public class UserMessage
??? {
??????? private string user = String.Empty;
??????? private string authKey = String.Empty;
??????? [MessageBodyMember(
????????? Name = "UserName",
????????? Namespace = "http://www.wcf.com")]
??????? public string User
??????? {
??????????? get { return user; }
??????????? set { user = value; }
??????? }
??????? [MessageHeader(
????????? Name = "AuthKey",
????????? Namespace = "http://www.wcf.com",
????????? MustUnderstand = true
??????? )]
??????? public string AuthKey
??????? {
??????????? get { return authKey; }
??????????? set { this.authKey = value; }
??????? }
}
User成員被聲明為MessageBody(消息體)的一個(gè)成員,AuthKey被聲明為消息頭(MessageHeader)的一個(gè)成員。這個(gè)類(lèi)將可以生成如下的SOAP消息。
<s:Envelope>
??? <s:Header>
??????? <a:Action s:mustUnderstand="1">http://UserMessage/Action</a:Action>
??? ????<h:AuthKey s:mustUnderstand="1" xmlns:h="http://www.wcf.com">xxxx</h:AuthKey>
??? </s:Header>
??? <s:Body>
??????? <UserMessage xmlns="Microsoft.WCF.Documentation">
??? ?????????<User xmlns="http://www.wcf.com">abcd</User>
?????? </UserMessage>
??? </s:Body>???
</s:Envelope>
?
MessageHeader中,MustUnderstand參數(shù)表示讀取該頭的程序必須能夠識(shí)別頭的內(nèi)容,否則不能繼續(xù)處理。Name/Namespace的作用與前面的元素相同。另有Relay參數(shù),若為true,頭的內(nèi)容被接收到以后會(huì)在響應(yīng)消息中回發(fā)給消息發(fā)送端。
?
?
下面是51CTO 的版本:
WCF Data Contract之集合類(lèi)型
在.Net中將實(shí)現(xiàn)了IEnumerable接口的所有類(lèi)型(包括數(shù)組和泛型)都稱(chēng)之為集合類(lèi)型。把其中實(shí)現(xiàn)了IDictionary接口或泛型IDictionary接口的集合類(lèi)型稱(chēng)為字典集合,剩下的其他集合類(lèi)型為列表集合。
1、集合的數(shù)據(jù)契約(協(xié)定)缺省名稱(chēng)??????
缺省情況下,WCF框架對(duì)集合類(lèi)型是內(nèi)建支持的,也就說(shuō)你不需要應(yīng)用任何屬性,就可以將集合應(yīng)用在數(shù)據(jù)契約(協(xié)定)中,但前提是集合中的元素必須是應(yīng)用了DataContractAttribute屬性或者是可序列化的類(lèi)型。這時(shí),數(shù)據(jù)契約(協(xié)定)名稱(chēng)和命名空間就依賴(lài)集合中包含的元素的類(lèi)型的名稱(chēng)和命名空間了,它們不受集合類(lèi)型本身的名稱(chēng)和命名空間的影響。
缺省集合類(lèi)型數(shù)據(jù)契約(協(xié)定)的格式是(不包括“+”):
列表集合:
名稱(chēng):ArrayOf+集合中包含的元素類(lèi)型
循環(huán)元素名稱(chēng):集合中包含的元素類(lèi)型
字典集合:
??? 名稱(chēng):ArrayOfKeyValueOf+集合中Key的類(lèi)型+集合中包含的對(duì)象類(lèi)型
循環(huán)元素名稱(chēng):KeyValueOf+集合中Key的類(lèi)型+集合中包含的對(duì)象類(lèi)型
例如:
MyCollection1 : IList{…}的數(shù)據(jù)契約名稱(chēng)就是:ArrayOfint
MyCollection2 : ICollection{…}的數(shù)據(jù)契約名稱(chēng)就是:ArrayOfint
MyDictionary1 : Dictionary<int, int="">{…}的數(shù)據(jù)契約名稱(chēng)就是:ArrayOfKeyValueOfintint
MyCollection3 : ArrayList{…}的數(shù)據(jù)契約名稱(chēng)就是:ArrayOfanyType
MyDictionary2 : Dictionary<int, object="">{…}的數(shù)據(jù)契約名稱(chēng)就是:ArrayOfKeyValueOfintanyType
注意:如果是object的話(huà),使用的是anyType,因?yàn)樵赟chema中所有類(lèi)型的基類(lèi)是anyType。
如果集合是應(yīng)用于某個(gè)數(shù)據(jù)契約類(lèi)型中時(shí),那么它的名稱(chēng)將是字段名稱(chēng),如下面Customer的定義以及序列化后的表示:
?
| [DataContract] <Customer xmlns:i="http://www.w3.org/2001/XMLSchema-instance" <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:string">010-82371234</d2p1:Value> </d2p1:KeyValueOfintanyType> <d2p1:Value xmlns:d4p1="http://www.w3.org/2001/XMLSchema" i:type="d4p1:string">021-56781234</d2p1:Value> </d2p1:KeyValueOfintanyType> |
?
?
?
?
2、集合的契約等價(jià)
在WCF中應(yīng)用了CollectionDataContractAttribute屬性的集合稱(chēng)之為定制數(shù)據(jù)契約集合,否則為非定制數(shù)據(jù)契約集合。不管是非定制數(shù)據(jù)契約集合還是定制數(shù)據(jù)契約集合,只要它們的數(shù)據(jù)契約名稱(chēng)和循環(huán)元素的名稱(chēng)都相同(如果是字典集合其Key和Value也要是相同的),我們就說(shuō)它們是等價(jià)的。由于非定制數(shù)據(jù)契約集合的數(shù)據(jù)契約以及循環(huán)元素的名稱(chēng)由集合中的類(lèi)型決定,所以非定制數(shù)據(jù)契約集合的數(shù)據(jù)契約等價(jià)遵守以下幾個(gè)規(guī)則(關(guān)于數(shù)據(jù)契約等價(jià)的其他詳細(xì)信息請(qǐng)參見(jiàn)我以前的文章:WCF Data Contract之契約等價(jià)):
2.1、相同類(lèi)型的列表集合被認(rèn)為具有相同的數(shù)據(jù)契約(協(xié)定)例如:List和int[]是等價(jià)的。
2.2、具有相同相同鍵和值類(lèi)型的所有字典集合也被視為具有相同的數(shù)據(jù)契約(協(xié)定)
2.3、接口和實(shí)現(xiàn)該接口的具體集合類(lèi)的數(shù)據(jù)契約是等價(jià)的。例如IList和List等價(jià)。
2.4、非泛型集合與Object類(lèi)型的泛型集合的數(shù)據(jù)契約等價(jià)。例如:List<Object>與ArrayList等價(jià),ArrayList與Object[]也是等價(jià)的。
這就是為什么上面的示例中,實(shí)現(xiàn)IList和ICollection的集合類(lèi)型的數(shù)據(jù)契約名稱(chēng)都是ArrayOfint的原因。例如下面兩個(gè)數(shù)據(jù)契約是等價(jià)的:
?
| [DataContract(Name="Customer")] public class Customer1 { [DataMember] public string customerName; [DataMember] public Collection<string> addresses; [DataMember] public string[] telephones; } [DataContract(Name="Customer")] public class Customer2 { [DataMember] public string customerName; [DataMember] public ICollection<string> addresses; [DataMember] public List<string> telephones; } |
?
注意:Collection和ICollection是等價(jià)的,同時(shí)string[]和List也是等價(jià)的。
所以,針對(duì)Customer2的定義,我們可以將實(shí)現(xiàn)ICollection接口的任何集合類(lèi)的實(shí)例賦給addresses。同樣,我們也可以利用在數(shù)據(jù)契約中定義集合接口的機(jī)制來(lái)將WCF不支持的集合類(lèi)型(如:ReadOnlyCollection,具體見(jiàn)本文中WCF中對(duì)集合類(lèi)型的要求限制一節(jié))來(lái)應(yīng)用到我們的WCF應(yīng)用中。也就是說(shuō)我們可以將ReadOnlyCollection的實(shí)例賦給Customer2的addresses。
?
3、集合與KnowType
集合類(lèi)型和非集合類(lèi)型在多態(tài)增加KnowType類(lèi)型方面是不同的,關(guān)于非集合方面增加KnowType的詳細(xì)情況請(qǐng)我以前的文章:WCF Data Contract之KnowType。集合類(lèi)型在增加KnowType類(lèi)型遵守以下規(guī)則:
3.1、集合類(lèi)型是以多態(tài)方式來(lái)代替其他集合或集合接口的,您不需要將這樣的集合類(lèi)型添加到KnowType類(lèi)型中。例如上例中Customer2類(lèi)中的addresses,你可以將List的實(shí)例賦值給它,而不需要將List增加到KnowType類(lèi)型列表中。
3.2、當(dāng)您以多態(tài)方式使用集合來(lái)代替非集合類(lèi)型時(shí),則需要將它們添加到已知類(lèi)型。 例如,如果您聲明一個(gè) Object 類(lèi)型的數(shù)據(jù)成員并將其用于發(fā)送 ArrayList 的一個(gè)實(shí)例,則需要將 ArrayList 添加到已知類(lèi)型中。
3.3、等價(jià)的集合只能應(yīng)用KnowTypeAttribute屬性來(lái)將其增加到KnowType列表中一次。例如:不能將ArrayList和Object[]都添加到相同類(lèi)的KnowType列表中
4、定制集合的數(shù)據(jù)契約(協(xié)定)??????
我們可以使用CollectionDataContractAttribute的下列屬性來(lái)指定集合的數(shù)據(jù)契約的相關(guān)名稱(chēng)及命名空間:
4.1、Name屬性來(lái)指定集合數(shù)據(jù)契約的名稱(chēng)(如果沒(méi)有使用此屬性,將使用集合類(lèi)型的名稱(chēng))
4.2、Namespace屬性來(lái)指定其命名空間
4.3、ItemName 屬性來(lái)指定循環(huán)元素的名稱(chēng)
4.4、針對(duì)字典集合還可以用KeyName和ValueName來(lái)指定鍵和值的名稱(chēng)
例如,我們將第一節(jié)的例子更改成如下所示:
?
| [CollectionDataContract(Name = " telephones", ItemName = "telephone", KeyName = "Index", ValueName = "Number")] public class MyDictionary : Dictionary<int, object=""> { public new Dictionary<int,object>.Enumerator GetEnumerator() { Dictionary<int, object=""> innerObject = new Dictionary<int, object=""> { { 1, "010-82371234" }, { 2, "021-56781234" } }; return innerObject.GetEnumerator(); } } |
?
此類(lèi)將被序列化成:
?
| http://schemas.datacontract.org/2004/07/WCFTestSerializer"> ? 1 010-82371234 ? ? 2 021-56781234 |
?
對(duì)于定制數(shù)據(jù)契約的集合類(lèi)型來(lái)說(shuō),前面所述的非定制數(shù)據(jù)契約的集合等價(jià)規(guī)則將失效。所以要盡量避免使用CollectionDataContractAttribute。
5、集合的反序列化
缺省情況下,使用Svcutil.exe生成客戶(hù)端代理時(shí),列表集合將反序列化成數(shù)組,字典集合將反序列化成Dictionary泛型。我們也可以通過(guò)/collectionType 命令行開(kāi)關(guān)(簡(jiǎn)寫(xiě)形式是 /ct)來(lái)指定我們希望反序列化的集合類(lèi)型(請(qǐng)記住,您還必須使用 /reference 開(kāi)關(guān)(簡(jiǎn)寫(xiě)形式是 /r)指定引用的集合類(lèi)型的程序集)。如果該類(lèi)型是泛型,則必須在類(lèi)型后面跟有反引號(hào)和泛型參數(shù)的數(shù)目。例如前面的例子中的Customer1類(lèi)可以通過(guò)下面的命令在客戶(hù)端使用List泛型:SvcUtil http://localhost:8000/?。
?
| /r:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.dll /ct:System.Collections.Generic.List`1 |
?
6、DataContractAttribute和CollectionContractAttribute??????
對(duì)于集合而言,WCF框架將隱含地自動(dòng)的為集合類(lèi)型應(yīng)用CollectionDataContractAttribute屬性的,這就是為什么你不需要為集合應(yīng)用任何屬性就可以在數(shù)據(jù)契約中使用的原因。但要注意:
(1)如果我們新建的集合類(lèi)型是繼承已有的集合類(lèi)型如List,那么我們就不能對(duì)新建的集合類(lèi)型應(yīng)用DataContractAttribute,否則運(yùn)行時(shí)會(huì)拋出InvalidDataContractException,但你可以應(yīng)用CollectionDataContractAttribute來(lái)定制集合類(lèi)型的數(shù)據(jù)契約。例如[DataContract]public class MyList:List{…}的集合定義將拋出異常。
(2)如果我們新建的集合類(lèi)型是實(shí)現(xiàn)了集合接口例如IList,IDictionary<int,int>的話(huà),我們可以對(duì)此類(lèi)型應(yīng)用DataContractAttribute屬性,這樣的話(huà)此類(lèi)型將作為普通的數(shù)據(jù)契約類(lèi)型,而不是將其作為集合類(lèi)型來(lái)處理。也就是WCF框架將只序列化其中應(yīng)用了DataMemberAttribute屬性的成員。當(dāng)然你也可以不應(yīng)用任何屬性來(lái)讓系統(tǒng)缺省作為集合類(lèi)型來(lái)處理。(你也可以使用CollectionDataContractAttribute來(lái)定制數(shù)據(jù)契約)
(3)針對(duì)應(yīng)用CollectionDataContractAttribute屬性或者缺省不應(yīng)用任何屬性的集合類(lèi)型,如果其內(nèi)部有應(yīng)用了DataMemberAttribute的屬性或字段,在序列化時(shí)系統(tǒng)將忽略。
7、WCF中對(duì)集合類(lèi)型的要求限制
不是所有的集合類(lèi)型都可以在WCF中使用,只有滿(mǎn)足以下要求才可以使用:
7.1、該集合類(lèi)型有一個(gè)缺省的構(gòu)造函數(shù)
7.2、該集合類(lèi)型有一個(gè)名為Add的方法
這是因?yàn)樵诜葱蛄谢项?lèi)型時(shí),WCF框架首先調(diào)用該集合類(lèi)型的無(wú)參數(shù)的構(gòu)造函數(shù),然后通過(guò)非靜態(tài)的Add方法來(lái)將循環(huán)元素增加到集合中。所以以上限制主要是針對(duì)反序列化而設(shè)定的。
8、集合中的一些高級(jí)規(guī)則
8.1、WCF框架在序列化時(shí)支持集合的集合,也支持?jǐn)?shù)組的數(shù)組(交錯(cuò)數(shù)組),但不支持多唯數(shù)組。
8.2、字節(jié)數(shù)組和 XmlNode 數(shù)組是特殊的數(shù)組類(lèi)型,將被視為基元,而不是集合。 序列化字節(jié)數(shù)組會(huì)產(chǎn)生單個(gè)包含一個(gè) Base64 編碼數(shù)據(jù)塊的 XML 元素,而不是為每個(gè)字節(jié)都生成一個(gè)單獨(dú)的元素。(筆者認(rèn)為這是為了性能的考慮才這么處理的。)
8.3、如果集合類(lèi)型實(shí)現(xiàn)了IXMLSerializable接口,假設(shè)類(lèi)型為MyType:IList,IXMLSerializable{…},WCF框架將根據(jù)在數(shù)據(jù)契約中聲明的類(lèi)型來(lái)進(jìn)行序列化,如果聲明的是集(接口)如IList,那么該類(lèi)型將被認(rèn)為是列表集合來(lái)序列化,如果聲明的是IXMLSerializable,那么將按照IXMLSerializable來(lái)進(jìn)行序列化,當(dāng)然需要將該類(lèi)型加到KnowType類(lèi)型列表中。如果聲明的是該類(lèi)型本身(如MyType),那么將按照IXMLSerializable的規(guī)則來(lái)進(jìn)行序列化。
8.4、在對(duì)集合進(jìn)行序列化時(shí),將調(diào)用集合類(lèi)的GetEnumerator 方法來(lái)得到集合的內(nèi)容,在反序列化時(shí)將首先調(diào)用該集合類(lèi)型的無(wú)參數(shù)的構(gòu)造函數(shù),然后通過(guò)非靜態(tài)的Add方法來(lái)將循環(huán)元素增加到集合中。(注:雖然這與大家在MSDN的幫助文檔中看到的不同,認(rèn)為字典集合將調(diào)用get_Keys和get_Values,以及IList將調(diào)用索引器,但筆者使用VS2008驗(yàn)證時(shí)沒(méi)有得到以上方法被調(diào)用的結(jié)論,所以筆者認(rèn)為是MSDN文檔滯后或有誤,如果各位看官能得到和MSDN吻合的結(jié)論麻煩告訴一聲。)
8.5、如果集合類(lèi)型同時(shí)應(yīng)用了Serialized屬性或?qū)崿F(xiàn)了ISerializable接口,WCF框架將忽略它們;但是如果集合類(lèi)型不滿(mǎn)足集合類(lèi)型要求(例如缺少Add)方法,那么將按照Serialized或ISerializable來(lái)處理;但如果你對(duì)該集合同時(shí)應(yīng)用了CollectionDataContract屬性而且又不滿(mǎn)足集合要求,那么將拋出InvalidDataContractException,而不是按照Serialized或ISerializable來(lái)處理。
8.6、不能向?qū)崿F(xiàn)了IXmlSerializable接口的類(lèi)型使用CollectionDataContractAttribute屬性,否則會(huì)拋出InvalidDataContractException.向非集合應(yīng)用CollectionDataContractAttribute屬性以及非字典集合指定KeyName或者ValueName屬性也都將拋出此異常。
轉(zhuǎn)載于:https://www.cnblogs.com/yaoyao-li/archive/2013/03/18/2966520.html
總結(jié)
以上是生活随笔為你收集整理的关于数据契约(DataContract)待续的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: static_cast, dynamic
- 下一篇: cursor_sharing='SIMI