ASP.NET Core MVC (former MVC 6) Razor errors not getting caught by exception filter

前端 未结 2 433
-上瘾入骨i
-上瘾入骨i 2021-01-03 05:05

Background: ASP.NET 5 (ASP.NET Core 1.0) MVC 6 application using Dapper and the Repository Pattern

Obviously, like with every other website/app, I\'m trying to elimi

相关标签:
2条回答
  • 2021-01-03 05:37

    The trick to doing this is not in the attribute - it's by adding a middleware provider. Once your middleware is in the pipeline, you'll be able to catch exceptions thrown at any point (so your attribute will no longer be needed).

    The Logger

    This is the thing that's actually going to log errors. I've copied what I've seen from your IErrorRepo interface, but of course you could modify it to include any of the additional information passed into the Log method below.

    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()
            {
            }
        }
    }
    

    The Provider

    This is the factory that will create the logger. It's only going to be instantiated once, and will create all the loggers when it goes through the pipeline.

    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()
        {
        }
    }
    

    Registering the Provider

    Once added to the ILoggerFactory, it will be invoked on each request in the pipeline. Often this is done through a custom extension method, but we've already got a lot of new code so I'll omit that part.

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddProvider(new UnhandledExceptionLoggerProvider(new ErrorRepo()));
        // the rest
    
    0 讨论(0)
  • 2021-01-03 05:41

    I handle all exception (including Razor ones) with the following code:

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
    }
    else
    {
        var exceptionHandlingOptions = new ExceptionHandlerOptions()
        {
            ExceptionHandler = ExceptionHandler.OnException // !! this is the key line !!
            // ExceptionHandlingPath = "/Home/Error"
            // according to my tests, the line above is useless when ExceptionHandler is set
            // after OnException completes the user would receive empty page if you don't write to Resonse in handling method
            // alternatively, you may leave ExceptionHandlingPath without assigning ExceptionHandler and call ExceptionHandler.OnException in controller's action instead
            // write me if you need a sample code
        };
        app.UseExceptionHandler(exceptionHandlingOptions);
    }
    
    public static class ExceptionHandler
    {
        public static async Task OnException(HttpContext context)
        {
            var feature = context.Features.Get<IExceptionHandlerFeature>();
    
            var exception = feature?.Error;
    
            if (exception == null) return;
    
            //TODO: log exception here
        }
    }
    

    Do not forget to remove IExceptionFilter as it would handle some of the exceptions as well.

    0 讨论(0)
提交回复
热议问题