WCF ServiceHost.Close() 延迟
Posted
技术标签:
【中文标题】WCF ServiceHost.Close() 延迟【英文标题】:WCF ServiceHost.Close() Delay 【发布时间】:2010-11-04 17:52:12 【问题描述】:我有一个简单的 WCF 双工 TCP 服务,我试图以编程方式停止它。如果我没有任何连接的用户,ServiceHost.Close() 非常快,但如果我什至有一个连接的用户,我发现 Close() 函数需要相当长的时间,有时 > 30 秒。这是通常的行为吗?
另一方面,Abort() 几乎是即时的,我很想用它来代替。
【问题讨论】:
【参考方案1】:可能是这样。 docs 声明
Close 方法允许任何未完成的 在返回之前完成的工作。 例如,完成发送任何 缓冲消息。
Close()
有一个重载,它需要一个 TimeSpan
(如果超过时间跨度,throws
)
Abort()
看起来是立即停止 WCF 主机的最佳方式。
【讨论】:
【参考方案2】:确保您正在关闭客户端连接,如下所示:
var channel = factory.CreateChannel();
var channel.DoSomethingForMe();
(channel as ICommunicationObject).Close();
如果您不在频道上执行此 Close(),则服务器上的 Close() 会等待非常非常长的时间,即使您指定了很短的超时时间。
【讨论】:
【参考方案3】:如果您可以终止任何正在进行的服务调用,那么 Abort() 就是要走的路。 Close() 是关闭服务的礼貌方式。
【讨论】:
【参考方案4】:为了方便,我可以看到 Abort() 优于 Close() 的好处,但我想可能会发生一些不好的事情。就我而言,我想等待 Close() 以便我可以重用端口。此代码将等待服务实际关闭后再恢复。
Semaphore cont=new Semaphore(0, 1);
foreach (ServiceHost s in WCFServices)
try
s.Closed += delegate(Object o, System.EventArgs n)
cont.Release();
;
s.Close();
cont.WaitOne();
catch (Exception)
//try
//for
【讨论】:
我相信你可以重新安排,这样所有的“s.Close()”都会先发出,然后在信号量上等待。【参考方案5】:我也注意到了这个问题。 我的代码最初看起来像这样:
[TestMethod]
[Timeout(2000)]
public void ApiClientTest()
bool ApiSuccessSet, ClientSuccessSet = ApiSuccessSet = false;
Api apiService = new ApiTestService();
var clientService = new ClientTestService();
ServiceHost clientHost = new ServiceHost(clientService, new Uri(PipeService));
ServiceHost apiHost = new ServiceHost(apiService, new Uri(PipeService));
//To let us know the services were successfully opened
clientHost.Opened += (s, e) => ClientSuccessSet = true;
apiHost.Opened += (s, e) => ApiSuccessSet = true;
clientHost.AddServiceEndpoint(typeof(IClientService), new NetNamedPipeBinding(), ClientPipeServiceName);
apiHost.AddServiceEndpoint(typeof(IApiService), new NetNamedPipeBinding(), ApiPipeServiceName);
clientHost.BeginOpen(OnOpen, clientHost);
apiHost.BeginOpen(OnOpen, apiHost);
//This allows both services to be open for communication.
while (!ApiSuccessSet || !ClientSuccessSet)
Thread.Yield();
EndpointAddress ApiEndpoint = new EndpointAddress(PipeService + @"/" + ApiPipeServiceName);
EndpointAddress clientEndpoint = new EndpointAddress(PipeService + @"/" + ClientPipeServiceName);
InstanceContext context = new InstanceContext((IClientCallback)new TestClientCallback());
var ClientChannelFactory = new DuplexChannelFactory<IClientService>(context, new NetNamedPipeBinding(), clientEndpoint);
var ApiChannelFactory = new ChannelFactory<IApiService>(new NetNamedPipeBinding(), ApiEndpoint);
var ClientChannel = ClientChannelFactory.CreateChannel();
var ApiChannel = ApiChannelFactory.CreateChannel();
clientHost.Close();
apiHost.Close();
void OnOpen(IAsyncResult ar)
ServiceHost service = (ServiceHost)ar.AsyncState;
service.EndOpen(ar);
我注意到这段代码需要 20 秒才能运行。然后我决定像这样关闭渠道工厂:
[TestMethod]
[Timeout(2000)]
public void ApiClientTest()
bool ApiSuccessSet, ClientSuccessSet = ApiSuccessSet = false;
Api apiService = new ApiTestService();
var clientService = new ClientTestService();
ServiceHost clientHost = new ServiceHost(clientService, new Uri(PipeService));
ServiceHost apiHost = new ServiceHost(apiService, new Uri(PipeService));
//To let us know the services were successfully opened
clientHost.Opened += (s, e) => ClientSuccessSet = true;
apiHost.Opened += (s, e) => ApiSuccessSet = true;
clientHost.AddServiceEndpoint(typeof(IClientService), new NetNamedPipeBinding(), ClientPipeServiceName);
apiHost.AddServiceEndpoint(typeof(IApiService), new NetNamedPipeBinding(), ApiPipeServiceName);
clientHost.BeginOpen(OnOpen, clientHost);
apiHost.BeginOpen(OnOpen, apiHost);
//This allows both services to be open for communication.
while (!ApiSuccessSet || !ClientSuccessSet)
Thread.Yield();
EndpointAddress ApiEndpoint = new EndpointAddress(PipeService + @"/" + ApiPipeServiceName);
EndpointAddress clientEndpoint = new EndpointAddress(PipeService + @"/" + ClientPipeServiceName);
InstanceContext context = new InstanceContext((IClientCallback)new TestClientCallback());
var ClientChannelFactory = new DuplexChannelFactory<IClientService>(context, new NetNamedPipeBinding(), clientEndpoint);
var ApiChannelFactory = new ChannelFactory<IApiService>(new NetNamedPipeBinding(), ApiEndpoint);
var ClientChannel = ClientChannelFactory.CreateChannel();
var ApiChannel = ApiChannelFactory.CreateChannel();
ClientChannelFactory.Close();
ApiChannelFactory.Close();
clientHost.Close();
apiHost.Close();
这让我相信处理客户端的实例上下文需要很长时间。
我怀疑有 3 种方法可以更好地处理此解决方案。
首先是在管理结束会话的客户端上创建一个函数。这样您就可以在服务计划关闭之前调用该方法,从而加快关闭时间。
第二种是异步关闭,在连接关闭的同时做其他处理。
第三个是向客户端编程何时关闭连接(特别是如果您同时控制客户端和服务),以便客户端可以自行终止会话,服务可以优雅快速地关闭。
【讨论】:
以上是关于WCF ServiceHost.Close() 延迟的主要内容,如果未能解决你的问题,请参考以下文章