<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      傳說中的WCF(11):會話(Session)

      在標題中我加了一個大家都很熟悉的單詞——Session,熟吧?玩過Web開發的朋友肯定在夢中都會見到她。

      在Web中為什么要會話呢?畢竟每個用戶在一個Web應用中可能不止進行一次操作,比如,某二手飛機交易網站,用戶A登陸后,可能他會修改他的個人 信息,他也有可能看好了一架二手飛機,打算入手,就把商品放到他的“購物車”中,這些過程中,都會產生許多與用戶A相關的數據,這些數據只是對A有效,而 當用戶B登陸后,對于B,又會有他自己的數據,總的一句話就是,每個客戶端在服務器上都有其的獨立數據存儲區,互不相干,就好像A和服務器在單獨談話一樣,所以叫會話。

      在WCF中,會話的含義與Web中的會話概念是差不多的,就是客戶端與服務器端在“私聊”,這便是存在會話的調用;那么,沒有會話的調用呢,就是“群聊”;通信過程中,數據都以明文顯示,不進行加密保護,這叫“裸*聊”。

      好了,現在大家對于會話,肯定有點理解了。但是,會話是看不見摸不著的,怎么通過實例來檢驗它呢?

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

      namespace Server
      {
          [ServiceContract]
          public interface IService
          {
              [OperationContract(IsOneWay = true)]
              void SetValue(int n);
              [OperationContract]
              int GetValue();
          }
      }
      namespace Server
      {
          [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 mValue = int.MinValue;
      
              public void SetValue(int n)
              {
                  this.mValue = n;
                  Console.WriteLine("會話ID:{0}", OperationContext.Current.SessionId);
              }
      
              public int GetValue()
              {
                  Console.WriteLine("會話ID:{0}", OperationContext.Current.SessionId);
                  return this.mValue;
              }
          }
      }

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

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

      namespace Server
      {
          class Program
          {
              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);
                      }
                  }
              }
          }
      }

      然后,實現客戶端,為了使演示操作更方便,客戶端使用wpf項目,界面大致如下圖所示。

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

      namespace Client
      {
          /// <summary>
          /// Interaction logic for MainWindow.xaml
          /// </summary>
          public partial class MainWindow : Window
          {
              ServiceReference1.ServiceClient client = null;
      
              public MainWindow()
              {
                  InitializeComponent();
      
                  client = new ServiceReference1.ServiceClient();
                  // 關閉通道
                  this.Closing += (frmsender, frmargs) => client.Close();
              }
      
              private void button1_Click(object sender, RoutedEventArgs e)
              {
                  int v;
                  if (!int.TryParse(this.textBox1.Text, out v))
                  {
                      return;
                  }
                  client.SetValue(v);
              }
      
              private void button2_Click(object sender, RoutedEventArgs e)
              {
                  int v = client.GetValue();
                  this.textBox2.Text = v.ToString();
              }
          }
      }

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

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

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

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

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

              public void SetValue(int n)
              {
                  this.mValue = 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.mValue;
              }

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

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

       

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

          [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)的方法,這樣,不用等待客戶結束才結束會話,因為單向通訊,不需要向客戶端回復消息,因為它被調用后就可以馬上終止會話了。

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

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

              private void button2_Click(object sender, RoutedEventArgs e)
              {
                  int v = client.GetValue();
                  this.textBox2.Text = v.ToString();
                  client.EndSession();
              }

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

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

      posted @ 2016-08-09 11:08  閆寶平  閱讀(207)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产爆乳无码av在线播放| 亚洲色www成人永久网址| 日韩精品 在线一区二区| 国产午夜精品在人线播放| 99久久99这里只有免费费精品| 亚洲人妻一区二区精品| 国产精品成人午夜福利| 博野县| 欧洲lv尺码大精品久久久| 亚洲国产欧美一区二区好看电影| 中文人妻AV高清一区二区| 久久久久久伊人高潮影院| 日本边添边摸边做边爱| 中国老妇xxxx性开放| 国产在线无码精品无码| 午夜在线观看成人av| 一道本AV免费不卡播放| 海宁市| 日本少妇自慰免费完整版| 国产超碰无码最新上传| 一区二区和激情视频| 中文字幕亚洲制服在线看| 尹人香蕉久久99天天拍| 亚洲最大成人网色| 成年午夜免费韩国做受视频| 日韩av在线一区二区三区| 国产一区二区三区十八禁| 男人的天堂av社区在线| 九九久久精品国产| 亚洲色av天天天天天天 | 丁香婷婷激情俺也去俺来也| 成年在线观看免费人视频| 美女无遮挡免费视频网站| 亚洲免费人成在线视频观看| 国产伦码精品一区二区| 中文字幕无码乱码人妻系列蜜桃| 国产精品视频不卡一区二区| 国产日韩精品视频无码| 国产精品乱码久久久久久小说| 国产男女猛烈无遮挡免费视频| 精品人妻av综合一区二区|