zoukankan      html  css  js  c++  java
  • Learning WCF:Life Cycle of Service instance


    示例代码下载地址:WCFDemo1Day

    概述

    客户端向WCF服务发出请求后,服务端会实例化一个Service对象(实现了契约接口的对象)用来处理请求,实例化Service对象以及维护其生命周期的方式在WCF中共有三种不同的类型,分别是:

    • Per-Call
    • Per-Session
    • Single

    程序中通过设置ServiceBehavior特性来指定,如下:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class CommService : ICommContract
    {
    }
    

    这是枚举InstanceContextMode的内容:

    public enum InstanceContextMode
    {
        PerSession = 0,
        PerCall = 1,
        Single = 2,
    }
    

    Per-Call

    每次调用服务端服务端方法,服务端都会实例化一个对象来处理请求,为观察结果,现编写如下代码:

    服务类:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class CommService : ICommContract
    {
        public CommService()
        {
            Console.WriteLine("构造函数被执行");
        }
    
        public int Add(int a, int b)
        {
                Console.WriteLine("Add被调用,Thread:" + Thread.CurrentThread.ManagedThreadId + " fromPool:" + Thread.CurrentThread.IsThreadPoolThread);
    
            return a + b;
        }
    
        public void Dispose()
        {
            Console.WriteLine("对象销毁");
            Console.WriteLine("_____________________________");
        }
    
        public void SendStr(string str)
        {
            Console.WriteLine("SendStr被调用,Thread:" + Thread.CurrentThread.ManagedThreadId + " fromPool:" + Thread.CurrentThread.IsThreadPoolThread);
        }
    }
    

    如果服务类实现了接口IDisposable,当服务类被销毁时会回调Dispose方法,可以在Dispose方法中写一些WriteLine语句以观察对象的生命周期。

    客户端代码:

    class Program
    {
        static void Main(string[] args)
        {
            CommService.CommContractClient client = new CommService.CommContractClient();
    
            client.SendStr("hello");
            client.SendStr("hello");
            client.SendStr("hello");
    
            client.Close();
        }
    }
    

    运行效果:
    捕获.PNG-11.5kB

    Per-Session

    InstanceContextMode被设置为PerSession后,同一个客户端多次调用一个远程Web服务方法时,服务端只会实例化一次,修改上面的服务端代码第一行如下:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    

    再看运行效果:
    捕获.PNG-10.4kB

    上面的实例代码所使用的绑定模式为WSHttpBinding,如果使用BasicHttpBinding的话,即使是指定了InstanceContextModePerSession服务端也不会保存会话,现将支持Per-Session的绑定方式列举如下:

    • WSXXXBinding(with Message security or reliability)
    • NetTcpXXXBinding
    • NetXXXPipeBinding

    后两个容易理解,第一个括号里什么什么玩意儿,请看宿主代码:

     class Program
    {
        static void Main(string[] args)
        {
            Uri baseURI = new Uri("http://localhost:8000/Services");
            ServiceHost host = new ServiceHost(typeof(CommService), baseURI);
    
            try
            {
                WSHttpBinding binding = new WSHttpBinding();
                binding.Security.Mode = SecurityMode.None;
                host.AddServiceEndpoint(typeof(ICommContract), binding, "CommonService");
    
                ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
                smb.HttpGetUrl = new Uri("http://localhost:8080/Services");
                smb.HttpGetEnabled = true;
                host.Description.Behaviors.Add(smb);
    
                host.Open();
                Console.WriteLine("The service is ready.");
                Console.WriteLine("Press <ENTER> to terminate service.");
                Console.WriteLine();
                Console.ReadLine();
    
                host.Close();
            }
            catch (CommunicationException ce)
            {
                Console.WriteLine("An exception occurred: {0}", ce.Message);
                host.Abort();
            }
        }
    }
    

    binding.Security.Mode默认为Message,现在把它改成None再运行程序:

    捕获.PNG-11.5kB

    哈,虽然InstanceContextMode设置为了Per-Session,实际上还是Per-Call,这部分内容和安全性有关,希望我有时间以后会写到吧,今天暂时不去研究。

    除了绑定方式,还有一个地方也影响到了Per-Session是否起作用,它是契约接口特性ServiceContract的属性SessionMode,该枚举内容如下:

    public enum SessionMode
    {
        Allowed = 0,
        Required = 1,
        NotAllowed = 2,
    }
    

    SessionMode属性默认是Allowed,如果设置为Required表示必须启用会话模式,NotAllowed表示必须不能启动会话模式,Allowed表示无所谓。谁有兴趣可以一一尝试。现将契约接口的特性改成如下:

    [ServiceContract(Namespace = "zzy0471.cnblogs.com.CommService", SessionMode = SessionMode.NotAllowed)]
    public interface ICommContract : IDisposable
    {
        [OperationContract()]
        int Add(int a, int b);
    
         [OperationContract()]
        void SendStr(String str);
    }
    

    再运行程序:

    捕获.PNG-12.1kB

    虽然InstanceContextMode设置为了Per-Session,实际上还是Per-Call

    此外,还有一个需要注意的地方,如果在方法契约特性中设置属性IsTerminatingtrue,如下图

    [OperationContract(IsTerminating = true)]
    void SendStr(String str);
    

    运行服务端会导致运行时错误,IsTerminating设置为了truePer-Session模式相矛盾,IsTerminating的意思是:“获取或设置一个值,该值指示服务操作在发送答复消息(如果存在)后,是否会导致服务器关闭会话”

    Per-Single

    InstanceContextMode被设置为PerSingle后,所有的客户端请求都只有一个服务端实例对象来处理,服务启动时对象创建,服务关闭时对象销毁。现修改InstanceContextMode特性如下:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class CommService : ICommContract
    {
        public CommService()
        {
            Console.WriteLine("构造函数被执行");
        }
    
        public int Add(int a, int b)
        {
            Console.WriteLine("Add被调用,Thread:" + Thread.CurrentThread.ManagedThreadId + " fromPool:" + Thread.CurrentThread.IsThreadPoolThread);
    
            return a + b;
        }
    
        public void Dispose()
        {
            Console.WriteLine("对象销毁");
            Console.WriteLine("_____________________________");
        }
    
        public void SendStr(string str)
        {
            Console.WriteLine("SendStr被调用,Thread:" + Thread.CurrentThread.ManagedThreadId + " fromPool:" + Thread.CurrentThread.IsThreadPoolThread);
        }
    }
    

    为了方便观察,修改客户端代码,以模拟多个客户端:

    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 3; i++)
            {
                CommService.CommContractClient client = new CommService.CommContractClient();
    
                client.SendStr("hello");
                client.SendStr("hello");
                client.SendStr("hello");
    
                client.Close();
            }
        }
    }
    

    运行程序:
    捕获.PNG-14.5kB

  • 相关阅读:
    各种排序算法的时间复杂度和空间复杂度
    fork/join框架
    全文检索之solr学习
    【设计模式最终总结】概述、分类、原则
    ASP.NET MVC5+EF6+EasyUI 后台管理系统(75)-微信公众平台开发-用户管理
    下拉列表自己封装的
    下拉列表
    一个原生的JavaScript拖动方法
    JavaScript的jsonp
    angular2 的依赖注入
  • 原文地址:https://www.cnblogs.com/zzy0471/p/6931613.html
Copyright © 2011-2022 走看看