此示例通过设置ServiceThrottlingBehavior的属性来实现遏制控制。
为了容易在客户端看出效果,我们对每个服务方法定义了休眠时间。
如下为契约和服务类的代码:
Code
using System.ServiceModel; namespace Microsoft.ServiceModel.Samples
{
// Define a service contract.
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
[OperationContract]
double Add(double n1, double n2);
[OperationContract]
double Subtract(double n1, double n2);
[OperationContract]
double Multiply(double n1, double n2);
[OperationContract]
double Divide(double n1, double n2);
}
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class CalculatorService : ICalculator
{
public double Add(double n1, double n2)
{
System.Threading.Thread.Sleep(5000);
return n1 + n2;
}
{
System.Threading.Thread.Sleep(5000);
return n1 - n2;
}
{
System.Threading.Thread.Sleep(5000);
return n1 * n2;
}
{
System.Threading.Thread.Sleep(5000);
return n1 / n2;
}
}
}
using System.ServiceModel; namespace Microsoft.ServiceModel.Samples
{
// Define a service contract.
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
[OperationContract]
double Add(double n1, double n2);
[OperationContract]
double Subtract(double n1, double n2);
[OperationContract]
double Multiply(double n1, double n2);
[OperationContract]
double Divide(double n1, double n2);
}
// Service class which implements the service contract.
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class CalculatorService : ICalculator
{
public double Add(double n1, double n2)
{
System.Threading.Thread.Sleep(5000);
return n1 + n2;
}
public double Subtract(double n1, double n2)
{
System.Threading.Thread.Sleep(5000);
return n1 - n2;
}
public double Multiply(double n1, double n2)
{
System.Threading.Thread.Sleep(5000);
return n1 * n2;
}
public double Divide(double n1, double n2)
{
System.Threading.Thread.Sleep(5000);
return n1 / n2;
}
}
}
我们将服务的最大并发调用数限制为2,最大并发实例数限制为10,服务端的配置文件为:
Code
<system.serviceModel>
<services>
<service name="Microsoft.ServiceModel.Samples.CalculatorService" behaviorConfiguration="CalculatorServiceBehavior">
<!-- Service Endpoints -->
<endpoint address="" binding="wsHttpBinding" contract="Microsoft.ServiceModel.Samples.ICalculator">
<!--
部署时,应删除或替换下列标识元素,以反映
在其下运行部署服务的标识。删除之后,WCF 将
自动推导相应标识。
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点-->
<serviceMetadata httpGetEnabled="true"/>
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息-->
<serviceDebug includeExceptionDetailInFaults="false"/>
<!-- Specify throttling behavior -->
<serviceThrottling maxConcurrentCalls="2" maxConcurrentInstances="10"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.serviceModel>
<services>
<service name="Microsoft.ServiceModel.Samples.CalculatorService" behaviorConfiguration="CalculatorServiceBehavior">
<!-- Service Endpoints -->
<endpoint address="" binding="wsHttpBinding" contract="Microsoft.ServiceModel.Samples.ICalculator">
<!--
部署时,应删除或替换下列标识元素,以反映
在其下运行部署服务的标识。删除之后,WCF 将
自动推导相应标识。
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点-->
<serviceMetadata httpGetEnabled="true"/>
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息-->
<serviceDebug includeExceptionDetailInFaults="false"/>
<!-- Specify throttling behavior -->
<serviceThrottling maxConcurrentCalls="2" maxConcurrentInstances="10"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
客户端程序的代码为:
Code
using System; namespace Microsoft.ServiceModel.Samples
{
class Program
{
static void Main(string[] args)
{
// Create a client
CalculatorClient client = new CalculatorClient();
Console.WriteLine();
double value1 = 100.00D;
double value2 = 15.99D;
IAsyncResult arAdd = client.BeginAdd(value1, value2, AddCallback, client);
Console.WriteLine("Add({0},{1})", value1, value2);
value1 = 145.00D;
value2 = 76.54D;
IAsyncResult arSubtract = client.BeginSubtract(value1, value2, SubtractCallback, client);
Console.WriteLine("Subtract({0},{1})", value1, value2);
value1 = 9.00D;
value2 = 81.25D;
IAsyncResult arMultiply = client.BeginMultiply(value1, value2, MultiplyCallback, client);
Console.WriteLine("Multiply({0},{1})", value1, value2);
value1 = 22.00D;
value2 = 7.00D;
IAsyncResult arDivide = client.BeginDivide(value1, value2, DivideCallback, client);
Console.WriteLine("Divide({0},{1})", value1, value2);
client.Close();
}
{
double result = ((CalculatorClient)ar.AsyncState).EndAdd(ar);
Console.WriteLine("Add Result : {0}",result);
}
{
double result = ((CalculatorClient)ar.AsyncState).EndSubtract(ar);
Console.WriteLine("Subtract Result : {0}",result);
}
{
double result = ((CalculatorClient)ar.AsyncState).EndMultiply(ar);
Console.WriteLine("Multiply Result : {0}",result);
}
{
double result = ((CalculatorClient)ar.AsyncState).EndDivide(ar);
Console.WriteLine("Divide Result : {0}",result);
}
}
}
using System; namespace Microsoft.ServiceModel.Samples
{
class Program
{
static void Main(string[] args)
{
// Create a client
CalculatorClient client = new CalculatorClient();
Console.WriteLine(
"Press <ENTER> to terminate client once the output is displayed.");Console.WriteLine();
// BeginAdd
double value1 = 100.00D;
double value2 = 15.99D;
IAsyncResult arAdd = client.BeginAdd(value1, value2, AddCallback, client);
Console.WriteLine("Add({0},{1})", value1, value2);
// BeginSubstract
value1 = 145.00D;
value2 = 76.54D;
IAsyncResult arSubtract = client.BeginSubtract(value1, value2, SubtractCallback, client);
Console.WriteLine("Subtract({0},{1})", value1, value2);
// BeginMultiply
value1 = 9.00D;
value2 = 81.25D;
IAsyncResult arMultiply = client.BeginMultiply(value1, value2, MultiplyCallback, client);
Console.WriteLine("Multiply({0},{1})", value1, value2);
// BeginDivide
value1 = 22.00D;
value2 = 7.00D;
IAsyncResult arDivide = client.BeginDivide(value1, value2, DivideCallback, client);
Console.WriteLine("Divide({0},{1})", value1, value2);
Console.ReadLine();
//Closing the client gracefully closes the connection and cleans up resources
client.Close();
}
static void AddCallback(IAsyncResult ar)
{
double result = ((CalculatorClient)ar.AsyncState).EndAdd(ar);
Console.WriteLine("Add Result : {0}",result);
}
static void SubtractCallback(IAsyncResult ar)
{
double result = ((CalculatorClient)ar.AsyncState).EndSubtract(ar);
Console.WriteLine("Subtract Result : {0}",result);
}
static void MultiplyCallback(IAsyncResult ar)
{
double result = ((CalculatorClient)ar.AsyncState).EndMultiply(ar);
Console.WriteLine("Multiply Result : {0}",result);
}
static void DivideCallback(IAsyncResult ar)
{
double result = ((CalculatorClient)ar.AsyncState).EndDivide(ar);
Console.WriteLine("Divide Result : {0}",result);
}
}
}
下面把客户端程序运行结果贴出来:
我们会发现在运行减法后,将有5秒左右的停顿。
在配置文件中,我们看到了serviceThrottling这个元素,下面我把这个元素的属性列出如下:
属性 | 说明 | 默认值 |
---|---|---|
maxConcurrentCalls | 一个正整数值,指定对单个服务实例进行的并发调用的数量。 超出限制的调用会进行排队。 将此值设置为 0 与将其设置为 Int32.MaxValue 等效。 | 16 |
maxConcurrentInstances | 一个正整数,指定并发服务实例的最大数量。 创建其他实例的请求会进行排队,并在限制范围内的槽可用时完成。 | Int32.MaxValue |
maxConcurrentSessions | 一个正整数,指定与单个服务的并发连接的最大数量。 此服务将接受超出限制的连接,但是,只有处于限制范围之内的通道处于活动状态(会从此通道中读取消息)。 将此值设置为 0 与将其设置为 Int32.MaxValue 等效。 | 10 |