WCF數(shù)據(jù)契約變更基本應(yīng)用技巧分析
在WCF中,數(shù)據(jù)契約的應(yīng)用是一個(gè)十分重要而且基礎(chǔ)的操作技術(shù)。那么今天我們將會(huì)在這篇文章中為大家詳細(xì)講解一下有關(guān)WCF數(shù)據(jù)契約變更的相關(guān)知識(shí),以方便大家在實(shí)際應(yīng)用中獲得一些幫助。#t#
Person DataContract 定義了兩個(gè)屬性:FirstName 和LastName。如果客戶端引用了這個(gè)服務(wù),而你后來(lái)將LastName改成SurName,實(shí)際上客戶端不會(huì)中斷,但是在客戶端的代理類上的LastName屬性會(huì)顯示為空的。這是因?yàn)楫?dāng)客戶端解串信息到Person類的時(shí)候,不會(huì)找到任何叫做Lastname的元素。
這個(gè)簡(jiǎn)單的WCF數(shù)據(jù)契約變更不會(huì)引起客戶端的錯(cuò)誤,但它會(huì)導(dǎo)致更嚴(yán)重的問(wèn)題:一個(gè)意外的行為。這個(gè)錯(cuò)誤很容易跟蹤,但是跟蹤變更行為是非常困難的。
這個(gè)簡(jiǎn)單的例子說(shuō)明為什么任何服務(wù)變更和它們后續(xù)的影響是至關(guān)重要的。除非你自己知道利用你的web服務(wù)的每個(gè)客戶端應(yīng)用程序,否則變更會(huì)是個(gè)災(zāi)難。作為一名開(kāi)發(fā)人員,你需要盡一切努力使你的客戶端避免變更的出現(xiàn)。
首先,你可以應(yīng)用一些***的方法來(lái)幫助客戶端免于內(nèi)部變更。WCF數(shù)據(jù)契約變更的更新版本如以下所示:
- [DataContract(Namespace="http://types.mycompany.com/2009/05/25",
Name="PersonContract")]- public class Person : IExtensibleDataObject
- {
- private string _firstName = string.Empty;
- private string _lastName = string.Empty;
- private ExtensionDataObject _extensionData;
- [DataMember(Name="FirstName")]
- public string FirstName
- {
- get { return _firstName; }
- set { _firstName = value; }
- }
- [DataMember(Name="LastName")]
- public string LastName
- {
- get { return _lastName; }
- set { _lastName = value; }
- }
- public ExtensionDataObject ExtensionData
- {
- get { return _extensionData; }
- set { _extensionData = value; }
- }
- }
在DataContract上增加的Namespace, Name和Order參數(shù)以及DataMember屬性控制DataContractSerializer的行為。當(dāng)服務(wù)的reference被添加的時(shí)候,這個(gè)增加的東西生成客戶端代理。Name參數(shù)讓serializer使用所指出的值,而不是實(shí)際公布的成員或是屬性的名字。這個(gè)方法在沒(méi)有影響客戶端的情況下允許變更的內(nèi)部執(zhí)行。例如,考慮以下的WCF數(shù)據(jù)契約變更:
- [DataMember(Name="LastName")]
- public string SurName
- {
- get { return _lastName; }
- set { _lastName = value; }
- }
將"FirstName" 改成"SurName"的屬性名字變更不會(huì)中斷現(xiàn)有的客戶端,因?yàn)榭蛻舳耸褂玫腘ame參數(shù)仍然是"FirstName."。只是內(nèi)部執(zhí)行被該改變了。
第二個(gè)顯著的變化是增加了IExtensibleDataObject接口。執(zhí)行這個(gè)接口允許客戶端保留在契約中沒(méi)有明確定義的數(shù)據(jù)。這似乎看上去沒(méi)什么用,但是在客戶端希望執(zhí)行示例Person對(duì)象并返回它的情況下,客戶端可以保留新的數(shù)據(jù)項(xiàng)目。例如,用以下不會(huì)強(qiáng)迫現(xiàn)有的客戶端進(jìn)行更新的新成員來(lái)更新PersonContract:
- [DataMember(Name = "MiddleName", Order = 3)]
- public string SurName
- {
- get { return _middleName; }
- set { _middleName = value; }
- }
實(shí)際上,這個(gè)成員通過(guò)往返過(guò)程的服務(wù),允許現(xiàn)存的客戶端保留放在"MiddleName"中的值。執(zhí)行IExtensibleDataObject對(duì)你的WCF數(shù)據(jù)契約變更未來(lái)的論證是一個(gè)有益的方法。
請(qǐng)記住,實(shí)際上客戶端對(duì)一個(gè)外部構(gòu)架有驗(yàn)證信息的選擇權(quán)。(對(duì)WCF應(yīng)用程序添加信息構(gòu)架驗(yàn)證的詳細(xì)討論,請(qǐng)閱讀此文章this article)。因此,當(dāng)處理數(shù)據(jù)契約的變更時(shí)你有兩種情況需要考慮:有構(gòu)架驗(yàn)證和沒(méi)有構(gòu)架驗(yàn)證。
當(dāng)客戶端添加構(gòu)架驗(yàn)證的時(shí)候,在數(shù)據(jù)契約中進(jìn)行添加,變更或是減去任何項(xiàng)目將導(dǎo)致驗(yàn)證的失敗。所以,在嚴(yán)格的構(gòu)架驗(yàn)證被使用的情況下,不能對(duì)契約進(jìn)行改變。相反,你需要?jiǎng)?chuàng)建一個(gè)完整的新的契約并在這個(gè)契約中使用不同的命名空間來(lái)顯示新版本。
例如,從執(zhí)行的角度來(lái)看,你需要兩個(gè)單獨(dú)的服務(wù)終端使這兩個(gè)版本可用:
Original Version: [DataContract(Namespace="http://schemas.mycompany.com/2009/05/25")]
New Version: [DataContract(Namespace=http://schemas.mycompany.com/2009/06/18)]
幸運(yùn)的是,嚴(yán)格的構(gòu)架驗(yàn)證不是默認(rèn)的行為。這意思是在沒(méi)有中斷服務(wù)端的情況下,你可以添加或刪除數(shù)據(jù)成員。但是,由于先前所討論的有不預(yù)期的行為會(huì)產(chǎn)生,刪除數(shù)據(jù)成員不是一個(gè)好主意。另一方面,添加一個(gè)數(shù)據(jù)成員是很容易做到的,而且consumers會(huì)忽略它們還沒(méi)有意識(shí)到的外部成員。
關(guān)鍵的做法是使用DataMember屬性(先前討論過(guò)的)的Order參數(shù)。使用這個(gè)參數(shù)可以告訴serializers什么樣的順序(每個(gè)成員的)可以出現(xiàn)在XML中
來(lái)自基礎(chǔ)類型的成員
沒(méi)有order參數(shù)(按字母順序排列)的成員
有order參數(shù)(按值排列)的成員
WCF數(shù)據(jù)契約變更考慮的***情況是改變一個(gè)數(shù)據(jù)成員的類型。這種情況下,***的方法是創(chuàng)建一個(gè)新版本的數(shù)據(jù)契約并帶有新的服務(wù)契約,執(zhí)行和終端。