日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Programming WCF Services翻译笔记(五)

發(fā)布時(shí)間:2023/12/31 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Programming WCF Services翻译笔记(五) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本書的第3章主要講解了有關(guān)數(shù)據(jù)契約的知識。“從抽象層面看,WCF能夠托管CLR類型(接口和類)并將它們公開為服務(wù),也能夠以本地CLR接口和類的方式使用服務(wù)。WCF服務(wù)的操作接收和返回諸如int和string的CLR類型,WCF客戶端則傳遞和處理返回的CLR類型。然而,CLR類型卻屬于.NET的特定技術(shù)。由于面向服務(wù)的一個(gè)核心原則就是在跨越服務(wù)邊界時(shí),服務(wù)不能夠暴露它們的實(shí)現(xiàn)技術(shù)。因此,不管客戶端采用了何種技術(shù),它都能夠與服務(wù)交互。顯然,這就意味著WCF不允許在跨越服務(wù)邊界時(shí)公開CLR數(shù)據(jù)類型。我們需要找到一種辦法,實(shí)現(xiàn)CLR數(shù)據(jù)類型與標(biāo)準(zhǔn)的與平臺無關(guān)的表示形式之間的轉(zhuǎn)換。這樣的表示形式就是基于XML的樣式或信息集(Infoset)。此外,服務(wù)需要一種正式的方法聲明兩者之間的轉(zhuǎn)換。這個(gè)方法就是本章所要介紹的主題——數(shù)據(jù)契約。本章的第一部分介紹了數(shù)據(jù)契約啟用類型封送(Type Marshaling)與轉(zhuǎn)換的方法,以及如何通過基礎(chǔ)架構(gòu)處理類的層級與數(shù)據(jù)契約的版本控制。第二部分則介紹了如何將不同的.NET類型,例如枚舉、委托、數(shù)據(jù)表以及集合,作為數(shù)據(jù)契約使用。”

數(shù)據(jù)契約是服務(wù)之間傳遞的數(shù)據(jù)。由于必須支持跨進(jìn)程,乃至于跨機(jī)器的傳遞,WCF必須對數(shù)據(jù)進(jìn)行特殊的處理,否則無法實(shí)現(xiàn)數(shù)據(jù)的傳遞。在.NET Remoting與Web Service中,對數(shù)據(jù)的處理方式通常是利用序列化的方法,WCF同樣沿襲了這一做法,但為了更好的體現(xiàn)面向服務(wù)的特質(zhì),又特別引入了數(shù)據(jù)契約(DataContract)。此外,WCF還引入了消息契約(MessageContract),但本書沒有介紹。

WCF的序列化使用了.NET平臺自身支持的序列化機(jī)制,因此這里不再重復(fù)。

.NET提供的序列化機(jī)制雖然足以應(yīng)付SOA的要求,但仍然存在許多不足之處。本書總結(jié)了Serializable的缺陷:
“Serializable所指代的涵義是類型的所有成員都是可序列化的,這些成員是組成類型數(shù)據(jù)樣式的一部分。然而,更好的方式是能夠提供一種明確參與(Opt-In)途徑,只有那些契約的開發(fā)者明確包含的成員才應(yīng)該放到數(shù)據(jù)契約中。Serializable特性強(qiáng)制要求數(shù)據(jù)類型是可序列化的,從而使得類型可以被用作契約操作的參數(shù),但它卻無法實(shí)現(xiàn)類型的服務(wù)特性(具有成為WCF操作參數(shù)的能力)與序列化能力之間的職責(zé)分離。Serializalbe特性不支持類型名和成員名的別名,也無法將一個(gè)新類型映射為預(yù)定義的數(shù)據(jù)契約。由于Serializable特性可以直接操作成員字段,使得封裝了字段訪問的屬性形同虛設(shè)。訪問字段的最好辦法是通過屬性添加它們的值,而Serializable卻破壞了屬性的封裝性。最后,Serializable特性并沒有直接支持版本控制(Versioning),而版本控制的信息卻是格式器期望獲取的。無疑,它導(dǎo)致了版本控制的處理變得舉步維艱。”

