user2173353
user2173353

Reputation: 4640

How can I use both UseDeveloperExceptionPage() and custom logging?

I have the following code in my ASP.NET Core application to handle errors:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler(builder =>
    {
        builder.Run(async context =>
        {
            context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            var loggingService = context.RequestServices.GetService<ILoggingService>();
            var exceptionFeature = context.Features.Get<IExceptionHandlerFeature>();
            if (exceptionFeature != null)
            {
                Exception ex = exceptionFeature.Error;
                Console.Error.WriteLine(ex.Message + "   " + ex.StackTrace);
                loggingService.Error(ex);
            }
        });
    });
}

However, when being in a Development environment, I would like to use both the UseDeveloperExceptionPage() and the custom error handling for DB logging. But it seems that this does not work (the UseExceptionHandler() disables the functionality of UseDeveloperExceptionPage()).

Is there any way to achieve this, without writing the UseDeveloperExceptionPage() code form scratch?

Upvotes: 9

Views: 5546

Answers (2)

Edward
Edward

Reputation: 29996

The built-in UseDeveloperExceptionPage does not expose any extension method to customize the error process. You could try implement your own middleware to log the error like:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
};
app.Use(async (context, next) =>
{
    try
    {
        await next.Invoke();
    }
    catch (Exception ex)
    {
        //var loggingService = context.RequestServices.GetService<ILoggingService>();
        //loggingService.Error(ex);
        Console.Error.WriteLine(ex.Message + " My " + ex.StackTrace);
        throw;
    }

});

Upvotes: 4

Chris
Chris

Reputation: 27609

I was struggling with this and couldn't find any documentation on the subject however from looking at the source code I did find there is a way to add some logging into the Developer ExceptionPage. The source code is here and I will make some references to parts of it: https://github.com/dotnet/aspnetcore/blob/master/src/Middleware/Diagnostics/src/DeveloperExceptionPage/DeveloperExceptionPageMiddleware.cs

The part we care about is this:

    _exceptionHandler = DisplayException;

    foreach (var filter in filters.Reverse())
    {
        var nextFilter = _exceptionHandler;
        _exceptionHandler = errorContext => filter.HandleExceptionAsync(errorContext, nextFilter);
    }

Essentially it will take a set of filters and put them into a pipeline before the default DisplayExecution is run.

The filters are passed in as IEnumerable<IDeveloperPageExceptionFilter> by DI which means all we need to do is add our own class that implements IDeveloperPageExceptionFilter and it will be executed. Here is an example filter from my testing of this:

public class LoggingDeveloperPageExceptionFilter : IDeveloperPageExceptionFilter
{
    private readonly ILogService _logService;
    public LoggingDeveloperPageExceptionFilter(ILogService logService)
    {
        _logService = logService;
    }
    public Task HandleExceptionAsync(ErrorContext errorContext, Func<ErrorContext, Task> next)
    {
        _logService.Error(errorContext.Exception);
        return next(errorContext);
    }
}

And this is registered in my startup.cs as such:

services.AddSingleton<IDeveloperPageExceptionFilter, LoggingDeveloperPageExceptionFilter>();

So in this case it will call my error logging in log service passing the exception in and then call the next item in the processing chain. Since I only have one next for me will be the original DisplayException which does all our nice pretty error output.

Upvotes: 4

Related Questions