In this section we want to create a general middleware for error management in the program. This means that when an error occurs anywhere in the program, we can find the error with this middleware and show the appropriate message to the user. The way this middleware works is that it is placed in the middle of the middleware line or the same middleware (that is, if a request is sent, it first passes through this middleware and is provided to the next middleware, and finally after the rest Passed middleware The result is again accessible from this middleware). With this middleware, if an error occurs anywhere in the program (after passing this middleware), the error can be caught and we can show the appropriate response to the user. To implement, we first create a class to display the error text to the user.

public class ExceptionResult 
{
    public ExceptionResult(string message, int statusCode)
    {
        this.Message = message;
        this.StatusCode = statusCode;
    }
    public string Message { get; set; }
    public int StatusCode { get; set; }
}

In this class, we display the error text and StatusCode to the user. For example, if the user is not authenticated, we send the StatusCode with the value 401 to the user.

Then we create a class to implement error management called ExceptionMiddleware. Like the following:

public class AdvancedExceptionHandler
{
    private readonly RequestDelegate _next;
    private readonly ILogger<AdvancedExceptionHandler> _logger;
    private readonly IWebHostEnvironment _env;

    public AdvancedExceptionHandler(RequestDelegate next, ILogger<AdvancedExceptionHandler> logger, IWebHostEnvironment env)
    {
        _next = next;
        _logger = logger;
        _env = env;
    }
    public async Task Invoke(HttpContext context)
    {
        string message = null;
        HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError;
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex.Message, ex);

            if (_env.IsDevelopment())
            {
                var dic = new Dictionary<string, string>
                {
                    ["StackTrace"] = ex.StackTrace,
                    ["Exception"] = ex.Message
                };
                message = JsonConvert.SerializeObject(dic);
            }
            else
            {
                message = "an error has occurred";
            }
            await WriteToReponseAsync();
        }
        async Task WriteToReponseAsync()
        {
            if (context.Response.HasStarted)
                throw new InvalidOperationException("The response has already started");
            var exceptionResult = new ExceptionResult(message, (int)httpStatusCode);
            var result = JsonConvert.SerializeObject(exceptionResult);
            context.Response.StatusCode = (int)httpStatusCode;
            context.Response.ContentType = "application/json";
            await context.Response.WriteAsync(result);
        }
    }
}

To implement Middleware you need to create a method called Invoke  or InvokeAsync  that includes an HttpContext  input . In this section, we have used try / catch to catch program errors. Inside the try command block

 await _next(context);

By doing this, the request will pass through the first middleware, AdvancedExceptionHandler, and reach the other existing middleware, and if an error occurs in any of the subsequent middleware, it will enter the catch block. In this block, we first log the error by the built-in .NET Core logger, which is set by DI through the class constructor. Then use the Microsoft.Extensions.Hosting library to run the application environment from the IWebHostEnvironment variableWe have taken. If it is in production environment, only the message "an error has occurred" will be displayed to the user, but if it is in development environment, to display error information to the StackTrace programmer, we will serialize the Exception class in a dictionary and put it inside the message variable. We will show it to the user later. Finally, we send the error text and StatusCode to the user in json  format . Then we need to write a method extension to register this class to the .NET Core pipeline.

public static class ExceptionHandlerMiddlewareExtension
{
    public static void UseAdvancedExceptionHandler(this IApplicationBuilder app)
    {
        app.UseMiddleware<AdvancedExceptionHandler>();
    }
}

Finally, in the startup class in the Configure method, call this extension method.

public void Configure(IApplicationBuilder app)
{
    app.UseAdvancedExceptionHandler();//<--NOTE THIS
    app.UseCookiePolicy();
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
             name: "default",
             pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

;)

Powered by Froala Editor

Comments