注意:这个问题涉及到基于云的异常日志服务elmah.io (https://elmah.io/),而不是传统的Elmah .Net库。
我使用的是ASP.NET内核,并且有一个简单的异常处理中间件。
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:
HTTP/1.1 400 Bad Request
{"message":""}对于所有其他例外情况:
HTTP/1.1 500 Internal Server Error
{"message":""}我希望elmah.io记录500响应,忽略400响应(这是默认的elmah.io配置)。但是,当异常处理程序和elmah.io按此顺序在Startup的配置钩子中注册时,elmah.io中不会记录任何内容:
app.UseElmahIo("API_KEY", new Guid("LOG_ID"));
app.UseMiddleware<HandleExceptionMiddleware>()但是,如果我将注册顺序更改为以下内容,则会记录所有内容(包括400个响应)。这是有意义的,因为elmah.io在HandleExceptionMiddleware有机会更改响应之前处理异常:
app.UseMiddleware<HandleExceptionMiddleware>()
app.UseElmahIo("API_KEY", new Guid("LOG_ID"));配置这些服务以使elmah.io记录500个响应而忽略400个响应的最佳方法是什么?
我想出的唯一解决办法是创建和注册2个异常处理中间件,而不是仅仅注册一个在elmah.io之前注册和注册后注册的中间件。它起作用了,但看起来有点丑:
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
发布于 2017-04-26 17:57:13
配置elmah.io的正确方法是使用行为2。您希望在调用处理异常的其他方法之后调用UseElmahIo方法。这是因为许多错误处理中间件(包括您的HandleExceptionMiddleware)吞下了所有异常,并将结果转换为其他内容。在您的示例中,HandleExceptionMiddleware捕获所有异常并设置一个新响应。在这种情况下,我们的中间件从未收到关于异常的通知(正如您提到的那样)。
我们有几种不同的方法来解决这个问题:
解决方案1
在调用UseElmahIo后调用UseMiddleware,并添加一个自定义忽略筛选器来忽略错误,这些错误最终会导致错误请求:
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吞食):
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,因为这样可以确保所有异常都被捕获,包括堆栈跟踪和异常类型之类的信息。
https://stackoverflow.com/questions/43628196
复制相似问题