Pregunta

Estamos utilizando la excelente ELMAH para hacer frente a las excepciones no controladas en un ASP.NET 3.5 Web solicitud. Esto funciona muy bien para todo el sitio, aparte de los servicios de WCF que se está consumiendo uso de las funciones REST. Cuando se produce una excepción dentro de los métodos de operación que no es manejado por el código de la aplicación, WCF se encarga de varias maneras dependiendo de los contratos de servicios y opciones de configuración. Esto significa que la excepción no se terminan desencadenando el evento ASP.NET HttpApplication.Error que ELMAH usos . Las dos soluciones que conozco para hacer frente a esto son:

  • envolver todas las llamadas de método en un try {} catch (Exception ex) {Elmah.ErrorSignal.FromCurrentContext () Levante (ex.); lanzar; } Para llamar explícitamente Elmah dentro del bloque catch.
  • Utilice IErrorHandler como se describe en < a href = "http://will.hughesfamily.net.au/about/" rel = "noreferrer"> blog Will Hughes hacer WCF y ELMAH juegan bien juntos para factorizar la llamada a ELMAH a un ManejadorError separado.

La primera opción es extremadamente simple, pero no es exactamente SECO . La segunda opción sólo se requiere para decorar cada servicio con el atributo personalizado después de la implementación del atributo y el ManejadorError. He hecho esto en base a trabajo de Will pero quiero verificar que este es el enfoque correcto antes de publicar el código.

¿Hay una mejor manera de que me he perdido?

El Documenation MSDN para IErrorHandler dice que el HandleError método es el lugar para hacer el registro, pero ELMAH accesos la HttpContext.Current. ApplicationInstance , que es nula dentro de este método a pesar de que HttpContext.Current está disponible. Hacer la llamada a Elmah dentro del método ProvideFault es una solución que se ajusta ApplicationInstance pero esto no coincide con la intención se describe en la documentación de la API. ¿Me estoy perdiendo algo aquí? La documentación sí declara que no se debe confiar en el método HandleError que se llama en el hilo de la operación que puede ser la razón por ApplicationInstance es nulo en este ámbito.

¿Fue útil?

Solución

La solución de mi blog (se hace referencia en el OP) se basa en una solución existente nos / estamos usando para alterar los códigos de respuesta HTTP en un estado de error.

Por lo tanto, para nosotros fue un cambio de una línea para pasar la excepción a ELMAH. Si hay una solución mejor, me gustaría saber sobre él también.

Para la posteridad / Referencia y mejora potencial - Este es el código de la solución actual.

HttpErrorHandler y clases ServiceErrorBehaviourAttribute

using System;
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Collections.ObjectModel;
using System.Net;
using System.Web;
using Elmah;
namespace YourApplication
{
    /// <summary>
    /// Your handler to actually tell ELMAH about the problem.
    /// </summary>
    public class HttpErrorHandler : IErrorHandler
    {
        public bool HandleError(Exception error)
        {
            return false;
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            if (error != null ) // Notify ELMAH of the exception.
            {
                if (System.Web.HttpContext.Current == null)
                    return;
                Elmah.ErrorSignal.FromCurrentContext().Raise(error);
            }
        }
    }
    /// <summary>
    /// So we can decorate Services with the [ServiceErrorBehaviour(typeof(HttpErrorHandler))]
    /// ...and errors reported to ELMAH
    /// </summary>
    public class ServiceErrorBehaviourAttribute : Attribute, IServiceBehavior
    {
        Type errorHandlerType;

        public ServiceErrorBehaviourAttribute(Type errorHandlerType)
        {
            this.errorHandlerType = errorHandlerType;
        }

        public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
        }

        public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            IErrorHandler errorHandler;
            errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType);
            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
                channelDispatcher.ErrorHandlers.Add(errorHandler);
            }
        }
    }
}

Uso Ejemplo

Decorar sus servicios WCF con el ServiceErrorBehaviour Atributo:

[ServiceContract(Namespace = "http://example.com/api/v1.0/")]
[ServiceErrorBehaviour(typeof(HttpErrorHandler))]
public class MyServiceService
{
  // ...
}

Otros consejos

Al crear un BehaviorExtensionElement incluso es posible activar el comportamiento usando config:

public class ErrorBehaviorExtensionElement : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get { return typeof(ServiceErrorBehaviourAttribute); }
    }

    protected override object CreateBehavior()
    {
        return new ServiceErrorBehaviourAttribute(typeof(HttpErrorHandler));
    }
}

Config:

<system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name="elmah" type="Namespace.ErrorBehaviorExtensionElement, YourAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
      </behaviorExtensions>
    </extensions>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <elmah />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

De esta manera también es posible el uso de ELMAH en combinación con los servicios de RIA!

  

He hecho esto basado en el trabajo de Will   pero quiero verificar que este es el   enfoque correcto antes de la publicación de la   código.

Creo que esto es un gran acercamiento (felicitaciones a Will para este anuncio!). No creo que Will o he perdido nada aquí. Ejecución IErrorHandler es la forma preferida de la captura de todos los posibles excepciones del lado del servidor que de otro modo podría provocar que el canal de comunicación a ser criticado (rasgado abajo) y por lo tanto es un lugar natural para enganchar en algunos tala como ELMAH.

Marc

Esto bien puede ser obvio para algunas personas, pero me acaba de pasar bastante tiempo tratando de averiguar por qué mi HttpContext.Current era nula a pesar de seguir todos de excelente respuesta Will Hughes. Embarazosamente, me di cuenta que esto era debido a mi servicio WCF se activa mediante un mensaje de MSMQ.

Terminé reescribir el método ProvideFault():

if (HttpContext.Current == null)
{
    ErrorLog.GetDefault(null).Log(new Error(error));
}
else
{
    ErrorSignal.FromCurrentContext().Raise(error);
}

No he podido obtener la respuesta propuesto trabajar con un servicio de datos WCF. Telegrafié el atributo de comportamiento, etc, pero aun así no los errores registrados. En su lugar, acabé añadiendo lo siguiente a la implementación del servicio:

protected override void HandleException(HandleExceptionArgs args)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(args.Exception);
    base.HandleException(args);
}

No he intentado hacer esto de manera explícita con las cosas REST, y no han utilizado ELMAH mí mismo, pero otra opción vale la pena analizar podría ser a enganchar en WCF utilizando un IDispatchMessageInspector en lugar de un IErrorHandler.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top