在构建企业级应用程序时,通常需要考虑应用程序的可扩展性、性能、吞吐量和可靠性。Windows Communication Foundation (WCF) 提供了多种技术来实现这些特性。本文将详细介绍WCF服务行为的不同配置方式,包括并发模式、实例上下文模式和服务节流。
默认情况下,WCF服务一次只能处理一个请求,其他服务请求线程将被排队并逐个处理。并发元素允许客户端同时发送多个请求,但服务实现应该避免死锁等场景。并发模式有三种类型:
        单例并发模式将只允许一个请求同时进入服务实例,其他待处理请求将被维护在队列中并逐个处理。每当有新请求到来时,调度器在进入代码前会获取一个锁。以下是定义单例并发模式的代码示例:
        
        public class VisitorCount : IVisitorCount
        {
            [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single)]
        }
        
        多实例并发模式将允许并行请求,每个请求将由单独的线程处理。以下是定义多实例并发模式的代码示例:
        
        public class VisitorCount : IVisitorCount
        {
            [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
        }
        
        当客户端调用WCF服务时,将为该客户端调用分配一个线程锁。考虑一个场景,服务1对服务2进行外部调用。线程锁在服务调用完成之前不会被释放,因此所有其他客户端请求都在等待状态。可重入模式允许客户端在调用外部服务(服务2)之前释放锁,这将允许其他客户端使用服务1的设施,直到服务2的处理完成。以下是定义可重入并发模式的代码示例:
        
        public class VisitorCount : IVisitorCount
        {
            [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
        }
        
WCF实例化决定对象是如何创建的,并引用服务对象的生命周期。每当客户端发出请求时,运行时将创建服务对象以提供响应。通过实例化,可以控制服务实例想要保留多长时间。使用三种实例化模式:
        在这种情况下,对服务的所有调用都变为无状态的。对于每个线程请求,将创建一个新的服务实例。这将与所有服务绑定一起工作。以下是定义每次调用实例上下文模式的代码示例:
        
        public class VisitorCount : IVisitorCount
        {
            [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.PerCall)]
        }
        
        服务对象的生命周期与客户端通道的生命周期无关,因此每当建立新的通信会话时,将创建一个新的服务对象,并在会话结束后进行处理。每个客户端通道获得一个专用的服务实例,同一会话中的后续调用由相同的服务对象处理。这是实例化上下文的默认值,并且将与所有绑定一起工作,除了basicHttpBindings。以下是定义每次会话实例上下文模式的代码示例:
        
        public class VisitorCount : IVisitorCount
        {
            [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.PerSession)]
        }
        
        这将帮助全局共享数据。只能创建一个实例,并且相同的实例将在后续调用中被重用。与每次会话一样,这将与所有绑定一起工作,除了basicHttpBinding。单例实例在服务主机关闭之前不会被处理。以下是定义单例实例上下文模式的代码示例:
        
        public class VisitorCount : IVisitorCount
        {
            [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single)]
        }
        
WCF允许对特定服务类型进行负载节流。这包括:
        <serviceBehaviors>
            <behavior name="visitorCountServiceBehavior">
                <serviceThrottling maxConcurrentCalls="5" maxConcurrentInstances="10" maxConcurrentSessions="10">
                </serviceThrottling>
            </behavior>
        </serviceBehaviors>
        
        让创建一个示例应用程序来演示不同的服务行为。首先创建一个接口,并使用ServiceContract和OperationContract属性对其进行装饰,以指定这些操作可以由客户端应用程序使用。
        
        [ServiceContract]
        public interface IVisitorCount
        {
            [OperationContract]
            int GetVisitorCount();
        }
        
        现在需要创建一个服务类来实现上述接口方法。需要使用不同的服务行为来装饰服务类,以下代码解释了单例并发模式和单例实例上下文模式。
        
        [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.Single)]
        public class VisitorCount : IVisitorCount
        {
            int _visitorCount = 0;
            public VisitorCount()
            {
                Console.WriteLine("New Service Instance Created");
            }
            public int GetVisitorCount()
            {
                _visitorCount++;
                return _visitorCount;
            }
        }
        
        现在让看看如何使这个服务对客户端应用程序可用,配置文件App.Config的内容如下所示:
        
        <configuration>
            <system.web>
                <compilation debug="true">
                </compilation>
            </system.web>
            <system.serviceModel>
                <services>
                    <service name="InstanceContextModeService.VisitorCount">
                        <endpoint binding="wsHttpBinding" contract="InstanceContextModeService.IVisitorCount">
                            <identity>
                                <dns value="localhost">
                                </dns>
                            </identity>
                        </endpoint>
                        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange">
                            <host>
                                <baseAddresses>
                                    <add baseaddress="http://localhost:8732/InstanceContextModeService/VisitorCount/">
                                    </baseAddresses>
                                </add>
                            </host>
                        </endpoint>
                    </service>
                </services>
                <behaviors>
                    <serviceBehaviors>
                        <behavior>
                            <serviceMetadata httpGetEnabled="True">
                            <serviceDebug includeExceptionDetailInFaults="False">
                                <serviceThrottling maxConcurrentCalls="5" maxConcurrentInstances="10" maxConcurrentSessions="10">
                                </serviceThrottling>
                            </serviceDebug>
                            </serviceMetadata>
                        </behavior>
                    </serviceBehaviors>
                </behaviors>
            </system.serviceModel>
        </configuration>
        
        以下服务主机代码将托管VisitorCounter服务供客户端应用程序使用。
        
        class Program
        {
            private static ServiceHost host = null;
            static void Main(string[] args)
            {
                host = new ServiceHost(typeof(InstanceContextModeService.VisitorCount));
                host.Opened += new EventHandler(host_Opened);
                host.Closed += new EventHandler(host_Closed);
                host.Open();
                Console.ReadKey();
                host.Close();
                Console.ReadKey();
            }
            static void host_Closed(object sender, EventArgs e)
            {
                Console.WriteLine("Service Closed");
            }
            static void host_Opened(object sender, EventArgs e)
            {
                Console.WriteLine("Service Started");
            }
        }
        
        已经托管并定义了服务。以下代码解释了客户端如何使用服务和服务行为。
        
        static class Program
        {
            static void Main(string[] args)
            {
                VisitorCountClient client = new VisitorCountClient();
                Console.WriteLine("First Call-->" + client.GetVisitorCount());
                Console.ReadKey();
                Console.WriteLine("Second Call-->" + client.GetVisitorCount());
                Console.ReadKey();
                Console.WriteLine("Third Call-->" + client.GetVisitorCount());
                Console.ReadKey();
                Console.WriteLine("Forth Call-->" + client.GetVisitorCount());
                Console.ReadKey();
            }
        }