Throw original exception if exception handler is not found (#25062)
* Throw original exception if exception handler is not found
This commit is contained in:
parent
9a8a1d4903
commit
4c381e83d2
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
|
@ -19,6 +19,9 @@ namespace Microsoft.AspNetCore.Diagnostics
|
||||||
private static readonly Action<ILogger, Exception> _errorHandlerException =
|
private static readonly Action<ILogger, Exception> _errorHandlerException =
|
||||||
LoggerMessage.Define(LogLevel.Error, new EventId(3, "Exception"), "An exception was thrown attempting to execute the error handler.");
|
LoggerMessage.Define(LogLevel.Error, new EventId(3, "Exception"), "An exception was thrown attempting to execute the error handler.");
|
||||||
|
|
||||||
|
private static readonly Action<ILogger, Exception> _errorHandlerNotFound =
|
||||||
|
LoggerMessage.Define(LogLevel.Warning, new EventId(4, "HandlerNotFound"), "No exception handler was found, rethrowing original exception.");
|
||||||
|
|
||||||
// DeveloperExceptionPageMiddleware
|
// DeveloperExceptionPageMiddleware
|
||||||
private static readonly Action<ILogger, Exception> _responseStartedErrorPageMiddleware =
|
private static readonly Action<ILogger, Exception> _responseStartedErrorPageMiddleware =
|
||||||
LoggerMessage.Define(LogLevel.Warning, new EventId(2, "ResponseStarted"), "The response has already started, the error page middleware will not be executed.");
|
LoggerMessage.Define(LogLevel.Warning, new EventId(2, "ResponseStarted"), "The response has already started, the error page middleware will not be executed.");
|
||||||
|
|
@ -41,6 +44,11 @@ namespace Microsoft.AspNetCore.Diagnostics
|
||||||
_errorHandlerException(logger, exception);
|
_errorHandlerException(logger, exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ErrorHandlerNotFound(this ILogger logger)
|
||||||
|
{
|
||||||
|
_errorHandlerNotFound(logger, null);
|
||||||
|
}
|
||||||
|
|
||||||
public static void ResponseStartedErrorPageMiddleware(this ILogger logger)
|
public static void ResponseStartedErrorPageMiddleware(this ILogger logger)
|
||||||
{
|
{
|
||||||
_responseStartedErrorPageMiddleware(logger, null);
|
_responseStartedErrorPageMiddleware(logger, null);
|
||||||
|
|
|
||||||
|
|
@ -113,18 +113,22 @@ namespace Microsoft.AspNetCore.Diagnostics
|
||||||
};
|
};
|
||||||
context.Features.Set<IExceptionHandlerFeature>(exceptionHandlerFeature);
|
context.Features.Set<IExceptionHandlerFeature>(exceptionHandlerFeature);
|
||||||
context.Features.Set<IExceptionHandlerPathFeature>(exceptionHandlerFeature);
|
context.Features.Set<IExceptionHandlerPathFeature>(exceptionHandlerFeature);
|
||||||
context.Response.StatusCode = 500;
|
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||||
context.Response.OnStarting(_clearCacheHeadersDelegate, context.Response);
|
context.Response.OnStarting(_clearCacheHeadersDelegate, context.Response);
|
||||||
|
|
||||||
await _options.ExceptionHandler(context);
|
await _options.ExceptionHandler(context);
|
||||||
|
|
||||||
if (_diagnosticListener.IsEnabled() && _diagnosticListener.IsEnabled("Microsoft.AspNetCore.Diagnostics.HandledException"))
|
if (context.Response.StatusCode != StatusCodes.Status404NotFound)
|
||||||
{
|
{
|
||||||
_diagnosticListener.Write("Microsoft.AspNetCore.Diagnostics.HandledException", new { httpContext = context, exception = edi.SourceException });
|
if (_diagnosticListener.IsEnabled() && _diagnosticListener.IsEnabled("Microsoft.AspNetCore.Diagnostics.HandledException"))
|
||||||
|
{
|
||||||
|
_diagnosticListener.Write("Microsoft.AspNetCore.Diagnostics.HandledException", new { httpContext = context, exception = edi.SourceException });
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Optional re-throw? We'll re-throw the original exception by default if the error handler throws.
|
_logger.ErrorHandlerNotFound();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex2)
|
catch (Exception ex2)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,17 @@ using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
|
||||||
using Microsoft.AspNetCore.TestHost;
|
using Microsoft.AspNetCore.TestHost;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Logging.Testing;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Diagnostics
|
namespace Microsoft.AspNetCore.Diagnostics
|
||||||
|
|
@ -469,5 +469,79 @@ namespace Microsoft.AspNetCore.Diagnostics
|
||||||
"Alternatively, set one of the aforementioned properties in 'Startup.ConfigureServices' as follows: 'services.AddExceptionHandler(options => { ... });'.",
|
"Alternatively, set one of the aforementioned properties in 'Startup.ConfigureServices' as follows: 'services.AddExceptionHandler(options => { ... });'.",
|
||||||
exception.Message);
|
exception.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ExceptionHandlerNotFound_RethrowsOriginalError()
|
||||||
|
{
|
||||||
|
var sink = new TestSink(TestSink.EnableWithTypeName<ExceptionHandlerMiddleware>);
|
||||||
|
var loggerFactory = new TestLoggerFactory(sink, enabled: true);
|
||||||
|
|
||||||
|
using var host = new HostBuilder()
|
||||||
|
.ConfigureWebHost(webHostBuilder =>
|
||||||
|
{
|
||||||
|
webHostBuilder
|
||||||
|
.UseTestServer()
|
||||||
|
.ConfigureServices(services =>
|
||||||
|
{
|
||||||
|
services.AddSingleton<ILoggerFactory>(loggerFactory);
|
||||||
|
})
|
||||||
|
.Configure(app =>
|
||||||
|
{
|
||||||
|
app.Use(async (httpContext, next) =>
|
||||||
|
{
|
||||||
|
Exception exception = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await next();
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
exception = ex;
|
||||||
|
|
||||||
|
// This mimics what the server would do when an exception occurs
|
||||||
|
httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The original exception is thrown
|
||||||
|
Assert.NotNull(exception);
|
||||||
|
Assert.Equal("Something bad happened.", exception.Message);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
app.UseExceptionHandler("/non-existent-hander");
|
||||||
|
|
||||||
|
app.Map("/handle-errors", (innerAppBuilder) =>
|
||||||
|
{
|
||||||
|
innerAppBuilder.Run(async (httpContext) =>
|
||||||
|
{
|
||||||
|
await httpContext.Response.WriteAsync("Handled error in a custom way.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.Map("/throw", (innerAppBuilder) =>
|
||||||
|
{
|
||||||
|
innerAppBuilder.Run(httpContext =>
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Something bad happened.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).Build();
|
||||||
|
|
||||||
|
await host.StartAsync();
|
||||||
|
|
||||||
|
using (var server = host.GetTestServer())
|
||||||
|
{
|
||||||
|
var client = server.CreateClient();
|
||||||
|
var response = await client.GetAsync("throw");
|
||||||
|
Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
|
||||||
|
Assert.Equal(string.Empty, await response.Content.ReadAsStringAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.Contains(sink.Writes, w =>
|
||||||
|
w.LogLevel == LogLevel.Warning
|
||||||
|
&& w.EventId == 4
|
||||||
|
&& w.Message == "No exception handler was found, rethrowing original exception.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue