visual studio publicar habilitar c# .net wcf msmq

studio - servicehost c#



¿Cómo evito que un servicio WCF entre en un estado con falla? (6)

La documentación oficial sobre cómo manejar fallas está aquí:

con la página principal en la descripción general del modelo de canal

Hay un buen diagrama de estado que muestra cómo ocurren las cosas:

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.

Mis problemas son dos:

  1. Parece que el servicio se está tragando una excepción / error, por lo que no puedo depurarlo. ¿Cómo obtengo el servicio para exponer la excepción para poder registrarla o manejarla?
  2. El servicio entra en estado de error después de que se trague esta excepción. ¿Cómo evito que el servicio ingrese en un estado con fallas?

La mayoría de las excepciones, si no todas, se pueden ver en WCF Trace ( Configuración del seguimiento ) y la traza se ve mejor con Service Trace Viewer .

Obviamente, esto no es algo que deba ejecutarse todo el día en un entorno de producción, pero de todas maneras 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 solicitud / respuesta) usando el trace / traceviewer mencionado anteriormente.


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 general , hay 3 aspectos:

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

    • no use "usar"
    • subclase el proxy e invalidar Dispose ()
    • envuélvala, según el blog

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 activador de evento "Faulted" que se activa cuando falla el servicio WCF:

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

Es posible obtener la excepción que causa 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


Sobre 2)...

El truco es que debe usar "usar" y siempre debe llamar a Abort () en el proxy que arrojó una excepción. El artículo WCF Gotcha lo explica todo.

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


Tuve un problema donde el canal permaneció 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 solución para recuperar el servicio del estado en falla fue manejar el evento Faulted 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: Estoy ejecutando la configuración de WCF a través de código en lugar de usar enlaces en Web.config.