什麼是WCF WCF的全稱是:Windows Communication Foundation。從本質上來講,它是一套軟件開發包,是微軟公司推出的符合SOA思想的技術框架。
WCF爲程序員提供了豐富的功能,其中包括:託管、服務實例管理、異步、安全、事務管理、離線隊列等。而且WCF對產業中的標準協議進行了封裝和定義,它把程序員從繁瑣的通訊、格式編碼中解放出來,使得程序員可以專一於業務邏輯的實現。同時,WCF統一了微軟公司以前推出的多種分佈式技術,其中包括:
1. Web服務和WSE。
2. .Net Remoting。
3. .Net 企業服務。
4. 微軟消息隊列(MSMQ)。
WCF對這些技術的集成包括兩個方面:
1. WCF的架構自己吸收了這些技術的精華。
2. WCF開發的服務/客戶端能夠和現有的Web服務、MSMQ程序進行交互。
2.2 .Net Framework的四大致系架構
.Net Framework的四大致系包括:WCF、WF、WPF、WCS。
WCF(Windows Communication Foundation):主要是用來作鬆耦合的分佈式通信的,它還有另一個名字叫Indigo,是微軟邁向SOA一個重要的標誌。WCF是.Net Framework的一個子集。
WF(Windows Wordflow Foundation):工做流引擎。
WPF(Windows Presenttation Foundation):WPF使用矢量繪圖引擎,提供了一種聲明式編程語言XAML,用來開發具備炫目視覺效果的應用程序。
WCS(Windows Card Space):採用了一種新的數字標識技術來實現相似網銀單點登陸的功能,主要用來防止釣魚式攻擊等,從網絡安全方面提供了一個保障。
2.3 WCF體系框架
從圖上來看,WCF的體系基本包含了4個方面,分別爲契約、服務運行時、消息和寄宿。
1 契約(能幹什麼)
從SOA的概念上來看,契約屬於一個服務公開接口的一部分。一個服務的契約,定義了服務端公開的服務方法、使用的傳輸協議、可訪問的地址、傳輸的消息格式等內容。
基本上,契約的定義描述了該服務的功能和做用,它告訴SOA系統中的其它節點這個服務是「幹什麼」的。
2 服務運行時(怎麼幹)
服務運行時定義了服務在運行時的具體行爲。若是說契約描述了服務是「幹什麼」的,那麼服務運行時就在必定程度上描述了服務是「怎麼幹」的。
3 消息
消息方面包含了消息的傳輸方式、消息的編碼與解碼。消息方面的內容基本屬於服務邊界之內的具體實現。具體的傳遞時限,必須符合在契約中定義的綁定協議。
4 激活和宿主(在哪幹)
激活和宿主屬於WCF程序的部署方式。一個WCF服務須要在一個可運行的程序中寄宿,咱們能夠把宿主理解爲WCF運行的容器。經常使用的寄宿方式包括自寄宿、IIS寄宿、Windows激活服務、Windows服務、Com+組件等。根據SOA的原則,激活和宿主類型的變化不會影響服務自己的特性和外部對該服務的訪問,而WCF在這一方面也確實作的很是出色。
2.4 WCF基礎概念介紹
WCF框架中包含了大量的基礎概念,本小節將以簡短的篇幅帶領你們瀏覽這些概念,使你們可以對WCF的基本概念有所瞭解。
1. 地址(Address)
在WCF框架中,每一個服務都具備惟一的地址。在SOA系統中,其它服務和客戶端經過服務的地址來對服務進行訪問。一個服務的地址由一個統一資源標示符(URI)來表示。下面是幾個地址示例:
http://localhost /Service
net.tcp://dc3web1:9023/MyService
net.msmq://localhost/MyMsMqService
實際上地址的形式不止這些,它們的構成形式以下所示:
http://[Hostname]:[Port]/[ServiceAddress]
https://[Hostname]:[Port]/[ServiceAddress]
net.tcp://[Hostname]:[Port]/[ServiceAddress]
net.pipe://[Hostname]:[Port]/[ServiceAddress]
net.msmq://[Hostname]/public(private)/[QueueName]
msmq.formatname://{msmq format name}
2. 綁定(Binging)
綁定定義了服務與外部通訊的方式。它由一組稱爲綁定元素的元素而構成,這些元素組合在一塊兒造成通訊基礎結構。一個綁定能夠包含如下內容。
1. 通訊所使用的協議,如HTTP、TCP、P2P等。
2. 消息編碼方式,如純文本、二進制編碼、MTOM等。
3. 消息安全保障策略。
4. 通訊堆棧的其它任何要素。
3. 契約(Contract)
在2.3節中,筆者已經介紹了契約的基本概念。在WCF中一共包含了4種契約,分別是服務契約、數據契約、錯誤契約和消息契約。
1. 服務契約[ServiceContract]
服務契約將多個相關的操做聯繫在一塊兒,組成單個功能單元。
2. 數據契約[DataContract]
數據類型的說明稱爲數據契約。服務使用的數據類型必須在元數據中進行描述,以使其它各方面能夠與該服務進行交互操做。
3. 錯誤契約[FaultContract]
錯誤類型的說明稱爲錯誤契約。
4. 消息契約[MessageContract]
消息契約描述消息的格式。
5. 終節點(EndPoint)
終結點是用來發送或接收消息(或同時執行這兩種操做)的構造。一個終節點由三個要素組成,分別是筆者已經介紹了的:地址、綁定和契約。以SOA的思想來看,一個終節點就至關於服務的公共接口。
6. 元數據
服務的元數據描述服務的特徵,外部實體須要瞭解這些特徵以便與該服務進行通訊。服務所公開的元數據包括XML架構文檔(用於定義服務的數據協定)和WSDL文檔(用於描述服務的方法)。啓用元數據後,WCF經過檢查服務及其終節點自動生成服務的元數據。
在WCF的行爲章節中,筆者將介紹兩種WCF的元數據發佈方式。
7. 宿主
服務必須承載於某個進程中。宿主是控制服務的生存期的應用程序。
3 第一個WCF程序
在瞭解了WCF的基本概念之後,本節將按照程序員學習新技術的習慣,給出一個簡單的服務契約的HelloWord實例跟一個數據契約的實例。
3.1 HelloWord服務契約的定義程序員
using System.ServiceModel ; [ServiceContract] public interface IService1 { [OperationContract] string HelloWord(string name); } public class Service1 : IService1 { public string HelloWord(string name) { return name + "說:HelloWord"; } }
Demo1服務契約
3.2 數據契約的定義web
using System.ServiceModel ; using System.Runtime.Serialization ; [DataContract] public class People { [DataMember] public string name; [DataMember] public int age; public People(string name,int age) { this.name = name; this.age = age; } } [ServiceContract] public interface IService1 { [OperationContract] string GetInfomation(People people); }
Demo2數據契約
知識點:經過自寄宿在服務器端模擬客戶端
4 WCF消息交換模式
WCF客戶端與服務器之間是經過消息進行通信,瞭解WCF的消息交換模式有助於你們對消息的發送和接受由更直觀的理解。在WCF中,有三種消息交換模式:數據報模式、請求-響應模式、雙工模式。
4.1 數據報模式(One-Way Calls)
數據報模式指的是發送端負責把消息發送給對方而且收到確認消息以後,就完成交互的方式。在這種模式下,發送方惟一能肯定的就是消息發送成功,而對於消息是否最終到達服務的終節點、是否被成功處理、發揮的結果如何都一無所知。
數據報模式存在如下特色:
1. 返回類型只能是void
2. 不能包含ref或者out類型的參數
3. 只有客戶端發起請求,服務端並不會對請求進行回覆。
經過設置OperationContract的IsOneWay=True能夠將消息模式設置爲數據報模式,具體方法以下:
[OperationContract(IsOneWay=true)]
void Test();
Demo3數據報模式與請求-響應模式
4.2 請求-響應模式(Request/Reply)
在請求響應模式中,客戶端發送一個消息而且接收一個返回消息來完成一次交互。在該模式中,消息的發起端必然是客戶端,而且從服務端返回只有一條消息。客戶端在發送出消息後會阻止當前線程而且等待服務端返回消息。
請求響應模式是缺省的消息交換模式,相似於HTTP協議中的請求/響應模型,這種消息交換模式是使用最多的一種。請求-響應模式有以下特色:
1. 調用服務方法後須要等待服務的消息返回
2. 在這種模式下,服務端永遠是服務端,客戶端就是客戶端,職責分明。
它是缺省的消息交換模式,設置OperationContract即可以設置爲此種消息交換模式,方法以下:
[OperationContract]
void Test();
Demo3數據報模式與請求-響應模式
4.3 雙工模式(Duplex)
在雙工模式中,客戶端和服務端均可以任意地向對方發送消息,而對方也能夠以任意的次序來接收消息。在這種模式下,發送端和接收端的概念變得再也不適用,取而代之的是通訊的兩個端點。
這種模式相對較複雜一些,服務端的契約定義以下所示:編程
public interface ICallBack { [OperationContract(IsOneWay = true )] void UpdateInterval(int seconds); } [ServiceContract(CallbackContract=typeof(ICallBack ))] public interface IService1 { [OperationContract] void Heartbeat(); }
Demo4雙工模式
5 WCF綁定
綁定的本質是一個配置好的通道棧,爲了方便程序員專一於業務邏輯,WCF提供了一系列經常使用的綁定。
5.1 標準綁定
在.NET Framework 3.5中WCF一共提供了12種標準綁定,這些綁定基本可以覆蓋用戶全部的傳輸要求。
表5.1 12種標準綁定簡要說明
綁定名稱 簡要介紹 所需.Net Framework版本
basicHttpBinding 基於WS-I Basic Profile 1.1的Web服務 3.0
wsHttpBinding 針對改進的Web服務的綁定,包括WS-Security,WS-Transaction等元素 3.0
wsDualHttpBinding 提供雙工通訊的HTTP綁定 3.0
webHttpBinding 支持REST/POX服務的綁定,使用XML/JSON序列化 3.0
netTcpBinding 使用TCP傳輸協議在跨主機的局域網內使用,支持可靠性、事務、安全等特性、而且該綁定被特別優化來支持WCF系統。可是,使用該綁定須要確保通訊雙方都基於WCF構建,這裏並不符合SOA的原則 3.0
netNamedPipeBinding 支持和netTcpBinding大體相同的特性,但因爲使用命名管道進行通訊,因此通訊不能跨越主機 3.0
netMsmqBinding 使用微軟消息隊列(MSMQ)協議來進行異步脫機的消息交互。關於該綁定的交互方式,在本書的後續章節中有詳細的介紹 3.0
netPeerTcpBinding 使用P2P協議在網格中進行消息交互 3.0
msmqIntegrationBinding 該綁定能夠用來在WCF消息和MSMQ消息中進行轉換 3.0
wsFederationHttpBinding 該綁定支持使用了聯合安全機制的Web服務 3.0
ws2007HttpBinding 該綁定繼承自wsHttpBinding,其主要涉及目的是爲了支持2007年新制定的WS標準 3.5
ws2007FederationHttpBinding 該綁定繼承自wsFederationHttpBinding,和wsHttpBinding同樣,其設計目的是爲了支持2007年新制定的WS標準 3.5
5.2 設置綁定的方式
在WCF程序中,有兩種方式來設置綁定,在代碼中設置綁定和在配置文件中設置綁定。通常來講,在配置文件中設置綁定更爲經常使用,這是由於綁定的設置經常須要根據部署環境的改變而改變。
1. 在配置文件中設置綁定設計模式
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.web> <compilation debug="true" /> </system.web> <system.serviceModel> <services> <servicename="WcfServiceLibrary1.Service1" behaviorConfiguration="WcfServiceLibrary1.Service1Behavior"> <endpoint address ="HelloWord " binding="wsHttpBinding " contract="WcfServiceLibrary1.IService1 "> </endpoint> </service> </services> </system.serviceModel> </configuration>
2. 在代碼中設置綁定瀏覽器
using System.ServiceModel; using System.ServiceModel.Channels; NetNamedPipeBinding binding = new NetNamedPipeBinding (); EndpointAddress address = new EndpointAddress(new Uri("net.pipe://localhost/HelloWorld ")); using (HelloWorldProxy proxy = new HelloWorldProxy()) { Console.WriteLine(proxy.HelloWorld("Kevin")); //利用代理調用服務 Console.Read(); }
6 WCF契約
6.1 契約的定義和分類
6.1.1 什麼是契約
在2.3節中,筆者已經介紹了契約的基本概念。
契約(Contract)是 WCF 的消息標準,告知客戶端如何與服務器聯繫交互。通常狀況下,咱們用接口(Interface)來定義服務契約(Service Contract)。
6.1.2 契約的分類
在WCF中一共包含了4種契約,分別是服務契約、數據契約、錯誤契約和消息契約。
6.2 服務契約
在第3節中,筆者已經針對服務契約和數據契約作過兩個Demo,所以服務契約和數據契約本節不作重點。
下面來看下服務契約都有哪些屬性:
ServiceContract
? ConfigurationName:其設置信息在配置文件中的名稱。
? Name / Namespace:自定義該服務契約的名稱和命名空間。
? SessionMode:設置服務契約的 Session 方式,包括Allowe、NotAllowed、Required。
? CallbackContract:設置 duplex 模式時的回調類型。
? ProtectionLevel:指定消息保護方式,能夠對消息進行加密和簽名處理。
OperationContract
? AsyncPattern:用於定義異步服務方法。
? IsInitiating:指示服務方法可否啓動一個 Session。
? IsTerminating:指示服務方法調用完成是否結束 Session。
6.3 數據契約
在第3節中,筆者已經針對服務契約和數據契約作過兩個Demo,所以服務契約和數據契約本節不作重點。
下面來看下數據契約都有哪些屬性:
DataContract
? Name / Namespace:自定義名稱和命名空間。
DataMember
? Name:自定義名稱。
? IsRequired:指示該成員序列化前必須被賦值。
6.4 錯誤契約
在WCF中消息首先會被序列化爲SOAP消息再進行發送。也就是說,全部的數據都包含在SOAP消息中,包括異常信息。SOAP規定了異常消息的攜帶方式,那就是所有放入Fault節點中。Fault節點必須是Body節點的子節點,同時,一個SOAP消息中只能出現一個Fault節點。
表6.1 Fault的子節點
子節點 描述
<Code> 供識別故障的代碼,可包含兩個子節點:Code和Subcode
<Reason> 可供人閱讀的有關故障的說明
<Node> 可選,指向SOAP消息中引起錯誤的節點
<Role> 可選,發生錯誤時節點所處的角色
<Detail> 可選,包含了詳細的錯誤信息
說明:不管是使用哪一種錯誤方式:WCF系統最終會把錯誤信息放入Fault節點中進行傳輸。
6.4.1 WCF中默認的異常處理
WCF 將服務異常(Exception)轉換成 SOAP faults,傳遞到客戶端後再次轉換成 Exception。只不過缺省狀況下,咱們很難從中獲取有意義的信息。
[ServiceContract]
public interface IService1
{
[OperationContract]
int Add(int a, int b);
}
public class Service1 : IService1
{
public int Add(int a, int b)
{
throw new Exception("錯誤");
}
}
異常信息以下所示:
Unhandled Exception: System.ServiceModel.FaultException: The server was unable t
o process the request due to an internal error. For more information about the
error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehavio
rAttribute or from the <serviceDebug> configuration behavior) on the server in o
rder to send the exception information back to the client, or turn on tracing as
per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server t
race logs.
Server stack trace:
at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message
reply, MessageFault fault, String action, MessageVersion version, FaultConverte
r faultConverter)
at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRunt
ime operation, ProxyRpc&rpc)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean on
eway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpantim
eout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean on
eway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCall
Message methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage req
Msg, IMessageretMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&msgDa
ta, Int32 type)
at ConsoleClient.ServiceReference1.IService1.TestException()
at ConsoleClient.ServiceReference1.Service1Client.TestException() in e:\wcf講
稿(kevin)\demo-kevin\demo5wcf中默認異常處理\consoleclient\service references\s
ervicereference1\reference.cs:line 50
at ConsoleClient.Program.Main(String[] args) in E:\WCF講稿(Kevin)\Demo-Kevi
n\Demo5WCF中默認異常處理\ConsoleClient\Program.cs:line 13
請按任意鍵繼續. . .
6.4.2 WCF中的FaultException
咱們將代碼改成以下:
public void TestException()
{
throw new Exception(new FaultException("異常測試").ToString());
}
此次輸出信息要有好的多,異常信息以下所示:
Unhandled Exception: System.ServiceModel.FaultException: 異常測試
Server stack trace:
at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRunt
ime operation, ProxyRpc&rpc)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean on
eway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpantim
eout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean on
eway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCall
Message methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage req
Msg, IMessageretMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData&msgDa
ta, Int32 type)
at Client.ServiceReference1.IService1.Add(Int32 a, Int32 b)
at Client.ServiceReference1.Service1Client.Add(Int32 a, Int32 b) in e:\wcf講
稿(kevin)\demo異常處理\異常處理\client\service references\servicereference1\re
ference.cs:line 50
at Client.Program.Main(String[] args) in E:\WCF講稿(Kevin)\Demo異常處理\異
常處理\Client\Program.cs:line 13
請按任意鍵繼續. . .
6.4.3 WCF中的FaultContractAttribute
另外,咱們能夠經過FaultContractAttribute傳遞更詳細的異常信息給客戶端。
代碼以下所示:安全
[ServiceContract] public interface IService1 { [OperationContract] [FaultContract(typeof(FaultMessage))] int Add(inta,int b); } [DataContract] public class FaultMessage { [DataMember] public string Message; [DataMember] public interrorCode; } public class Service1 : IService1 { public int Add(int a, int b) { FaultMessagefaultMessage = new FaultMessage(); faultMessage.Message = "錯誤信息"; faultMessage.errorCode = 1234; throw new FaultException<FaultMessage>(faultMessage, faultMessage.Message); } }
客戶端的異常信息
Unhandled Exception: System.ServiceModel.FaultException`1[Client.ServiceReferenc
e1.FaultMessage]: 錯誤信息 (Fault Detail is equal to Client.ServiceReference1.Fa
ultMessage).
注意:因爲單程操做沒有任何返回值,也不回把任何錯誤發還給客戶端,因此不能在單程操做上使用錯誤契約,否則會致使運行時異常。
6.5 消息契約
使用數據契約已經足以應付消息交互雙方對數據內容的全部要求,可是對消息的格式卻沒法全面控制。若是想要定製SOAP消息的Head和Body內容,這就須要定製SOAP消息的Head和Body內容,這就須要用到消息契約。消息契約在實際WCF編程中使用的並很少,本節不作詳細討論,只給出一個簡單的示例:服務器
[MessageContract ] public interface MyMessage { [MessageHeader ] public intSessionId; [MessageHeader] public string Description; [MessageBodyMember ] public string A; [MessageBodyMember] public string B; [MessageBodyMember] public string C; }
說明:消息中包含Header跟Body兩部分。Header用來存放上下文信息,Body用來存放數據信息。
7 WCF中的行爲
行爲(Behaviors)指的是那些影響WCF系統運行的設置。行爲在宿主和客戶端啓動後發揮做用,WCF系統中行爲包括服務行爲(Service Behavior)和操做行爲(Operation Behavior)。服務行爲做用在終節點上,常見的服務行爲包括實例控制、併發控制、元數據發佈等。操做行爲做用於某一服務操做上,常見的操做行爲包括事務流設置等。
7.1 實例控制
當服務端接收到客戶端的調用以後,須要把該消息發送到具體的服務實例上。實例管理,就是和全部實例的分配、管理有關的技術統稱。實例管理屬於服務行爲的一種,本節將簡要介紹下實例管理。
7.1.1 實例管理的設置
全部的服務行爲都經過ServiceBehavior特性來進行設置,實例管理業不例外。實例管理經過ServiceBehavior特性的InstanceContextMode屬性進行設置,該屬性的類型爲InstanceContextMode枚舉類型。枚舉類型定義以下:
public enumInstanceContextMode
{
PerSession = 0 ,
PerCall = 1 ,
Single = 2
}
下面將經過一個例子來演示如何爲服務類型配置實例策略網絡
using System.ServiceModel; [ServiceContract] public interface IService1 { [OperationContract] string HelloWord(string name); } [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession )] public class Service1 : IService1 { public string HelloWord(string name) { return name + "說:HelloWord"; } }
7.1.2 PerSession實例策略
PerSession是默認的實例策略,PerSession表明了會話的實例管理模式。會話管理模式相對較爲負責,僅僅設置服務行爲是不夠的,須要知足一下3個方面才能在客戶端和服務端之間創建會話。這3個方面是:
1. 服務契約的會話設置
2. 服務行爲的實例模式設置
3. 綁定的選擇
7.1.2.1 服務契約的會話設置
服務契約的會話設置經過ServerContract的SessionMode屬性進行設置,SessionMode屬性是枚舉類型,SessionMode定義以下:
public enumSessionMode
{
Allowed = 0,
Required = 1,
NotAllowed = 2
}
服務契約的SessionMode設置以下所示:
[ServiceContract(SessionMode=SessionMode.Allowed)]
public interface IService1
{
[OperationContract]
string HelloWord(string name);
}
7.1.2.2 服務行爲的實例模式設置
這裏沒有太多可討論的話題,爲了使用會話模式,實例模式必須設置爲PerSession。
7.1.2.3 綁定的選擇
綁定的選擇須要注意的就是綁定是否支持會話,如basicHttpBinding則沒法應用於會話實例管理模式。
7.1.3 PerCall實例策略
當服務端採用了PerCall實例策略後,每一個客戶端的請求消息都會被分發到一個新的服務實例上。而一旦這個調用返回後,服務實例則會被銷燬。
7.1.4 Single實例策略
Single實例策略很是相似設計模式中的單件模式,全部的客戶端代理髮送的消息都會被應用到同一個服務實例上。
7.2 併發控制
併發的概念也能夠理解爲多線程,在WCF中,併發也屬於一種服務行爲。
7.2.1 併發管理的設置
和實例管理同樣,併發管理業經過服務行爲的屬性來設置。併發管理的屬性名爲ConcurrencyMode,它的類型是枚舉類型,該定義類型以下:
public enumConcurrencyMode
{
Single = 0,
Reentrant = 1,
Multiple = 2
}
7.2.2 Single併發模式
ConcurrentMode.Single併發模式是默認的併發設置,當設置了Single模式之後,WCF會爲服務實例的操做提供同步鎖。Single併發模式的策略較爲極端,等同於在整個操做上加上了同步鎖,在不少狀況下,這並非必須的。
7.2.3 Multiple併發模式
ConcurrentMode.Multiple表示WCF不會主動爲服務操做添加任何鎖,每一個操做都容許客戶端多個請求同時訪問,這樣作的好處是提升了系統的運行效率,防止消息被阻塞。
7.2.4 Reentrant併發模式
本質上,ConcurrentMode.Reentrant與ConcurrentMode.Single模式同樣:在同一時間只容許一個線程訪問服務操做,在訪問進入操做以前必須得到同步鎖。所不一樣的是,ConcurrentMode.Reentrant模式解決了ConcurrentMode.Single模式的死鎖問題。
實際上ConcurrentMode.Reentrant模式的設計正是爲了解決死鎖問題。當服務操做在調用其它服務,或者回調客戶端操做時,會釋放服務端的同步鎖,這樣就可以保證在回調消息返回或者調用鏈回到服務端時不會發生死鎖。在一些消息量較大,服務操做中較長時間訪問其它操做的狀況下,ConcurrentMode.Reentrant模式可以有效的保證配對消息可以在服務操做向外調用時進入操做。
7.3 元數據發佈
在之前的小節中,筆者已經介紹了關於元數據的概念。
在WCF中,爲了使客戶端得到這些元數據而且知道如何訪問服務,宿主程序每每會採用某種方式來發布服務的元數據,本節將討論具體元數據的發佈技術。
7.3.1 HTTP-GET方式發佈元數據
下面的配置文件展現瞭如何配置元數據行爲來容許客戶端使用HTTP-GET方式獲取元數據多線程
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.web> <compilation debug="true" /> </system.web> <system.serviceModel> <services> <service name="WcfServiceLibrary1.Service1" behaviorConfiguration="WcfServiceLibrary1.Service1Behavior"> <host> <baseAddresses> <add baseAddress = "http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/" /> </baseAddresses> </host> <endpoint address ="" binding="wsHttpBinding" contract="WcfServiceLibrary1.IService1"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WcfServiceLibrary1.Service1Behavior"> <serviceMetadatahttpGetEnabled="True "/> <serviceDebugincludeExceptionDetailInFaults="False" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
當啓動了HTTP-GET的元數據獲取方式後,能夠嘗試經過瀏覽器來查看服務端的元數據。在地址欄輸入http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/?wsdl
就能夠獲得下圖的結果:
說明:除了在配置文件中配置元數據行爲,還能夠經過程序設置是否啓用HTTP-GET,可是筆者不推薦你們這樣去作。在此只是想讓你們知道有這一作法。
7.3.2 MEX終節點方式發佈元數據
MEX終節點方式發佈元數據配置起來也很簡單,下面請看一個配置文件:架構
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.web> <compilation debug="true" /> </system.web> <system.serviceModel> <services> <service name="WcfServiceLibrary1.Service1" behaviorConfiguration="WcfServiceLibrary1.Service1Behavior"> <host> <baseAddresses> <add baseAddress = "http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/" /> </baseAddresses> </host> <endpoint address ="" binding="wsHttpBinding" contract="WcfServiceLibrary1.IService1"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/> <endpoint address="mex" binding="mexNamedPipeBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WcfServiceLibrary1.Service1Behavior"> <serviceMetadatahttpGetEnabled="True"/> <serviceDebugincludeExceptionDetailInFaults="False" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
當配置好MEX終節點之後,就能夠再VS2008中的客戶端,點擊Add Service Reference…,而後輸入元數據的地址,來獲取服務器端的元數據。本例中的經過mexHttpBinding訪問的元數據地址爲http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/mex,tcp跟namepipe的訪問地址須要根據實際狀況來進行構造。具體構造方法請參照之前章節的綁定。