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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

重温WCF之会话Session(九)

發布時間:2025/5/22 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 重温WCF之会话Session(九) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載地址:http://blog.csdn.net/tcjiaan/article/details/8281782

每個客戶端在服務器上都有其的獨立數據存儲區,互不相干,就好像A和服務器在單獨談話一樣,所以叫會話

?下面,我們寫一個例子,看看在不支持會話的綁定上連續調用兩個有關聯的代碼,會發生什么情況。

?

[ServiceContract]public interface IService{[OperationContract(IsOneWay = true)]void SetValue(int n);[OperationContract]int GetValue();}[ServiceBehavior(IncludeExceptionDetailInFaults = true)]public class MyService : IService{public MyService(){Console.WriteLine("-------------------------------");Console.WriteLine("{0} - 服務被實例化。",DateTime.Now.ToLongTimeString());}// 在析構函數中也輸出信息~MyService(){Console.WriteLine("{0} - 服務實例被釋放。", DateTime.Now.ToLongTimeString());Console.WriteLine("--------------------------------");}/// <summary>/// 私有字段/// </summary>private int m_Value = int.MinValue;public void SetValue(int n){this.m_Value = n;Console.WriteLine("會話ID:{0}", OperationContext.Current.SessionId);}public int GetValue(){Console.WriteLine("會話ID:{0}", OperationContext.Current.SessionId);return this.m_Value;}}

在服務類中,我們分別在構造函數和析構函數中輸出一些內容,以便于在運行時看到服務什么時候被實例化,什么時候被釋放。同時,在調用每個操作協定時,我們也輸出當前會話的ID,如果空就說明當前沒有啟用會話。

接著,實現服務主機,我們使用不支持的Bindding。

static void Main(string[] args){Console.Title = "WCF服務器端";using (ServiceHost host = new ServiceHost(typeof(MyService), new Uri("http://127.0.0.1:1211/sv"))){// 綁定BasicHttpBinding binding = new BasicHttpBinding();binding.Security.Mode = BasicHttpSecurityMode.None;//不需要安全模式host.AddServiceEndpoint(typeof(IService), binding, "/ep");// 服務元數據ServiceMetadataBehavior mb = new ServiceMetadataBehavior();mb.HttpGetEnabled = true;mb.HttpGetUrl = new Uri("http://127.0.0.1:8008/meta");host.Description.Behaviors.Add(mb);host.Opened += (sender, arg) =>{Console.WriteLine("服務已啟動。");};try{host.Open();//打開服務 Console.Read();}catch (Exception ex){Console.WriteLine(ex.Message);}}}

然后,實現客戶端,為了使演示操作更方便,客戶端使用Windows Forms項目,界面大致如下圖所示,源代碼我后面會上傳到資源。

?

服務有兩個操作,從前面服務類的定義我們知道,我在服務類內部定義了一個私有字段,而公開的兩個操作協定,分別是設置這個值和獲取這個值。

public partial class Form1 : Form{WS.ServiceClient client = null;public Form1(){InitializeComponent();client = new WS.ServiceClient();// 關閉通道this.FormClosing += (frmsender, frmargs) => client.Close();}private void btnCall1_Click(object sender, EventArgs e){int v;if (!int.TryParse(this.txtInput.Text, out v)){return;}client.SetValue(v);}private void btnCall2_Click(object sender, EventArgs e){int v = client.GetValue();this.txtOutput.Text = v.ToString();}}

?

我們現在要測試一下,看看先后調用這兩個方法,能不能得到我們預期的值。即如果我調用SetValue(100),那么,在調用GetValue時應該返回100,事實是不是這樣呢?

八格牙路,我沒有看到預期的值。

?我輸入了100,可是取出來的是Min int,再看一看服務器端輸出了哪些信息。

?很明顯,每調用一次操作,服務類就被實例化一次,意思就是:調用SetValue時是實例A,而調用GetValue時可能是實例B了,所以,私有字段的值沒有被保存。

那么,如何證明兩次調用的操作不屬于同一個服務實例呢?還記得GetHashCode嗎?對的,只要在內存中不是同一個實例的,其哈希值肯定不同。是不是這樣呢,我們把上面的服務代碼改一下。

public void SetValue(int n){this.m_Value = n;Console.WriteLine("------------------------");Console.WriteLine("當前實例的哈希值:{0}", this.GetHashCode().ToString("x"));Console.WriteLine("會話ID:{0}", OperationContext.Current.SessionId);}public int GetValue(){Console.WriteLine("------------------------");Console.WriteLine("當前實例的哈希值:{0}", this.GetHashCode().ToString("x"));Console.WriteLine("會話ID:{0}", OperationContext.Current.SessionId);return this.m_Value;}

?

那么,這次又會發生什么事呢,看結果。

這個結果證實了我之前的推斷,先后調用的兩個方法不是同一個實例的。

?

?

?那么,如果啟用了會話,結果又會如何呢?

[ServiceContract(SessionMode = SessionMode.Required)]public interface IService{。。。。。}

在定義服務協定的時候,設置SessionMode可以讓服務要求客戶端啟用會話。

接下來,要使用支持會話的綁定。

// 綁定//BasicHttpBinding binding = new BasicHttpBinding();//binding.Security.Mode = BasicHttpSecurityMode.None;//不需要安全模式//host.AddServiceEndpoint(typeof(IService), binding, "/ep");NetTcpBinding binding = new NetTcpBinding();binding.Security.Mode = SecurityMode.None;host.AddServiceEndpoint(typeof(IService), binding, "net.tcp://127.0.0.1:2377/ep");

把客戶端的服務引用更新一下。然后看看這回會不會達到我們的目的。

?


怎么樣,高興吧?終于看到我們要的效果了,我輸入了100,取出來的還是100,這一回從服務器端的輸出看,服務類只被實例化了一次,而且看看兩個哈希值是相同的,這證明了確實是同一個實例,同時,我們也看到了兩次調用的會話ID是一樣的,這也說明了,客戶端兩次調用都基于同一個會話進行的,這么一來,輸進去的100就能順利取出來了。

你不妨多開幾個客戶端來試試。

?

?

?看到那個不同的會話ID,哈希值和實例化時間了吧?這表明了:服務器獨立維護著與每個客戶端的會話

?

下面還要對我們的解決方案進行修改。

服務器端,把服務協定改為:

[ServiceContract(SessionMode = SessionMode.Required)]public interface IService{[OperationContract(IsOneWay = true,IsInitiating = true, IsTerminating = false)]void SetValue(int n);[OperationContract]int GetValue();[OperationContract(IsInitiating = false, IsTerminating = true)]void EndSession();}

在服務類中增加對EndSession方法的實現。

public void EndSession(){Console.WriteLine("會話結束。");}

?

看到變化了嗎?

我們在使用OperationContractAttribute定義操作協定時,設置了兩個屬性:

a、IsInitiating:如果為真,則當調用該操作時就啟用會話。

b、IsTerminating:如果為真,則說明當該用該操作時終結會話。

所以,上面的例子是,當調用SetValue時開始會話,當調用EndSession方法后會話結束,在選擇作為結束會話的方法時,最好使用返回值為void或者單向通訊(One Way)的方法,這樣,不用等待客戶結束才結束會話,因為單向通訊,不需要向客戶端回復消息,因為它被調用后就可以馬上終止會話了。

?

在客戶端代碼中,我們要取消之前的關閉通道的代碼,因為不再需要,會話一旦終結,通道就自動關閉,服務實例就會自動人間消失。

WS.ServiceClient client = null;public Form1(){InitializeComponent();client = new WS.ServiceClient();// 關閉通道//this.FormClosing += (frmsender, frmargs) => client.Close();}

?

然后,在調用完GetValue后馬上就EndSession,看看這回又會發生什么。



這樣,一旦三個方法調用完之后,會話結束,服務實例也解放了。

再說明一下,IsInitiating = true的操作開始新會話,IsTerminating = true的操作終結會話

總結

以上是生活随笔為你收集整理的重温WCF之会话Session(九)的全部內容,希望文章能夠幫你解決所遇到的問題。

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