1

In a layered web application I want to move all error logging from the Domain and Data layers to the global exception handler, but I'm not sure what is the trade-off. I want to remove any logging call and replace it by a more specific Exception (custom if it's necessary) or remove the catching:

try{
   . . . 
}
catch
{
   Logger.Error('Info'); // <-- remove this for a: throw new CustomException('Info', ex);
   throw;                // <-- then, remove this line
}

There is a configured Global Exception Handler as middle-ware in the WebAPI, then as part of the handler method I'm going to log any exception occurred

// Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseExceptionHandler(
    error =>
    {
        GlobalExceptionHandler.ErrorHandling(error, env);
    });
}

// GlobalExceptionHandler.cs
public static class GlobalExceptionHandler
{
    public static void ErrorHandling(IApplicationBuilder errorApp, IHostingEnvironment env)
    {
        errorApp.Run(async context =>
        {
            .
            .
            .

            Log.Current.Error(exception.Message, () => exception);
        }
    }
}

Could be a better approach to avoid duplicated logging records?

1
  • Moving exception logging out of classes and into middleware or interceptors is good practice. If a method catches an exception, logs it, and rethrows it, then an AOP approach lets the you eliminate all those try/catches and let something outside the class handle it. Once in a while you may still need logging in a class, like in scenarios where the class actually handles an exception and does something to account for it, but you still want to log something so you know the exception happened. Commented May 2, 2019 at 15:43

1 Answer 1

1

In the applications I build I like to use the approach you are suggesting. I'll post the middleware that I use:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using MyProject.Interfaces;

namespace MyProject.Middlewares
{
    public class ErrorReporterMiddleware
    {
        private readonly RequestDelegate RequestDelegate;

        public ErrorReporterMiddleware(RequestDelegate requestDelegate)
        {
            RequestDelegate = requestDelegate ?? throw new ArgumentNullException(nameof(requestDelegate));
        }

        public async Task Invoke(HttpContext httpContext, IErrorReporter errorReporter)
        {
            try
            {
                await RequestDelegate(httpContext);
            }
            catch (Exception e)
            {
                await errorReporter?.CaptureAsync(e);
                throw;
            }
        }
    }
}

In this case IErrorReporter is an interface I have defined in the MyProject.Interfaces namespace. I use it to abstract the logging service:

using System;
using System.Threading.Tasks;

namespace MyProject.Interfaces
{
    public interface IErrorReporter
    {
        Task CaptureAsync(Exception exception);
        Task CaptureAsync(string message);
    }
}

Then in the Startup.cs I just add the following line to the Configure method:

app.UseMiddleware<ErrorReporterMiddleware>();

Nothing special but I think it's a clean approach.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.