Закрытие узла службы WCF блокируется открытыми сеансами, и настройка receiveTimeout не помогает - PullRequest
1 голос
/ 26 апреля 2011

Мне нужна моя размещенная служба 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 ]

3 голосов
/ 09 июля 2011

странно, что связанный с TCP * хост службы WCF * не может разорвать соединение, когда ему это нравится, но это прелесть TCP в отличие от, скажем, именованных каналов.

в любом случае, один хороший шаблон, который мне нравится использовать, - это обернуть все операции узла службы в отдельный .net AppDomain . именно в этом вторичном домене приложений размещается служба, а не основной домен приложений . думать об этом как о песочнице. затем, когда вы захотите завершить работу, вы завершите работу, используя обычные методы закрытия хоста службы, а затем попросите основной домен приложения выполнить AppDomain.Unload (), который гарантирует не только хороший способ очистки памяти но также разрывает всех тех надоедливых клиентов, которые не закрываются должным образом .

такой шаблон абсолютно необходим в именованных каналах WCF, потому что клиенты могут предотвратить запуск сервера снова, как я обнаружил в предыдущем проекте. (из-за потерянных связей)

надеясь, что все пройдет хорошо

0 голосов
/ 21 сентября 2011

Я предполагаю, что, поскольку вы используете net.tcp, ваш клиент не подключается через веб-прокси к вашему серверу. В этом случае я бы разрешил вам переключиться на дуплексную привязку net.tcp, чтобы решить эту проблему.

Используя дуплексную привязку, вы можете позволить клиентам вызывать метод подписки при подключении и сохранять экземпляр контракта обратного вызова. В контракт обратного вызова вы можете добавить операцию, которая позволит клиенту узнать, что вы хотите закрыть сервер.

У меня уже есть дуплексный контракт в нашем проекте для этой цели, но мне все еще нужно реализовать решение, описанное выше, когда OnStop в нашей службе Windows просит клиентов отключиться. К сожалению, я не знаю, как перехватить BeginClose в ситуации размещения IIS. Возможно, используя пользовательский ServiceHost?

...