【问题标题】:WebApi v2 ExceptionHandler not called未调用 WebApi v2 ExceptionHandler
【发布时间】:2014-04-05 20:47:22
【问题描述】:

为什么从来没有调用自定义ExceptionHandler 而是返回标准响应(不是我想要的响应)?

这样注册

config.Services.Add(typeof(IExceptionLogger), new ElmahExceptionLogger());
config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());

并像这样实现

public class GlobalExceptionHandler : ExceptionHandler
{
    public override void Handle(ExceptionHandlerContext context)
    {
        context.Result = new ExceptionResponse
        {
            statusCode = context.Exception is SecurityException ? HttpStatusCode.Unauthorized : HttpStatusCode.InternalServerError,
            message = "An internal exception occurred. We'll take care of it.",
            request = context.Request
        };
    }
}

public class ExceptionResponse : IHttpActionResult
{
    public HttpStatusCode statusCode { get; set; }
    public string message { get; set; }
    public HttpRequestMessage request { get; set; }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        var response = new HttpResponseMessage(statusCode);
        response.RequestMessage = request;
        response.Content = new StringContent(message);
        return Task.FromResult(response);
    }
}

并像这样抛出(测试)

throw new NullReferenceException("testerror");

在控制器或存储库中。

更新

我没有另一个ExceptionFilter

我找到了这种行为的触发因素:

给定网址

GET http://localhost:XXXXX/template/lock/someId

发送此标头,我的 ExceptionHandler 有效

Host: localhost:XXXXX

发送此标头,它不起作用,内置处理程序会返回错误

Host: localhost:XXXXX
Origin: http://localhost:YYYY

这可能是 CORS 请求的问题(我在全局范围内使用带有通配符的 WebAPI CORS 包)或最终是我的 ELMAH 记录器。托管在 Azure(网站)上时也会发生这种情况,尽管内置的错误处理程序不同。

知道如何解决这个问题吗?

【问题讨论】:

  • 你也有异常过滤器吗?您还可以分享您的控制器或存储库代码的外观...我们希望确保您没有在某处捕获它并将其转换为 HttpResponseException 或在这种情况下不会调用异常处理程序的东西。
  • @KiranChalla:上面有有趣的更新,谢谢!

标签: c# asp.net-web-api


【解决方案1】:

原来默认只处理最外层的异常,而不是存储库类中的异常。所以下面也必须被覆盖:

public virtual bool ShouldHandle(ExceptionHandlerContext context)
{
    return context.ExceptionContext.IsOutermostCatchBlock;
}

更新 1

WebAPI v2 不再使用IsOutermostCatchBlock。无论如何,我的实现没有任何变化,因为ShouldHandle 中的新代码仍然阻止我的错误处理程序。所以我正在使用它,我的错误处理程序被调用一次。我通过这种方式捕获控制器和存储库中的错误。

public virtual bool ShouldHandle(ExceptionHandlerContext context)
{
    return true;
}

更新 2

由于这个问题引起了如此多的关注,请注意当前的解决方案是下面 cmets 中@JustAMartin 的linked

【讨论】:

  • 请注意这个:stackoverflow.com/questions/22038800/… 似乎他们已将 IsOutermostCatchBlock 替换为 IsTopLevel
  • 感谢@Martin 的更新。还是一样,不知道为什么标准实现不处理Controller错误。
  • 我刚刚找到了一个使用 CORS 处理异常的解决方案,看看这是否对您有帮助:stackoverflow.com/questions/24189315/… 似乎连 ASP.NET 团队都不再使用 ShouldHandle 但他们没有提及任何地方,从而造成混乱。我建议您忘记 ExceptionHandler 基类并像 ASP.NET 团队那样实现您的解决方案:aspnetwebstack.codeplex.com/SourceControl/latest#src/…
  • 非常感谢!这对我有用,唯一的区别是我使用公共覆盖而不是公共虚拟。
  • 公共覆盖 bool ShouldHandle(ExceptionHandlerContext context) => true;成功了。谢谢!
【解决方案2】:

这里真正的罪魁祸首是消息处理管道中EnableCors方法插入的CorsMessageHandler。 catch 块拦截任何异常并转换为响应,然后才能到达 HTTPServer 的 try-catch 块并可以调用 ExceptionHandler 逻辑

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
    CorsRequestContext corsRequestContext = request.GetCorsRequestContext();
    HttpResponseMessage result;
    if (corsRequestContext != null)
    {
    try
    {
        if (corsRequestContext.IsPreflight)
        {
        result = await this.HandleCorsPreflightRequestAsync(request, corsRequestContext, cancellationToken);
        return result;
        }
        result = await this.HandleCorsRequestAsync(request, corsRequestContext, cancellationToken);
        return result;
    }
    catch (Exception exception)
    {
        result = CorsMessageHandler.HandleException(request, exception);
        return result;
    }
    }
    result = await this.<>n__FabricatedMethod3(request, cancellationToken);
    return result;
}

【讨论】:

猜你喜欢
  • 2018-07-26
  • 2012-06-02
  • 2016-08-01
  • 2013-04-16
  • 2019-10-13
  • 2018-11-26
  • 2014-08-28
  • 2016-08-15
  • 2018-03-25
相关资源
最近更新 更多