WCF服务主机关闭被打开的会话阻止,并且设置receiveTimeout没有帮助

时间:2011-04-26 14:43:20

标签: c# .net wcf iis-7 servicehost

我需要我的WAS托管服务(PerCall,Concurrency.Multiple)才能正常关闭/回收,但任何非活动(但打开)的客户端代理都会阻止服务正常关闭。

我曾预料到receiveTimout会启动并抛弃非活动会话,但看起来它不会那样工作。

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();
        }
    }
}

2 个答案:

答案 0 :(得分:3)

奇怪的是 TCP绑定 * WCF服务主机*无论什么时候都不能切断连接,这就像TCP的优点一样,不像命名管道。

无论如何,我喜欢使用的一个好模式是将所有服务主机操作包装在单独的.net AppDomain 中。它位于此辅助AppDomain中,托管服务而不是主AppDomain 。把它想象成一个沙盒。然后,当您希望关闭时,使用普通服务主机关闭方法关闭,然后让主应用程序域执行 AppDomain.Unload (),这样可以保证内存清理的一种很好的方式< / em>还切断所有那些没有正确关闭的讨厌的客户

这样的模式在命名管道 WCF中绝对必须,因为客户端可以阻止服务器再次启动,就像我在之前的项目中找到的那样。 (由于孤儿的连接)

希望一切顺利

答案 1 :(得分:0)

我假设您使用net.tcp,因此您的客户端不会通过Web代理连接到您的服务器。在这种情况下,我会考虑切换到双工net.tcp绑定来解决问题。

使用双工绑定,您可以让客户端在连接并存储回调协定实例时调用订阅方法。在回调合同中,您可以添加一个操作,让客户端知道您要关闭服务器。

我的项目中已经为此目的签订了双工合同,但我仍然需要实施上述解决方案,我们的Windows服务中的OnStop会要求客户断开连接。不幸的是我不知道如何在IIS托管情况下拦截BeginClose。也许使用自定义ServiceHost?