ASP.NET Core MVC(以前的MVC 6)Razor错误没有被异常过滤器捕获

gan*_*ers 4 c# razor asp.net-core-mvc asp.net-core

背景:使用Dapper和Repository Pattern的ASP.NET 5(ASP.NET Core 1.0)MVC 6应用程序

显然,就像每个其他网站/应用程序一样,我正在尝试消除我网站中弹出的大多数/所有异常.

我实现了一个ExceptionFilter以便捕获所有未处理的异常,如下所示:

public class UnhandledExceptionFilter : ActionFilterAttribute, IExceptionFilter
{
    private readonly IErrorRepo _errorRepo;

    public UnhandledExceptionFilter(IErrorRepo errorRepo)
    {
        _errorRepo = errorRepo;
    }

    public void OnException(ExceptionContext context)
    {
        try
        {
            _errorRepo.SaveException(context.Exception);
        }
        catch { }
    }
}
Run Code Online (Sandbox Code Playgroud)

当错误来自C#代码时,这很有用.但我故意在我的剃刀视图(cshtml文件)中输入错误,并且这些错误不会被这个过滤器捕获.

是否有一个额外的属性/接口,我需要继承以捕获剃刀异常?

更新:

这是在ConfigureServices方法的startup.cs文件中指定filter属性的位置.

    services.AddMvc(options =>
    {
        options.Filters.Add(new UnhandledExceptionFilter(new ErrorRepo(Configuration)));
    });
Run Code Online (Sandbox Code Playgroud)

Wil*_*Ray 5

这样做的诀窍不在于属性 - 它是通过添加中间件提供程序来实现的.一旦您的中间件进入管道,您将能够捕获在任何点抛出的异常(因此将不再需要您的属性).

记录器

这实际上是记录错误的事情.我已经复制了我在您的IErrorRepo界面上看到的内容,但当然您可以修改它以包含传递给Log下面方法的任何其他信息.

public class UnhandledExceptionLogger : ILogger
{
    private readonly IErrorRepo _repo;

    public UnhandledExceptionLogger(IErrorRepo repo)
    {
        _repo = repo;
    }
    public IDisposable BeginScopeImpl(object state) =>
        new NoOpDisposable();

    public bool IsEnabled(LogLevel logLevel) =>
        logLevel == LogLevel.Critical || logLevel == LogLevel.Error;

    public void Log(LogLevel logLevel, int eventId, object state, Exception exception, Func<object, Exception, string> formatter)
    {
        if (IsEnabled(logLevel))
        {
            _repo.SaveException(exception);
        }
    }

    private sealed class NoOpDisposable : IDisposable
    {
        public void Dispose()
        {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

提供者

这是将创建记录器的工厂.它只会被实例化一次,并且会在通过管道时创建所有记录器.

public class UnhandledExceptionLoggerProvider : ILoggerProvider
{
    private readonly IErrorRepo _repo;

    public UnhandledExceptionLoggerProvider(IErrorRepo repo)
    {
        _repo = repo;
    }

    public ILogger CreateLogger(string categoryName) =>
        new UnhandledExceptionLogger(_repo);

    public void Dispose()
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

注册提供商

一旦添加到ILoggerFactory,它将在管道中的每个请求上调用.通常这是通过自定义扩展方法完成的,但我们已经有了很多新代码,因此我将省略该部分.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddProvider(new UnhandledExceptionLoggerProvider(new ErrorRepo()));
    // the rest
Run Code Online (Sandbox Code Playgroud)