WCF提供的數(shù)據(jù)契約DataContract基本上解決了以上的問題。通常,DataContract必須與DataMember結(jié)合使用。只有應(yīng)用了DataMember特性的屬性才被公開到元數(shù)據(jù)中。雖然DataMember特性也可以應(yīng)用到對象的字段上,但WCF并不推薦這樣做,原因與類的設(shè)計(jì)原則相同。

數(shù)據(jù)契約與服務(wù)契約相似,數(shù)據(jù)成員或數(shù)據(jù)契約的訪問限定與WCF之間并沒有因果關(guān)系。數(shù)據(jù)契約完全可以包含私有數(shù)據(jù)成員等內(nèi)部類型:
[DataContract]
struct Contact
{
?? [DataMember]
?? string m_FirstName;

?? [DataMember]
?? string m_LastName;
}

即使DataMember特性被直接應(yīng)用到字段上,在導(dǎo)入的客戶端定義仍然會以屬性來表示。如下的數(shù)據(jù)契約定義:
[DataContract]
struct Contact
{
?? [DataMember]
?? public string FirstName;

?? [DataMember]
?? public string LastName;
}
導(dǎo)入的客戶端定義為:
[DataContract]
public partial struct Contact
{
?? string FirstNameField;
?? string LastNameField;

?? [DataMember]
?? public string FirstName
?? {
????? get
????? {
???????? return FirstNameField;
????? }
????? set
????? {
???????? FirstNameField = value;
????? }
?? }

?? [DataMember]
?? public string LastName
?? {
????? get
????? {
???????? return LastNameField;
????? }
????? set
????? {
???????? LastNameField = value;
????? }
?? }
}
它會將字段名作為屬性名,而導(dǎo)入的定義中,則在屬性名后加上Field后綴作為字段名。但我們也可以手工修改客戶端的定義。

如果數(shù)據(jù)契約的數(shù)據(jù)成員為私有的,導(dǎo)入的客戶端定義會自動修改為公有的。“當(dāng)DataMember特性應(yīng)用到屬性上時(shí)(不管是服務(wù)還是客戶端),該屬性必須具有g(shù)et和set訪問器。如果沒有,在調(diào)用時(shí)就會拋出InvalidDataContractException異常。因?yàn)楫?dāng)屬性自身就是數(shù)據(jù)成員時(shí),WCF會在序列化和反序列化時(shí)使用該屬性,使開發(fā)者能夠?qū)⒍ㄖ七壿嫅?yīng)用到屬性中。”

“不要將DataMember特性既應(yīng)用到屬性上,又應(yīng)用到相對應(yīng)的字段上,這會導(dǎo)致導(dǎo)入的成員定義重復(fù)。”

如果服務(wù)端的數(shù)據(jù)被標(biāo)記為Serializable特性,在導(dǎo)入這樣的定義時(shí),會使用DataContract。而且“對于每一個(gè)可序列化的成員,不管是公有的還是私有的,都是數(shù)據(jù)成員。”?

傳統(tǒng)的格式器不能序列化只標(biāo)記了DataContract特性的類型。要序列化這樣的類型,必須同時(shí)應(yīng)用DataContract特性和Serializable特性。對于如此類型生成的傳輸型表示形式(Wire Representation),就好似僅僅應(yīng)用了DataContract特性一般,同時(shí),我們?nèi)匀恍枰獮槌蓡T添加DataMember特性。

在WCF的數(shù)據(jù)契約中,很明顯地體現(xiàn)出WCF還不能夠完全支持面向?qū)ο蟮脑O(shè)計(jì)思想。在第2章對服務(wù)契約的描述中,對契約的繼承層級的處理方式來看,已經(jīng)體現(xiàn)了這一缺陷的端倪。而對于數(shù)據(jù)契約而言,更是進(jìn)一步暴露了這樣的缺陷。

