學習WCF的目的在於使用WCF建立服務,使Sivlerlight程式能夠查詢和修改Oracle資料的內容,資料庫的操作不可避免要涉及資料庫事務(Transaction),而基於資料庫事務的操作則要求對於某特定用戶端程式,開始事務(Transaction Begin)後,事務對象保持不變,才能保證Commit或Rollback操作的成功,為此,查詢了相關資料,好像可以通過WCF的服務執行個體(Service Instance)來控制。
一、基本介紹
嘗試了建立一個基本的WCF執行個體後,開始學習WCF的服務執行個體,服務執行個體主要控制WCF用戶端與服務端互動時服務端的行為,有三類執行個體模式:
1:單調服務(Per-Call Service):每次的用戶端請求分配一個新的服務執行個體。
2:會話服務(Sessionful Service):則為每次用戶端串連分配一個服務執行個體
3:單例服務(Singleton Service):所有的用戶端會為所有的串連和啟用物件共用一個相同的服務執行個體。類似於Net Remoting的SingleTon模式
二、範例程式碼
通過一個例子來說明幾種服務的區別:
1.契約(CONTRACT)
包括三個函數:SetValue、GetValue、GetSid
[ServiceContract] public interface IService1 { [OperationContract] string SetValue(int value); [OperationContract] string GetSid(); [OperationContract] string GetValue(); // TODO: Add your service operations here }
服務功能實現(ServiceBehavior)
(1):建構函式:列印當前串連的SessionId
(2):SetValue函數:為類中的intvalue變數賦值
(3):GetValue函數:擷取類中的intvalue變數的值
(4):GetSid函數:擷取當前串連的SessionId
(5):Dispose函數:顯示中斷連線的資訊,以及該串連的SessionId
public class Service1 : IService1,IDisposable { private int intvalue; private string currentsid; public Service1() { try { currentsid = OperationContext.Current.SessionId; } catch (Exception ex) { Console.WriteLine("get current sid failed,operatincontext.currect is null?" +(OperationContext.Current == null) +" "); } Console.WriteLine("Service1 connected:" + currentsid); } public string SetValue(int value) { intvalue = value; return string.Format("You entered: {0}", value); } public string GetSid() { return currentsid; } public string GetValue() { return intvalue.ToString(); } #region IDisposable Members public void Dispose() { Console.WriteLine("Service1 disconnected:" + currentsid); } #endregion }
2.寄宿(Host):
ServiceReference1.Service1Client sc1 = new ServiceReference1.Service1Client(); string a; int tmpInt; while ((a = Console.ReadLine()) != "exit") { if (int.TryParse(a,out tmpInt)) Console.WriteLine(sc1.SetValue(tmpInt)); else if (a == "get") Console.WriteLine(sc1.GetValue()); else if (a == "sid") Console.WriteLine(sc1.GetSid()); } ((IDisposable)sc1).Dispose();
Host對應的app.config:
<?xml version="1.0" encoding="utf-8" ?> - <configuration>- <system.serviceModel> <diagnostics performanceCounters="All" /> - <behaviors>- <serviceBehaviors>- <behavior name="NewBehavior0"> <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:8585/is/metadata" /> </behavior> </serviceBehaviors> </behaviors>- <services>- <service behaviorConfiguration="NewBehavior0" name="WcfService1.Service1"> <endpoint address="" binding="wsDualHttpBinding" bindingConfiguration="" name="ep1" contract="WcfService1.IService1" /> - <host>- <baseAddresses> <add baseAddress="http://127.0.0.1:8585/is" /> </baseAddresses> </host> </service> </services> </system.serviceModel> </configuration>
這裡使用了wsDualHttpBinding的binging,是因為並不是所有的Binding都支援 Session ,對Per-Call和Singleton而言,binding影響不大。對PerSession,就必須使用特定的Binding, 才可以,否則最終指向的是PerCall,具體的可再進行相關查詢
3.用戶端(Client)
功能:
當使用者在命令列輸入一個數字時,則調用SetValue函數,將該數字賦給WCF的intvalue值並列印提示資訊,
當使用者在命令列中輸入get時,調用GetValue函數擷取intvalue值並列印出來
當使用者在命令列中輸入sid時,調用GetSid函數擷取當前的SessionId並列印出來
當使用者在命令列中輸入exit時,中斷連線並退出函數
ServiceReference1.Service1Client sc1 = new ServiceReference1.Service1Client(); string a; int tmpInt; while ((a = Console.ReadLine()) != "exit") { if (int.TryParse(a,out tmpInt)) Console.WriteLine(sc1.SetValue(tmpInt)); else if (a == "get") Console.WriteLine(sc1.GetValue()); else if (a == "sid") Console.WriteLine(sc1.GetSid()); } ((IDisposable)sc1).Dispose();
三、三種執行個體模式的測試
1:persession模式
WCF預設即為該模式,不用對代碼進行修改,直接運行即可。
開啟多個Client命令列,發現每開啟一個命令列,Host的命令列即會列印出一個SessionID
在各Client命令列中,執行setvalue,getvalue,getsid的操作,在Session內部都是一致的,且不與其它Session相關,相關如下:
2:percall模式
需要在Service1的類聲明前加上一句聲明,加完後如下:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] public class Service1 : IService1,IDisposable
該模式下,每一次任何操作均會開啟一個新的Session,但SessionID相同,操作完成後馬上關閉該Session,且intvalue的值也不會儲存,如果開啟多個Client,其SessoinID也相同,如下:
3.Single模式
需要在Service1的類聲明前加上一句聲明,加完後如下:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class Service1 : IService1,IDisposable
該模式下,無論開啟多少個Client,服務端只有一個Session,多個Client的intvalue值是共用的(也就是說ClientA將該值設為123,那ClientB擷取的值就是123)
此外,在這個模式下,沒有SessionID的概念,在嘗試擷取這個ID時,會返回空值,如下: