首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使elmah.io与ASP.NET内核和错误处理中间件很好地工作?

如何使elmah.io与ASP.NET内核和错误处理中间件很好地工作?
EN

Stack Overflow用户
提问于 2017-04-26 07:58:31
回答 1查看 1.3K关注 0票数 2

注意:这个问题涉及到基于云的异常日志服务elmah.io (https://elmah.io/),而不是传统的Elmah .Net库。

我使用的是ASP.NET内核,并且有一个简单的异常处理中间件。

代码语言:javascript
复制
public class HandleExceptionMiddleware
{
    public HandleExceptionMiddleware(RequestDelegate next)
    {
        Next = next;
    }

    RequestDelegate Next { get; }

    public async Task Invoke(HttpContext httpContext)
    {
        try
        {
            await Next(httpContext);
        }
        catch (Exception ex)
        {
            await HandleExceptionAsync(httpContext, ex);
        }
    }

    Task HandleExceptionAsync(HttpContext context, Exception ex)
    {
        var code = HttpStatusCode.InternalServerError;

        if (ex is ArgumentException)
            code = HttpStatusCode.BadRequest;

        var result = JsonConvert.SerializeObject(new { message = ex.Message });
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = (int)code;
        return context.Response.WriteAsync(result);
    }
}

这个中间件将根据它看到的异常返回以下JSON响应:

对于ArgumentException:

代码语言:javascript
复制
HTTP/1.1 400 Bad Request

{"message":""}

对于所有其他例外情况:

代码语言:javascript
复制
HTTP/1.1 500 Internal Server Error

{"message":""}

我希望elmah.io记录500响应,忽略400响应(这是默认的elmah.io配置)。但是,当异常处理程序和elmah.io按此顺序在Startup的配置钩子中注册时,elmah.io中不会记录任何内容:

代码语言:javascript
复制
    app.UseElmahIo("API_KEY", new Guid("LOG_ID"));
    app.UseMiddleware<HandleExceptionMiddleware>()

但是,如果我将注册顺序更改为以下内容,则会记录所有内容(包括400个响应)。这是有意义的,因为elmah.io在HandleExceptionMiddleware有机会更改响应之前处理异常:

代码语言:javascript
复制
    app.UseMiddleware<HandleExceptionMiddleware>()
    app.UseElmahIo("API_KEY", new Guid("LOG_ID"));

配置这些服务以使elmah.io记录500个响应而忽略400个响应的最佳方法是什么?

我想出的唯一解决办法是创建和注册2个异常处理中间件,而不是仅仅注册一个在elmah.io之前注册和注册后注册的中间件。它起作用了,但看起来有点丑:

代码语言:javascript
复制
    app.UseMiddleware<HandleInternalExceptionMiddleware>() // set 500 responses (these will have already been logged in elmah.io)
    app.UseElmahIo("API_KEY", new Guid("LOG_ID"));
    app.UseMiddleware<HandleExternalExceptionMiddleware>() // set 400 responses but ignore exceptions that should return 500 (these won't be logged in elmah.io)

我在这里创建了一个示例项目来演示这种行为:https://github.com/johnnyoshika/elmah-io-experiment

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-26 17:57:13

配置elmah.io的正确方法是使用行为2。您希望在调用处理异常的其他方法之后调用UseElmahIo方法。这是因为许多错误处理中间件(包括您的HandleExceptionMiddleware)吞下了所有异常,并将结果转换为其他内容。在您的示例中,HandleExceptionMiddleware捕获所有异常并设置一个新响应。在这种情况下,我们的中间件从未收到关于异常的通知(正如您提到的那样)。

我们有几种不同的方法来解决这个问题:

解决方案1

在调用UseElmahIo后调用UseMiddleware,并添加一个自定义忽略筛选器来忽略错误,这些错误最终会导致错误请求:

代码语言:javascript
复制
app.UseMiddleware<HandleExceptionMiddleware>();
app.UseElmahIo("API_KEY", new Guid("LOG_ID"), new ElmahIoSettings
{
    OnFilter = msg => msg.Type == typeof(ArgumentException).Name
});

这种方法的缺点是,您需要在HandleExceptionMiddleware和elmah.io配置中维护一组类似的规则。

解决方案2

在调用UseElmahIo之前调用UseMiddleware,并指定要记录的状态代码,即使没有引发异常(在本例中为HandleExceptionMiddleware吞食):

代码语言:javascript
复制
app.UseElmahIo("API_KEY", new Guid("LOG_ID"), new ElmahIoSettings
{
    HandledStatusCodesToLog = new List<int> { 404, 500, ... }
});
app.UseMiddleware<HandleExceptionMiddleware>();

如果这种方法的缺点是,您需要手动指定所有状态代码,并且从实际异常引发的信息在elmah.io上不可用。这样做的原因同样是,HandleExceptionMiddleware使elmah.io无法看到抛出异常。

我个人更喜欢解决方案1,因为这样可以确保所有异常都被捕获,包括堆栈跟踪和异常类型之类的信息。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43628196

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档