我需要我的 WAS 托管服务(PerCall、Concurrency.Multiple)正常关闭/回收,但任何不活动(但打开)的客户端代理将阻止服务正常关闭。
我原以为 receiveTimout 会启动并丢弃不活动的 session ,但它看起来不像那样工作。
IIS/WAS 回收将调用 ServiceHost.BeginClose,关闭超时设置为 TimeSpan.MaxValue。
我需要使用 netTcpBinding 允许长期存在的客户端代理(我无法真正控制),因为吞吐量和低延迟是必须的。
我已经重现了下面的问题,很乐意提供任何解决方法和有关该问题的帮助。
using System;
using System.ServiceModel;
namespace Test
{
[ServiceContract(Name = "MyService", SessionMode = SessionMode.Allowed)]
public interface IHelloWorldService
{
[OperationContract]
void PrintHelloWorld();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class HellowWorldService : IHelloWorldService
{
[OperationBehavior]
public void PrintHelloWorld()
{
Console.WriteLine("Hello world!");
}
}
public class ThaProgram
{
static void Main(string[] args)
{
const string ServiceAddress = "net.tcp://localhost:12345/HelloWorld";
var netTcpBinding = new NetTcpBinding(SecurityMode.None, false);
netTcpBinding.ReceiveTimeout = TimeSpan.FromSeconds(3);
var serviceHost = new ServiceHost(typeof(HellowWorldService), new Uri("net.tcp://localhost:12345"));
serviceHost.AddServiceEndpoint(typeof(IHelloWorldService), netTcpBinding, ServiceAddress);
serviceHost.Open();
Console.WriteLine("Service host state: {0}", serviceHost.State);
netTcpBinding.ReceiveTimeout = TimeSpan.FromSeconds(10);
var channel = new ChannelFactory<IHelloWorldService>(netTcpBinding, ServiceAddress).CreateChannel();
channel.PrintHelloWorld();
// Uncomment to make everything work (then the session will be closed before the service enters the closing state)
// Thread.Sleep(4000);
// Simulate application pool shutdown
var asyncResult = serviceHost.BeginClose(TimeSpan.MaxValue, null, null);
Console.WriteLine("Service host state: {0}", serviceHost.State);
serviceHost.EndClose(asyncResult);
Console.WriteLine("Service host state: {0}", serviceHost.State);
Console.WriteLine("Hit Enter to close the application");
Console.ReadLine();
}
}
}
最佳答案
奇怪的是 TCP-bound *WCF 服务主机* 无法随时切断连接,这就是 TCP 与命名管道不同的优点。
无论如何,我喜欢使用的一个好模式是将所有服务主机操作包装在一个单独的 .net AppDomain 中。它是在这个辅助 AppDomain 中托管服务,而不是 Primary AppDomain。把它想象成一个沙箱。然后,当您希望关闭时,您可以使用正常的服务主机关闭方法关闭,然后让主应用程序域执行 AppDomain.Unload() 这不仅是内存清理的好方法 而且切断所有那些没有正确关闭的讨厌的客户端。
这种模式在命名管道 WCF 中是绝对必须的,因为客户端可以阻止服务器再次启动,正如我在之前的项目中发现的那样。 (由于孤立连接)
希望一切顺利
关于c# - WCF 服务主机关闭被打开的 session 阻止并且设置 receiveTimeout 没有帮助,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5792052/