开发者

WCF Service host closing is blocked by open sessions and setting receiveTimeout doesn't help

开发者 https://www.devze.com 2023-02-28 15:38 出处:网络
I need my WAS hosted service (PerCall, Concurrency.Multiple) to shutdown/recycle gracefully but any inactive (but open) client proxies will block the service from shuttingdown gracefully.

I need my WAS hosted service (PerCall, Concurrency.Multiple) to shutdown/recycle gracefully but any inactive (but open) client proxies will block the service from shuttingdown gracefully.

I had expected the receiveTimout to kick in and toss out the inactive sessions but it looks like it doesn't work that way.

The IIS/WAS recycle will call ServiceHost.BeginClose with closing timeout set to TimeSpan.MaxValue.

I need to allow long lived client proxies (which I can not really control) with netTcpBinding, since throughput and low latency is a must.

I have reproduced the problem below and would be glad for any workarounds and help regarding the problem.

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.FromSec开发者_如何转开发onds(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();
        }
    }
}


strange that TCP-bound *WCF service host* cant sever the connection when-ever it likes, that's the nice-ity of TCP unlike say named pipes.

in any event, one good pattern that i like to use is to wrap all service host operation in a separate .net AppDomain. it is in this secondary AppDomain that hosts the service and not the Primary AppDomain. think of it as a sandbox. then when you wish to shutdown, you shutdown using normal service host close methods then have the primary appdomain do a AppDomain.Unload() which guarentees not only a nice way of memory clean-up but also severing all those pesky clients who dont close properly.

such a pattern is an absolute must in named pipes WCF because clients can prevent the server from starting up again as i found in a previous project. (due to orphaned connections)

hoping all goes well


I'll assume that since you are using net.tcp, your client doesn't connect through a web proxy to your server. In that case, I'd let you consider switching to a duplex net.tcp binding to solve the problem.

Using a duplex binding, you could let the clients call a subscribe method when they connect and store an instance of the callback contract. In the callback contract you can add an operation that lets the client know you want to close the server.

I already have a duplex contract in our project for this purpose but I still need to implement the solution above where OnStop in our Windows Service asks the clients to disconnect. Unfortunately I don't know how to intercept the BeginClose in the IIS hosting situation. Perhaps using a custom ServiceHost?

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号