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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

WCF服务编程 学习笔记(2)

發布時間:2024/1/17 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 WCF服务编程 学习笔记(2) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

(承接上文,只是不好意思,在文中用到的圖片自己沒有插入。)

12.終結點
服務與地址、綁定以及契約有關。其中,地址定義了服務的位置,綁定定義了服務通信的方式,契約則定義了服務的內容。為便于記憶,我們可以將這種類似于“三權分立”一般管理服務的方式簡稱為服務的 ABC。WCF 用終結點表示這樣一種組成關系。終結點就是地址、契約與綁定的混成品(參見圖 1-5)。
每一個終結點都包含了三個元素,而宿主則負責公開終結點。從邏輯上講,終結點相當于服務的接口,就像 CLR 或者 COM 接口一樣。注意,圖 1-5 使用了傳統的“棒棒糖”形式展示了一個終結點的構成。
注意:從概念上講,不管是 C#還是 VB,一個接口就相當于一個終結點:地址就是類型虛擬表的內存地址,綁定則是 CLR 的 JIT(Just-In-Time)編譯,而契約則代表接口本身。 由于經典的.NET 編程模式不需要處理地址或綁定,你可能認為它們是理所當然存在的。而WCF 并未規定地址與綁定,因而必須對它們進行配置。
每個服務至少必須公開一個業務終結點,每個終結點有且只能擁有一個契約。服務上的所有終結點都包含了唯一的地址,而一個單獨的服務則可以公開多個終結點。這些終結點可以使用相同或不同的綁定,公開相同或不同的契約。每個服務提供的不同終結點之間絕對沒有任何關聯。
重要的一點是,服務代碼并沒有包含它的終結點,它們通常放在服務代碼之外。我們可以通過管理方式(Administratively)使用配置文件或者通過編程方式(Programmatically)配置終結點。
(1).管理方式配置終結點
以管理方式配置一個終結點需要將終結點放到托管進程的配置文件中。
例 1-6 演示了配置文件要求的配置入口。在每個服務類型下列出它的終結點。此為以管理方式配置終結點。
當我們指定服務和契約類型時,必須使用類型全名。在本書的其余例子中,為簡略起見,我省略了類型的命名空間,但在實際應用中,命名空間是必備的。注意,如果終結點已經提供了基地址,則地址的樣式必須與綁定一致,例如 HTTP 對應 WSHttpBinding。如果兩者不匹配,就會在裝載服務時導致異常。
例 1-7 的配置文件為一個單獨的服務公開了多個終結點。多個終結點可以配置相同的基地址,前提是 URI 互不不同。
例 1-7:相同服務的多個終結點
<service name = "MyService">
<endpoint address?? = " http://localhost:8000/MyService/" binding="wsHttpBinding" contract = "IMyContract" />
<endpoint address?? = "net.tcp://localhost:8001/MyService/" binding= "netTcpBinding" contract = "IMyContract" />
<endpoint address?? = "net.tcp://localhost:8002/MyService/" binding = "netTcpBinding" contract = "IMyOtherContract" />
</service>
大多數情況下,我們的首選是管理的配置方式,因為它非常靈活,即使修改了服務的地址、綁定和契約,也不需要重新編譯服務和重新部署服務。
(2).使用基地址
例 1-7 中的每個終結點都提供了自己獨有的基地址。如果我們提供了顯式的基地址,它會重寫宿主提供的所有基地址。
我們也可以讓多個終結點使用相同的基地址,只要終結點地址中的 URI 不同:
<service name = "MyService">??
<endpoint address="net.tcp://localhost:8001/MyService/" binding = "netTcpBinding" contract = "IMyContract" />
<endpoint address="net.tcp://localhost:8001/MyOtherService/" binding= "netTcpBinding" contract = "IMyContract"?? />
</service>
反之,如果宿主提供了與傳輸樣式匹配的基地址,則可以省略地址項。此時,終結點地址與該基地址完全相同:
<endpoint binding?? = "wsHttpBinding" contract = "IMyContract" />
如果宿主沒有提供匹配的基地址,則在裝載服務宿主時會拋出異常。 配置終結點地址時,可以為基地址添加相對 URI:
<endpoint address= "SubAddress" binding= "wsHttpBinding" contract= "IMyContract"/>
此時,終結點地址等于它所匹配的基地址加上 URI。當然,前提是宿主必須提供匹配的基地址。
(3).綁定配置
使用配置文件可以為終結點使用的綁定進行定制。為此,需要在<endpoint>節中添加 bindingConfiguration 標志,它的值應該與<bindings>配置節中定制的綁定名一致。例1-8 介紹了使用這種技術啟用事務傳播的方法。其中的 transactionFlow 標志會在第 7 章詳細介紹。
例 1-8:服務端綁定的配置
<system.serviceModel>????
? <services>???????
??? <service name = "MyService">??????????
?   <endpoint address="net.tcp://localhost:8000/MyService/" bindingConfiguration="TransactionalTCP" binding="netTcpBinding" contract =     ?????????? "IMyContract"/>?????????
   <endpoint address= "net.tcp://localhost:8001/MyService/"? bindingConfiguration ="TransactionalTCP" binding="netTcpBinding"??contract =    ????????? "IMyOtherContract" />?????????????
  </service>????
