WCF,ServiceHost-CreateChannel,don';t创建新的远程实例
本文关键字:程实例 实例 创建 don ServiceHost-CreateChannel WCF | 更新日期: 2023-09-27 18:21:36
我得到了一个常见的WCF服务,设置如下:
private ServiceHost serviceHost = null;
protected override void OnStart(string[] args)
{
if (serviceHost != null)
serviceHost.Close();
Uri[] baseAddress = new Uri[]{
new Uri("net.pipe://localhost")};
string PipeName = "DatabaseService";
serviceHost = new ServiceHost(typeof(Kernel), baseAddress); // Kernel implements IDatabase
serviceHost.AddServiceEndpoint(typeof(IDatabase), new NetNamedPipeBinding(), PipeName);
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null && serviceHost.State != CommunicationState.Closed)
{
serviceHost.Close();
serviceHost = null;
}
}
我想,从这段代码中,创建了一个"Kernel"实例,因为我只运行过一次这个服务。
我使用ChannelFactory创建了一个代理对象,如下所示:
pipeFactory = new ChannelFactory<IDatabase>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/DatabaseService"));
m_Database = pipeFactory.CreateChannel();
我不得不说,我的内核实例访问一个本地文件,因此,我只获得一个此类的物理实例是非常重要的。我希望我的服务能解决这个问题,但我的问题来了。
当服务正在运行并且创建了一个通道并处于活动状态时,第二个客户端也会出现并想要创建一个通道。这可以正常工作,但如果我开始使用代理对象,就会抛出FaultException,因为我的Kernel类的第二个实例已经创建。
因此,我猜测Kernel类的一个实例是由每个CreateChannel调用创建的。
是否可以避免创建新实例,并在调用CreateChannel时始终返回对单个内核类实例的引用?
谨致问候,inva
是的,默认情况下,WCF使用每个会话或每个调用的调用约定,例如,来自客户端的每个传入服务请求都会获得服务(实现)类的一个新的独立实例。
当然,您可以使用InstanceContextMode
(PerSession
是默认设置,至少在支持它的绑定上是这样)、PerCall
是推荐的最佳实践,Single
是Singleton)和服务上的ConcurrencyMode
设置来控制这一点。
您可以在配置中定义这些,也可以直接在服务类上定义。
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class CalculatorService : ICalculatorInstance
{
...
}
请参阅有关WCF会话、实例化和并发的MSDN文档,以获得对所有详细信息的详尽解释。另请阅读MSDN杂志上Juval Lowy的文章《发现开发WCF应用程序的强大实例管理技术》,这是一篇非常棒的资源!
如果您确实将服务类切换为单例(InstanceContextMode=InstanceContextMode.Single
),则需要注意两个权衡:
或者将
ConcurrencyMode
定义为Single
,这实际上意味着一次只能处理一个请求;请求将被序列化,也就是说,如果处理请求需要相当长的时间,那么后续的请求将不得不开始等待,并且可能会超时另一种选择是将
ConcurrencyMode
设置为Multiple
,这样您的singleton服务类就可以同时处理多个请求;但这也意味着,您必须以完全线程安全的方式编写服务类,并且您需要同步和保护对共享数据成员的任何并发访问-这通常是一个非常棘手且难以正确执行的编程练习