web-dev-qa-db-fra.com

Besoin d'un exemple complet pour gérer les exceptions non gérées à l'aide de "ExceptionHandler" dans ASP.NET Web Api?

J'avais vérifié ce lien http://www.asp.net/web-api/overview/web-api-routing-and-actions/web-api-global-error-handling ..____ .Dans ce lien, ils ont mentionné comme ça

class OopsExceptionHandler : ExceptionHandler
{
    public override void HandleCore(ExceptionHandlerContext context)
    {
        context.Result = new TextPlainErrorResult
        {
            Request = context.ExceptionContext.Request,
            Content = "Oops! Sorry! Something went wrong." +
                      "Please contact [email protected] so we can try to fix it."
        };
    }

    private class TextPlainErrorResult : IHttpActionResult
    {
        public HttpRequestMessage Request { get; set; }

        public string Content { get; set; }

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
        {
            HttpResponseMessage response = 
                             new HttpResponseMessage(HttpStatusCode.InternalServerError);
            response.Content = new StringContent(Content);
            response.RequestMessage = Request;
            return Task.FromResult(response);
        }
    }
}

Je ne sais pas comment appeler cette classe dans mes actions d'API Web. Ainsi, quelqu'un peut-il me donner l'échantillon complet en utilisant cette ExceptionHandler.

28
user3331492

Dans votre configuration WebApi, vous devez ajouter la ligne suivante:

config.Services.Replace(typeof (IExceptionHandler), new OopsExceptionHandler());

Assurez-vous également que vous avez créé la classe ExceptionHandler de base qui implémente IExceptionHandler:

public class ExceptionHandler : IExceptionHandler
{
    public virtual Task HandleAsync(ExceptionHandlerContext context, 
                                    CancellationToken cancellationToken)
    {
        if (!ShouldHandle(context))
        {
            return Task.FromResult(0);
        }

        return HandleAsyncCore(context, cancellationToken);
    }

    public virtual Task HandleAsyncCore(ExceptionHandlerContext context, 
                                       CancellationToken cancellationToken)
    {
        HandleCore(context);
        return Task.FromResult(0);
    }

    public virtual void HandleCore(ExceptionHandlerContext context)
    {
    }

    public virtual bool ShouldHandle(ExceptionHandlerContext context)
    {
        return context.CatchBlock.IsTopLevel;
    }
} 

Notez que cela ne concerne que les exceptions qui ne sont pas gérées ailleurs (par exemple, par les filtres Exception).

26
Jon Susiak

Vous n'avez pas besoin d'implémenter le mécanisme de bas niveau IExceptionHandler vous-même.

Au lieu de cela, vous pouvez simplement hériter de ExceptionHandler et remplacer la méthode Handle .

public class MyExceptionHandler: ExceptionHandler
{
  public override void Handle(ExceptionHandlerContext context)
  {
    //TODO: Do what you need to do
    base.Handle(context);
  }
}

ExceptionHandler implements IExceptionHandler et gère les mécanismes de base (comme l'async et cette exception doit être gérée ou non).

Utilisez votre gestionnaire d'exceptions comme ça:

config.Services.Replace(typeof(IExceptionHandler), new MyExceptionHandler());

La source

Cette page explique comment implémenter IExceptionHandler, mais il y a quelques fautes de frappe et le code ne reflète pas la dernière version de WebApi.

Il n'y a pas de documentation sur l'espace de noms System.Web.Http.ExceptionHandling (un peu sur NuDoq ).

Alors.. en utilisant un .NET Assembly decompiler En regardant le code source sur GitHub , j’ai vu la classe ExceptionHandler qui implémente IExceptionHandler et possède quelques méthodes virtuelles. 

ExceptionHandler ressemble à ça:

namespace System.Web.Http.ExceptionHandling
{
    /// <summary>Represents an unhandled exception handler.</summary>
    public abstract class ExceptionHandler: IExceptionHandler
    {
        /// <returns>Returns <see cref="T:System.Threading.Tasks.Task" />.</returns>
        Task IExceptionHandler.HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            ExceptionContext arg_14_0 = context.ExceptionContext;
            if (!this.ShouldHandle(context))
            {
                return TaskHelpers.Completed();
            }
            return this.HandleAsync(context, cancellationToken);
        }

        /// <summary>When overridden in a derived class, handles the exception asynchronously.</summary>
        /// <returns>A task representing the asynchronous exception handling operation.</returns>
        /// <param name="context">The exception handler context.</param>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        public virtual Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
        {
            this.Handle(context);
            return TaskHelpers.Completed();
        }

        /// <summary>When overridden in a derived class, handles the exception synchronously.</summary>
        /// <param name="context">The exception handler context.</param>
        public virtual void Handle(ExceptionHandlerContext context)
        {
        }

        /// <summary>Determines whether the exception should be handled.</summary>
        /// <returns>true if the exception should be handled; otherwise, false.</returns>
        /// <param name="context">The exception handler context.</param>
        public virtual bool ShouldHandle(ExceptionHandlerContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            ExceptionContext exceptionContext = context.ExceptionContext;
            ExceptionContextCatchBlock catchBlock = exceptionContext.CatchBlock;
            return catchBlock.IsTopLevel;
        }
    }
}

Vous pouvez voir clairement que ShouldHandle est implémenté à l'aide de ExceptionContextCatchBlock.IsTopLevel et que HandleAsync appelle Handle :)

J'espère que cela vous aidera jusqu'à ce que la documentation complète apparaisse.

82
Yves M.

Selon la réponse de Jon Susiak, vous devez utiliser:

config.Services.Replace(typeof (IExceptionHandler), new OopsExceptionHandler());

Notez l'appel Replace et non pas Add. La raison en est telle que décrite à l'article sur ce lien:

Traitement des erreurs globales dans l’API Web ASP.NET 2

Vue d'ensemble de la solution

Nous fournissons deux nouveaux services remplaçables par l'utilisateur, IExceptionLogger et IExceptionHandler, pour consigner et gérer les exceptions non gérées. 

Le les services sont très similaires, avec deux différences principales: 

Nous prenons en charge l’enregistrement de plusieurs enregistreurs d’exceptions mais d’un seul gestionnaire d'exception

Et comme il existe déjà un gestionnaire enregistré par défaut, vous ne pouvez pas en ajouter un autre.

public DefaultServices(HttpConfiguration configuration)
    {
      if (configuration == null)
        throw System.Web.Http.Error.ArgumentNull("configuration");
      this._configuration = configuration;
      this.SetSingle<IActionValueBinder>((IActionValueBinder) new DefaultActionValueBinder());
      this.SetSingle<IApiExplorer>((IApiExplorer) new ApiExplorer(configuration));
      this.SetSingle<IAssembliesResolver>((IAssembliesResolver) new DefaultAssembliesResolver());
      this.SetSingle<IBodyModelValidator>((IBodyModelValidator) new DefaultBodyModelValidator());
      this.SetSingle<IContentNegotiator>((IContentNegotiator) new DefaultContentNegotiator());
      this.SetSingle<IDocumentationProvider>((IDocumentationProvider) null);
      this.SetMultiple<IFilterProvider>((IFilterProvider) new ConfigurationFilterProvider(), (IFilterProvider) new ActionDescriptorFilterProvider());
      this.SetSingle<IHostBufferPolicySelector>((IHostBufferPolicySelector) null);
      this.SetSingle<IHttpActionInvoker>((IHttpActionInvoker) new ApiControllerActionInvoker());
      this.SetSingle<IHttpActionSelector>((IHttpActionSelector) new ApiControllerActionSelector());
      this.SetSingle<IHttpControllerActivator>((IHttpControllerActivator) new DefaultHttpControllerActivator());
      this.SetSingle<IHttpControllerSelector>((IHttpControllerSelector) new DefaultHttpControllerSelector(configuration));
      this.SetSingle<IHttpControllerTypeResolver>((IHttpControllerTypeResolver) new DefaultHttpControllerTypeResolver());
      this.SetSingle<ITraceManager>((ITraceManager) new TraceManager());
      this.SetSingle<ITraceWriter>((ITraceWriter) null);
      this.SetMultiple<ModelBinderProvider>((ModelBinderProvider) new TypeConverterModelBinderProvider(), (ModelBinderProvider) new TypeMatchModelBinderProvider(), (ModelBinderProvider) new KeyValuePairModelBinderProvider(), (ModelBinderProvider) new ComplexModelDtoModelBinderProvider(), (ModelBinderProvider) new ArrayModelBinderProvider(), (ModelBinderProvider) new DictionaryModelBinderProvider(), (ModelBinderProvider) new CollectionModelBinderProvider(), (ModelBinderProvider) new MutableObjectModelBinderProvider());
      this.SetSingle<ModelMetadataProvider>((ModelMetadataProvider) new DataAnnotationsModelMetadataProvider());
      this.SetMultiple<ModelValidatorProvider>((ModelValidatorProvider) new DataAnnotationsModelValidatorProvider(), (ModelValidatorProvider) new DataMemberModelValidatorProvider());
      this.SetMultiple<ValueProviderFactory>((ValueProviderFactory) new QueryStringValueProviderFactory(), (ValueProviderFactory) new RouteDataValueProviderFactory());
      this.SetSingle<IModelValidatorCache>((IModelValidatorCache) new ModelValidatorCache(new Lazy<IEnumerable<ModelValidatorProvider>>((Func<IEnumerable<ModelValidatorProvider>>) (() => ServicesExtensions.GetModelValidatorProviders((ServicesContainer) this)))));

      this.SetSingle<IExceptionHandler>((IExceptionHandler) new DefaultExceptionHandler());

      this.SetMultiple<IExceptionLogger>();
      this._serviceTypesSingle = new HashSet<Type>((IEnumerable<Type>) this._defaultServicesSingle.Keys);
      this._serviceTypesMulti = new HashSet<Type>((IEnumerable<Type>) this._defaultServicesMulti.Keys);
      this.ResetCache();
    }
4
rism

Vous pouvez consulter l'exemple suivant de l'équipe Web API:

http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/Elmah/ReadMe.txt

0
Kiran Challa