首先WCF并不支持Liskov替換原則(LSP),“默認(rèn)情況下,我們不能用數(shù)據(jù)契約的子類去替換基類。” 考慮如下的服務(wù)契約:
[ServiceContract]
interface IContactManager
{
?? //Cannot accept Customer object here:
?? [OperationContract]
?? void AddContact(Contact contact);

?? //Cannot return Customer objects here:
?? [OperationContract]
?? Contact[] GetContacts(? );
}
假定客戶端同時(shí)定義了一個(gè)Customer類:

[DataContract]
class Customer : Contact
{
?? [DataMember]
?? public int OrderNumber;
}
以下代碼能夠成功通過編譯,但在運(yùn)行時(shí)卻會失敗:

Contact contact = new Customer(? );
contact.FirstName = "Juval";
contact.LastName = "Lowy";

ContactManagerClient proxy = new ContactManagerClient(? );
//Service call will fail:
proxy.AddContact(contact);
proxy.Close(? );
因?yàn)樵谶@個(gè)例子中,我們傳遞了一個(gè)Customer對象,而不是Contact對象。由于服務(wù)無法識別Customer對象,也就無法反序列化它所接收到的Contact對象。

雖然WCF引入了Known Types(已知類型)來解決這一問題,然而對于理解面向?qū)ο笏枷氲脑O(shè)計(jì)者而言,這樣的設(shè)計(jì)無疑會引入父類與子類之間的耦合度。因?yàn)樵谖覀冊O(shè)計(jì)父類的時(shí)候,就必須事先知道子類的定義。當(dāng)我們需要擴(kuò)展子類時(shí),還需要修改父類的定義。

WCF引入的服務(wù)已知類型,比較已知類型而言,有一定程度的改善。因?yàn)樗梢詫⒏割惻c子類在層級上的耦合度縮小到方法級上。但這樣的耦合,依然是不可接受的。例如:
[DataContract]
class Contact
{...}

[DataContract]
class Customer : Contact
{...}
?
[ServiceContract]
interface IContactManager
{
?? [OperationContract]
?? [ServiceKnownType(typeof(Customer))]
?? void AddContact(Contact contact);

?? [OperationContract]
?? Contact[] GetContacts(? );
}
當(dāng)然,服務(wù)已知類型也可以應(yīng)用到契約接口上,此時(shí),該契約以及實(shí)現(xiàn)該契約的所有服務(wù)包含的所有操作都能夠接收已知的子類。

為了解決這一問題,WCF提供了配置已知類型的方法。例如:
<system.runtime.serialization>
?? <dataContractSerializer>
????? <declaredTypes>
???????? <add type = "Contact,Host,Version=1.0.0.0,Culture=neutral,
????????????????????????????????????????????????????????????? PublicKeyToken=null">
??????????? <knownType type = "Customer,MyClassLibrary,Version=1.0.0.0,
???????????????????????????????????????????? Culture=neutral,PublicKeyToken=null"/>
???????? </add>
????? </declaredTypes>
?? </dataContractSerializer>
</system.runtime.serialization>

注意上述的配置文件中,我們配置的已知類型必須是類型的fullname。包括命名空間、版本號、Culture等。雖然這種方式可以避免在增加子類的情況下,修改代碼、重新編譯和重新部署,但無疑加重了開發(fā)者的負(fù)擔(dān),尤其是對配置文件的管理以及后期的維護(hù)。

不過,“如果已知類型對于另一個(gè)程序集而言是內(nèi)部(internal)類型,要添加一個(gè)已知類型,只有使用配置文件聲明它。”

