.Net Remoting的激活方式也有三种:SingleTon模式、SingleCall模式、客户端激活方式,WCF服务实例激活类型包括三种方式:单调服务(Call Service),会话服务(Sessionful Service),单例服务(Singleton Service).他们之间有什么联系。WCF服务激活类型的优势和缺点,以及如何在项目里编程开发和设置服务实例。全文分为5个部分,首先一次介绍单调服务(Call Service),会话服务(Sessionful Service),单例服务(Singleton Service)的相关概念,优势和缺点,其次是示例代码分析和讲解部分,最后是全文的总结部分。结构如下:【1】单调服务(Call Service)【2】会话服务(Sessionful Service)【3】单例服务(Singleton Service)【4】示例代码分析【5】总结。最后会上传本文的代码。

【引言】:

WCF分布式开发必备知识(2):.Net Remoting这篇文章里我已经介绍过了Net Remoting相关的概念,其中也包括Net Remoting的激活方式:SingleTon模式、SingleCall模式、客户端激活方式。其实WCF服务的激活方式也与此相似。服务激活方式也是WCF借鉴Net Remoting的一个明显的例子。Net Remoting相关的概念大家可以查阅WCF分布式开发必备知识(2):.Net Remoting这篇文章。 下面我们就来详细的介绍WCF服务激活类型相关的知识点。首先来介绍的是单调服务。

WCF支持三种实例激活的类型:

1>.单调服务(Per-Call Service):每次的客户端请求分配一个新的服务实例。类似于Net Remoting的SingleCall模式;

2>.会话服务(Sessionful Service):则为每次客户端连接分配一个服务实例。类似于Net Remoting的客户端激活模式;

3>.单例服务(Singleton Service):所有的客户端会为所有的连接和激活对象共享一个相同的服务实例。类似于Net Remoting的SingleTon模式。

这里的服务激活模式是由我们定义的服务的上下文模式InstanceContextMode
属性来配置的,其代码如下:

public enum InstanceContextMode
{
    PerSession,
    PerCall,
    Single
}

【1】单调服务(Call Service):
【1.1】基本概念

单调服务(Per-Call Service):每次的客户端请求分配一个新的服务实例。服务实例的生存周期紧紧限制于一次调用的开始与结束之间。客户端的每次请求都会产生新的服务实例来响应这个调用。类似于Net Remoting的SingleCall模式。 执行步骤如下: 
1. 客户端调用代理,代理将调用转发给服务。 
2. WCF创建一个服务实例,然后调用服务实例的方法。 
3. 当方法调用返回时,如果对象实现了IDisposable接口,WCF将调用IDisposable.Dispose()方法。 
4. 客户端调用代理,代理将调用转发给服务。 
5. WCF创建一个对象,然后调用对象的方法。 
                                                          单调服务的实例化模型图:

【1.2】开发配置:
    单调服务开发配置十分简单,我们使用[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]配置服务属性完成。这样的WCF服务模式为单调模式,WCF框架对自动更具设置的属性来决定具体的服务激活类型。代码如下所示:

    [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
    public class WCFServicePerCall : IWCFService,IDisposable
    {     }

【1.3】注意:

(1)[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]特性只能应用到类上。
    (2) 如果使用了昂贵的资源,如数据库连接等非托管资源,继承IDisposable接口,        //实现接口定义的方法Dispose()方法显示释放资源。但是也有弊端,频繁地创建与销毁实例,仍然会对性能造成一定的影响。 
    (3)对于WCF服务而言,单调服务可以算是最佳的实例激活模式。  单调服务的一个最重要优势在于它能够节省资源,支持系统的可伸缩性。另外在事务编程与队列服务中优势更为明显,在事务编程中新建服务实例,减少实例状态的同步;而消息队列,单调服务能够建立服务实例与队列消息之间的简单映射。详细信息会在后续文章中介绍。

【2】会话服务(Sessionful Service):

【2.1】基本概念:

会话服务(Sessionful Service):则为每次客户端连接分配一个服务实例。类似于Net Remoting的客户端激活模式。为每个客户端创建一个专门的服务实例。只要会话没有结束,该实例就不会被销毁。 对于会话服务而言,是一个客户端代理对应一个服务实例。也就是说,会话服务中的服务是与代理相对应的,而不是对应于一个客户端。

【2.2】配置开发:
    服务实例的默认激活方式为会话服务模式。我们也可以显示配置会话服务的方式,使用[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)],具体代码如下所示:

 //3.服务类.会话服务
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class WCFServicePerSession : IWCFService
    {
    }

