2008-11-24 11 views
30

Tengo un servicio WCF que no debe entrar en estado de falla. Si hay una excepción, debe registrarse y el servicio debe continuar ininterrumpidamente. El servicio tiene un contrato de operación unidireccional y está leyendo mensajes de un MSMQ.¿Cómo impido que un servicio WCF entre en un estado con falla?

Mis problemas son de dos tipos:

  1. El servicio parece estar tragando una excepción/error, así que soy incapaz de depurarlo. ¿Cómo obtengo el servicio para exponer la excepción para que I pueda registrarla o manejarla?
  2. El servicio es entrando en estado de error después de esta excepción se ha tragado. ¿Cómo evito que el servicio ingrese al en un estado de falla?
+0

aquí puede obtener toda la teoría http://msdn.microsoft.com/en-us/library/ms789041(v=vs.110).aspx –

Respuesta

18

La mayoría, si no todas las excepciones se pueden ver en WCF Trace (Configuring Tracing) y la traza se ve mejor con Service Trace Viewer.

Obviamente, esto no es algo que deba tener funcionando todo el día en un entorno de producción, pero de todos modos ayuda a solucionar problemas.

Aparte de eso, tenga en cuenta que oneways puede no ejecutarse como un verdadero "fuego y olvidar", dependiendo del modo de sesión que utilice. Si tiene su servicio configurado para SessionMode.Allowed o incluso SessionMode.Required, la operación oneway se ejecutará como si no fuera unidireccional (esto se puede observar cuando se usa oneways sobre netTcpBinding). Para ser sincero, sin embargo, no sé si eso cambia el tipo de excepciones que puede obtener o cuándo las obtiene. Sin embargo, en cualquier caso, debe obtener una excepción si la solicitud no se puede enviar en absoluto. AFAIK, la única "finaliza" cuando se enquista con éxito en el lado del servidor. Entonces, hay algún lugar para excepciones (relacionadas con el marco WCF) hasta entonces (la serialización/deserialización viene a la mente).

Entonces, tales excepciones relacionadas con el marco se ven mejor (incluso un IErrorHandler no las obtiene todas debido al hecho de que se llama en el flujo de solicitud/respuesta) usando el trace/traceviewer mencionado anteriormente.

+0

Estoy enfrentando un problema similar. Tengo el servicio ejecutándose en Production con netTcpBinding teniendo pocos métodos como IsOneway = True y SessionMode set Requerido. Sin embargo, cuando se produce una excepción, los servicios pasan al estado Faulted. Para que funcione tengo que reiniciarlo –

11

Las excepciones fallarán el proxy. No se puede hacer mucho al respecto: no causar excepciones ;-p

Estoy un poco sorprendido de que un solo sentido todavía está causando un problema, pero para tragar en los géneros l, hay 3 aspectos:

  1. ¿Estás arrojando faults? o excepciones? es importante (y debería ser "fallas")
  2. como un truco, puede habilitar los mensajes de excepción de depuración, pero apáguelos por favor !!!
  3. ¿Está "usando" el objeto de servicio? Solo tengo blogged sobre este tema exacto ... básicamente, su "uso" puede tragar la excepción. 3 opciones:

    • no utilizan el "uso"
    • subclase el proxy y anular dispose()
    • envolverlo, según el blog
+0

Gracias por los comentarios Marc. Dejé de usarlo para intentar rastrear las excepciones pero no tuve suerte. La capa empresarial a la que llama el servicio WCF arroja excepciones, pero se están tragando en alguna parte ... Misterio ... – Guy

+1

Puede intentar cambiar a FaultException donde T es un error publicado, eso podría ayudar.Y tenga en cuenta que sigue siendo muy importante cerrar el proxy; simplemente que "usar" no hace necesariamente lo que queremos en esta ocasión. –

+0

Creo que solo las excepciones que no han sido capturadas y envueltas por el servicio tendrán fallas en el proxy, pero no todas las excepciones –

7

Sobre 2) ...

El truco es que usted debe utilizar el "uso" y siempre debe llamar Abortar() en el proxy que inició una excepción. El artículo WCF Gotcha lo explica todo.

Utilizamos una clase de servicio inspirada en ese artículo que envuelve las llamadas de servicio. Este es código de muestra de mi proyecto:

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

Y este es el código de ServiceHelper, ligeramente modificado desde el artículo. Hasta ahora nos ha servido realmente bien.

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

El enlace a la publicación 'WCF Gotcha' está roto, pero no tengo suficientes representantes para editarlo. Aquí está el buen enlace: http://old.iserviceoriented.com/blog/post/Indisposable+-+WCF+Gotcha+1.aspx. – yzorg

+0

@yzorg - Gracias por el enlace, acabo de actualizar la respuesta. – LamonteCristo

6

Tuve un problema donde el canal permanecía en estado de error después de una excepción ReceiveTimeout. Esto provocaría que el servicio se vuelva inutilizable por cualquier conexión posterior.

La corrección para recuperar el servicio desde el estado de fallo para mí era para controlar el evento con fallo del canal de comunicación:

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

A continuación, defina OnChannelFaulted:

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

Nota: Me postulo la configuración de WCF a través del código versus el uso de enlaces en el Web.config.

8

Por lo general, el servicio WCF está alojado en un ServiceHost; si el WCF-Service falla, la única opción es eliminar el servicio WCF e iniciar uno nuevo.

El ServiceHost tiene un desencadenador de eventos "en fallo" que se activa cuando el Servicio WCF falla:

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

Es posible conseguir la excepción causando la falla, pero requiere un poco más de trabajo:

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

Créditos http://www.haveyougotwoods.ca/2009/06/24/creating-a-global-error-handler-in-wcf

+1

Probé esto, pero el método HandleError nunca se golpea, aunque presioné el controlador de evento Faulted. – Brent

Cuestiones relacionadas