Domanda

Stiamo usando il eccellente ELMAH a che fare con le eccezioni non gestite in un ASP.NET 3.5 Web applicazione. Questo funziona molto bene per tutto il sito oltre a servizi WCF che vengono consumati utilizzando le funzionalità REST. Quando si verifica un'eccezione all'interno dei metodi di funzionamento, che non viene gestito dal codice dell'applicazione, WCF gestisce in vari modi a seconda dei contratti di servizio e le impostazioni di configurazione. Ciò significa che l'eccezione non finisce generare l'evento ASP.NET HttpApplication.Error che ELMAH usi . Le due soluzioni sono a conoscenza per affrontare questo sono:

  • Avvolgere tutte le chiamate di metodo in un try {} catch (Exception ex) {Elmah.ErrorSignal.FromCurrentContext () Raise (ex).; gettare; } Per chiamare in modo esplicito Elmah all'interno del blocco catch.
  • IErrorHandler come descritto in < a href = "http://will.hughesfamily.net.au/about/" rel = "noreferrer"> post del blog di Will Hughes' fare WCF e ELMAH bel gioco insieme per scomporre la chiamata a ELMAH ad un ErrorHandler separata.

La prima opzione è estremamente semplice, ma non è esattamente DRY . La seconda opzione richiede solo di decorare ogni servizio, con l'attributo personalizzato dopo l'implementazione l'attributo e l'ErrorHandler. Ho fatto questo in base a lavoro di Will ma voglio verificare che questo è il approccio corretto prima di inviare il codice.

C'è un modo migliore che ho perso?

Il documenation MSDN per IErrorHandler dice che la HandleError metodo è il posto per fare la registrazione, ma ELMAH accessi la HttpContext.Current. ApplicationInstance , che è nullo all'interno di questo metodo anche se HttpContext.Current è disponibile. Effettuare la chiamata al Elmah all'interno del metodo ProvideFault è una soluzione come ApplicationInstance è impostato ma questo non corrisponde l'intento descritto nella documentazione API. Mi sto perdendo qualcosa qui? La documentazione fa stato che non si dovrebbe fare affidamento sul metodo HandleError chiamato sul thread operazione che può essere il motivo per cui ApplicationInstance è nullo in questo ambito.

È stato utile?

Soluzione

La soluzione dal mio post sul blog (si fa riferimento nel PO) si è basata su una soluzione esistente stavamo / stiamo usando per modificare codici di risposta HTTP durante uno stato di errore.

Quindi, per noi è stato un cambiamento di una sola riga di passare l'eccezione alla ELMAH. Se c'è una soluzione migliore, mi piacerebbe sapere troppo.

Ai posteri / di riferimento, e di possibile miglioramento - Ecco il codice della soluzione corrente.

HttpErrorHandler e Classi 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);
            }
        }
    }
}

Utilizzo Esempio

Decora il tuo servizi WCF con l'attributo ServiceErrorBehaviour:

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

Altri suggerimenti

Quando si crea un BehaviorExtensionElement è anche possibile attivare il comportamento utilizzando 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>

In questo modo è anche possibile utilizzare ELMAH in combinazione con i servizi RIA!

  

Ho fatto questo basato sul lavoro di Will   ma voglio verificare che questo è il   approccio corretto prima di pubblicare la   codice.

Credo che questo sia un grande approccio (complimenti a Will per questo intervento!). Non credo Volontà o sei mancato nulla qui. Implementazione IErrorHandler è il modo preferito di catturare tutte le eccezioni possibili lato server che potrebbero altrimenti provocare il canale di comunicazione per essere soddisfacente (demolita) e quindi è un luogo naturale per agganciare in un log come ELMAH.

Marc

Questo potrebbe essere ovvio per alcune persone, ma ho appena trascorso un po 'di tempo a cercare di capire il motivo per cui il mio HttpContext.Current è stato nullo, nonostante seguendo tutte risposta eccellente Will Hughes'. Embarassingly, mi sono reso conto che questo era perché il mio servizio WCF viene attivato da un messaggio MSMQ.

Ho finito per riscrivere il metodo ProvideFault():

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

Non sono riuscito a ottenere la soluzione proposta di lavoro con un servizio dati WCF. Ho cablato l'attributo comportamento, ecc, ma ancora non ha ottenuto gli eventuali errori registrati. Invece, ho finito di aggiungere quanto segue alla implementazione del servizio:

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

Non ho provato a fare questo in modo esplicito con la roba REST, e non hanno usato ELMAH me stesso, ma un'altra opzione merita di essere esaminata potrebbe essere quello di collegare in WCF utilizzando un IDispatchMessageInspector invece di un IErrorHandler.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top