62 votes

Journalisation des exceptions pour les services WCF utilisant ELMAH

Nous sommes l'aide de l'excellent ELMAH pour traiter les exceptions non gérées dans un ASP.NET 3.5 application web. Cela fonctionne très bien pour tous le site en dehors de la WCF services qui sont consommés en utilisant les fonctionnalités du RESTE. Lorsqu'une exception se produit au sein de l'opération des méthodes qui n'est pas géré par le code de l'application, WCF poignées de différentes manières, selon les contrats de service et les paramètres de configuration. Cela signifie que l'exception ne fait pas la fin de la cuisson, l'ASP.NET HttpApplication.Événement d'erreur ELMAH utilise. Les deux solutions que je suis conscient de traiter ce sont:

  • L'emballage de tous les appels de méthode dans un try { } catch(Exception ex) { Elmah.ErrorSignal.FromCurrentContext().Soulever des(ex); throw; } appeler explicitement Elmah dans le bloc catch.
  • Utilisation IErrorHandler comme décrit dans la Volonté Hughes blog de Prise de WCF et ELMAH jouer bien ensemble pour le facteur de l'appel à ELMAH à un autre ErrorHandler.

La première option est extrêmement simple, mais n'est pas exactement SÈCHE. La deuxième option ne vous oblige à décorer chaque service avec l'attribut personnalisé après la mise en œuvre de l'attribut et de la ErrorHandler. J'ai fait cela repose sur la Volonté de travailler, mais je veux vérifier que c'est la bonne approche avant de poster le code.

Est-il une meilleure façon que j'ai manqué?

La MSDN documenation pour IErrorHandler dit que le HandleError méthode est l'endroit pour faire l'enregistrement, mais ELMAH accède à la HttpContext.Actuel.ApplicationInstance, qui est nulle dans cette méthode, même si HttpContext.Le courant est disponible. De faire l'appel à Elmah dans le ProvideFault méthode est une solution de contournement comme ApplicationInstance est fixé, mais cela ne correspond pas à l'objectif décrit dans la documentation de l'API. Suis-je manqué quelque chose? La documentation fait état que vous ne devriez pas compter sur la HandleError appel d'une méthode sur l'opération de filetage qui est peut-être pourquoi ApplicationInstance est nul dans ce champ d'application.

88voto

Will Hughes Points 5058

La solution à partir de mon blog (référencé dans l'OP) a été basé sur une solution existante, nous avons été/sont l'aide à modifier les Codes de Réponse HTTP au cours d'un état d'erreur.

Donc, pour nous, c'était un changement de ligne pour passer l'Exception de ELMAH. Si il y a une meilleure solution, j'aimerais savoir à ce sujet aussi.

Pour la Postérité/de Référence, et le potentiel d'amélioration de l' - voici le code à partir de la solution courante.

HttpErrorHandler et ServiceErrorBehaviourAttribute Classes

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

Exemple D'Utilisation

Décorer vos Services WCF avec le ServiceErrorBehaviour Attribut:

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

9voto

riezebosch Points 849

Lors de la création d'un BehaviorExtensionElement, il est même possible d'activer le comportement à l'aide de 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 cette façon, il est également possible d'utiliser ELMAH en combinaison avec les services RIA!

2voto

marc_s Points 321990

Je l'ai fait basé sur l'œuvre de will mais je veux vérifier que c'est le approche correcte avant de poster le code.

Je pense que c'est une bonne approche (bravo à will pour cette publication!). Je ne pense pas que la Volonté ou vous avez oublié quelque chose ici. La mise en œuvre de IErrorHandler est la voie privilégiée pour la capture de tous les possibles côté serveur exceptions pouvant causer le canal de communication pour être prise en défaut (démoli) et donc c'est un lieu naturel pour crochet dans certains enregistrement comme ELMAH.

Marc

2voto

Steve Rukuts Points 2708

Cela peut sembler évident à certaines personnes, mais je viens de passer un bon moment à essayer de comprendre pourquoi mon HttpContext.Current était nul bien que toutes les réponses de Will Hughes soient excellentes. Embarrassant, j'ai réalisé que c'était parce que mon service WCF est activé par un message MSMQ.

J'ai fini par réécrire la méthode ProvideFault() :

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

1voto

Daniel Points 794

Je n'ai pas pu obtenir la réponse proposée avec un service de données WCF. J'ai câblé l'attribut comportement, etc., mais je n'ai toujours pas enregistré d'erreur. Au lieu de cela, j'ai ajouté les éléments suivants à la mise en œuvre du service:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X