總之,在WCF中要實(shí)現(xiàn)面向?qū)ο蟮亩鄳B(tài),還未能做到最佳。如果能夠?qū)nownType特性應(yīng)用到子類上,為子類指名它所繼承的父類,無疑更加利于類的擴(kuò)展。遺憾的是WCF未能做到這一點(diǎn)。

如果數(shù)據(jù)契約本身實(shí)現(xiàn)了一個(gè)接口,情況就變得有趣了。從服務(wù)端的定義來看,這樣的數(shù)據(jù)契約仍然可以通過服務(wù)已知類型在服務(wù)契約上指定實(shí)現(xiàn)了數(shù)據(jù)契約接口的子數(shù)據(jù)契約類型。例如,數(shù)據(jù)契約Contact類實(shí)現(xiàn)了接口IContact:
interface IContact
{??
?? string FirstName
?? {get;set;}
?? string LastName
?? {get;set;}
}
[DataContract]
class Contact : IContact
{...}

那么在處理數(shù)據(jù)契約Contact的服務(wù)契約中,如果契約的操作需要以抽象方式,定義IContact類型的參數(shù),就必須使用ServiceKnownType特性指名其實(shí)現(xiàn)類Contact,如下所示:
[ServiceContract]
[ServiceKnownType(typeof(Contact))]
interface IContactManager
{
?? [OperationContract]
?? void AddContact(IContact contact);

?? [OperationContract]
?? IContact[] GetContacts(? );
}

注意,此時(shí)不能利用KnownType特性,將其直接應(yīng)用到IContact接口上,因?yàn)閷?dǎo)出的元數(shù)據(jù)無法包含接口本身。

服務(wù)端的定義無疑符合面向接口編程思想,除了增加了ServiceKnownType之外,整個(gè)設(shè)計(jì)還算優(yōu)雅。然而根據(jù)這樣的定義所導(dǎo)出的服務(wù)契約,卻未免顯得差強(qiáng)人意,如下所示:
[ServiceContract]
public interface IContactManager
{
??? [OperationContract]
??? [ServiceKnownType(typeof(Contact))]
??? [ServiceKnownType(typeof(object[]))]
??? void AddContact(object contact);
???
??? [OperationContract]
??? [ServiceKnownType(typeof(Contact))]
??? [ServiceKnownType(typeof(object[]))]
??? object[] GetContacts(? );
}

導(dǎo)出定義中,將應(yīng)用到契約的ServiceKnownType特性應(yīng)用到了每個(gè)操作上,并且為每個(gè)操作都指定了具體的數(shù)據(jù)契約子類以及一個(gè)object[]類型。特別要注意,在操作的返回值與參數(shù)中,原來的IContact類型全部被轉(zhuǎn)換為了object類型。原因在于,客戶端并沒有IContact接口的定義。基于object的契約定義無疑不具備類型安全性。

解決辦法自然是在客戶端中增加IContact接口的定義。如此,客戶端定義就可以修改為:
[ServiceContract]
public interface IContactManager
{
??? [OperationContract]
??? [ServiceKnownType(typeof(Contact))]
??? void AddContact(IContact contact);
???
??? [OperationContract]
??? [ServiceKnownType(typeof(Contact))]
??? IContact[] GetContacts(? );
}

但是,我們不能以具體的數(shù)據(jù)契約類型Contact,來替換原來的object類型。因?yàn)樘鎿Q為具體的數(shù)據(jù)契約類型,則客戶端的服務(wù)契約就與服務(wù)端的服務(wù)契約不兼容了。所以,下面的定義是錯(cuò)誤的:
[ServiceContract]
public interface IContactManager
{
??? [OperationContract]
??? void AddContact(Contact contact);
???
??? [OperationContract]
??? Contact[] GetContacts(? );
}

轉(zhuǎn)載于:https://www.cnblogs.com/illele/archive/2008/01/10/1033863.html

總結(jié)

以上是生活随笔為你收集整理的Programming WCF Services翻译笔记(五)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。