• WCF


    WCF 提供了三种实例上下文模式:PreCall、PreSession 以及 Single。开发人员通过 ServiceBehavior.InstanceContextMode 就可以很容易地控制服务对象的实例管理模式。而当 WCF 释放服务对象时,会检查该对象是否实现了 IDisposable 接口,并调用其 Dispose 方法,以便及时释放相关资源,同时也便于我们观察对象释放行为。

    1. PreCall

    在 PreCall 模式下,即便使用同一个代理对象,也会为每次调用创建一个服务实例。调用结束后,服务实例被立即释放(非垃圾回收)。对于不支持 Session 的 Binding,如 BasicHttpBinding,其缺省行为就是 PreCall。

    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        void Test();
    }
    
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class MyServie : IMyService, IDisposable
    {
        public MyServie()
        {
            Console.WriteLine("Constructor:{0}", this.GetHashCode());
        }
    
        [OperationBehavior]
        public void Test()
        {
            Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
        }
    
        public void Dispose()
        {
            Console.WriteLine("Dispose");
        }
    }
    
    public class WcfTest
    {
        public static void Test()
        {
            AppDomain.CreateDomain("Server").DoCallBack(delegate
            {
                ServiceHost host = new ServiceHost(typeof(MyServie), new Uri("http://localhost:8080/MyService"));
                host.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(), "");
                host.Open();
            });
    
            //-----------------------
    
            IMyService channel = ChannelFactory<IMyService>.CreateChannel(new WSHttpBinding(),
                new EndpointAddress("http://localhost:8080/MyService"));
    
            using (channel as IDisposable)
            {
                channel.Test();
                channel.Test();
            }
        }
    }


    输出:
    Constructor:30136159
    Test:urn:uuid:df549447-52ba-4c54-9432-31a7a533d9b4
    Dispose
    Constructor:41153804
    Test:urn:uuid:df549447-52ba-4c54-9432-31a7a533d9b4
    Dispose

    2. PreSession

    PreSession 模式需要绑定到支持 Session 的 Binding 对象。在客户端代理触发终止操作前,WCF 为每个客户端维持同一个服务对象,因此 PreSession 模式可用来保持调用状态。也正因为如此,PreSession 在大并发服务上使用时要非常小心,避免造成服务器过度负担。虽然支持 Session 的 Binding 对象缺省就会启用 PreSession 模式,但依然建议你强制指定 SessionMode.Required 和 InstanceContextMode.PerSession。

    [ServiceContract(SessionMode = SessionMode.Required)]
    public interface IMyService
    {
        [OperationContract]
        void Test();
    }
    
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class MyServie : IMyService, IDisposable
    {
        public MyServie()
        {
            Console.WriteLine("Constructor:{0}", this.GetHashCode());
        }
    
        [OperationBehavior]
        public void Test()
        {
            Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
        }
    
        public void Dispose()
        {
            Console.WriteLine("Dispose");
        }
    }
    
    public class WcfTest
    {
        public static void Test()
        {
            AppDomain.CreateDomain("Server").DoCallBack(delegate
            {
                ServiceHost host = new ServiceHost(typeof(MyServie), new Uri("http://localhost:8080/MyService"));
                host.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(), "");
                host.Open();
            });
    
            //-----------------------
    
            IMyService channel = ChannelFactory<IMyService>.CreateChannel(new WSHttpBinding(), 
                new EndpointAddress("http://localhost:8080/MyService"));
                
            using (channel as IDisposable)
            {
                channel.Test();
                channel.Test();
            }
        }
    }


    输出:
    Constructor:30136159
    Test:urn:uuid:2f01b61d-40c6-4f1b-a4d6-4f4bc3e8847a
    Test:urn:uuid:2f01b61d-40c6-4f1b-a4d6-4f4bc3e8847a
    Dispose

    3. Single

    一如其名,服务器会在启动时,创建一个唯一(Singleton)的服务对象。这个对象为所有的客户端服务,并不会随客户端终止而释放。

    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        void Test();
    }
    
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
    public class MyServie : IMyService, IDisposable
    {
        public MyServie()
        {
            Console.WriteLine("Constructor:{0}; {1}", DateTime.Now, this.GetHashCode());
        }
    
        [OperationBehavior]
        public void Test()
        {
            Console.WriteLine("Test:{0}; {1}", DateTime.Now, OperationContext.Current.SessionId);
        }
    
        public void Dispose()
        {
            Console.WriteLine("Dispose:{0}", DateTime.Now);
        }
    }
    
    public class WcfTest
    {
        public static void Test()
        {
            AppDomain.CreateDomain("Server").DoCallBack(delegate
            {
                ServiceHost host = new ServiceHost(typeof(MyServie), new Uri("http://localhost:8080/MyService"));
                host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
                host.Open();
            });
    
            //-----------------------
    
            for (int i = 0; i < 2; i++)
            {
                IMyService channel = ChannelFactory<IMyService>.CreateChannel(new BasicHttpBinding(), 
                    new EndpointAddress("http://localhost:8080/MyService"));
                    
                using (channel as IDisposable)
                {
                    channel.Test();
                    channel.Test();
                }
            }
        }
    }


    输出:

    Constructor:2007-4-17 17:31:01; 63238509
    Test:2007-4-17 17:31:03;
    Test:2007-4-17 17:31:03;
    Test:2007-4-17 17:31:03;
    Test:2007-4-17 17:31:03;

    还有另外一种方式来启动 Single ServiceHost。

    AppDomain.CreateDomain("Server").DoCallBack(delegate
    {
        MyServie service = new MyServie();
    
        ServiceHost host = new ServiceHost(service, new Uri("http://localhost:8080/MyService"));
        host.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "");
        host.Open();
    });


    此方式最大的好处是允许我们使用非默认构造,除此之外,和上面的例子并没有什么区别。

    需要特别注意的是,缺省情况下,Single 会对服务方法进行并发控制。也就是说,多个客户端需要排队等待,直到排在前面的其他客户端调用完成后才能继续。看下面的例子。

    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        void Test();
    }
    
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
    public class MyServie : IMyService, IDisposable
    {
        public MyServie()
        {
            Console.WriteLine("Constructor:{0}", this.GetHashCode());
        }
    
        [OperationBehavior]
        public void Test()
        {
            Console.WriteLine("Test:{0}", OperationContext.Current.SessionId);
            Thread.Sleep(2000);
            Console.WriteLine("Test End:{0}", OperationContext.Current.SessionId);
        }
    
        public void Dispose()
        {
            Console.WriteLine("Dispose");
        }
    }
    
    public class WcfTest
    {
        public static void Test()
        {
            AppDomain.CreateDomain("Server").DoCallBack(delegate
            {
                ServiceHost host = new ServiceHost(typeof(MyServie), new Uri("http://localhost:8080/MyService"));
                host.AddServiceEndpoint(typeof(IMyService), new WSHttpBinding(), "");
                host.Open();
            });
    
            //-----------------------
    
            for (int i = 0; i < 2; i++)
            {
                new Thread(delegate()
                {
                    IMyService channel = ChannelFactory<IMyService>.CreateChannel(new WSHttpBinding(), 
                        new EndpointAddress("http://localhost:8080/MyService"));
                        
                    using (channel as IDisposable)
                    {
                        while (true)
                        {
                            channel.Test();
                        }
                    }
                }).Start();
            }
        }
    }


    输出:
    Constructor:63238509
    Test:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
    Test End:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
    Test:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
    Test End:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
    Test:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
    Test End:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
    Test:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
    Test End:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
    Test:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
    Test End:urn:uuid:d613cfce-d454-40c9-9f4d-62b30a93ff27
    Test:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
    Test End:urn:uuid:313de31e-96b8-47c2-8cf3-7ae743236dfc
    ...

    我们可以通过修改并发模式(ConcurrencyMode)来改变这种行为,但需要自己维护多线程安全。

    [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
    public class MyServie : IMyService, IDisposable
    {
        //...
    }
    


    输出:
    Constructor:10261382
    Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
    Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
    Test End:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
    Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
    Test End:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
    Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
    Test End:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
    Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
    Test End:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
    Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
    Test End:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
    Test:urn:uuid:2bdac798-f774-40f2-b8f9-58de8d599d3c
    Test End:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09
    Test:urn:uuid:9a328d0e-8df7-4885-94ed-e04ceedc5a09

  • 相关阅读:
    对返回的json数据重写格式,用特性JsonConverter
    dev 的NavBarControl动态菜单
    获取oracel数据库的结构
    Java-背单词程序(俄语)
    实现同或操作 C++
    输入字符串先用cin后用getline函数失效原因
    C++全局变量与局部变量
    4.Redis事务
    3.持久化配置
    2.常用数据类型
  • 原文地址:https://www.cnblogs.com/wangchuang/p/5705181.html
Copyright © 2020-2023  润新知