Question

Nous utilisons l'excellent ELMAH pour traiter les exceptions non gérées dans un ASP.NET 3.5 Web application. Cela fonctionne très bien pour l'ensemble du site en dehors des services WCF qui sont consommés en utilisant les fonctionnalités de repos. Lorsqu'une exception se produit dans les méthodes de fonctionnement qui ne sont pas traitées par le code d'application, WCF gère de différentes manières en fonction des contrats de service et les paramètres de configuration. Cela signifie que l'exception ne se termine pas de tir l'événement HttpApplication.Error ASP.NET que ELMAH utilisations . Les deux solutions que je suis au courant de traiter ce sont:

  • Justifier les appels de méthode dans un try {} catch (Exception ex) {Elmah.ErrorSignal.FromCurrentContext () Raise (ex). jeter; } Pour appeler explicitement Elmah dans le bloc catch.
  • Utilisez IErrorHandler comme décrit dans < a href = "http://will.hughesfamily.net.au/about/" rel = "noreferrer"> afficherons blog Hughes faire WCF et ELMAH jouer agréable ensemble pour tenir l'appel à ELMAH à un ErrorHandler séparé.

La première option est extrêmement simple mais pas exactement SEC . La deuxième option ne nécessite que de décorer chaque service avec l'attribut personnalisé après la mise en œuvre et l'attribut ErrorHandler. Je l'ai fait basé sur travail de Will, mais je veux vérifier que c'est le approche correcte avant de poster le code.

Y at-il une meilleure façon que je l'ai manqué?

Le Documenation MSDN IErrorHandler dit que le HandleError méthode est le lieu de faire l'enregistrement, mais ELMAH accès le HttpContext.Current. ApplicationInstance , qui est nul dans ce même si la méthode HttpContext.Current est disponible. Faire appel à l'Elmah dans la méthode ProvideFault est une solution de contournement comme ApplicationInstance est défini, mais cela ne correspond pas à l'intention décrite dans la documentation de l'API. Est-ce que je manque quelque chose ici? La documentation fait état que vous ne devez pas compter sur la méthode HandleError appelée sur le fil d'opération qui peut être la raison pour laquelle ApplicationInstance est nulle dans ce champ.

Était-ce utile?

La solution

La solution de mon blog (référencé dans l'OP) était basée sur une solution existante nous / utilisons pour modifier des codes de réponse HTTP pendant un état d'erreur.

Alors, pour nous, ce fut un changement d'une ligne pour passer l'exception à ELMAH. S'il y a une meilleure solution, j'aimerais savoir à ce sujet aussi.

Pour Postérité / Référence et potentiel d'amélioration - est ici le code de la solution actuelle.

HttpErrorHandler et classes 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);
            }
        }
    }
}

Exemple d'utilisation

Décorez vos services WCF avec le ServiceErrorBehaviour Attribut:

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

Autres conseils

Lors de la création d'un BehaviorExtensionElement il est même possible d'activer le comportement en utilisant 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!

  

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

Je pense que cela est une bonne approche (kudos à Will pour cette annonce!). Je ne pense pas que Will ou vous avez oublié quelque chose ici. Mise en œuvre IErrorHandler est le meilleur moyen de capturer toutes les exceptions possibles côté serveur qui pourrait par ailleurs provoquer le canal de communication à être blâmée (démolie) et donc il est un endroit naturel pour accrocher dans une exploitation forestière comme ELMAH.

Marc

Cela pourrait bien être évident pour certaines personnes, mais je viens de passer un bon moment à essayer de comprendre pourquoi mon HttpContext.Current était nulle, malgré la suite tous une excellente réponse de Will Hughes. Embarassingly, je me suis aperçu 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);
}

Je ne pouvais pas obtenir la réponse proposée à travailler avec un service de données WCF. Je câblé l'attribut de comportement, etc, mais n'a pas eu d'erreurs enregistrées. Au lieu de cela, je fini par ajouter ce qui suit à la mise en œuvre du service:

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

Je n'ai pas essayé de faire explicitement avec les trucs REST, et n'ont pas utilisé ELMAH moi-même, mais une autre option dignes d'intérêt est peut-être pour accrocher dans WCF en utilisant un IDispatchMessageInspector au lieu d'un IErrorHandler.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top