服务配置[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]之后,需要在服务契约一级配置[ServiceContract(SessionMode=SessionMode.Allowed)],服务元数据将包含SessionMode值。客户端的WCF反序列化后会包含此信息,来确定服务是否使用了会话模式,SessionMode为枚举类型:

public enum SessionMode
{
Allowed,
Required,
NotAllowed

不是所有的绑定协议都支持会话传输模式,TCP协议为传输控制协议,会与客户端维护一个连接。而HTTP为无连接状态,我们无法保证其与客户端的会话连接。

【2.3】注意:

(1)会话服务存在可伸缩性的问题。由于每个客户端都需要维护一个会话,需要占用较多的资源来保存服务会话状态。如果存在多个独立的客户端,则创建专门的服务实例的代价太大。 
(2)WCF服务绑定协议与会话特性之间的关系见下表:

 

Binding

Session mode

Context mode

Async Dispose()

Instance mode

Basic

Allowed/NotAllowed

PerCall/PerSession

Yes

PerCall

TCP, IPC

Allowed/Required

PerCall

No

PerCall

TCP, IPC

Allowed/Required

PerSession

Yes

PerSession

WS (no security, no reliability)

NotAllowed/Allowed

PerCall/PerSession

Yes

PerCall

WS (with security or reliability)

Allowed/Required

PerSession

Yes

PerSession

WS (with security or reliability)

NotAllowed

PerCall/PerSession

Yes

PerCall

(3) 应该避免将单调服务与会话契约混合定义在相同的会话服务类型中,会话应该保证是可靠的,一个实现了会话契约的服务,它包含的所有终结点所公开的契约都应该使用支持可靠传输会话的绑定。 
(4) InactivityTimeout可以配置一个新的空闲超时值,服务实例空闲时间超过这个范围时候就会终止会话。InactivityTimeout属性的默认值为10分钟。不能将该值设置为小于或等于0的值,否则会抛出ArgumentOutOfRangeException异常。

【3】单例服务(Singleton Service):

【3.1】基本概念:

设计模式中最简单和容易理解的就是单例(单件)模式(SingleTon),单例服务(Singleton Service)也是一种单件模式的实践应用的例子。单例服务(Singleton Service)就是针对所有客户端而言,都只有一个服务实例。单例服务的生存期是不受GC管理,不会终止,只有在关闭宿主时,才会被释放。创建宿主时,单例服务的实例就会被创建(这个可以再托管宿主的监控状态信息中得到证实,宿主运行时候,单例服务的已经显示实例化完毕,而单调服务和会话服务实例尚未启动),并且只能被创建一次,一直运行下去,有且仅有一个服务实例来响应客户端服务调用的请求。

【3.2】配置与开发:
    服务实例的单调激活模式可以通过[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]配置完成,具体的代码如下:

 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class WCFServiceSingleTon : IWCFService
    {
    }

【3.3】注意:

(1)单例服务同一时间内只能相应一个客户端请求。因此在系统的吞吐量、相应效率、系统服务性能上都存在严重的瓶颈。

【4】示例代码分析:

下面我们来介绍本次的示例代码,这里我们分别定义了三种激活类型的服务类:单调服务(Per-Call Service),会话服务(Sessionful Service),单例服务(Singleton Service),托管宿主分别进行托管,这里为了测试,我们使用的绑定协议也是TCP方式,其他的协议这里没做具体的实现,有兴趣的朋友可以自己扩展修改代码,进行测试。

【4.1】服务端:

,定义了一个服务契约,一个操作SayHello(),具体的服务类型定义和激活类型配置如下:


//此例定义了一个服务契约,三种服务分别为单调服务、会话服务、单例服务或单件服务
namespace WCFService
{
    //1.服务契约
    [ServiceContract(SessionMode=SessionMode.Allowed, Namespace = "http://www.cnblogs.com/frank_xl/")]
    public interface IWCFService
    {
        //操作契约
        [OperationContract]
        void SayHello();
    }
    //2.服务类.单调服务
    [ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
    public class WCFServicePerCall : IWCFService,IDisposable
    {
        //服务实例计数
        private int mCcount =0;
        //构造函数
        public WCFServicePerCall()
        {
            Console.WriteLine("WCFServicePerCall Instance is Created ");
        }
        //实现接口定义的方法
        public void SayHello()
        {
            mCcount++;
            Console.WriteLine("WCFServicePerCall Instance Count is: {0} ",mCcount);
        }
        //实现接口定义的方法Dispose
        public void Dispose()
        {
            Console.WriteLine("WCFServicePerCall Instance is disposed ");
        }
    }
    //3.服务类.会话服务
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
    public class WCFServicePerSession : IWCFService
    {
        //服务实例计数
        private int mCcount = 0;
        //构造函数
        public WCFServicePerSession()
        {
            Console.WriteLine("WCFServicePerSession Instance is Created ");
        }
        //实现接口定义的方法
        public void SayHello()
        {
            mCcount++;
            Console.WriteLine("WCFServicePerSession Instance Count is: {0} ", mCcount);
        }
        //实现接口定义的方法Dispose
        public void Dispose()
        {
            Console.WriteLine("WCFServicePerSession Instance is disposed ");
        }
    }
    //4.服务类.单例服务
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class WCFServiceSingleTon : IWCFService
    {
        //服务实例计数
        private int mCcount = 0;
        //构造函数
        public WCFServiceSingleTon()
        {
            Console.WriteLine("WCFServiceSingleTon Instance is Created ");
        }
        //实现接口定义的方法
        public void SayHello()
        {
            mCcount++;
            Console.WriteLine("WCFServiceSingleTon Instance Count is: {0} ", mCcount);
        }
        //实现接口定义的方法Dispose
        public void Dispose()
        {
            Console.WriteLine("WCFServiceSingleTon Instance is disposed ");
        }
    } }

【4.2】宿主:

针对三种激活类型的服务分别定义了三个宿主实例:hostWCFServicePerCall、hostWCFServicePerSession、hostWCFServiceSingleTon。测试完毕,关闭宿主。代码具体如下:


//采用自托管方式,也可以是IIS、WAS,Windows服务等用户自定义程序托管服务
   public class WCFHost
    {
        static void Main(string[] args)
        {
            //1.单调服务WCFServicePerCall
            ServiceHost hostWCFServicePerCall = new ServiceHost(typeof(WCFService.WCFServicePerCall));
            //判断是否以及打开连接,如果尚未打开,就打开侦听端口
            if (hostWCFServicePerCall.State != CommunicationState.Opening)
                hostWCFServicePerCall.Open();
            //显示运行状态
            Console.WriteLine("WCFServicePerCall Host is runing! and state is {0}", hostWCFServicePerCall.State);             //2.会话服务WCFServicePerSession
            ServiceHost hostWCFServicePerSession = new ServiceHost(typeof(WCFService.WCFServicePerSession));
            
            //判断是否以及打开连接,如果尚未打开,就打开侦听端口
            if (hostWCFServicePerSession.State != CommunicationState.Opening)
                hostWCFServicePerSession.Open();
            //显示运行状态
            Console.WriteLine("WCFServicePerSession Host is runing! and state is {0}", hostWCFServicePerSession.State);             //3.单例服务WCFServiceSingleTon
            ServiceHost hostWCFServiceSingleTon = new ServiceHost(typeof(WCFService.WCFServiceSingleTon));
                //判断是否以及打开连接,如果尚未打开,就打开侦听端口
            if (hostWCFServiceSingleTon.State != CommunicationState.Opening)
                hostWCFServiceSingleTon.Open();
            //显示运行状态
            Console.WriteLine("WCFServiceSingleTon Host is runing! and state is {0}", hostWCFServiceSingleTon.State);
            //等待输入即停止服务
            Console.Read();             //4 Close Host
            hostWCFServicePerCall.Close();
            hostWCFServicePerSession.Close();
            hostWCFServiceSingleTon.Close();
        }

绑定协议这里使用的是TCP,三个服务分别配置了服务的终结点,包括契约、地址、绑定。元数据交换节点也进行了配置。具体配置文件如下:

Code

【4.3】客户端:

运行宿主,添加服务引用,反序列化服务元数据为本地代码。完成以后添加测试的代码。每种服务激活类型创建2个代理实例,分别调用2次服务,测试不同的服务激活类型设置对服务实例的影响。我们来观察服务实例化的次数。具体代码如下:


////////////////////////////////////////////单调服务//////////////////////////////////////////////////
            #region //1.单调服务代理1 实例化,每次调用操作,会创建不同的服务实例
            WCFServicePerCall.WCFServicePerCallClient WCFServicePerCallProxy1 = new WCFServicePerCall.WCFServicePerCallClient();
            //调用2次服务
            for (int i = 0; i < 2;i++ )
            {
                WCFServicePerCallProxy1.SayHello();
            }
            //关闭服务代理
            WCFServicePerCallProxy1.Close();             WCFServicePerCall.WCFServicePerCallClient WCFServicePerCallProxy2 = new WCFServicePerCall.WCFServicePerCallClient();
            //调用2次服务
            for (int i = 0; i < 2; i++)
            {
                WCFServicePerCallProxy2.SayHello();
            }
            //关闭服务代理
            WCFServicePerCallProxy2.Close();
            #endregion             ////////////////////////////////////////会话服务////////////////////////////////////////////////////////
            #region//2.会话服务代理 实例化,一个客户端代理对应一个服务实例
            WCFServicePerSession.WCFServicePerSessionClient WCFServicePerSessionProxy1 = new WCFServicePerSession.WCFServicePerSessionClient();
            //调用2次服务
            for (int i = 0; i < 2; i++)
            {
                WCFServicePerSessionProxy1.SayHello();
            }
            //关闭服务代理
            WCFServicePerSessionProxy1.Close();             WCFServicePerSession.WCFServicePerSessionClient WCFServicePerSessionProxy2 = new WCFServicePerSession.WCFServicePerSessionClient();
            //调用2次服务
            for (int i = 0; i < 2; i++)
            {
                WCFServicePerSessionProxy2.SayHello();
            }
            //关闭服务代理
            WCFServicePerSessionProxy2.Close();
            #endregion             ////////////////////////////////////////////单例服务//////////////////////////////////////////////////
            #region//2.单例服务代理 实例化,也叫单件模式。所有的服务只有一个服务实例
            WCFServiceSingleTon.WCFServiceSingleTonClient WCFServiceSingleTonProxy1 = new WCFServiceSingleTon.WCFServiceSingleTonClient();
            //调用2次服务
            for (int i = 0; i < 2; i++)
            {
                WCFServiceSingleTonProxy1.SayHello();
            }
            WCFServiceSingleTonProxy1.Close();             WCFServiceSingleTon.WCFServiceSingleTonClient WCFServiceSingleTonProxy2 = new WCFServiceSingleTon.WCFServiceSingleTonClient();
            //调用2次服务
            for (int i = 0; i < 2; i++)
            {
                WCFServiceSingleTonProxy2.SayHello();
            }
            WCFServiceSingleTonProxy2.Close();
            #endregion
            //4.For Debugging
            Console.WriteLine("Press any key to continue");
            Console.Read();

【4.4】运行结果:

启动托管宿主,运行客户端进行测试,监控服务输出信息如下:

【5】总结:

(1)单调服务每次都重新创建服务的实例,操作完成以后,释放服务对象,每次想用用户操作请求的服务实例不同。

(2)会话服务针对每次会话创建一个特定的服务实例对象,在一次会话中的所有请求由一个服务对象相应。我们的服务调用计数也在会话期间随客户端调用的次数增加,上图可见。

(3)单例服务在宿主创建时就进行了实例化。他和会话和调用次数没有关系,所有的客户单服务调用操作均有同一个服务实例来响应。客户单调用的次数越多,服务端实际调用次数就会随之增加。上图可见。

(4)另外我们也可以编程或者配置系统的最大并发调用数、最大并发会话数、最大并发实例数,来控制和管理服务实例的负荷和流量。

以上就是本节的全部内容,最后上传此次的示例代码,供大家参考/Files/frank_xl/WCFServiceActivationFrankXuLei.rar.欢迎留言交流~下面会继续学习服务操作相关的内容学习。

参考文章:

1.《Programming WCF Services》;

2.WCF分布式开发必备知识(2):.Net Remoting

WCF分布式开发步步为赢(9):WCF服务实例激活类型编程与开发的更多相关文章

