使用 Elmah.io 和 ExceptionFilterAttribute 处理异常
Handle exception with Elmah.io and ExceptionFilterAttribute
我在 asp.net 核心应用程序中使用 elmah.io 记录错误:
app.UseElmahIo("API_KEY", new Guid("LOG_ID"));
它只是一个中间件,看起来像:
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
await MessageShipper.ShipAsync(_apiKey, _logId, "Unsuccessful status code in response", context, _settings);
}
catch (Exception exception)
{
await exception.ShipAsync(_apiKey, _logId, context, _settings);
throw;
}
}
此外,我有自己的自定义 ExceptionFilter
来处理错误和 return 给客户的特定消息:
public class ApiExceptionFilter : ExceptionFilterAttribute
{
private ApiError _apiError;
public override void OnException(ExceptionContext context)
{
if (context.Exception is ApiException)
{
HandleKnownError(context);
}
else if (context.Exception is UnauthorizedAccessException)
{
HandleUnauthorizedException(context);
}
else
{
UnhandeledException(context);
}
context.Result = new JsonResult(_apiError);
base.OnException(context);
}
private void UnhandeledException(ExceptionContext context)
{
var msg = context.Exception.GetBaseException().Message;
string stack = context.Exception.StackTrace;
_apiError = new ApiError(msg) {Detail = stack};
context.HttpContext.Response.StatusCode = 500;
}
private void HandleKnownError(ExceptionContext context)
{
var ex = context.Exception as ApiException;
context.Exception = null;
_apiError = new ApiError(ex.Message);
context.HttpContext.Response.StatusCode = ex.StatusCode;
}
}
在这种情况下,如果我在某处抛出异常,在 elmah.io 中我只会看到消息 Unsuccessful status code in response
。我相信这是因为我的 ApiExceptionFilter
首先处理异常,而 elmah 中间件没有异常,只是状态不好。如何解决?
PS。 Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.Configure<Settings>(Configuration);
ConfigureCors(services);
services.AddMvc(o =>
{
o.Filters.Add(new ApiResponseWrapper());
o.Filters.Add(typeof(ApiExceptionFilter));
})
... a lot of my services
}
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
IServiceProvider serviceProvider)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
var logPath = Path.Combine(env.WebRootPath, "Logs/App-log-{Date}.txt");
loggerFactory.AddFile(logPath);
app.UseElmahTo("API",new Guid("LOG_ID"));
app.UseCors("CorsPolicy");
ConfigureAuth(app, env);
app.UseMvc();
}
你是对的,你的异常过滤器在执行 elmah.io 中间件之前吞下了异常。您通常会将 elmah.io 中间件添加为链中的最后一个,以确保其他中间件的行为不会像这样。但在您的情况下,过滤器是在 elmah.io 收到有关错误的通知之前执行的。
您可以通过以下方式解决此问题:
将错误过滤器作为中间件实现。无论如何,您当前的解决方案可能会破坏 ASP.NET Core 中的一些内置中间件。
通过扩展 UnhandledException
方法,将未处理的异常手动记录到 elmah.io:
private void UnhandeledException(ExceptionContext context)
{
context.Exception.Ship("API_KEY", new System.Guid("LOG_ID"), context.HttpContext);
var msg = context.Exception.GetBaseException().Message;
string stack = context.Exception.StackTrace;
_apiError = new ApiError(msg) { Detail = stack };
context.HttpContext.Response.StatusCode = 500;
}
我在 asp.net 核心应用程序中使用 elmah.io 记录错误:
app.UseElmahIo("API_KEY", new Guid("LOG_ID"));
它只是一个中间件,看起来像:
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
await MessageShipper.ShipAsync(_apiKey, _logId, "Unsuccessful status code in response", context, _settings);
}
catch (Exception exception)
{
await exception.ShipAsync(_apiKey, _logId, context, _settings);
throw;
}
}
此外,我有自己的自定义 ExceptionFilter
来处理错误和 return 给客户的特定消息:
public class ApiExceptionFilter : ExceptionFilterAttribute
{
private ApiError _apiError;
public override void OnException(ExceptionContext context)
{
if (context.Exception is ApiException)
{
HandleKnownError(context);
}
else if (context.Exception is UnauthorizedAccessException)
{
HandleUnauthorizedException(context);
}
else
{
UnhandeledException(context);
}
context.Result = new JsonResult(_apiError);
base.OnException(context);
}
private void UnhandeledException(ExceptionContext context)
{
var msg = context.Exception.GetBaseException().Message;
string stack = context.Exception.StackTrace;
_apiError = new ApiError(msg) {Detail = stack};
context.HttpContext.Response.StatusCode = 500;
}
private void HandleKnownError(ExceptionContext context)
{
var ex = context.Exception as ApiException;
context.Exception = null;
_apiError = new ApiError(ex.Message);
context.HttpContext.Response.StatusCode = ex.StatusCode;
}
}
在这种情况下,如果我在某处抛出异常,在 elmah.io 中我只会看到消息 Unsuccessful status code in response
。我相信这是因为我的 ApiExceptionFilter
首先处理异常,而 elmah 中间件没有异常,只是状态不好。如何解决?
PS。 Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.Configure<Settings>(Configuration);
ConfigureCors(services);
services.AddMvc(o =>
{
o.Filters.Add(new ApiResponseWrapper());
o.Filters.Add(typeof(ApiExceptionFilter));
})
... a lot of my services
}
public void Configure(IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
IServiceProvider serviceProvider)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
var logPath = Path.Combine(env.WebRootPath, "Logs/App-log-{Date}.txt");
loggerFactory.AddFile(logPath);
app.UseElmahTo("API",new Guid("LOG_ID"));
app.UseCors("CorsPolicy");
ConfigureAuth(app, env);
app.UseMvc();
}
你是对的,你的异常过滤器在执行 elmah.io 中间件之前吞下了异常。您通常会将 elmah.io 中间件添加为链中的最后一个,以确保其他中间件的行为不会像这样。但在您的情况下,过滤器是在 elmah.io 收到有关错误的通知之前执行的。
您可以通过以下方式解决此问题:
将错误过滤器作为中间件实现。无论如何,您当前的解决方案可能会破坏 ASP.NET Core 中的一些内置中间件。
通过扩展
UnhandledException
方法,将未处理的异常手动记录到 elmah.io:
private void UnhandeledException(ExceptionContext context)
{
context.Exception.Ship("API_KEY", new System.Guid("LOG_ID"), context.HttpContext);
var msg = context.Exception.GetBaseException().Message;
string stack = context.Exception.StackTrace;
_apiError = new ApiError(msg) { Detail = stack };
context.HttpContext.Response.StatusCode = 500;
}