WCF 服务实例的生存期
本文关键字:生存期 实例 服务 WCF | 更新日期: 2023-09-27 18:20:34
在创建WCF服务的过程中,我遇到了一个对我来说很陌生的术语。基本上在指定InstanceContextMode
时,我有几个选择,包括; PerSession
,PerCall
和Single
。下面是我正在学习的示例中的代码:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class EvalService : IEvalService { ...
现在,他通过这样做声明在运行时只会创建我的服务的一个实例。这是什么意思?我认为每次与 Web 服务建立连接时,它都会被视为一个单独的实例。
对于提出的每个请求,它是否仍然存在,我的服务实例?从文档中提到的其他成员来看,是否可以安全地假设这是它的工作方式?
根据文档:
只有一个实例上下文对象用于所有传入调用,并且 调用后不回收。如果服务对象没有 存在,一个被创造。
因此,只有一个实例,并且在进行调用后不会清理它。 这类似于 WCF 服务的单一实例。 因此,您需要注意共享内存和资源。
回答你的问题 - 是的,这就是它的工作方式。
更新 添加的示例:我修改了 MSDN 中的一些示例以显示InstanceContextMode.Single
的效果。 您将看到,即使我使用两个不同的客户端,操作计数也会继续增加。 如果我将InstanceContextMode
更改为 PerCall
,计数会有所不同(将为零(。
自托管服务:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class CalculatorService : ICalculatorInstance
{
static Object syncObject = new object();
static int instanceCount;
int instanceId;
int operationCount;
public CalculatorService()
{
lock (syncObject)
{
instanceCount++;
instanceId = instanceCount;
}
}
public double Add(double n1, double n2)
{
operationCount++;
return n1 + n2;
}
public double Subtract(double n1, double n2)
{
Interlocked.Increment(ref operationCount);
return n1 - n2;
}
public double Multiply(double n1, double n2)
{
Interlocked.Increment(ref operationCount);
return n1 * n2;
}
public double Divide(double n1, double n2)
{
Interlocked.Increment(ref operationCount);
return n1 / n2;
}
public string GetInstanceContextMode()
{ // Return the InstanceContextMode of the service
ServiceHost host = (ServiceHost)OperationContext.Current.Host;
ServiceBehaviorAttribute behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
return behavior.InstanceContextMode.ToString();
}
public int GetInstanceId()
{ // Return the id for this instance
return instanceId;
}
public int GetOperationCount()
{ // Return the number of ICalculator operations performed
// on this instance
lock (syncObject)
{
return operationCount;
}
}
}
public class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:12345/calc");
using (ServiceHost host = new ServiceHost(typeof(CalculatorService), baseAddress))
{
// Enable metadata publishing.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
// Open the ServiceHost to start listening for messages. Since
// no endpoints are explicitly configured, the runtime will create
// one endpoint per base address for each service contract implemented
// by the service.
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
// Close the ServiceHost.
host.Close();
}
Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();
}
}
客户:
class Program
{
static void Main()
{
// Create a client.
CalculatorInstanceClient client = new CalculatorInstanceClient();
string instanceMode = client.GetInstanceContextMode();
Console.WriteLine("InstanceContextMode: {0}", instanceMode);
Console.WriteLine("client1's turn");
Console.WriteLine("2 + 2 = {0}", client.Add(2, 2).ToString());
Console.WriteLine("3 - 1 = {0}", client.Subtract(3, 1).ToString());
Console.WriteLine("number of operations = {0}", client.GetOperationCount().ToString());
// Create a second client.
CalculatorInstanceClient client2 = new CalculatorInstanceClient();
Console.WriteLine("client2's turn");
Console.WriteLine("2 + 2 = {0}", client2.Add(2, 2).ToString());
Console.WriteLine("3 - 1 = {0}", client2.Subtract(3, 1).ToString());
Console.WriteLine("number of operations = {0}", client2.GetOperationCount().ToString());
Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();
}
}
InstanceContextMode.Single
对应于单例服务,即服务实例服务器端对于所有传入请求都是相同的。
几点意见:
- 即使主机是单一实例,您的服务也可能被主机终止,如果您的服务托管在 IIS 中,则可能就是这种情况 它是实例上下文,它是一个
- 单例,可能与实际的服务实例分离(但现在让我们保持简单......
- 如果在单一实例服务中未正确捕获异常,则可能会阻止任何后续请求成功
这意味着 WCF 只创建了类的一个实例。所有请求都由该实例处理。包括多线程和并发问题。
尽管这可能是一个实现细节,但我怀疑您的类是否持久(它必须是可序列化的,这不是必需的(。只要需要,一个实例就存在(即关联的ServiceHost
是开放的(。
是的,共享服务实例意味着服务器只创建了一个实例,在请求之间共享。
特别是,服务对象的构造函数将在创建实例时调用一次。例如,如果您使用某种形式的身份验证来模拟上下文的标识,这可能很重要(共享实例可能需要一些额外的工作来处理这种情况(。