  1. WCF分布式开发步步为赢(3)WCF服务元数据交换、配置及编程开发

    今天我们继续WCF分布式开发步步为赢(3)WCF服务元数据交换.配置及编程开发的学习.经过前面两节的学习,我们了解WCF分布式开发的相关的基本的概念和自定义宿主托管服务的完整的开发和配置过程.今天我们 ...

  2. WCF分布式开发步步为赢(13):WCF服务离线操作与消息队列MSMQ

    之前曾经写过一个关于MSMQ消息队列的文章:WCF分布式开发必备知识(1):MSMQ消息队列 ,当时的目的也是用它来作为学习WCF 消息队列MSMQ编程的基础文章.在那篇文章里,我们详细介绍了MSMQ ...

  3. WCF分布式开发步步为赢(7):WCF数据契约与序列化

    本节继续学习WCF分布式开发步步为赢(7):WCF数据契约与序列化.数据契约是WCF应用程序开发中一个重要的概念,毫无疑问实现客户端与服务端数据契约的传递中序列化是非常重要的步骤.那么序列化是什么?为 ...

  4. WCF分布式开发步步为赢(4):WCF服务可靠性传输配置与编程开发

    今天继续WCF分布式开发步步为赢系列的第4节:WCF服务可靠性传输配置与编程开发.这个章节,我们要介绍什么是WCF服务的可靠性传输,随便介绍网络协议的概念,Web Service为什么不支持可靠性传出 ...

