实例上下文模式:会话模式

一、会话模式简介与示例代码  

会话模式下,客户端和服务实例上下文、服务实例是一一对应关系,每一个客户端都在服务端都有自己对应的服务实例上下文。如下图所示
                 

服务端使用会话模式的条件:

1.使用支持会话模式的绑定,如WSHttpBinding、WS2007HttpBinding、NetTcpBinding、NetNamedPipeBinding。

不支持会话的绑定有 BasicHttpBinding、NetMsmqBinding。Msmq属于离线状态的绑定,交互使用消息机制,因此不支持会话模式。

2.上下文模式设置为PerSession。

3.服务契约的SessionModel设置为Allowed或Required。

如下代码设置:

   [ServiceContract(SessionMode=SessionMode.Allowed)]
    public interface ICalculator
    {
        [OperationContract]
        int Add();
    }
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
    public class Calculator : ICalculator
    {
        public int i = 0;
        public int Add()
        {
            return ++i;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(new WSHttpBinding);
            ServiceHost host = new ServiceHost(typeof(Calculator));
            host.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "http://localhost:4216");
            host.Opened += delegate { Console.WriteLine("Service Start!"); };
            host.Open();
            Console.Read();
        }
    }

创建两个客户端时,都调用Add方法。因为两个客户端都是拥有各自的服务实例上下文,所以i值不是共享的,

下面是客户端代码,分别创建两个client1和client2,它们用于自己的i值。

 static void Main(string[] args)
        {
           ICalculator client1= ChannelFactory<ICalculator>.CreateChannel(new WSHttpBinding(), new EndpointAddress("http://localhost:4216"));
           Console.WriteLine("client1:" + client1.Add());
           ICalculator client2 = ChannelFactory<ICalculator>.CreateChannel(new WSHttpBinding(), new EndpointAddress("http://localhost:4216"));
           Console.WriteLine("client2:" + client2.Add());
           Console.WriteLine("        " + client2.Add());
        }

二、单例模式、单调模式、会话模式

      单调模式和单调模式唯一决定与InstanceContextMode的设置,与SessionMode无关。只要设置ServiceBehavior的InstanceContextMode设置为InstanceContextMode.PerCall或 Single已经决定了服务实例上下文的模式,与ServiceContract中的SessionMode无关。

会话模式要求

1.上下文模式设置为PerSession。

2.SessionMode设置为Required或者Allowed。

3.使用WSHttpBinding或WS2007HttpBinding时,保证开启安全模式和可靠性中的一个。若绑定既不可靠也不安全则无法实现会话模式。

4.NetTcpBinding或者NetNamedPipeBinding默认使用会话信道,默认就是会话模式。

WSHttpBinding和WS2007HttpBinding默认的安全模式为Message,不可靠会话。因此使用者两种绑定默认就是会话模式。

  static void Main(string[] args)
        {
            var binds = new List<WSHttpBinding>
            {
                new WSHttpBinding(),
                new WS2007HttpBinding()
            };
            binds.ForEach(b=>Console.WriteLine("Security:{0}  ReliableSession.Enabled:{1}",b.Security.Mode,b.ReliableSession.Enabled));
         }

三、自定义实现会话模式

会话模式的机制就是客户端的会话信道和服务实例上下文一一对应,那我们实现一个IInstanceContextProvider在内部维护会话信道和服务上下文实例的关系即可。下面代码所示,内部有一个Dictionary<IContextChannel, InstanceContext>,在InitializeInstanceContext函数调用时将会话信道和上下文存入字典,并用反射调用instanceContext的BindIncomingChannel方法,此方法将会话信道加入到上下文的内部信道管理器中,这样就不会每次处理完流程后都调用IsIdle来判断服务上下文是否空闲了。因为只有内部信道管理器中没有信道时才会调用IsIdle。

GetExistingInstanceContext返回信道对应的上下文,并且将不处于打开状态的信道移除,这些信道就处于没有根引用状态,不久之后就会被GC回收。

 public class PersionProvider : IInstanceContextProvider
    {
        private Dictionary<IContextChannel, InstanceContext> dic = new Dictionary<IContextChannel, InstanceContext>();
        public InstanceContext GetExistingInstanceContext(Message message, IContextChannel channel)
        {
            if (null == channel.InputSession)
            {
                return null;
            }
            var closeChannels = (from c in dic.Keys where c.State != CommunicationState.Opened select c);
            if (null != closeChannels && closeChannels.ToList().Count > 0)
            {
                closeChannels.ToList().ForEach(c => dic.Remove(c));
            }
            return dic.ContainsKey(channel) ? dic[channel] : null;
        }

        public void InitializeInstanceContext(InstanceContext instanceContext, Message message, IContextChannel channel)
        {
            dic[channel] = instanceContext;
            MethodInfo info = typeof(InstanceContext).GetMethod("BindIncomingChannel", BindingFlags.NonPublic | BindingFlags.Instance);
            info.Invoke(instanceContext, new object[] { channel });
        }

        public bool IsIdle(InstanceContext instanceContext)
        {
            return true;
        }

        public void NotifyIdle(InstanceContextIdleCallback callback, InstanceContext instanceContext)
        {}
    }

之后只需要在每个终结点分发器的运行时上设置我们自定义的PersionProvider即可。

    public class myPersionAttribute : Attribute, IServiceBehavior
    {
      public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {}        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)        {}     public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
            {
                foreach (EndpointDispatcher endDiapacher in dispatcher.Endpoints)
                {
                    endDiapacher.DispatchRuntime.InstanceContextProvider = new PersionProvider();
                }
            }
        }
   }

