WCF會話(Session)與實例(Instance)管理


一、理解Session

1.Session的作用:保留Client和Service之間交互的狀態,確保Client與Service之間交互唯一性(SessionId),即:多個Client同時訪問Service,Service能夠區別;

2.ASP.NET Session 與 WCF Session區別:

在WCF中,Session屬於Service Contract的范疇,並在Service Contract定義中通過SessionModel參數來實現。WCF中會話具有以下幾個重要的特征:

  • Session都是由Client端顯示啟動和終止的。

  在WCF中Client通過創建的代理對象來和服務進行交互,在支持Session的默認情況下,Session是和具體的代理對象綁定在一起,當Client通過調用代理對象的某個方法來訪問服務時,Session就被初始化,直到代理的關閉,Session則被終止。我們可以通過兩種方式來關閉代理:一是調用ICommunicationObject.Close 方法,二是調用ClientBase<TChannel>.Close 方法 。我們也可以通過服務中的某個操作方法來初始化、或者終止Session,可以通過OperationContractAttribute的IsInitiating和IsTerminating參數來指定初始化和終止Session的Operation。

  • 在WCF會話期間,傳遞的消息按照它發送的順序被接收。
  • WCF並沒有為Session支持保存相關的狀態數據。

  而Asp.net中的Session具有以下特性:

  • Asp.net的Session總是由服務端啟動的,即在服務端進行初始化的。
  • Asp.net中的Session是無序的,不能保證請求處理是有序的。
  • Asp.net是通過在服務端以某種方式保存State數據來實現對Session的支持,例如保存在Web Server端的內存中。

二、WCF實例管理

對於Client來說,它實際上不能和Service進行直接交互,它只能通過客戶端創建的Proxy來間接地和Service進行交互,然而真正的調用而是通過服務實例來進行的。我們把通過Client的調用來創建最終的服務實例過程稱作激活,在.NET Remoting中包括Singleton模式、SingleCall模式和客戶端激活方式,WCF中也有類似的服務激活方式:單調服務(PerCall)、會話服務(PerSession)和單例服務(Singleton)。

  • 單調服務(Percall):為每個客戶端請求分配一個新的服務實例。類似.NET Remoting中的SingleCall模式
  • 會話服務(Persession):在會話期間,為每次客戶端請求共享一個服務實例,類似.NET Remoting中的客戶端激活模式。
  • 單例服務(Singleton):所有客戶端請求都共享一個相同的服務實例,類似於.NET Remoting的Singleton模式。但它的激活方式需要注意一點:當為對於的服務類型進行Host的時候,與之對應的服務實例就被創建出來,之后所有的服務調用都由這個服務實例進行處理。

注意:

1.WCF中服務激活的默認方式是PerSession,但不是所有的Bingding都支持Session,比如BasicHttpBinding就不支持Session。

2.通過在服務契約接口上ServiceContract(SessionMode = 會話模式)來顯式設置會話模式,禁用會話模式,可設為:SessionMode.NotAllowed

3.通過在Service實現類上ServiceBehavior(InstanceContextMode=激活方式)來顯式設置服務實例激活方式

三、運用WCF 的單例服務(Singleton)及會話模式,實現系統同一時間只能允許同一用戶名登錄(即:單次登錄),代碼如下:

1.定義服務契約及創建服務類

using System.ServiceModel;

namespace WcfServiceLibrary1
{
    [ServiceContract(SessionMode = SessionMode.Required)]
    public interface ILogin
    {
        [OperationContract]
        string Login(string username, string password);

        [OperationContract(IsOneWay=true)]
        void Logout();
    }
}


using System.Collections.Generic;
using System.ServiceModel;

namespace WcfServiceLibrary1
{
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
    public class LoginService:ILogin
    {
        private Dictionary<string,string> loginUsers;

        public LoginService()
        {
            this.loginUsers = new Dictionary<string, string>();
        }

        public string Login(string username, string password)
        {
            if (!string.IsNullOrEmpty(username) && password == "123456")
            {
                if (!this.loginUsers.ContainsValue(username))
                {
                    this.loginUsers.Add(OperationContext.Current.SessionId,username);
                    return null;
                }
                else
                {
                    return string.Format("用戶{0}已在其它地方有登錄,同一時間不允許同一用戶重復登錄!", username);
                }
            }
            else
            {
                return "用戶名或密碼錯誤!";
            }
        }

        public void Logout()
        {
            this.loginUsers.Remove(OperationContext.Current.SessionId);
        }

    }
}

2.創建宿主程序

CONFIG配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <behaviors>
        <behavior name="LoginServicemetadatabehavior">
          <serviceMetadata httpGetEnabled="true"/>
        </behavior>
    </behaviors>
    <services>
      <service name="WcfServiceLibrary1.LoginService" behaviorConfiguration="LoginServicemetadatabehavior">
        <endpoint address="" binding="wsHttpBinding" contract="WcfServiceLibrary1.ILogin"></endpoint>
        <host>
          <baseAddresses>
            <add baseAddress="http://127.0.0.1:10900/LoginService"/>
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>
</configuration>

代碼部份:

using System;
using WcfServiceLibrary1;
using System.ServiceModel;
using System.ServiceModel.Description;


namespace ConsoleApplicationHost
{
    class Program
    {
        static void Main(string[] args)
        {
            BuildLoginServiceHostByConfig();
        }

        static void BuildLoginServiceHostByConfig()
        {
            using (ServiceHost host = new ServiceHost(typeof(LoginService)))
            {
                host.Opened += (s, e) => { Console.WriteLine("LoginService已經啟動,按按回車鍵終止服務!"); };
                host.Open();
                Console.ReadLine();
            }
        }
    }
}

3.在客戶端程序調用WCF服務

首先添加並引用WCF服務,VS自動生成WCF服務相關的接口與代理類,這里是:LoginClient

然后就可以直接使用LoginClient來調用WCF服務相關方法,代碼如下:

using System;
using System.ServiceModel;
using WcfServiceLibrary1;

namespace ConsoleApplicationClient
{
    class Program
    {
        static void Main(string[] args)
        {
            CallLoginService();
            Console.WriteLine("按任意鍵結束。");
            Console.Read();
        }

        static void CallLoginService()
        {
            using (LoginServices.LoginClient proxy = new LoginServices.LoginClient())
            {
                Console.Write("請輸入用戶名:");
                string input1 = Console.ReadLine();
                Console.Write("請輸入密碼:");
                string input2 = Console.ReadLine();
                string loginResult = proxy.Login(input1, input2);
                if (!string.IsNullOrEmpty(loginResult))
                {
                    Console.WriteLine(loginResult);
                    return;
                }

                Console.WriteLine("恭喜你,登錄成功!");
                Console.Write("若需登出,請輸入Y:");
                string input3 = Console.ReadLine();
                if (input3 == "Y")
                {
                    proxy.Logout();
                    Console.WriteLine("登出成功!");
                }
                
            }
        }
    }
}

如果同時打開多個客戶端程序,並輸入相同的用戶名,只要有一個登錄成功或登錄成功后不登出,其余的均會登錄不上,報錯!效果如下圖示:

當然也可以利用其它激活方式實現更多功能,在此就不再重述,原理相同!

本文參考與引用了以下作者的文章:

跟我一起學WCF(8)——WCF中Session、實例管理詳解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM