我得到了一个通常的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;
}
}
从这段代码中,我想,创建了一个“内核”实例,因为我只运行了一次该服务。
我使用ChannelFactory创建一个代理对象,如下所示:
pipeFactory = new ChannelFactory<IDatabase>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/DatabaseService"));
m_Database = pipeFactory.CreateChannel();
我不得不说,我的内核实例访问本地文件,因此我只获得此类的物理实例非常重要。我希望我的服务能够解决这个问题,但这就是我的问题。
当服务正在运行且单个频道已创建并处于活动状态时,会出现第二个客户端,并且也想要创建频道。这工作正常,但如果我开始使用代理对象,则会抛出FaultException,因为我的内核类的第二个实例已创建。
因此,我猜测每个CreateChannel调用都会创建一个Kernel类的实例。
是否可以避免创建新实例并在调用CreateChannel时始终返回对单个内核类实例的引用?
此致 INVA
答案 0 :(得分:3)
是,默认情况下,WCF使用每会话或每个呼叫的呼叫约定,例如来自客户端的每个传入服务请求都会获得一个新的,独立的服务(实现)类实例。
当然,您可以使用InstanceContextMode
之类的内容来控制这一点(PerSession
是默认设置 - 至少在支持它的绑定上,PerCall
推荐的最佳做法,以及<{1}}是Singleton)和服务上的Single
设置。
您可以在config中定义,也可以直接在服务类上定义。
ConcurrencyMode
请参阅MSDN documentation on WCF Sessions, Instancing and Concurrency,详细了解所有细节。另请阅读Juval Lowy撰写的优秀MSDN杂志文章Discover Mighty Instance Management Techniques For Developing WCF Apps,这是一个很好的资源!
如果您确实将服务类切换为单身([ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class CalculatorService : ICalculatorInstance
{
...
}
),则需要注意两个权衡因素:
要么将InstanceContextMode=InstanceContextMode.Single
定义为ConcurrencyMode
,这实际上意味着一次只能处理一个请求;请求将被序列化,也就是说,如果处理请求需要相当长的时间,后续请求将不得不开始等待并可能最终超时
另一个选项是将Single
设置为ConcurrencyMode
,然后您的单件服务类可以同时处理多个请求;但这也意味着,您必须以完全线程安全方式编写服务类,并且需要同步并保护对共享数据成员的任何并发访问 - 通常是非常棘手且难以 - 做正确的编程练习