在构建企业级应用程序时,通常需要考虑应用程序的可扩展性、性能、吞吐量和可靠性。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();
}
}