РЕДАКТИРОВАТЬ: Кажется, есть некоторые недостатки с закрытием и повторным открытием клиента несколько раз.Я исследую решения здесь и обновлю и дополню этот код, если он будет найден.(или если Дэвид Хайкин отправит ответ, я отмечу его как принятый)
После нескольких лет работы с этим кодом ниже, моя предпочтительная стратегия ( после просмотра этого сообщения в блоге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 );
}
}
}