  5. WCF分布式开发步步为赢(11):WCF流处理(Streaming)机制

    WSE3.0框架提供了数据优化传输机制,WSE3.0构建Web服务安全(4):MTOM消息传输优化和文件上传.下载 疑问里进行了介绍.WCF同样也提供了流操作来支持大数据对象的传输和处理优化机制,今天 ...

  6. WCF分布式开发步步为赢(14):WCF安全编程--基本概念

    WCF安全机制是个非常复杂的问题,因为涉及的知识点较多,所以今天这个文章,会分析进行WCF安全开发应该了解的哪些知识点.如何查看资料.为了更好地理解WCF安全相关知识,我把WCF安全机制主要知识点整理 ...

  7. WCF分布式开发步步为赢(12):WCF事务机制(Transaction)和分布式事务编程

    今天我们继续学习WCF分布式开发步步为赢系列的12节:WCF事务机制(Transaction)和分布式事务编程.众所周知,应用系统开发过程中,事务是一个重要的概念.它是保证数据与服务可靠性的重要机制. ...

  8. [WCF REST] 一个简单的REST服务实例

    Get:http://www.cnblogs.com/artech/archive/2012/02/04/wcf-rest-sample.html [01] 一个简单的REST服务实例 [02] We ...

  9. HDD线上沙龙·创新开发专场:多元服务融合,助力应用创新开发

