2010-01-05 9 views
11

Cuando se usa una única instancia ClientBase<T> para múltiples llamadas al servicio WCF, puede poner un canal en un estado en falla (es decir, cuando el servicio está inactivo).Cómo curar canales WCF con fallas?

Me gustaría curar el canal automáticamente cuando vuelva a aparecer el servicio. La única manera que he encontrado es llamar al siguiente código antes de cada llamada al método:

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

me dio la sensación de que esta no es la forma correcta de hacerlo. Alguien tiene una mejor idea?

Respuesta

18

No puede. Una vez que un canal tiene una falla, falla para siempre. Debes crear un nuevo canal Los canales de WCF son con estado (por así decirlo), por lo que un canal con errores significa que el estado puede estar dañado.

Lo que puede hacer es poner la lógica que está utilizando en un método de utilidad:

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(); 
     } 
    } 
} 

A continuación, puede invocar a su servicio con el siguiente:

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

O si lo desea utilice el constructor sin parámetros predeterminado, solo:

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

Dado que también maneja el caso donde t El servicio es null, no necesita inicializar el servicio antes de llamarlo.

Bastante lo mejor que puedo ofrecer. Tal vez alguien más tenga una mejor manera.

+1

¿Necesita T también para implementar IDisposable? –

+0

@DavidGardiner: No si implementa 'ICommunicationObject'. La implementación 'Dispose' en los canales WCF es en realidad parte del problema. – Aaronaught

+0

Pero la interfaz ICommunicationObject (http://msdn.microsoft.com/en-us/library/system.servicemodel.icommunicationobject.aspx) no implementa IDisposable, por lo que el ejemplo anterior no funcionará sin el lanzamiento de co a IDisposable. –

0

Esto es lo que estoy haciendo actualmente, pero tampoco puedo decir que esta sea la mejor opción.

Recreo el proxy cuando se detecta una excepción en la llamada.

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(); 
} 
+0

Nunca capture 'SystemException', ** especialmente ** si no está volviendo a tirar. Ese árbol incluye instancias como 'OutOfMemoryException' y' StackOverflowException'. Además, no está eliminando correctamente el antiguo canal aquí. – Aaronaught

+0

Entendido. Ese fue solo un ejemplo rápido. ¿Ves un gran problema al permitir que el canal se recopile en lugar de eliminarlo explícitamente? Supongo que no vamos a volver a intentar esta operación 1000 veces antes de darnos por vencidos. –

+0

Lo probé y causó más problemas –

Cuestiones relacionadas