ASP.NET Core-同时使用UseDeveloperExceptionPage()和自定义日志记录

时间:2019-04-05 10:28:24

标签: c# asp.net-core error-handling .net-core

我在ASP.NET Core应用程序中具有以下代码来处理错误:

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler(builder =>
            {
                builder.Run(async context =>
                {
                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                    var loggingService = context.RequestServices.GetService<ILoggingService>();
                    var exceptionFeature = context.Features.Get<IExceptionHandlerFeature>();
                    if (exceptionFeature != null)
                    {
                        Exception ex = exceptionFeature.Error;
                        Console.Error.WriteLine(ex.Message + "   " + ex.StackTrace);
                        loggingService.Error(ex);
                    }
                });
        }

但是,当处于Development环境中时,我想同时使用UseDeveloperExceptionPage()和自定义错误处理来进行数据库日志记录。但这似乎不起作用(UseExceptionHandler()禁用了UseDeveloperExceptionPage()的功能)。

是否有任何方法可以实现,而无需编写UseDeveloperExceptionPage()代码形式的草稿?

2 个答案:

答案 0 :(得分:1)

对于内置UseDeveloperExceptionPage,它没有公开任何扩展方法来自定义错误过程,您可以尝试实现自己的中间件来记录错误,例如

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
};
app.Use(async (context, next) =>
{
    try
    {
        await next.Invoke();
    }
    catch (Exception ex)
    {
        //var loggingService = context.RequestServices.GetService<ILoggingService>();
        //loggingService.Error(ex);
        Console.Error.WriteLine(ex.Message + " My " + ex.StackTrace);
        throw;
    }

});

答案 1 :(得分:0)

我为此苦苦挣扎,但是找不到有关该主题的任何文档,但是通过查看源代码,我确实找到了一种方法,可以将一些日志记录添加到Developer ExceptionPage中。源代码在这里,我将对其部分内容进行一些引用:https://github.com/dotnet/aspnetcore/blob/master/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs

我们关心的部分是:

    _exceptionHandler = DisplayException;

    foreach (var filter in filters.Reverse())
    {
        var nextFilter = _exceptionHandler;
        _exceptionHandler = errorContext => filter.HandleExceptionAsync(errorContext, nextFilter);
    }

基本上,它将需要一组过滤器并将它们放入管道中,然后运行默认的DisplayExecution。

过滤器由DI以IEnumerable<IDeveloperPageExceptionFilter>的形式传入,这意味着我们需要做的就是添加自己的实现IDeveloperPageExceptionFilter的类,它将被执行。这是我对此进行测试的示例过滤器:

public class LoggingDeveloperPageExceptionFilter : IDeveloperPageExceptionFilter
{
    private readonly ILogService _logService;
    public LoggingDeveloperPageExceptionFilter(ILogService logService)
    {
        _logService = logService;
    }
    public Task HandleExceptionAsync(ErrorContext errorContext, Func<ErrorContext, Task> next)
    {
        _logService.Error(errorContext.Exception);
        return next(errorContext);
    }
}

这是这样在我的startup.cs中注册的:

services.AddSingleton<IDeveloperPageExceptionFilter, LoggingDeveloperPageExceptionFilter>();

因此,在这种情况下,它将在传递异常的日志服务中调用我的错误日志记录,然后在处理链中调用下一项。因为我只有一个next,所以我将是原始的DisplayException,它将完成我们所有漂亮的错误输出。