Exception using middleware and page

I am new to the concept of middleware and I am currently struggling to handle exceptions in my MVC Core project.

I want an Exception to be caught, logged, and then send the user to a friendly error page with a message. At first I tried to manage all of this in a middleware framework, but realized that I probably wasn't doing it right.

So, if I want this thread to happen, should I use both my middleware to log the exception and app.UseExceptionHandler ("/ Error") so that the middleware throws the exception onto the page? And if so, how do I get the exception data on the Error page? And is it correct that the exception handling mechanism I want to catch first should be the last one in Configure?

All examples I've found are strictly related to HTTP status code errors such as 404; I'm looking to handle the actual Exceptions (and their subclasses). This way, in my view pages, I can use my own Exceptions if applicable (for example, if the view provides a null for a required field.)

Startup.cs snapshots:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
                      ILoggerFactory loggerFactory, LoanDbContext context) {
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    app.UseStatusCodePages();
    if (env.IsDevelopment() || env.IsEnvironment("qa")) {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
    } else {
        app.UseExceptionHandler("/Error");
    }
    app.UseMiddleware<MyExceptionHandler>(loggerFactory);
    // ... rest of Configure is irrelevant to this issue

      

MyExceptionHandler.cs

using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Data.SqlClient;
using System.Threading.Tasks;

namespace MyCompany.MyProject.Helpers
{
    /// <summary>
    /// A custom Exception Handler Middleware which can be re-used in other projects.
    /// </summary>
    public sealed class MyExceptionHandler
    {
        private readonly RequestDelegate _next;
        private readonly ILogger _logger;

        public MyExceptionHandler(RequestDelegate next, ILoggerFactory loggerFactory) {
            _next = next;
            _logger = loggerFactory.CreateLogger<MyExceptionHandler>();
        }

        public async Task Invoke(HttpContext context) {
            try {
                await _next(context);
            } catch (Exception ex) {
                HandleException(ex);
            }
        }

        // I realize this function looks pointless, but it will have more meat to it eventually.
        public void HandleException(Exception ex) {
            if (ex is ArgumentException argEx) {
                _logger.LogError(0, argEx, argEx.Message);
            } else if (ex is InvalidOperationException ioEx) {
                _logger.LogError(0, ioEx, "An Invalid Operation Exception occurred. This is usually caused by a database call that expects "
                    + "one result, but receives none or more than one.");
            } else if (ex is SqlException sqlEx) {
                _logger.LogError(0, sqlEx, $"A SQL database exception occurred. Error Number {sqlEx.Number}");
            } else if (ex is NullReferenceException nullEx) {
                _logger.LogError(0, nullEx, $"A Null Reference Exception occurred. Source: {nullEx.Source}.");
            } else if (ex is DbUpdateConcurrencyException dbEx) {
                _logger.LogError(0, dbEx, "A database error occurred while trying to update your item. This is usually due to someone else modifying the item since you loaded it.");
            } else {
                _logger.LogError(0, ex, "An unhandled exception has occurred.")
            }
        }
    }
}

      

+3


source to share


1 answer


Should I use both my middleware to log the exception and app.UseExceptionHandler("/Error")

have the middleware throw the exception onto the page?

Yes.

Using just a snippet of your example.

public async Task Invoke(HttpContext context) {
    try {
        await _next(context);
    } catch (Exception ex) {
        HandleException(ex);
         // re -throw the original exception
         // after logging the information
        throw;
    }
}

      

The above information will be re-fetched the original error after it has been logged so that another handler in the pipeline will catch it and perform borderless processing.

Source Error Handling in ASP.NET Core

How do I get exception data on the Error page?



Use IExceptionHandlerPathFeature

to get exception and Path

public IActionResult Error()
{
    // Get the details of the exception that occurred
    var exceptionFeature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();

    if (exceptionFeature != null)
    {
        // Get which route the exception occurred at
        string routeWhereExceptionOccurred = exceptionFeature.Path;

        // Get the exception that occurred
        Exception exceptionThatOccurred = exceptionFeature.Error;

        // TODO: Do something with the exception
        // Log it with Serilog?
        // Send an e-mail, text, fax, or carrier pidgeon?  Maybe all of the above?
        // Whatever you do, be careful to catch any exceptions, otherwise you'll end up with a blank page and throwing a 500
    }

    return View();
}

      

Source Adding Global Error Handling and Logging to ASP.NET Core with IExceptionHandlerPathFeature

In the example above, they mention doing logging in the view, but you would already do that in your custom handler.

Pay close attention to this little comment when rendering error representations.

No matter what you do, be careful to catch any exceptions, otherwise you will end up with a blank page and throw 500

By connecting to a pipeline, you avoid re-creating functions that are already provided in the framework, as well as solving cross-cutting problems.

+7


source







All Articles