3

我需要我的 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();
        }
    }
}
4

2 回答 2

3

奇怪的是,绑定 TCP 的*WCF 服务主机 * 不能随时断开连接,这就是 TCP 的优点,不像命名管道。

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

这种模式在命名管道WCF中是绝对必须的,因为客户端可以阻止服务器再次启动,正如我在之前的项目中发现的那样。(由于孤立的连接)

希望一切顺利

于 2011-07-09T05:46:06.853 回答
0

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

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

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

于 2011-09-21T05:52:00.027 回答