WCF ServiceHost.Close () Задержка - PullRequest
6 голосов
/ 22 июня 2009

У меня есть простой дуплексный TCP-сервис WCF, который я пытаюсь программно остановить. Если у меня нет подключенных пользователей, ServiceHost.Close () работает очень быстро, но если у меня даже есть один подключенный пользователь, я считаю, что функция Close () занимает довольно много времени, иногда> 30 секунд. Это обычное поведение?

С другой стороны, Abort () почти мгновенный, и я испытываю желание использовать его вместо этого.

Ответы [ 5 ]

10 голосов
/ 22 июня 2009

Может быть. документы утверждают, что

Метод Close разрешает любое незаконченное работа должна быть завершена до возвращения. Например, завершить отправку любого буферизованные сообщения.

Существует перегрузка на Close(), которая принимает TimeSpanthrows, если превышен временной интервал)

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

7 голосов
/ 02 октября 2012

Убедитесь, что вы закрываете соединение на стороне клиента, например:

var channel = factory.CreateChannel();
var channel.DoSomethingForMe();
(channel as ICommunicationObject).Close();

Если вы не сделаете это Close () на канале, Close () на сервере будет ждать очень и очень долго, даже если вы укажете короткий тайм-аут.

1 голос
/ 30 августа 2009

Если вы согласны прервать любые текущие сервисные вызовы, тогда Abort () - путь Close () - это вежливый способ закрыть службу.

0 голосов
/ 08 июля 2014

Я тоже заметил эту проблему. Мой код изначально выглядел так:

[TestMethod]
[Timeout(2000)]
public void ApiClientTest()
    {
        bool ApiSuccessSet, ClientSuccessSet = ApiSuccessSet = false;
        Api apiService = new ApiTestService();
        var clientService = new ClientTestService();

        ServiceHost clientHost = new ServiceHost(clientService, new Uri(PipeService));
        ServiceHost apiHost = new ServiceHost(apiService, new Uri(PipeService));

        //To let us know the services were successfully opened
        clientHost.Opened += (s, e) => ClientSuccessSet = true;
        apiHost.Opened += (s, e) => ApiSuccessSet = true;
        clientHost.AddServiceEndpoint(typeof(IClientService), new NetNamedPipeBinding(), ClientPipeServiceName);
        apiHost.AddServiceEndpoint(typeof(IApiService), new NetNamedPipeBinding(), ApiPipeServiceName);
        clientHost.BeginOpen(OnOpen, clientHost);
        apiHost.BeginOpen(OnOpen, apiHost);

        //This allows both services to be open for communication.
        while (!ApiSuccessSet || !ClientSuccessSet)
            Thread.Yield();


        EndpointAddress ApiEndpoint = new EndpointAddress(PipeService + @"/" + ApiPipeServiceName);
        EndpointAddress clientEndpoint = new EndpointAddress(PipeService + @"/" + ClientPipeServiceName);

        InstanceContext context = new InstanceContext((IClientCallback)new TestClientCallback());
        var ClientChannelFactory = new DuplexChannelFactory<IClientService>(context, new NetNamedPipeBinding(), clientEndpoint);
        var ApiChannelFactory = new ChannelFactory<IApiService>(new NetNamedPipeBinding(), ApiEndpoint);
        var ClientChannel = ClientChannelFactory.CreateChannel();
        var ApiChannel = ApiChannelFactory.CreateChannel();


        clientHost.Close();
        apiHost.Close();
    }

void OnOpen(IAsyncResult ar)
    {
        ServiceHost service = (ServiceHost)ar.AsyncState;
        service.EndOpen(ar);
    }

Я заметил, что запуск этого кода занял 20 секунд. Затем я решил закрыть фабрики каналов следующим образом:

    [TestMethod]
    [Timeout(2000)]
    public void ApiClientTest()
    {
        bool ApiSuccessSet, ClientSuccessSet = ApiSuccessSet = false;
        Api apiService = new ApiTestService();
        var clientService = new ClientTestService();

        ServiceHost clientHost = new ServiceHost(clientService, new Uri(PipeService));
        ServiceHost apiHost = new ServiceHost(apiService, new Uri(PipeService));

        //To let us know the services were successfully opened
        clientHost.Opened += (s, e) => ClientSuccessSet = true;
        apiHost.Opened += (s, e) => ApiSuccessSet = true;
        clientHost.AddServiceEndpoint(typeof(IClientService), new NetNamedPipeBinding(), ClientPipeServiceName);
        apiHost.AddServiceEndpoint(typeof(IApiService), new NetNamedPipeBinding(), ApiPipeServiceName);
        clientHost.BeginOpen(OnOpen, clientHost);
        apiHost.BeginOpen(OnOpen, apiHost);


        //This allows both services to be open for communication.
        while (!ApiSuccessSet || !ClientSuccessSet)
            Thread.Yield();


        EndpointAddress ApiEndpoint = new EndpointAddress(PipeService + @"/" + ApiPipeServiceName);
        EndpointAddress clientEndpoint = new EndpointAddress(PipeService + @"/" + ClientPipeServiceName);

        InstanceContext context = new InstanceContext((IClientCallback)new TestClientCallback());
        var ClientChannelFactory = new DuplexChannelFactory<IClientService>(context, new NetNamedPipeBinding(), clientEndpoint);
        var ApiChannelFactory = new ChannelFactory<IApiService>(new NetNamedPipeBinding(), ApiEndpoint);
        var ClientChannel = ClientChannelFactory.CreateChannel();
        var ApiChannel = ApiChannelFactory.CreateChannel();


        ClientChannelFactory.Close();
        ApiChannelFactory.Close();
        clientHost.Close();
        apiHost.Close();
    }

Это заставляет меня поверить, что на избавление от контекста клиента уходит много времени.

Я подозреваю, что есть 3 способа лучше справиться с этим решением.

Первое - создать на клиенте функцию, которая управляет завершением сеанса. Таким образом, вы можете вызвать этот метод до того, как служба планирует завершить работу, и это ускорит время выключения.

второе - асинхронное закрытие и выполнение другой обработки во время закрытия соединения.

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

0 голосов
/ 06 апреля 2010

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

Semaphore cont=new Semaphore(0, 1);
foreach (ServiceHost s in WCFServices) {
    try {
        s.Closed += delegate(Object o, System.EventArgs n) {
            cont.Release();
        };
        s.Close();
        cont.WaitOne();                 
    } catch (Exception) {
    }//try
}//for
...