zoukankan      html  css  js  c++  java
  • 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、实例管理详解

  • 相关阅读:
    一些常用编程经验
    “一键GHOST”系统备份与还原(icmzn)
    office2010安装不成功提示缺少MSXML 6.10.1129.0?
    python 的几种启动方式
    win7 环境安装Python + IDE(vs2010)开发
    U盘单个文件最大4G限制问题
    第一百零三节,JavaScript对象和数组
    第一百零二节,JavaScript函数
    第一百零一节,JavaScript流程控制语句
    第一百节,JavaScript表达式中的运算符
  • 原文地址:https://www.cnblogs.com/zuowj/p/4368552.html
Copyright © 2011-2022 走看看