    5月24日,由华为开发者联盟主办的HUAWEI Developer Day(华为开发者日,简称HDD)线上沙龙·创新开发专场在华为开发者学堂及各大直播平台与广大开发者见面.直播内容主要聚焦Harmon ...

随机推荐

  1. android 连续点击退出程序

    package com.test.twiceexit; import java.util.Timer; import android.app.Activity;import android.os.Bu ...

  2. linux下操作

    一.没有正确安装GNOME电源管理器的默认配置 二.oracle启停 1. linux下启动oraclesu - oraclesqlplus /nologconn /as sysdbastartupe ...

  3. 上传图片的回调函数,callback作为一个函数针对回调函数

    Tool.ImageUpload = function (selector, callback) { /// <summary>图片上传</summary> /// <p ...

  4. 认识Linux

    Linux的内核版本 1.如何查看Linux的内核版本 # uname -r -.el6.i686 2. 2.6.32-358的含义    主版本.次版本.释出版本-修改版本 3.主次版本编号规则  ...

  5. IO和NIO的区别

    http://my.oschina.net/u/1010990/blog/192558 传统的socket IO中,需要为每个连接创建一个线程,当并发的连接数量非常巨大时,线程所占用的栈内存和CPU线 ...

  6. SAXReader

    DOM4j读取XML文件(SAXReader) 一. 总结: Document document=new SAXReader.reader(“xml文路径/文件名xxx.xml”);//得到Docum ...

  7. 15、android 用toast实现简单的进度显示

    if(mtoast!=null) { mtoast.setText(progress); } else { mtoast=Toast.makeText(getApplicationContext(), ...

  8. 【Validate Binary Search Tree】cpp

    题目: Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is define ...

  9. ubuntu mysql 使用

    环境:ubuntu 12.04.5    mysql-server-5.5 安装:sudo apt-get install mysql-server-5.5 (服务端 第一台虚拟机) sudo apt ...

  10. 先进的自动布局工具箱(autolayout)

    原文:Advanced Auto Layout Toolbox 这篇文章并没有具体介绍自动布局的一些基本概念,主要讲解了一些高级的使用方法和调试技巧,文中有的句子比较长,意思也有点难懂,所以需要静下心 ...