Как предотвратить переход службы WCF в ошибочное состояние? - PullRequest
33 голосов
/ 25 ноября 2008

У меня есть служба WCF, которая не должна переходить в состояние отказа. Если есть исключение, оно должно быть зарегистрировано, и служба должна продолжаться непрерывно. Служба имеет односторонний контракт на работу и читает сообщения из MSMQ.

У меня две проблемы:

  1. Сервис, похоже, глотает исключение / ошибка, поэтому я не могу отладить это. Как я могу получить услугу выставить исключение, чтобы я можете войти или обработать это?
  2. Услуга вход в неисправное состояние после это исключение проглочено. Как Я не даю сервису войти в неисправное состояние?

Ответы [ 6 ]

28 голосов
/ 10 мая 2011

Официальная документация по устранению неисправностей находится здесь:

с главной страницей Обзор модели канала

Есть хорошая диаграмма состояний, показывающая, как все происходит:

enter image description here

19 голосов
/ 25 ноября 2008

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

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

Кроме того, обратите внимание, что односторонние действия могут не работать как настоящий «выстрел и забыть» в зависимости от используемого вами SessionMode. Если у вас настроен сервис для SessionMode.Allowed или даже SessionMode.Required, операция одностороннего действия будет выполняться так, как если бы она вообще не была односторонней (это можно наблюдать при использовании односторонних путей через netTcpBinding). Честно говоря, я не знаю, изменит ли это тип исключений, которые вы можете получить, или когда вы их получите. Однако в любом случае вы должны получить исключение, если запрос вообще не может быть отправлен. AFAIK, односторонний путь «заканчивается», когда он успешно обработан на стороне сервера. Таким образом, до этого момента есть место для (связанных со структурой WCF) исключений (на ум приходит сериализация / десериализация).

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

11 голосов
/ 25 ноября 2008

Исключения приведут к ошибке прокси. Вы не можете ничего с этим поделать: не вызывайте исключений; -p

Я немного удивлен, что односторонний вызов все еще вызывает проблемы, но для глотания в родах l есть 3 аспекта:

  1. вы выбрасываете неисправностей ? или исключения? это имеет значение (и должно быть "ошибки")
  2. как хак, вы можете включить сообщения об исключениях отладки - но выключите его, пожалуйста !!!
  3. вы "используете" объект службы? Я только что написал на эту тему ... в принципе, ваше "использование" может проглотить исключение. 3 варианта:

    • не используйте "using"
    • подкласс прокси и переопределение Dispose ()
    • заверните, как в блоге
9 голосов
/ 02 декабря 2009

Обычно служба WCF размещается в ServiceHost, если происходит сбой службы WCF, тогда единственным вариантом является уничтожение службы WCF и запуск новой.

ServiceHost имеет триггер события «Сбой», который активируется при сбое службы WCF:

ServiceHost host = new ServiceHost(new Service.MyService());
host.Faulted += new EventHandler(host_faulted);
host.Open();

Возможно получить исключение, вызывающее ошибку, но это требует немного больше работы:

public class ErrorHandler : IErrorHandler
{
    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {

    }

    public bool HandleError(Exception error)
    {
        Console.WriteLine("exception");
        return false;
    }
}

public class ErrorServiceBehavior : IServiceBehavior
{
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {

    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {

    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        ErrorHandler handler = new ErrorHandler();
        foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
        {
            dispatcher.ErrorHandlers.Add(handler);
        }
    }
}

ServiceHost host = new ServiceHost(new Service.MyService());
host.Faulted += new EventHandler(host_faulted);
host.Description.Behaviors.Add(new ErrorServiceBehavior());
host.Open();

Кредиты http://www.haveyougotwoods.ca/2009/06/24/creating-a-global-error-handler-in-wcf

7 голосов
/ 26 сентября 2009

У меня была проблема, когда канал оставался в неисправном состоянии после исключения ReceiveTimeout. Это может привести к тому, что служба станет непригодной для любых последующих подключений.

Исправление для восстановления службы из состояния «ошибка» для меня заключалось в обработке события «Ошибка» канала связи:

 channelFactory = new ChannelFactory<IService>(endpoint);
 channelFactory.Faulted += OnChannelFaulted;
 var channel = channelFactory.CreateChannel();

Затем определите OnChannelFaulted:

 void OnChannelFaulted(object sender, EventArgs e)
 {
     channelFactory.Abort();
 }

Примечание. Я запускаю конфигурацию WCF с помощью кода, а не привязок в файле Web.config.

7 голосов
/ 25 ноября 2008

О 2) ...

Хитрость в том, что вы должны использовать «using» и всегда должны вызывать Abort () для прокси-сервера, выдавшего исключение. Статья WCF Gotcha объясняет все это.

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

ServiceHelper<CodeListServiceClient, CodeListService.CodeListService>.Use(
    proxy => seasonCodeBindingSource.DataSource = proxy.GetSeasonCodes(brandID);
);

А это код ServiceHelper, слегка модифицированный из статьи. До сих пор это служило нам очень хорошо.

using System;
using System.ServiceModel;

namespace Sportina.EnterpriseSystem.Client.Framework.Helpers
{
    public delegate void UseServiceDelegate<TServiceProxy>(TServiceProxy proxy);

    public static class ServiceHelper<TServiceClient, TServiceInterface> where TServiceClient : ClientBase<TServiceInterface>, new() where TServiceInterface : class
    {
        public static void Use(UseServiceDelegate<TServiceClient> codeBlock)
        {
            TServiceClient proxy = null;
            bool success = false;
            try
            {
                proxy = new TServiceClient();               
                codeBlock(proxy);
                proxy.Close();
                success = true;
            }
            catch (Exception ex)
            {
                Common.Logger.Log.Fatal("Service error: " + ex);                                
                throw;
            }
            finally
            {
                if (!success && proxy != null)
                    proxy.Abort();
            }
        }
    }
}
...