WCF分布式开发步步为赢(9):WCF服务实例激活类型编程与开发

简介:
 .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,三个服务分别配置了服务的终结点,包括契约、地址、绑定。元数据交换节点也进行了配置。具体配置文件如下:
<service behaviorConfiguration="WCFService.WCFServiceBehavior" name="WCFService.WCFServicePerCall"> 
                <endpoint 
                    address="net.tcp://localhost:9001/WCFServicePerCall" 
                    binding="netTcpBinding" 
                    contract="WCFService.IWCFService"> 
                </endpoint> 
                <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" /> 
                <host> 
                    <baseAddresses> 
                        <add baseAddress="net.tcp://localhost:9001/"/> 
                    </baseAddresses> 
                </host> 
            </service> 
            <service behaviorConfiguration="WCFService.WCFServiceBehavior" name="WCFService.WCFServicePerSession"> 
                <endpoint 
                    address="net.tcp://localhost:9002/WCFServicePerSession" 
                    binding="netTcpBinding" 
                    contract="WCFService.IWCFService"> 
                </endpoint> 
                <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" /> 
                <host> 
                    <baseAddresses> 
                        <add baseAddress="net.tcp://localhost:9002/"/> 
                    </baseAddresses> 
                </host> 
            </service> 
            <service behaviorConfiguration="WCFService.WCFServiceBehavior" name="WCFService.WCFServiceSingleTon"> 
                <endpoint 
                    address="net.tcp://localhost:9003/WCFServiceSingleTon" 
                    binding="netTcpBinding" 
                    contract="WCFService.IWCFService"> 
                </endpoint> 
                <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" /> 
                <host> 
                    <baseAddresses> 
                        <add baseAddress="net.tcp://localhost:9003/"/> 
                    </baseAddresses> 
                </host> 
            </service> 
        </services>
【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》;







 本文转自 frankxulei 51CTO博客,原文链接:http://blog.51cto.com/frankxulei/320413,如需转载请自行联系原作者

相关文章
|
7月前
|
NoSQL Java Redis
【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的分布式锁的功能组件(一)
【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的分布式锁的功能组件
96 0
|
5天前
|
数据管理 API 调度
鸿蒙HarmonyOS应用开发 | 探索 HarmonyOS Next-从开发到实战掌握 HarmonyOS Next 的分布式能力
HarmonyOS Next 是华为新一代操作系统,专注于分布式技术的深度应用与生态融合。本文通过技术特点、应用场景及实战案例,全面解析其核心技术架构与开发流程。重点介绍分布式软总线2.0、数据管理、任务调度等升级特性,并提供基于 ArkTS 的原生开发支持。通过开发跨设备协同音乐播放应用,展示分布式能力的实际应用,涵盖项目配置、主界面设计、分布式服务实现及部署调试步骤。此外,深入分析分布式数据同步原理、任务调度优化及常见问题解决方案,帮助开发者掌握 HarmonyOS Next 的核心技术和实战技巧。
122 76
鸿蒙HarmonyOS应用开发 | 探索 HarmonyOS Next-从开发到实战掌握 HarmonyOS Next 的分布式能力
|
7天前
|
分布式计算 大数据 数据处理
技术评测:MaxCompute MaxFrame——阿里云自研分布式计算框架的Python编程接口
随着大数据和人工智能技术的发展,数据处理的需求日益增长。阿里云推出的MaxCompute MaxFrame(简称“MaxFrame”)是一个专为Python开发者设计的分布式计算框架,它不仅支持Python编程接口,还能直接利用MaxCompute的云原生大数据计算资源和服务。本文将通过一系列最佳实践测评,探讨MaxFrame在分布式Pandas处理以及大语言模型数据处理场景中的表现,并分析其在实际工作中的应用潜力。
34 2
|
2月前
|
NoSQL Java Redis
开发实战:使用Redisson实现分布式延时消息,订单30分钟关闭的另外一种实现!
本文详细介绍了 Redisson 延迟队列(DelayedQueue)的实现原理,包括基本使用、内部数据结构、基本流程、发送和获取延时消息以及初始化延时队列等内容。文章通过代码示例和流程图,逐步解析了延迟消息的发送、接收及处理机制,帮助读者深入了解 Redisson 延迟队列的工作原理。
|
7月前
|
NoSQL Java Redis
【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的分布式锁的功能组件(二)
【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的分布式锁的功能组件
48 0
|
4月前
|
开发者 云计算 数据库
从桌面跃升至云端的华丽转身:深入解析如何运用WinForms与Azure的强大组合,解锁传统应用向现代化分布式系统演变的秘密,实现性能与安全性的双重飞跃——你不可不知的开发新模式
【8月更文挑战第31天】在数字化转型浪潮中,传统桌面应用面临新挑战。本文探讨如何融合Windows Forms(WinForms)与Microsoft Azure,助力应用向云端转型。通过Azure的虚拟机、容器及无服务器计算,可轻松解决性能瓶颈,满足全球用户需求。文中还提供了连接Azure数据库的示例代码,并介绍了集成Azure Storage和Functions的方法。尽管存在安全性、网络延迟及成本等问题,但合理设计架构可有效应对,帮助开发者构建高效可靠的现代应用。
36 0
|
7月前
|
分布式计算 资源调度 Hadoop
MapReduce分布式编程
MapReduce分布式编程
88 1
|
7月前
|
分布式计算 并行计算 Java
【分布式计算框架】 MapReduce编程初级实践
【分布式计算框架】 MapReduce编程初级实践
232 2
|
7月前
|
存储 Java 分布式数据库
【分布式计算框架】HBase数据库编程实践
【分布式计算框架】HBase数据库编程实践
125 1
|
7月前
|
分布式计算 数据可视化 Hadoop
【分布式计算框架】HDFS常用操作及编程实践
【分布式计算框架】HDFS常用操作及编程实践
208 1

热门文章

最新文章