Skip to content

Commit 5dc0694

Browse files
committed
Add the ability to create a separate DI scope
1 parent 2772a78 commit 5dc0694

File tree

4 files changed

+43
-0
lines changed

4 files changed

+43
-0
lines changed

src/Middleware/Diagnostics/src/ExceptionHandler/ExceptionHandlerExtensions.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,25 @@ public static IApplicationBuilder UseExceptionHandler(this IApplicationBuilder a
4747
});
4848
}
4949

50+
/// <summary>
51+
/// Adds a middleware to the pipeline that will catch exceptions, log them, reset the request path, and re-execute the request.
52+
/// The request will not be re-executed if the response has already started.
53+
/// </summary>
54+
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
55+
/// <param name="errorHandlingPath">The <see cref="string"/> path to the endpoint that will handle the exception.</param>
56+
/// <param name="newScope">Whether or not to create a new <see cref="IServiceProvider"/> scope.</param>
57+
/// <returns></returns>
58+
public static IApplicationBuilder UseExceptionHandler(this IApplicationBuilder app, string errorHandlingPath, bool newScope)
59+
{
60+
ArgumentNullException.ThrowIfNull(app);
61+
62+
return app.UseExceptionHandler(new ExceptionHandlerOptions
63+
{
64+
ExceptionHandlingPath = new PathString(errorHandlingPath),
65+
UseNewServiceResolutionScope = newScope
66+
});
67+
}
68+
5069
/// <summary>
5170
/// Adds a middleware to the pipeline that will catch exceptions, log them, and re-execute the request in an alternate pipeline.
5271
/// The request will not be re-executed if the response has already started.

src/Middleware/Diagnostics/src/ExceptionHandler/ExceptionHandlerMiddlewareImpl.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Microsoft.AspNetCore.Http.Features;
1111
using Microsoft.Extensions.Logging;
1212
using Microsoft.Extensions.Options;
13+
using Microsoft.Extensions.DependencyInjection;
1314

1415
namespace Microsoft.AspNetCore.Diagnostics;
1516

@@ -70,6 +71,7 @@ public ExceptionHandlerMiddlewareImpl(
7071
public Task Invoke(HttpContext context)
7172
{
7273
ExceptionDispatchInfo edi;
74+
7375
try
7476
{
7577
var task = _next(context);
@@ -141,8 +143,16 @@ private async Task HandleException(HttpContext context, ExceptionDispatchInfo ed
141143
{
142144
context.Request.Path = _options.ExceptionHandlingPath;
143145
}
146+
var oldScope = _options.UseNewServiceResolutionScope ? context.RequestServices : null;
147+
using var scope = _options.UseNewServiceResolutionScope ? context.RequestServices.GetRequiredService<IServiceScopeFactory>().CreateScope() : null;
148+
144149
try
145150
{
151+
if (scope != null)
152+
{
153+
context.RequestServices = scope.ServiceProvider;
154+
}
155+
146156
var exceptionHandlerFeature = new ExceptionHandlerFeature()
147157
{
148158
Error = edi.SourceException,
@@ -216,6 +226,10 @@ private async Task HandleException(HttpContext context, ExceptionDispatchInfo ed
216226
finally
217227
{
218228
context.Request.Path = originalPath;
229+
if (oldScope != null)
230+
{
231+
context.RequestServices = oldScope;
232+
}
219233
}
220234

221235
_metrics.RequestException(exceptionName, ExceptionResult.Unhandled, handler: null);

src/Middleware/Diagnostics/src/ExceptionHandler/ExceptionHandlerOptions.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ public class ExceptionHandlerOptions
1717
/// </summary>
1818
public PathString ExceptionHandlingPath { get; set; }
1919

20+
/// <summary>
21+
/// Gets or sets whether the handler needs to create a separate <see cref="IServiceProvider"/> scope and
22+
/// replace it on <see cref="HttpContext"/>.
23+
/// </summary>
24+
/// <remarks>The default value is <see langword="false"/>.</remarks>
25+
public bool UseNewServiceResolutionScope { get; set; }
26+
2027
/// <summary>
2128
/// The <see cref="RequestDelegate" /> that will handle the exception. If this is not
2229
/// explicitly provided, the subsequent middleware pipeline will be used by default.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#nullable enable
2+
Microsoft.AspNetCore.Builder.ExceptionHandlerOptions.UseNewServiceResolutionScope.get -> bool
3+
Microsoft.AspNetCore.Builder.ExceptionHandlerOptions.UseNewServiceResolutionScope.set -> void
24
Microsoft.AspNetCore.Diagnostics.IExceptionHandler
35
Microsoft.AspNetCore.Diagnostics.IExceptionHandler.TryHandleAsync(Microsoft.AspNetCore.Http.HttpContext! httpContext, System.Exception! exception, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<bool>
46
Microsoft.AspNetCore.Diagnostics.StatusCodeReExecuteFeature.OriginalStatusCode.get -> int
7+
static Microsoft.AspNetCore.Builder.ExceptionHandlerExtensions.UseExceptionHandler(this Microsoft.AspNetCore.Builder.IApplicationBuilder! app, string! errorHandlingPath, bool newScope) -> Microsoft.AspNetCore.Builder.IApplicationBuilder!
58
static Microsoft.Extensions.DependencyInjection.ExceptionHandlerServiceCollectionExtensions.AddExceptionHandler<T>(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!

0 commit comments

Comments
 (0)