Как исцелить неисправные каналы WCF?

Если для нескольких вызовов службы WCF используется один экземпляр ClientBase<T>, он может получить канал в состояние с ошибкой (т.е. когда служба не работает).

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

if (clientBase.InnerChannel.State == CommunicationState.Faulted)
{
      clientBase.Abort();
      ((IDisposable)clientBase).Dispose();
      clientBase = new SampleServiceClientBase();
}

У меня возникло ощущение, что это неправильный способ сделать это. Кто-нибудь получил лучшую идею?

Ответ 1

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

Что вы можете сделать, так это использовать логику, которую вы используете, в утилите:

public static class Service<T> where T : class, ICommunicationObject, new()
{
    public static void AutoRepair(ref T co)
    {
        AutoRepair(ref co, () => new T());
    }

    public static void AutoRepair(ref T co, Func<T> createMethod)
    {
        if ((co != null) && (co.State == CommunicationState.Faulted))
        {
            co.Abort();
            co = null;
        }
        if (co == null)
        {
            co = createMethod();
        }
    }
}

Затем вы можете вызвать свою услугу следующим образом:

Service<SampleServiceClient>.AutoRepair(ref service,
    () => new SampleServiceClient(someParameter));
service.SomeMethod();

Или, если вы хотите использовать конструктор без параметров без параметров, просто:

Service<SampleServiceClient>.AutoRepair(ref service);
service.SomeMethod();

Поскольку он также обрабатывает случай, когда служба null, вам не нужно инициализировать службу перед ее вызовом.

Довольно много лучшего, что я могу предложить. Возможно, у кого-то есть лучший способ.

Ответ 2

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

Я воссоздаю прокси-сервер, когда исключение попадает на вызов.

try
{
    ListCurrentProcesses();
}
catch (TypeLoadException ex)
{
    Debug.Print("Oops: " + ex.Message);
    m_Proxy = new ProcessManagerProxy();
}
catch (EndpointNotFoundException endpointEX)
{
    Debug.Print("Oops: " + endpointEX.Message);
    m_Proxy = new ProcessManagerProxy();
}
catch (CommunicationException communicationEx)
{
    Debug.Print("Oops: " + communicationEx.Message);
    m_Proxy = new ProcessManagerProxy();
}