-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Use [DebuggerDisableUserUnhandledExceptions] #57148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
bccb9e3
e45a915
217e774
f138f77
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using System.Diagnostics; | ||
| using System.Runtime.CompilerServices; | ||
| using System.Runtime.InteropServices; | ||
| using System.Text; | ||
| using System.Text.Encodings.Web; | ||
|
|
@@ -37,6 +39,9 @@ public void InitializeStreamingRenderingFraming(HttpContext httpContext, bool is | |
| } | ||
| } | ||
|
|
||
| // We do not want the debugger to consider NavigationExceptions caught by this method as user unhandled. | ||
| [MethodImpl(MethodImplOptions.NoInlining)] | ||
| [DebuggerDisableUserUnhandledExceptions] | ||
| public async Task SendStreamingUpdatesAsync(HttpContext httpContext, Task untilTaskCompleted, TextWriter writer) | ||
| { | ||
| // Important: do not introduce any 'await' statements in this method above the point where we write | ||
|
|
@@ -80,6 +85,10 @@ public async Task SendStreamingUpdatesAsync(HttpContext httpContext, Task untilT | |
| HandleExceptionAfterResponseStarted(_httpContext, writer, ex); | ||
| await writer.FlushAsync(); // Important otherwise the client won't receive the error message, as we're about to fail the pipeline | ||
| await _httpContext.Response.CompleteAsync(); | ||
|
|
||
| // We need to inform the debugger that this exception should be considered user unhandled unlike the NavigationException. | ||
| // Review: Is this necessary if the method attributed with [DebuggerDisableUserUnhandledExceptions] rethrows like this does? | ||
| Debugger.BreakForUserUnhandledException(ex); | ||
|
||
| throw; | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| using System.Diagnostics.CodeAnalysis; | ||
| using System.Diagnostics.Metrics; | ||
| using System.Linq; | ||
| using System.Runtime.CompilerServices; | ||
| using System.Text; | ||
| using System.Text.Json; | ||
| using System.Text.Json.Serialization; | ||
|
|
@@ -102,8 +103,14 @@ private static void SetExceptionHandlerFeatures(ErrorContext errorContext) | |
| /// </summary> | ||
| /// <param name="context"></param> | ||
| /// <returns></returns> | ||
| [MethodImpl(MethodImplOptions.NoInlining)] | ||
| [DebuggerDisableUserUnhandledExceptions] | ||
| public async Task Invoke(HttpContext context) | ||
| { | ||
| // We want to avoid treating exceptions as user unhandled if an exception filter like the DatabaseDeveloperPageExceptionFilter | ||
| // handles the exception rather than letting it flow to the default DisplayException method. This is because we don't want to stop the | ||
| // debugger if the developer shouldn't be handling the exception and instead just needs to do something like click a link to run a | ||
| // database migration. | ||
| try | ||
| { | ||
| await _next(context); | ||
|
|
@@ -122,6 +129,11 @@ public async Task Invoke(HttpContext context) | |
| context.Response.StatusCode = StatusCodes.Status499ClientClosedRequest; | ||
| } | ||
|
|
||
| // Generally speaking, we do not expect application code to handle things like IOExceptions during a request | ||
| // body read due to a client disconnect. But this kind of thing should be rare in development, and developers | ||
| // might be surprised if an IOException propagating through user code was not considered user unhandled. | ||
| // That said, if developers complain, we consider removing the following line. | ||
| Debugger.BreakForUserUnhandledException(ex); | ||
| return; | ||
| } | ||
|
|
||
|
|
@@ -131,6 +143,8 @@ public async Task Invoke(HttpContext context) | |
| { | ||
| _logger.ResponseStartedErrorPageMiddleware(); | ||
| _metrics.RequestException(exceptionName, ExceptionResult.Skipped, handler: null); | ||
|
|
||
| Debugger.BreakForUserUnhandledException(ex); | ||
| throw; | ||
| } | ||
|
|
||
|
|
@@ -161,11 +175,17 @@ public async Task Invoke(HttpContext context) | |
| } | ||
| catch (Exception ex2) | ||
| { | ||
| // Inform the debugger that the exception filter itself threw an exception. | ||
| // REVIEW: Is it okay for the same method to potentially call Debugger.BreakForUserUnhandledException | ||
| // multiple times with different exceptions in the same invocation? | ||
| Debugger.BreakForUserUnhandledException(ex2); | ||
|
||
|
|
||
| // If there's a Exception while generating the error page, re-throw the original exception. | ||
| _logger.DisplayErrorPageException(ex2); | ||
| } | ||
|
|
||
| _metrics.RequestException(exceptionName, ExceptionResult.Unhandled, handler: null); | ||
| Debugger.BreakForUserUnhandledException(ex); | ||
| throw; | ||
| } | ||
|
|
||
|
|
@@ -178,6 +198,9 @@ public async Task Invoke(HttpContext context) | |
| // Assumes the response headers have not been sent. If they have, still attempt to write to the body. | ||
| private Task DisplayException(ErrorContext errorContext) | ||
| { | ||
| // We need to inform the debugger that this exception should be considered user unhandled since it wasn't handled by an exception filter. | ||
| Debugger.BreakForUserUnhandledException(errorContext.Exception); | ||
|
|
||
| var httpContext = errorContext.HttpContext; | ||
| var headers = httpContext.Request.GetTypedHeaders(); | ||
| var acceptHeader = headers.Accept; | ||
|
|
||

Uh oh!
There was an error while loading. Please reload this page.