Как обрабатывать исключения WCF (сводный список с кодом) - PullRequest
48 голосов
/ 26 мая 2011

Я пытаюсь расширить этот ответ для SO , чтобы заставить клиента WCF повторить попытку при кратковременных сетевых сбоях и обработать другие ситуации, требующие повторной попытки, такие как истечение срока действия аутентификации.*

Вопрос:

Какие исключения WCF необходимо обработать и как правильно их обрабатывать?

Вот несколько примеров техник, которые я надеюсь увидеть вместо или в дополнение к proxy.abort():

  • Задержка X секунд до повтора
  • Закройте и заново создайте клиент New () WCF.Утилизируйте старый.
  • Не повторяйте и не перебрасывайте эту ошибку
  • Повторите N раз, затем бросьте

Поскольку вряд ли один человек знает все исключенияспособы их решения, делитесь тем, что знаете.Я соберу ответы и подходы в примере кода ниже.

    // USAGE SAMPLE
    //int newOrderId = 0; // need a value for definite assignment
    //Service<IOrderService>.Use(orderService=>
    //{
    //  newOrderId = orderService.PlaceOrder(request);
    //}




    /// <summary>
    /// A safe WCF Proxy suitable when sessionmode=false
    /// </summary>
    /// <param name="codeBlock"></param>
    public static void Use(UseServiceDelegateVoid<T> codeBlock)
    {
        IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
        bool success = false;
        try
        {
            codeBlock((T)proxy);
            proxy.Close();
            success = true;
        }
        catch (CommunicationObjectAbortedException e)
        {
                // Object should be discarded if this is reached.  
                // Debugging discovered the following exception here:
                // "Connection can not be established because it has been aborted" 
            throw e;
        }
        catch (CommunicationObjectFaultedException e)
        {
            throw e;
        }
        catch (MessageSecurityException e)
        {
            throw e;
        }
        catch (ChannelTerminatedException)
        {
            proxy.Abort(); // Possibly retry?
        }
        catch (ServerTooBusyException)
        {
            proxy.Abort(); // Possibly retry?
        }
        catch (EndpointNotFoundException)
        {
            proxy.Abort(); // Possibly retry?
        }
        catch (FaultException)
        {
            proxy.Abort();
        }
        catch (CommunicationException)
        {
            proxy.Abort();
        }
        catch (TimeoutException)
        {
         // Sample error found during debug: 

         // The message could not be transferred within the allotted timeout of 
         //  00:01:00. There was no space available in the reliable channel's 
         //  transfer window. The time allotted to this operation may have been a 
         //  portion of a longer timeout.

            proxy.Abort();
        }
        catch (ObjectDisposedException )
        {
            //todo:  handle this duplex callback exception.  Occurs when client disappears.  
            // Source: /1091147/obnaruzhenie-smerti-klienta-v-dupleksnyh-kontraktah-wcf#1091148
        }
        finally
        {
            if (!success)
            {
                proxy.Abort();
            }
        }
    }

Ответы [ 4 ]

21 голосов
/ 29 февраля 2012

РЕДАКТИРОВАТЬ: Кажется, есть некоторые недостатки с закрытием и повторным открытием клиента несколько раз.Я исследую решения здесь и обновлю и дополню этот код, если он будет найден.(или если Дэвид Хайкин отправит ответ, я отмечу его как принятый)

После нескольких лет работы с этим кодом ниже, моя предпочтительная стратегия ( после просмотра этого сообщения в блогеwayback machine ) для обработки повторов WCF и обработки исключений.

Я исследовал каждое исключение, что я хотел бы сделать с этим исключением, и заметил общую черту;каждое исключение, которое требовало «повторной попытки», унаследовано от общего базового класса.Я также заметил, что каждое исключение permFail, которое переводит клиента в недопустимое состояние, также происходит из общего базового класса.

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

Пример использования клиента WCF

После создания прокси на стороне клиента это все, что вам нужно для его реализации.

Service<IOrderService>.Use(orderService=>
{
  orderService.PlaceOrder(request);
}

ServiceDelegate.cs

Добавьте этот файл в свое решение.Изменения в этом файле не требуются, если только вы не хотите изменить количество повторных попыток или какие исключения вы хотите обработать.

public delegate void UseServiceDelegate<T>(T proxy);

public static class Service<T>
{
    public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>(""); 

    public static void Use(UseServiceDelegate<T> codeBlock)
    {
        IClientChannel proxy = null;
        bool success = false;


       Exception mostRecentEx = null;
       int millsecondsToSleep = 1000;

       for(int i=0; i<5; i++)  // Attempt a maximum of 5 times 
       {
           // Proxy cann't be reused
           proxy = (IClientChannel)_channelFactory.CreateChannel();

           try
           {
               codeBlock((T)proxy);
               proxy.Close();
               success = true; 
               break;
           }
           catch (FaultException customFaultEx)
           {
               mostRecentEx = customFaultEx;
               proxy.Abort();

               //  Custom resolution for this app-level exception
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           }

           // The following is typically thrown on the client when a channel is terminated due to the server closing the connection.
           catch (ChannelTerminatedException cte)
           {
              mostRecentEx = cte;
               proxy.Abort();
               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep  * (i + 1)); 
           }

           // The following is thrown when a remote endpoint could not be found or reached.  The endpoint may not be found or 
           // reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable.
           catch (EndpointNotFoundException enfe)
           {
              mostRecentEx = enfe;
               proxy.Abort();
               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           }

           // The following exception that is thrown when a server is too busy to accept a message.
           catch (ServerTooBusyException stbe)
           {
              mostRecentEx = stbe;
               proxy.Abort();

               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           }
           catch (TimeoutException timeoutEx)
           {
               mostRecentEx = timeoutEx;
               proxy.Abort();

               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           } 
           catch (CommunicationException comException)
           {
               mostRecentEx = comException;
               proxy.Abort();

               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           }


           catch(Exception e)
           {
                // rethrow any other exception not defined here
                // You may want to define a custom Exception class to pass information such as failure count, and failure type
                proxy.Abort();
                throw e;  
           }
       }
       if (success == false && mostRecentEx != null) 
       { 
           proxy.Abort();
           throw new Exception("WCF call failed after 5 retries.", mostRecentEx );
       }

    }
}
4 голосов
/ 01 июня 2011

Я запустил проект на Codeplex, который имеет следующие функции

  • Обеспечивает эффективное повторное использование клиентского прокси
  • Очищает все ресурсы, включая EventHandlers
  • Работает на дуплексных каналах
  • Работает с услугами Per-Call
  • Поддерживает конструктор конфигурации, или по умолчанию

http://smartwcfclient.codeplex.com/

Это незавершенная работа, и в ней очень много комментариев. Буду признателен за любые отзывы, касающиеся его улучшения.

Пример использования в режиме экземпляра:

 var reusableSW = new LC.Utils.WCF.ServiceWrapper<IProcessDataDuplex>(channelFactory);

 reusableSW.Reuse(client =>
                      {
                          client.CheckIn(count.ToString());
                      });


 reusableSW.Dispose();
2 голосов
/ 31 мая 2011

Ниже ссылки могут помочь обработать исключения WCF:

http://www.codeproject.com/KB/WCF/WCFErrorHandling.aspx

http://msdn.microsoft.com/en-us/library/cc949036.aspx

2 голосов
/ 29 мая 2011

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

Таким образом, вы можете многое упростить, если хотите. Тем не менее, вот некоторые типичные ошибки, которые мы ловим:

Тайм-аут сервера
Сервер слишком занят
Сервер недоступен.

...