zoukankan      html  css  js  c++  java
  • Programming WCF Services翻译笔记(八)

    本文在IT168已发表:http://tech.it168.com/msoft/2007-10-25/200710251312468.shtml

    分步操作


    WCF提供了一种被称之为分步操作(Demarcating Operation)的方法,以应对服务契约的操作需要指定执行顺序的情况。分步操作是使用OperationContract特性的IsInitiating和IsTerminating属性:
    [AttributeUsage(AttributeTargets.Method)]
    public sealed class OperationContractAttribute : Attribute
    {
       public bool IsInitiating
       {get;set;}
       public bool IsTerminating
       {get;set;}
       //More members
    }

    一个分步操作的应用如下:
    [ServiceContract(SessionMode = SessionMode.Required)]
    interface IOrderManager
    {
       [OperationContract]
       void SetCustomerId(int customerId);

       [OperationContract(IsInitiating = false)]
       void AddItem(int itemId);

       [OperationContract(IsInitiating = false)]
       decimal GetTotal(  );

       [OperationContract(IsInitiating = false,IsTerminating = true)]
       bool ProcessOrders(  );
    }
    此时,操作AddItem()、GetTotal()以及ProcessOrder()都不能是启动会话的第一个操作。同时,ProcessOrder()操作则会成为终止会话的操作。这与业务的要求是一脉相承的。

    IsInitiating属性的默认值为true,IsTerminating属性的默认值则为false。

    如果IsInitiating值为true,并不必然代表该操作必然是启动会话的第一个操作。如果其它相同设置的操作首先被调用,就会启动一个会话,而原操作则在调用时被加入会话,成为会话的一部分。但如果IsTermination的值为true,则代表该操作必须是终止会话的操作。虽然在服务契约定义时,允许将多个操作的IsTerminating值设置为true,但一旦调用了IsTerminating值为true的方法,就不能再调用服务实例的其它方法,除非在客户端重新创建一个代理对象。此外,即使操作的IsTermination值为true,它也可以是启动会话的第一个操作,但在操作执行后它会终止会话。因此,如下的两个操作定义是等效的:
    [OperationContract(IsTerminating = true)]
    void StartAndEndSession();
    [OperationContract(IsInitiating=true, IsTerminating = true)]
    void StartAndEndSession();

    然而,如下的两个操作则是不等效的,因为后者要求该操作不能为启动会话的第一个操作:
    [OperationContract(IsTerminating = true)]
    void StartAndEndSession();
    [OperationContract(IsInitiating=false, IsTerminating = true)]
    void StartAndEndSession();

    实例停用(Instance Deactivation)

    实例停用只针对会话服务而言。单例服务虽然也可以应用,但却无效。

    “会话实际要做的不仅是关联客户端消息,同时还要关联托管了服务的上下文。启动会话时,宿主会创建一个新的上下文。会话终止时,上下文也随之而终止。默认情况下,上下文的生命周期与发布的服务实例的生命周期相同。然而,出于优化的目的,WCF为服务设计者提供了一个分离两种生命周期的选项,该选项允许WCF独立地停用实例,而不必依赖于它的上下文。实际上,WCF还允许不包含实例的上下文存在,如下图所示。”
    figure-4.2.gif 

    这种实例管理技术称为上下文停用(Context Deactivation)。控制上下文停用的最常见办法是通过OperationBehavior特性的ReleaseInstanceMode属性:
    public enum ReleaseInstanceMode
    {
       None,
       BeforeCall,
       AfterCall,
       BeforeAndAfterCall,
    }
    [AttributeUsage(AttributeTargets.Method)]
    public sealed class OperationBehaviorAttribute : Attribute,...
    {
       public ReleaseInstanceMode ReleaseInstanceMode
       {get;set;}
       //More members
    }

    “通常,我们只需要将实例停用应用到部分服务方法上,而不是全部方法;或者为不同的方法设置不同的值。”例如:
    class MyService : IMyContract,IDisposable
    {
       [OperationBehavior(ReleaseInstanceMode = ReleaseInstanceMode.AfterCall)]
       public void MyMethod(  )
       {...}
       public void MyOtherMethod(  )
       {...}
       public void Dispose(  )
       {...}
    }

    ReleaseInstanceMode属性的默认值为ReleaseInstanceMode.None。关于ReleaseInstanceMode属性值,以下四张图片足以说明它们的工作方式:
    figure-4.3.gif 
    ReleaseInstanceMode.None

    figure-4.4.gif
    ReleaseInstanceMode.BeforeCall

    figure-4.5.gif 
    ReleaseInstanceMode.AfterCall

    figure-4.6.gif 
    ReleaseInstanceMode.BeforeAndAfterCall

    准确地选择ReleaseInstanceMode,可以有效地提高系统的性能,优化内存以及资源的利用。

    除了可以通过应用OperationBehaviorAttribute应用ReleaseInstanceMode,也可以通过编程方式在服务的操作中显式地完成对实例的停止。方法是利用InstanceContext的ReleaseServiceInstance()方法:
    class MyService : IMyContract,IDisposable
    {
       public void MyMethod(  )
       {
          //Do some work then
          OperationContext.Current.InstanceContext.ReleaseServiceInstance(  );
       }
       public void Dispose(  )
       {...}
    }

    这两种实现实例停止的方式还可以结合使用,例如在应用了OperationBehavior特性,并将ReleaseInstanceMode设置为BeforeCall的方法中,如果显式调用ReleaseServiceInstance()方法,其效果就相当于将ReleaseInstanceMode设置为BeforeAndAfterCall。

    限流(Throttling)


    限流“允许开发者限制客户端连接数以及服务的负荷。限流可以避免服务的最大化,以及分配与使用重要资源的最大化。引入限流技术后,一旦超出配置的设置值,WCF就会自动地将等待处理的调用者放入到队列中,然后依次从队列中取出。在队列中等待处理调用时,如果客户端的调用超时,客户端就会获得一个TimeoutException异常。每个服务类型都可以应用限流技术,也就是说,它会影响到服务的所有实例以及服务类型的所有终结点。实现方式是为限流与服务使用的每个通道分发器建立关联。”

    限流由ServiceThrottlingBehavior类定义,包括三个重要的属性:MaxConcurrentCalls、MaxConcurrentSessions、MaxConcurrentInstances,它们分别的默认值为16,10和Int.MaxValue。

    在翻译过程中,我在查阅MSDN时,发现MaxConcurrentSessions的默认值为64,这让我感觉很奇怪,莫非作者在这里出现了错误。然而经过我仔细地查阅相关资料,发现在WCF的早期版本中,MaxConcurrentSessions的默认值确实为64,但在2006年6月的CTP版本中已经被修改为16。

    设置限流值可以通过配置文件,也可以通过编码方式。前者例如:
    <system.serviceModel>
       <services>
          <service name = "MyService" behaviorConfiguration = "ThrottledBehavior">
             ...
          </service>
       </services>
       <behaviors>
          <serviceBehaviors>
             <behavior name = "ThrottledBehavior">
                <serviceThrottling
                   maxConcurrentCalls     = "12"
                   maxConcurrentSessions  = "34"
                   maxConcurrentInstances = "56"
                />
             </behavior>
          </serviceBehaviors>
       </behaviors>
    </system.serviceModel>

    WCF并没有提供关于限流的特性。但实现该特性的方法非常简单,如下内容是我定义的关于限流的特性,本书并没有提供:
        public class ServiceThrottlingAttribute : Attribute, IServiceBehavior
        {
            private ServiceThrottlingBehavior throttle;

            public ServiceThrottlingAttribute(
              int maxConcurrentCalls,
              int maxConcurrentInstances,
              int maxConcurrentSessions)
            {
                this.throttle = new ServiceThrottlingBehavior();
                throttle.MaxConcurrentCalls = maxConcurrentCalls;
                throttle.MaxConcurrentInstances = maxConcurrentInstances;
                throttle.MaxConcurrentSessions = maxConcurrentSessions;
            }

            #region IServiceBehavior Members

            void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription,
    ServiceHostBase serviceHostBase,
    System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints,
    System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
            { }

            void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription,
    ServiceHostBase serviceHostBase)
            {
                ServiceThrottlingBehavior currentThrottle = serviceDescription.Behaviors.Find<ServiceThrottlingBehavior>();
                if (currentThrottle == null)
                {
                    serviceDescription.Behaviors.Add(this.throttle);
                }
            }

            void IServiceBehavior.Validate(ServiceDescription serviceDescription,
     ServiceHostBase serviceHostBase)
            {  }

            #endregion
        }

    定义的ServiceThrottlingAttribute特性继承了Attribute,并实现了IServiceBehavior接口。在特性内,则使用了ServiceThrottlingBehavior类,以设置限流的相关值。如果要配置服务的限流值,就可以应用该特性,例如:
    [ServiceThrottling(12, 34, 56)]
    class MyService : IMyContract,IDisposable
    {
         public void MyMethod(  )
         {
            ChannelDispatcher dispatcher = OperationContext.Current.Host.ChannelDispatchers[0] as ChannelDispatcher;
            ServiceThrottle serviceThrottle = dispatcher.ServiceThrottle;
            
            Trace.WriteLine("MaxConcurrentCalls = " + serviceThrottle.MaxConcurrentCalls);
            Trace.WriteLine("MaxSessions = " + serviceThrottle.MaxConcurrentSessions);
            Trace.WriteLine("MaxInstances = " + serviceThrottle.MaxConcurrentInstances);
         }
    }

    则输出结果为:
    MaxConcurrentCalls = 12
    MaxSessions = 56
    MaxInstances = 34
  • 相关阅读:
    AndroidStudio修改程序的包名,可以修改com.example.xxx之类的详解
    【Android】Android开发点击查看手机电量的小功能。学习广播的一个小技能小Demo
    linux系统工程师修改打开文件数限制代码教程。服务器运维技术
    修改linux操作系统的时间可以使用date指令 运维系统工程师必会技术
    MySQL常用指令,java,php程序员,数据库工程师必备。程序员小冰常用资料整理
    android开发之java代码中字符串对比忽略大小写。java程序员必回,可用来比对验证码等问题
    android开发之使edittext输入弹出数字软键盘。亲测可用。手机号登陆注册常用。
    java工具类去掉字符串String中的.点。android开发java程序员常用工具类
    JS——tab函数封装
    JS——样式类的添加
  • 原文地址:https://www.cnblogs.com/wayfarer/p/956561.html
Copyright © 2011-2022 走看看