此示例演示如何通过ServiceBehaviorAttribute.InstanceContextMode 属性控制响应客户端请求来创建服务类的实例。
契约和服务类的代码如下:
using System.ServiceModel;
using System.Threading; namespace Microsoft.ServiceModel.Samples
{
// Define a service contract.
[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode = SessionMode.Required)]
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);
}
[ServiceContract(Namespace
= "http://Microsoft.ServiceModel.Samples", SessionMode = SessionMode.Required)]public interface ICalculatorInstance : ICalculator
{
[OperationContract]
string GetInstanceContextMode();
[OperationContract]
[OperationContract]
}
// enable one of the following instance modes to compare instancing behaviors
// PerSession crates an instance per channel session
// This requires a binding that supports session
//[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
// PerCall creates a new instance for each operation
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
// Singleton creates a single instance for application lifetime
//[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class CalculatorService : ICalculatorInstance
{
static object syncObject = new object();
static int instanceCount;
int instanceId;
int operationCount;
// WCF 只能使用服务类的默认构造函数,要避免使用带参构造函数。
public CalculatorService()
{
lock (syncObject)
{
// 每生成一个实例,实例计数加 1。
instanceCount++;
// 实例的 ID 即为当前已创建的实例总数
instanceId = instanceCount;
}
}
#region ICalculator 成员
// 每调用一个操作,操作的总数加 1。
double ICalculator.Add(double n1, double n2)
{
// 以原子操作的形式递增指定变量的值并存储结果
Interlocked.Increment(ref operationCount);
return n1 + n2;
}
double ICalculator.Subtract(double n1, double n2)
{
Interlocked.Increment(ref operationCount);
return n1 - n2;
}
double ICalculator.Multiply(double n1, double n2)
{
Interlocked.Increment(ref operationCount);
return n1 * n2;
}
double ICalculator.Divide(double n1, double n2)
{
Interlocked.Increment(ref operationCount);
return n1 / n2;
}
#endregion
#region ICalculatorInstance 成员
string ICalculatorInstance.GetInstanceContextMode()
{
// Return the InstanceContextMode of the service
ServiceHost host = (ServiceHost)OperationContext.Current.Host;
ServiceBehaviorAttribute behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
return behavior.InstanceContextMode.ToString();
}
int ICalculatorInstance.GetInstanceID()
{
// Return the id for this instance
return instanceId;
}
int ICalculatorInstance.GetOperationCount()
{
// Return the number of ICalculator operations performed on this instance
lock (syncObject)
{
return operationCount;
}
}
#endregion
}
}
宿主配置文件为:
<system.serviceModel>
<services>
<service name="Microsoft.ServiceModel.Samples.CalculatorService" behaviorConfiguration="CalculatorServiceBehavior">
<!-- Service Endpoints -->
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="BindingWithSession" contract="Microsoft.ServiceModel.Samples.ICalculatorInstance">
<!--
部署时,应删除或替换下列标识元素,以反映
在其下运行部署服务的标识。删除之后,WCF 将
自动推导相应标识。
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="BindingWithSession">
<reliableSession enabled="true"/>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点-->
<serviceMetadata httpGetEnabled="true"/>
<!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息-->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
调用代理的客户程序为:
using System; namespace Microsoft.ServiceModel.Samples
{
class Program
{
static void Main(string[] args)
{
// Create a client
CalculatorInstanceClient client = new CalculatorInstanceClient();
string instanceMode = client.GetInstanceContextMode();
Console.WriteLine("InstanceContextMode : {0}",instanceMode);
DoCalculations(client);
// Create a client
CalculatorInstanceClient client2 = new CalculatorInstanceClient();
DoCalculations(client2);
// Closing the client gracefully closes the connection and cleans up resources
client.Close();
client2.Close();
Console.Read();
}
static void DoCalculations(CalculatorInstanceClient client)
{
// Call the Add service operation
double value1 = 100.00D;
double value2 = 15.99D;
double result = client.Add(value1, value2);
Console.WriteLine("Add({0},{1}) = {2}",value1,value2,result);
Console.Write("InstanceId : {0}",client.GetInstanceID());
Console.WriteLine(" , OperationCount: {0}",client.GetOperationCount());
// Call the Subtract service operation
value1 = 145.00D;
value2 = 76.54D;
result = client.Subtract(value1, value2);
Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);
Console.Write("InstanceId : {0}", client.GetInstanceID());
Console.WriteLine(" , OperationCount: {0}", client.GetOperationCount());
// Call the Multiply service operation.
value1 = 9.00D;
value2 = 81.25D;
result = client.Multiply(value1, value2);
Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);
Console.Write("InstanceId : {0}", client.GetInstanceID());
Console.WriteLine(" , OperationCount: {0}", client.GetOperationCount());
// Call the Divide service operation.
value1 = 22.00D;
value2 = 7.00D;
result = client.Divide(value1, value2);
Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
Console.Write("InstanceId : {0}", client.GetInstanceID());
Console.WriteLine(" , OperationCount: {0}", client.GetOperationCount());
}
}
}
下面分别将客户程序的输出结果列出如下:
如果将服务类的实例化模式设置为:PerSession,则客户端运行结果为
InstanceContextMode : PerSession
Add(
InstanceId : 1 , OperationCount: 1
Subtract(145,76.54) = 68.46
InstanceId : 1 , OperationCount: 2
Multiply(9,81.25) = 731.25
InstanceId : 1 , OperationCount: 3
Divide(22,7) = 3.14285714285714
InstanceId : 1 , OperationCount: 4
Add(100,15.99) = 115.99
InstanceId : 2 , OperationCount: 1
Subtract(145,76.54) = 68.46
InstanceId : 2 , OperationCount: 2
Multiply(9,81.25) = 731.25
InstanceId : 2 , OperationCount: 3
Divide(22,7) = 3.14285714285714
InstanceId : 2 , OperationCount: 4
如果将服务类的实例化模式设置为:PerCall,则客户端运行结果为
InstanceContextMode : PerCall
Add(
InstanceId : 3 , OperationCount: 0
Subtract(145,76.54) = 68.46
InstanceId : 6 , OperationCount: 0
Multiply(9,81.25) = 731.25
InstanceId : 9 , OperationCount: 0
Divide(22,7) = 3.14285714285714
InstanceId : 12 , OperationCount: 0
Add(100,15.99) = 115.99
InstanceId : 15 , OperationCount: 0
Subtract(145,76.54) = 68.46
InstanceId : 18 , OperationCount: 0
Multiply(9,81.25) = 731.25
InstanceId : 21 , OperationCount: 0
Divide(22,7) = 3.14285714285714
InstanceId : 24 , OperationCount: 0
如果将服务类的实例化模式设置为:Single,则客户端运行结果为
InstanceContextMode : Single
Add(
InstanceId : 1 , OperationCount: 1
Subtract(145,76.54) = 68.46
InstanceId : 1 , OperationCount: 2
Multiply(9,81.25) = 731.25
InstanceId : 1 , OperationCount: 3
Divide(22,7) = 3.14285714285714
InstanceId : 1 , OperationCount: 4
Add(100,15.99) = 115.99
InstanceId : 1 , OperationCount: 5
Subtract(145,76.54) = 68.46
InstanceId : 1 , OperationCount: 6
Multiply(9,81.25) = 731.25
InstanceId : 1 , OperationCount: 7
Divide(22,7) = 3.14285714285714
InstanceId : 1 , OperationCount: 8
在此示例程序中有以下需要说明的地方:
1.InstanceContextMode枚举的成员列表如下:
成员名称 | 说明 |
---|---|
PerSession | 为每个会话创建一个新的 InstanceContext 对象。 |
PerCall | 新的 InstanceContext 对象在每次调用前创建,在调用后回收。如果信道未创建会话,则该值的行为就如同 PerCall 一样。 |
Single | 只有一个 InstanceContext 对象用于所有传入呼叫,并且在调用后不回收。如果服务对象不存在,则创建一个。 |
2.在配置文件中有个名为reliableSession的配置节,该配置节的属性列表如下:
属性 | 说明 | 默认值 |
---|---|---|
inactivityTimeOut | 一个 TimeSpan,指定通道在出错之前允许其他通信方不发送任何消息的最大持续时间。通道上的活动被定义为接收应用程序或基础结构消息。 如果在此属性指定的时间内未检测到活动,则基础结构会中止会话,且通道会出错。 可靠会话被中止。 | 00:10:00 |
Ordered | 一个布尔值,指定是否保证消息以其发送顺序抵达。 | true |
3.如果 InstanceContextMode 值设置为 Single,那么结果是该服务一次只能处理一条消息,除非还将 ConcurrencyMode 值设置为 Multiple。
4.对于单一实例生存期行为(例如,如果主机应用程序调用 ServiceHost 构造函数并传递一个对象以用作该服务),该服务类必须将 InstanceContextMode 设置为 Single,否则运行时会引发异常。