??? </services>????
??? <bindings>??????
  <netTcpBinding>??????????
  ??? <binding name ="TransactionalTCP" transactionFlow = "true" />???????
  </netTcpBinding>????
??? </bindings>
</system.serviceModel>
如例 1-8 所示,我們可以在多個終結點中通過指向定制綁定的方式,重用已命名的綁定配置。
(4).編程方式配置終結點
編程方式配置終結點與管理方式配置終結點等效。但它不需要配置文件,而是通過編程調用將終結點添加到 ServiceHost 實例中。這些調用不屬于服務代碼的范圍。ServiceHost 定義了重載版本的 AddServiceEndpoint()方法,傳入 AddServiceEndpoint()方法的地址可以是相對地址,也可以是絕對地址,這與使用配 置文件的方式相似。例 1-9 演示了編程配置的方法,它配置的終結點與例 1-7 的終結點相同。
例 1-9:服務端編程配置終結點
ServiceHost host = new ServiceHost(typeof(MyService));
Binding wsBinding?? = new WSHttpBinding();
Binding tcpBinding = new NetTcpBinding();
host.AddServiceEndpoint(typeof(IMyContract),wsBinding, "http://localhost:8000/MyService");
host.AddServiceEndpoint(typeof(IMyContract),tcpBinding, "net.tcp://localhost:8001/MyService");
host.AddServiceEndpoint(typeof(IMyOtherContract),tcpBinding, "net.tcp://localhost:8002/MyService");
host.Open();?
以編程方式添加終結點時,address 參數為 string 類型,contract 參數為 Type 類型,而binding 參數的類型則是 Binding 抽象類的其中一個子類。
由于宿主提供了基地址,因此若要使用基地址,可以將空字符串賦給 address 參數,或者只設置 URI 值,此時使用的地址就應該是基地址加上 URI:
Uri tcpBaseAddress = new Uri("net.tcp://localhost:8000/");??
ServiceHost host = new ServiceHost(typeof(MyService),tcpBaseAddress);??
Binding tcpBinding = new NetTcpBinding();??
//使用基地址作為地址
host.AddServiceEndpoint(typeof( IMyContract),tcpBinding,"");
//添加相對地址
host.AddServiceEndpoint(typeof(IMyContract),tcpBinding,"MyServi ce");
//忽略基地址
host.AddServiceEndpoint(typeof(IMyContract),tcpBinding, "net.tcp://localhost:8001/MyService");
host.Open();??
使用配置文件進行管理方式的配置,宿主必須提供一個匹配的基地址,否則會引發異常。事實上,編程方式配置與管理方式配置并沒有任何區別。使用配置文件時,WCF 會解析文件,然后執行對應的編程調用。
(5).綁定配置
我們可以通過編程方式設置綁定的屬性。例如,以下代碼就實現了與例 1-8 相似的功能,啟用事務傳播:
ServiceHost host = new Servi ceHost(typeof(MyService));
NetTcpBinding tcpBinding = new NetTcpBinding();
tcpBinding.TransactionFlow = true;
host.AddServiceEndpoint(typeof(IMyContract),tcpBinding, "net.tcp://localhost:8000/MyService");
host.Open();????????
注意,在處理特定的綁定屬性時,通常應該與具體的綁定子類如 NetTcpBinding 交互,而不是使用抽象類 Binding,正如例 1-9 所示。
13.元數據交換
服務有兩種方案可以發布自己的元數據。一種是基于 HTTP-GET 協議提供元數據,另一種則是后面將要討論的使用專門的終結點的方式。WCF 能夠為服務自動提供基于 HTTP-GET的元數據,但需要顯式地添加服務行為(Behavior)以支持這一功能。本書后面的章節會介紹行為的相關知識。現在,我們只需要知道行為屬于服務的本地特性,例如是否需要基于HTTP-GET 交換元數據,就是一種服務行為。我們可以通過編程方式或管理方式添加行為。
在例 1-10 演示的宿主應用程序的配置文件中,所有引用了定制<behavior>配置節的托管服務都支持基于 HTTP-GET 協議實現元數據交換。為了使用 HTTP-GET,客戶端使用的地址需要注冊服務的 HTTP 基地址。我們也可以在行為中指定一個外部 URL 以達到同樣的目的。
一旦啟用了基于 HTTP-GET 的元數據交換,在瀏覽器中就可以通過 HTTP 基地址(如果存在)進行訪問。如果一切正確,就會獲得一個確認頁面,如圖 1-6 所示,告知開發者已經成功托管了服務。確認頁面與 IIS 托管無關,即使使用自托管,我們也可以使用瀏覽器定位服務地址。
(1).編程方式啟用元數據交換
若要以編程方式啟用基于 HTTP-GET 的元數據交換,首先需要將行為添加到行為集合中,該行為集合是宿主針對服務類型而維持的。ServiceHostBase 類定義了 Description 屬性,類型為 ServiceDescription 。
顧名思義,ServiceDescription 就是對服務各個方面與行為的描述。Service-Description類定義了類型為 KeyedByTypeCollection<I>的屬性 Behaviors。所有行為的類與特性均實現了 IServiceBehavior 接口。
例 1-11:編程方式啟用元數據交換行為
ServiceHost host = new ServiceHost(typeof(MyService));??
ServiceMetadataBehavior metadataBehavior;
metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if(metadataBehavior == null)
{ metadataBehavior = new ServiceMetadataBehavior();
metadataBehavior.HttpGetEnabled = true;
host.Description.Behaviors .Add(metadataBehavior); }
host.Open();
ServiceMetadataBehavior 類定義在 System.ServiceModel. Description 命名空間 下,如果返回的行為為 null,托管代碼就會創建一個新的 ServiceMetadataBehavior 對象,并將 HttpGetEnabled 屬性值設為 true,然后將它添加到服務描述的 behaviors 屬性中。
(2).元數據交換終結點
元數據交換終結點是一種特殊的終結點,有時候又被稱為 MEX 終結點。服務能夠根據元數據交換終結點發布自己的元數據。
圖 1-7 展示了一個具有業務終結點和元數據交換終結點的服務。不過,在通常情況下并不需要在設計圖中顯示元數據交換終結點。
元數據交換終結點支持元數據交換的行業標準,在 WCF 中表現為IMetadataExchange 接口,IMetadataExchange 接口定義的細節并不合理。它與多數行業標準相似,都存在難以實現的問題。所幸,WCF 自動地為服務宿主提供了 IMetadataExchange 接口的實現,公開元數據交換終結點。我們只需要指定使用的地址和綁定,以及添加服務元數據行為。對于綁定,WCF 提供了專門的基于 HTTP、HTTPS、TCP 和 IPC 協議的綁定傳輸元素。對于地址,我們可以提供完整的地址,或者使用任意一個注冊了的基地址。沒有必要啟用 HTTP-GET 選項,但是即使啟用了也不會造成影響。
例 1-12 演示的服務公開了三個 MEX 終結點,分別基于 HTTP、TCP 和 IPC。出于演示的目的,TCP 和 IPC 的 MEX 終結點使用了相對地址,HTTP 則使用了絕對地址。
(3).編程方式添加MEX終結點
與其他終結點相似,我們只能在打開宿主之前通過編碼方式添加元數據交換終結點。WCF并沒有為元數據交換終結點提供專門的綁定類型。為此,我們需要創建定制綁定。定制綁定使用了與之匹配的傳輸綁定元素,然后將綁定元素對象作為構造函數的參數,傳遞給定制綁定實例。最后,調用宿主的 AddServiceEndpoint()方法,參數值分別為地址、定制綁定與IMetadataExchange 契約類型。例 1-13 的代碼添加了基于 TCP 的 MEX 終結點。注意,在添加終結點之前,必須校驗元數據行為是否存在。 例 1-13:編程方式添加 TCP MEX 終結點
BindingElement bindingElement = new TcpTransportBindingElement();
CustomBinding binding = new CustomBinding(bindingElement);
Uri tcpBaseAddress = new Uri("net.tcp://localhost:9000/");
ServiceHost host = new ServiceHost(typeof(MyService),tcpBaseAddress);??
ServiceMetadataBehavior metadataBehavior;
metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if(metadataBehavior == null) { metadataBehavior = new ServiceMetadataBehavior(); host.Description.Behaviors .Add(metadataBehavior); } host.AddServiceEndpoint(typeof(IMetadataExchange),binding,"MEX" );
host.Open();
(4).簡化ServiceHost<T>類
我們可以擴展 ServiceHost<T>類,從而自動實現例 1-11 和例 1-13 中的代碼。 ServiceHost<T>定義了 Boolean 型屬性 EnableMetadataExchange,通過調用該屬性添加 HTTP-GET 元數據行為和 MEX 終結點。 如果 EnableMetadataExchange 屬性設置為 true,就會添加元數據交換行為。如果沒有可用的 MEX 終結點,它就會為每個已注冊的基地址樣式添加一個 MEX 終結點。使用ServiceHost<T>,例 1-11 和例 1-13 就可以簡化為。 ServiceHost<T>還定義了 Boolean 屬性 HasMexEndpoint。如果服務包含了任意一個 MEX 終結點(與傳輸協議無關),則返回 true。ServiceHost<T>定義的AddAllMexEndPoints()方法可以為每個已注冊的基地址添加一個 MEX 終結點,這些基地址的樣式類型包括 HTTP、TCP 或 IPC。例 1-14 介紹了這些方法的實現。 對于ServiceHost<T>的實現請查看對應的ServiceHost<T>的文件。
(5).元數據瀏覽器
元數據交換終結點提供的元數據不僅描述了契約與操作,還包括關于數據契約、安全性、事務性、可靠性以及錯誤的信息。為了可視化表示正在運行的服務的元數據,我們開發了元數據瀏覽器工具,它的實現包含在本書附帶的源代碼中。
14.客戶端編程
若要調用服務的操作,客戶端首先需要導入服務契約到客戶端的本地描述(Native Representation)中。如果客戶端使用了 WCF,調用操作的常見做法是使用代理。代理是一個 CLR 類,它公開了一個單獨的 CLR 接口用以表示服務契約。注意,如果服務支持多個契約(至少是多個終結點),客戶端則需要一個代理對應每個契約類型。代理不僅提供了與服務契約相同的操作,同時還包括管理代理對象生命周期的方法,以及管理服務連接的方法。代理完全封裝了服務的每個方面:服務的位置、實現技術、運行時平臺以及通信傳輸。
(1).生成代理
如果服務是自托管的,則首先需要啟動服務,然后從客戶端項目的快捷菜單中選擇“Add Service Reference...”。 如果服務托管在 IIS 或 WAS 中,則無需預先啟動服務。值得注意的是,如果服務同時又作為客戶端項目自托管在相同解決方案的另一個項目中,則可以在 Visual Studio 2005 中啟動宿主,并添加引用。
也可以使用命令行工具 SvcUtil.exe工具來生成代理。
代理類的閃光之處在于它可以只包含服務公開的契約,而不需要添加對服務實現類的引用。我們可以通過提供地址和綁定的客戶端配置文件使用代理,也可以不通過配置文件直接使用。注意,每個代理的實例都確切地指向了一個終結點。創建代理時需要與終結點交互。正如前文提及,如果服務端契約沒有提供命名空間,則默認的命名空間為http://tempuri.org 。
(2).管理方式配置客戶端
客戶端需要知道服務的位置,需要使用與服務相同的綁定,當然,客戶端還要導入服務契約的定義。本質上講,它的信息與從服務的終結點獲取的信息完全相同。為了體現這些信息,客戶端配置文件需要包含目標終結點的信息,甚至使用與宿主完全相同的終結點配置樣式。 客戶端配置文件可以列出同樣多的對應服務支持的終結點,客戶端能夠使用這些終結點中的任意一個。注意,客戶端配置文件中的每個終結點都有一個唯一的名稱。
(3).綁定配置 我們可以使用與服務配置相同的風格定制匹配服務綁定的客戶端標準綁定。
(4).生成客戶端配置文件
在默認情況下,SvcUtil也可以自動生成客戶端配置文件output.config。建議永遠不要使用SvcUtil工具生成配置文件。原因在于它會自動地為關鍵的綁定節設置默認值,反而導致了整個配置文件的混亂。
(5).進程內托管配置
對于進程內托管,客戶端配置文件就是服務宿主的配置文件。同一個文件既包含了服務配置入口,也包含了客戶端的配置入口。 注意,進程內宿主使用了命名管道綁定。
(6).SvcConfigEditor編輯器
對于使用 SvcConfigEditor,優劣參半。一方面,它可以幫助開發者輕松快捷地編輯配置文件,從而節約了掌握配置樣式的時間。另一方面,它卻不利于開發者對 WCF 配置的整體理解。
(7).創建和使用代理
代理類派生自ClientBase類,ClientBase 類通過泛型類型參數識別代理封裝的服務契約。ClientBase 的 Channel 屬性類型就是泛型參數的類型。ClientBase 的子類通過 Channel 調用它指向的服務契約的方法。
若要使用代理,客戶端首先需要實例化代理對象,并為構造函數提供終結點信息,即配置文件中的終結點節名。如果沒有使用配置文件,則為終結點地址和綁定對象。然后,客戶端使用代理類的方法調用服務。一旦客戶端調用完畢,就會關閉代理實例。
如果在客戶端配置文件中,只為代理正在使用的契約類型定義了一個終結點,則客戶端可以省略構造函數中的終結點名。然而,如果相同的契約類型包含了多個可用的終結點,則代理會拋出異常。
(8).關閉代理
最佳的做法是在客戶端調用代理完畢之后要關閉代理。第 4 章會詳細解釋為何在正確情況下客戶端需要關閉代理,因為關閉代理會終止與服務的會話,關閉連接。 使用代理的 Dispose()方法同樣可以關閉代理。這種方式的優勢在于它支持 using 語句的使用,即使出現異常,仍然能夠調用:
using(MyContractClient proxy = new MyContractClient())
{ ? proxy.MyMethod(); }??
如果客戶端直接聲明了契約,而不是具體的代理類,則客戶端可以首先判斷代理對象是否實現了 IDisposable 接口:
IMyContract proxy = new MyContractClient());
proxy.MyMethod();
IDisposable disposable = proxy as IDisposable;
if(disposable != null) { disposable.Dispose(); }?
或者使用 using 語句,省略對類型的判斷:
IMyContract proxy = new MyContractClient();
using(proxy as IDisposable) { ? proxy.MyMethod(); }
(9).調用超時
WCF 客戶端的每次調用都必須在配置的超時值內完成。無論何種原因,一旦調用時間超出該時限,調用就會被取消,客戶端會收到一個 TimeoutException 異常。綁定的一個屬性用于設定超時的確切值,默認的超時值為 1min。若要設置不同的超時值,可以設置 Binding抽象基類的 SendTimeout 屬性。
(10).編程方式配置客戶端
如果不借助于配置文件,客戶端也可以通過編程方式創建匹配服務終結點的地址與綁定對象,并將它們傳遞給代理類的構造函數。既然代理的泛型類型參數就是契約,因此不必為構造函數提供契約。為了表示地址,客戶端需要實例化 EndpointAddress 類。 與在配置文件中使用綁定節的方法相似,客戶端可以通過編程方式配置綁定屬性:
WSHttpBinding wsBinding = new WSHttpBinding();
wsBinding.SendTimeout = TimeSpan.FromMinutes(5);
wsBinding.TransactionFlow = true;??
EndpointAddress endpointAddress = new?? EndpointAddress(" http://localhost:8000/MyService/ ");??
MyContractClient proxy = new MyContractClient(wsBinding,endpointAddress);
proxy.MyMethod();
proxy.Close();
注意,使用 Binding 類的具體子類,是為了訪問與綁定相關的屬性,例如事務流。
(11).編程方式配置與管理方式配置
目前介紹的配置客戶端與服務的兩種技術各有所長,相輔相成。管理配置方式允許開發者在部署服務之后,修改服務與客戶端的主要特性,而不需要重新編譯或重新部署。主要缺陷則是不具備類型安全,只有在運行時才能發現配置的錯誤。 如果配置的決策完全是動態的,那么編程配置方式就體現了它的價值,它可以在運行時基于當前的輸入或條件對服務的配置進行處理。如果判斷條件是靜態的,而且是恒定不變的,就可以采取硬編碼方式。例如,如果我們只關注于進程內托管的調用,就可以采取硬編碼方式,使用 NetNamePipeBinding 以及它的配置。不過,大體而言,大多數客戶端和服務都會使用配置文件。
15.通道Channel(自定義知識點)
(1).WCF體系框架
WCF 提供了對可靠性、事務性、并發管理、安全性以及實例激活等技術的有力支持,它們均依賴于基于攔截機制的 WCF 體系架構(WCF Architecture)。通過代理與客戶端的交互意味著 WCF 總是處于服務與客戶端之間,攔截所有的調用,執行調用前和調用后的處理。當代理將調用棧幀(Stack Frame)序列化到消息中,并將消息通過通道鏈向下傳遞時,WCF 就開始執行攔截。通道相當于一個攔截器,目的在于執行一個特定的任務。每個客戶端通道都會執行消息的調用前處理。鏈的組成與結構主要依賴于綁定。
例如,一個通道對消息編碼(二進制格式、文本格式或者 MTOM),另一個通道傳遞安全的調用上下文;還有一個通道傳播客戶端的事務,一個通道管理可靠會話,另一個通道對消息正文(Message Body)加密(如果進行了配置),諸如此類。客戶端的最后一個通道是傳輸通道,根據配置的傳輸方式發送消息給宿主。
在宿主端,消息同樣通過通道鏈進行傳輸,它會對消息執行宿主端的調用前處理。宿主端的第一個通道是傳輸通道,接收傳輸過來的消息。隨后的通道執行不同的任務,例如消息正文的解密、消息的解碼、參與傳播事務、設置安全準則、管理會話、激活服務實例。宿主端的最后一個通道負責將消息傳遞給分發器(Dispatcher)。分發器將消息轉換到一個棧幀,并調用服務實例。執行順序如圖 1-11 所示。?
服務并不知道它是否被本地客戶端調用。事實上,服務會被本地客戶端? ——? 分發器調用。客戶端與服務端的攔截器確保了它們能夠獲得運行時環境,以便于它們執行正確的操作。服務實例會執行調用,然后將控制權(Control)返回給分發器。分發器負責將返回值以及錯誤信息(如果存在)轉換為一條返回消息。分發器獲得控制權,執行的過程則剛好相反:分發器通過宿主端通道傳遞消息,執行調用后的處理,例如管理事務、停用實例、回復消息的編碼與加密等。為了執行客戶端調用后的處理,包括解密、解碼、提交或取消事務等任務,傳輸通道會將返回消息發送到客戶端通道。最后一個通道將消息傳遞給代理。代理將返回消息轉化到棧幀,然后將控制權返回給客戶端。
特別值得注意的是,體系架構中的所有要點均與可擴展性息息相關。我們可以為專有交互定制通道,為實例管理定制行為,以及定制安全行為等。事實上,WCF 提供的標準功能都能夠通過相同的可擴展模式實現。本書介紹了許多針對可擴展性的實例與應用。
(2).宿主體系架構
如何將與技術無關的面向服務交互轉換為 CLR 接口與類,對這一技術的探索無疑充滿了趣味。宿主消除了兩者之間的鴻溝,搭建了相互之間轉換的橋梁。每個.NET 宿主進程都包含了多個應用程序域。每個應用程序域則包含了零到多個宿主實例。每個服務宿主實例專門對應于一個特殊的服務類型。創建一個宿主實例,實際上就是為對應于基地址的宿主機器的類型,注冊一個包含了所有的終結點的服務宿主實例。每個服務宿主實例擁有零到多個上下文(Context)。上下文是服務實例最核心的執行范圍。一個上下文最多只能與一個服務實例關聯,這意味著上下文可能為空,不包含任何服務實例。體系架構如圖 1-12 所示。
注意:WCF 上下文的概念與企業服務上下文(Enterprise Services Context)或者.NET 上下文綁定對象(Context-Bound Object)的上下文概念相似。
WCF 上下文將服務宿主與公開本地 CLR 類型為服務的上下文組合在一起。當消息經由通道進行傳遞時,宿主會將消息 。
(3).使用通道
我們可以直接使用通道調用服務的操作,而無須借助于代理類。ChannelFactory<T>類(以及它所支持的類型)有助于我們輕松地創建代理,如例 1-21 所示。
我們需要向 ChannelFactory<T>類的構造函數傳遞一個終結點對象,終結點名稱可以從客戶端配置文件中獲取;或者傳遞綁定與地址對象,或者傳遞 ServiceEndpoint 對象。接著,調用 CreateChannel()方法獲得代理的引用,然后使用代理的方法。最后,通過將代理強制轉換為 IDisposable 類型,調用 Dispose()方法關閉代理。當然,也可以將代理強制轉換為ICommunicationObject 類型,通過調用 Close()方法關閉代理:
ChannelFactory<IMyContract> factory = new ChannelFactory<IMyContract>();??
IMyContract proxy1 = factory.CreateChannel();
using(proxy1 as IDisposable) { proxy1.MyMethod(); }
IMyContract proxy2 = factory.CreateChannel();
proxy2.MyMethod();
ICommunicationObject c hannel = proxy2 as ICommunicationObject;
Debug.Assert(channel != null);
channel.Close();
我們還可以直接調用 CreateChannel()靜態方法,根據給定的綁定和地址值創建代理,這樣就不需要創建 ChannelFactory<T>類的實例了。
Binding binding = new NetTcpBinding();
EndpointAddress address = new EndpointAddress("net.tcp://localhost:8000");
IMyContract proxy = ChannelFactory<IMyContract>.CreateChannel(binding,address);
using(proxy as IDisposable) { proxy1.MyMethod(); }
16.可靠性
WCF 與其他面向服務技術之間最大的區別在于傳輸可靠性(Transport Reliability)與消息可靠性(Message Reliability)。傳輸可靠性(例如通過 TCP 傳輸)在網絡數據包層提供了點對點保證傳遞(Point-to-Point Guaranteed Delivery),以確保數據包的順序無誤。傳輸可靠性不會受到網絡連接的中斷或其他通信問題的影響。
顧名思義,消息可靠性負責處理消息層的可靠性,它與傳遞消息的數據包數量無關。消息可靠性提供了端對端保證傳遞(End-to-End Guaranteed Delivery),確保消息的順序無誤。消息可靠性與引入的中間方的數量無關,與網絡跳數(Network Hops)的數量也沒有關聯。消息可靠性基于一個行業標準。該行業標準為可靠的基于消息的通信維持了一個在傳輸層的會話。如果傳輸失敗,例如無線連接中斷,消息可靠性就會提供重試(Retries)功能。它還能夠自動處理網絡阻塞(Congestion)、消息緩存(Message Buffering)以及流控制(Flow Control),根據具體情況適時調整發送的消息數。消息可靠性還能夠通過對連接的驗證管理連接自身,并在不需要連接時清除它們。
(1).綁定與可靠性
WCF 的可靠性是在綁定中控制與配置的。一個特定的綁定可以支持可靠消息傳輸(Reliable Messaging),也可以不支持它。如果支持,也可以通過設置為啟用或禁用。何種綁定支持何種可靠性值,要根據綁定的目標場景而定。表 1-2 總結了綁定、可靠性、有序傳遞(Ordered Delivery)以及它們各自的默認值之間的關系。 BasicHttpBinding、NetPeerTcpBinding 以及兩種 MSMQ 綁定(NetMsmqBinding 和 MsmqIntegrationBinding)不支持可靠性。因為 BasicHttpBinding 面向舊的 ASMX Web服務,是不具有可靠性的。NetPeerTcpBinding 則為廣播場景設計。MSMQ 綁定針對斷開調用,在任何情況下都不存在傳輸會話。 WSDualHttpBinding 總是支持可靠性的,它能夠保持回調通道,確保基于 HTTP 協議的客戶端存在。
NetTcpBinding 綁定以及各種 WS 綁定,默認情況下并不支持可靠性,但是允許啟用對它的支持。由于 NetNamedPipeBinding 綁定總是擁有一個確定的從客戶端到服務的跳數,因而它的可靠性是綁定固有的。
(2).有序消息
消息可靠性確保了消息的有序傳遞,允許消息按照發送順序而非接收順序執行。此外,它保證了消息只會被傳遞一次。 WCF 允許開發者只啟用可靠性,而不啟用有序傳遞。此時,消息按照接收它們的順序進行傳遞。如果同時啟用了可靠性與有序傳遞,則所有綁定的默認值均支持可靠性。
(3).配置可靠性
通過編程方式或管理方式都可以配置可靠性(以及有序傳遞)。如果我們啟用了可靠性,則客戶端與服務宿主端必須保持一致,否則客戶端無法與服務通信。我們可以只對支持它的綁定配置可靠性。例 1-23 所示的服務端配置文件,使用了綁定配置節,啟用了 TCP 綁定的可靠性。 例 1-23:啟用 TCP 綁定的可靠性 .... <bindings>
<netTcpBinding>
<binding name = "ReliableTCP">
<reliableSession enabled = "true"/>
</binding>
</netTcpBinding>
</bindings>
.....
至于編程配置方式,TCP 綁定和 WS 綁定提供了略微不同的屬性來配置可靠性。例如,NetTcpBinding 綁定接受一個 Boolean 型的構造函數參數,用來啟動可靠性:? public class NetTcpBinding : Binding,... { public NetTcpBinding(...,bool reliableSessionEnabled); //更多成員 } 我們只能在對象的構造期間啟用可靠性。 NetTcpBinding 定義了只讀的 ReliableSession 類,通過它獲取可靠性的狀態。
(4).必備有序傳遞
理論上,服務代碼和契約定義應該與它使用的綁定及屬性無關。服務不應該考慮綁定,在服務代碼中也不應該包含它所使用的綁定。不管配置的綁定是哪一種,服務都應該能夠正常工作。然而實際上,服務的實現或者契約本身都會依賴于消息的有序傳遞(Ordered Delivery)。為了幫助契約或服務的開發者能夠約束支持的綁定,WCF 定義了DeliveryRequirementsAttribute 特性DeliveryRequirements 特性可以應用到服務一級,對服務的所有終結點施加影響,或者只對公開了特定契約的終結點施加影響;如果應用到服務一級,則意味著選用有序傳遞是根據具體實現作出的決策。DeliveryRequirements 特性也可以應用到契約一級,它會對所有支持該契約的服務施加影響。這樣一種在契約一級的應用,體現了對有序傳遞的要求是根據設計作出的決策。這一約束會在裝載服務時得到執行與驗證。如果一個終結點包含的綁定并不支持可靠性;或者支持可靠性,卻被禁用了;或者雖然啟用了可靠性,但卻禁用了有序傳遞,那么裝載服務就會失敗,拋出 InvalidOperationException 異常。
注意:命名管道綁定符合有序傳遞的約束。 舉例來說,如果不考慮契約,要求服務的所有終結點都啟用有序傳遞,則可以將 DeliveryRequirements 特性直接應用到服務類上:
[DeliveryRequirements(RequireOrderedDelivery = true)]
class MyService : IMyContract,IMyOtherContract {...}?
通過設置 TargetContract 屬性,只有支持目標契約的服務終結點才需要遵循可靠的有序傳遞的約束:??
[DeliveryRequirements(TargetContract=typeo(IMyContract), RequireOrderedDelivery = true)]
class MyService : IMyContract,IMyOtherContract {...}?
如果將 DeliveryRequirements 特性應用到契約接口上,則支持該契約的所有服務都必須遵循這一約束:?
[DeliveryRequirements(RequireOrderedDelivery = true)]
[ServiceContract]
interface IMyContract {...}??
class MyService : IMyContract {...}??
class MyOtherService : IMyContract {...}??
RequireOrderedDelivery 的默認值為 false,如果只應用了 DeliveryRequirements 特性,沒有設置 RequireOrderedDelivery 的值,則是無效的。 [ServiceContract]
interface IMyContract {...}
[DeliveryRequirements]
[ServiceContract]
interface IMyContract {...}
[DeliveryRequirements(RequireOrderedDelivery = false)]
[ServiceContract]
interface IMyContract {...}

?

?

轉載于:https://www.cnblogs.com/SanMaoSpace/archive/2012/05/19/2509137.html

總結

以上是生活随笔為你收集整理的WCF服务编程 学习笔记(2)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。