Add ExceptionHandled to ExceptionContext (#4825)
This commit is contained in:
parent
8c8fd6446b
commit
5339a3e0ce
|
|
@ -68,6 +68,11 @@ namespace Microsoft.AspNetCore.Mvc.Filters
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets an indication that the <see cref="Exception"/> has been handled.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool ExceptionHandled { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the <see cref="IActionResult"/>.
|
/// Gets or sets the <see cref="IActionResult"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ using Microsoft.AspNetCore.Mvc.Controllers;
|
||||||
using Microsoft.AspNetCore.Mvc.Core;
|
using Microsoft.AspNetCore.Mvc.Core;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using Microsoft.Extensions.Internal;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Internal
|
namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
|
@ -354,7 +353,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
Result = _exceptionContext.Result,
|
Result = _exceptionContext.Result,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (_exceptionContext.Exception != null)
|
else if (_exceptionContext.Exception != null && !_exceptionContext.ExceptionHandled)
|
||||||
{
|
{
|
||||||
// If we get here, this means that we have an unhandled exception.
|
// If we get here, this means that we have an unhandled exception.
|
||||||
// Exception filted didn't handle this, so send it on to resource filters.
|
// Exception filted didn't handle this, so send it on to resource filters.
|
||||||
|
|
@ -412,7 +411,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
await InvokeExceptionFilterAsync();
|
await InvokeExceptionFilterAsync();
|
||||||
|
|
||||||
Debug.Assert(_exceptionContext != null);
|
Debug.Assert(_exceptionContext != null);
|
||||||
if (_exceptionContext.Exception != null)
|
if (_exceptionContext.Exception != null && !_exceptionContext.ExceptionHandled)
|
||||||
{
|
{
|
||||||
_diagnosticSource.BeforeOnExceptionAsync(_exceptionContext, current.FilterAsync);
|
_diagnosticSource.BeforeOnExceptionAsync(_exceptionContext, current.FilterAsync);
|
||||||
|
|
||||||
|
|
@ -422,7 +421,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
|
||||||
_diagnosticSource.AfterOnExceptionAsync(_exceptionContext, current.FilterAsync);
|
_diagnosticSource.AfterOnExceptionAsync(_exceptionContext, current.FilterAsync);
|
||||||
|
|
||||||
if (_exceptionContext.Exception == null)
|
if (_exceptionContext.Exception == null || _exceptionContext.ExceptionHandled)
|
||||||
{
|
{
|
||||||
_logger.ExceptionFilterShortCircuited(current.FilterAsync);
|
_logger.ExceptionFilterShortCircuited(current.FilterAsync);
|
||||||
}
|
}
|
||||||
|
|
@ -435,7 +434,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
await InvokeExceptionFilterAsync();
|
await InvokeExceptionFilterAsync();
|
||||||
|
|
||||||
Debug.Assert(_exceptionContext != null);
|
Debug.Assert(_exceptionContext != null);
|
||||||
if (_exceptionContext.Exception != null)
|
if (_exceptionContext.Exception != null && !_exceptionContext.ExceptionHandled)
|
||||||
{
|
{
|
||||||
_diagnosticSource.BeforeOnException(_exceptionContext, current.Filter);
|
_diagnosticSource.BeforeOnException(_exceptionContext, current.Filter);
|
||||||
|
|
||||||
|
|
@ -445,7 +444,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
|
|
||||||
_diagnosticSource.AfterOnException(_exceptionContext, current.Filter);
|
_diagnosticSource.AfterOnException(_exceptionContext, current.Filter);
|
||||||
|
|
||||||
if (_exceptionContext.Exception == null)
|
if (_exceptionContext.Exception == null || _exceptionContext.ExceptionHandled)
|
||||||
{
|
{
|
||||||
_logger.ExceptionFilterShortCircuited(current.Filter);
|
_logger.ExceptionFilterShortCircuited(current.Filter);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task InvokeAction_InvokesExceptionFilter_ShortCircuit()
|
public async Task InvokeAction_InvokesExceptionFilter_ShortCircuit_ExceptionNull()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var filter1 = new Mock<IExceptionFilter>(MockBehavior.Strict);
|
var filter1 = new Mock<IExceptionFilter>(MockBehavior.Strict);
|
||||||
|
|
@ -171,7 +171,62 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task InvokeAction_InvokesAsyncExceptionFilter_ShortCircuit()
|
public async Task InvokeAction_InvokesExceptionFilter_ShortCircuit_ExceptionHandled()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter1 = new Mock<IExceptionFilter>(MockBehavior.Strict);
|
||||||
|
|
||||||
|
var filter2 = new Mock<IExceptionFilter>(MockBehavior.Strict);
|
||||||
|
filter2
|
||||||
|
.Setup(f => f.OnException(It.IsAny<ExceptionContext>()))
|
||||||
|
.Callback<ExceptionContext>(context =>
|
||||||
|
{
|
||||||
|
context.ExceptionHandled = true;
|
||||||
|
})
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
|
var invoker = CreateInvoker(new[] { filter1.Object, filter2.Object }, actionThrows: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await invoker.InvokeAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
filter2.Verify(
|
||||||
|
f => f.OnException(It.IsAny<ExceptionContext>()),
|
||||||
|
Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeAction_InvokesAsyncExceptionFilter_ShortCircuit_ExceptionNull()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var filter1 = new Mock<IExceptionFilter>(MockBehavior.Strict);
|
||||||
|
var filter2 = new Mock<IAsyncExceptionFilter>(MockBehavior.Strict);
|
||||||
|
|
||||||
|
filter2
|
||||||
|
.Setup(f => f.OnExceptionAsync(It.IsAny<ExceptionContext>()))
|
||||||
|
.Callback<ExceptionContext>(context =>
|
||||||
|
{
|
||||||
|
filter2.ToString();
|
||||||
|
context.Exception = null;
|
||||||
|
})
|
||||||
|
.Returns<ExceptionContext>((context) => Task.FromResult(true))
|
||||||
|
.Verifiable();
|
||||||
|
|
||||||
|
var filterMetadata = new IFilterMetadata[] { filter1.Object, filter2.Object };
|
||||||
|
var invoker = CreateInvoker(filterMetadata, actionThrows: true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await invoker.InvokeAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
filter2.Verify(
|
||||||
|
f => f.OnExceptionAsync(It.IsAny<ExceptionContext>()),
|
||||||
|
Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task InvokeAction_InvokesAsyncExceptionFilter_ShortCircuit_ExceptionHandled()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var filter1 = new Mock<IExceptionFilter>(MockBehavior.Strict);
|
var filter1 = new Mock<IExceptionFilter>(MockBehavior.Strict);
|
||||||
|
|
@ -181,8 +236,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
||||||
.Setup(f => f.OnExceptionAsync(It.IsAny<ExceptionContext>()))
|
.Setup(f => f.OnExceptionAsync(It.IsAny<ExceptionContext>()))
|
||||||
.Callback<ExceptionContext>(context =>
|
.Callback<ExceptionContext>(context =>
|
||||||
{
|
{
|
||||||
filter2.ToString();
|
context.ExceptionHandled = true;
|
||||||
context.Exception = null;
|
|
||||||
})
|
})
|
||||||
.Returns<ExceptionContext>((context) => Task.FromResult(true))
|
.Returns<ExceptionContext>((context) => Task.FromResult(true))
|
||||||
.Verifiable();
|
.Verifiable();
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ namespace FiltersWebSite
|
||||||
{
|
{
|
||||||
public override void OnException(ExceptionContext context)
|
public override void OnException(ExceptionContext context)
|
||||||
{
|
{
|
||||||
context.Exception = null;
|
context.ExceptionHandled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue