Allow content to be written after caught exception from child TagHelper.

- The issue was that the `executeChildContentAsync` call was stopping the invocation of the `_endTagHelperWritingScope`. Therefore, we'd never finish the TagHelper content scope and all following content would be ignored.
- Added two tests to validate the new functionality.

#2561
This commit is contained in:
N. Taylor Mullen 2018-08-29 15:45:44 -07:00
parent f703a288dd
commit 852ad8df87
2 changed files with 63 additions and 4 deletions

View File

@ -258,8 +258,14 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
if (childContent == null)
{
_startTagHelperWritingScope(null);
await _executeChildContentAsync();
childContent = _endTagHelperWritingScope();
try
{
await _executeChildContentAsync();
}
finally
{
childContent = _endTagHelperWritingScope();
}
}
Debug.Assert(!Output.IsContentModified);
@ -292,8 +298,14 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
if (!useCachedResult || childContent == null)
{
_startTagHelperWritingScope(encoder);
await _executeChildContentAsync();
childContent = _endTagHelperWritingScope();
try
{
await _executeChildContentAsync();
}
finally
{
childContent = _endTagHelperWritingScope();
}
if (encoder == null)
{

View File

@ -15,6 +15,53 @@ namespace Microsoft.AspNetCore.Razor.Runtime.TagHelpers
{
public class TagHelperExecutionContextTest
{
[Fact]
public async Task SetOutputContentAsync_CanHandleExceptionThrowingChildContent()
{
// Arrange
var calledEnd = false;
var executionContext = new TagHelperExecutionContext(
"p",
tagMode: TagMode.StartTagAndEndTag,
items: new Dictionary<object, object>(),
uniqueId: string.Empty,
executeChildContentAsync: () => throw new Exception(),
startTagHelperWritingScope: _ => { },
endTagHelperWritingScope: () =>
{
calledEnd = true;
return new DefaultTagHelperContent();
});
// Act & Assert
await Assert.ThrowsAsync<Exception>(async () => await executionContext.SetOutputContentAsync());
Assert.True(calledEnd);
}
[Fact]
public async Task GetChildContentAsync_CanHandleExceptionThrowingChildContent()
{
// Arrange
var calledEnd = false;
var executionContext = new TagHelperExecutionContext(
"p",
tagMode: TagMode.StartTagAndEndTag,
items: new Dictionary<object, object>(),
uniqueId: string.Empty,
executeChildContentAsync: () => throw new Exception(),
startTagHelperWritingScope: _ => { },
endTagHelperWritingScope: () =>
{
calledEnd = true;
return new DefaultTagHelperContent();
});
// Act & Assert
await Assert.ThrowsAsync<Exception>(
async () => await executionContext.GetChildContentAsync(useCachedResult: false, encoder: null));
Assert.True(calledEnd);
}
[Fact]
public async Task SetOutputContentAsync_SetsOutputsContent()
{