最后直接使用自定义的myPersionAttribute可以实现同样的会话模式效果。

    [myPersion]
    public class Calculator : ICalculator
    {
        public int i = 0;
        public int Add()
        {
            return ++i;
        }
    }
时间: 2024-08-15 04:58:13

实例上下文模式:会话模式的相关文章

WCF实例上下文模式与并发模式对性能的影响

实例上下文模式 InstanceContextMode 控制在响应客户端调用时,如何分配服务实例.InstanceContextMode 可以设置为以下值: •Single – 为所有客户端调用分配一个服务实例. •PerCall – 为每个客户端调用分配一个服务实例. •PerSession – 为每个客户端会话分配一个服务实例. InstanceContextMode 的默认设置为 PerSession 并发模式ConcurrencyMode 控制一次允许多少个线程进入服务.Concurre

实例上下文模式:单例模式

单例模式效果可以用下面这张图表示,服务端的服务实例只有一个,任何一个客户端访问的服务端都是相同的服务实例.意味着服务端可以留下不同客户端的脚印. 使用也很简单,只需要将ServiceBehavior的上下文模式InstanceContextMode设置为Single即可.可以参照上一篇介绍实例上下文模式:单调模式 [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] public class Calculator :

Hyper-V Server增强会话模式

Windows Server 2012 R2开始,通过使用Hyper-V增强会话模式,Hyper-V 中的虚拟机连接允许重定向虚拟机连接会话中的本地资源.虚拟机连接增强了为需要连接到虚拟机的 Hyper-V 管理员提供的交互式会话体验.当你与虚拟机交互时,它可以提供类似于远程桌面连接的功能. 在以往版本的 Hyper-V 中,虚拟机连接仅提供虚拟机屏幕.键盘和鼠标的重定向以及有限的复制功能.若要获取更多重定向功能,可以启动与虚拟机之间的远程桌面连接,但这需要提供虚拟机的网络路径.如图所示,图一是

学习ASP.NET MVC框架揭秘笔记-实例演示:SC模式的应用

实例演示:SC模式的应用 为了对SC模式下的MVP,尤其是该模式下的View和Presenter之间的交互方式有一个深刻的认识,我们现在来做一个实例演示.我们采用员工查询的场景,用ASP.NET Web Forms来建立这个简单的应用. 我们先来定义员工的数据类型,Employee来表示一个员工,有5个属性:ID.姓名.性别.出生日期和部门. public class Employee { public string Id { get; private set; } public string

Hyper-v Server 2012 R2增强会话模式

从Windows Server 2012 R2开始,通过使用Hyper-v增强会话模式Hyper-v中的虚拟机允许重定向虚拟机连接会话中的本地资源.这是因为Windows Server 2012 及早期的Hyper-v 虚拟机连接只是一个仿真显卡的位图界面和仿真的鼠标键盘,这样一来,很多的操作和控制都受到的限制.以前在论坛上有很多人都在讨论为什么Hyper-v不能像VMWARE一样能在宿主机和来宾系统之间复制.粘贴文件,其实,连复制.粘贴文本也不行,当时大多数人的解释是微软为了安全才这样做的,其

在Windows Server 2012 R2的Hyper-V中设置虚拟机启用增强会话模式

在Windows Server 2012 R2的Hyper-V中,可以为虚拟机提供一种全新的连接方式,就是“增强会话模式”,它将让您更加方便的对虚拟机进行操作,比如分辨率的调整.设备的加载,最为方便的是在虚拟机和主机间的文件交换,就是我们平常最常用的操作复制和粘贴(不支持拖拽的方式). 虚拟机的增强会话模式默认并未开启,但开启操作也并不复杂: 使用条件: 虚拟机系统需要是Windows 8.1或Windows Server 2012 虚拟机中的Remote Desktop Service必须启用

java中多线程通信实例:生产者消费者模式

线程间的通信: 其实就是多个线程再操作同一个资源,但是操作的动作不同   当某个线程进入synchronized块后,共享数据的状态不一定满足该线程的需要,需要其他线程改变共享数据的状态后才能运行,而由于当时线程对共享资源时独占的,它必须解除对共享资源的锁定的状态,通知其他线程可以使用该共享资源. Java中的 wait(),notify(),notifyAll()可以实现线程间的通信. 生产者--消费者问题是典型的线程同步和通信问题 /** * 生产者和消费者问题,生产者生成出产品,消费者去购

.Net简单工厂模式,工厂模式,抽象工厂模式实例

1.定义   简单工厂模式:是由一个工厂对象决定创建出哪一种产品类的实例.简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现. 工厂模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类. 抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类. 2.实例 用工人种蔬菜的例子来说明,蔬菜植物的产品器官有根.茎.叶.花.果等5类,因此按产品器官分类也分成5种,分别是根菜类,茎菜类,叶莱类,花菜类以及果菜类.我们以根菜类,茎菜类为例,

Windows 2008 关闭远程桌面的单用户多会话模式

Windows 2008 关闭远程桌面的单用户多会话模式 在腾讯云上购买了一台云服务器. 因为设置了自动登录,在远程桌面连接后会启动一个新的会话,然后软件被运行了两次,端口被占用,无法起动. 还有可能会造成程序出错,因为用的同一个数据库. 在这里可以关闭. 原文地址:https://www.cnblogs.com/F4NNIU/p/9860729.html