diff --git a/src/Microsoft.AspNetCore.Razor.Runtime/Runtime/TagHelpers/TagHelperExecutionContext.cs b/src/Microsoft.AspNetCore.Razor.Runtime/Runtime/TagHelpers/TagHelperExecutionContext.cs index 030e898b44..140c90597e 100644 --- a/src/Microsoft.AspNetCore.Razor.Runtime/Runtime/TagHelpers/TagHelperExecutionContext.cs +++ b/src/Microsoft.AspNetCore.Razor.Runtime/Runtime/TagHelpers/TagHelperExecutionContext.cs @@ -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) { diff --git a/test/Microsoft.AspNetCore.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperExecutionContextTest.cs b/test/Microsoft.AspNetCore.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperExecutionContextTest.cs index a071832ba2..5f81c88cb6 100644 --- a/test/Microsoft.AspNetCore.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperExecutionContextTest.cs +++ b/test/Microsoft.AspNetCore.Razor.Runtime.Test/Runtime/TagHelpers/TagHelperExecutionContextTest.cs @@ -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(), + uniqueId: string.Empty, + executeChildContentAsync: () => throw new Exception(), + startTagHelperWritingScope: _ => { }, + endTagHelperWritingScope: () => + { + calledEnd = true; + return new DefaultTagHelperContent(); + }); + + // Act & Assert + await Assert.ThrowsAsync(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(), + uniqueId: string.Empty, + executeChildContentAsync: () => throw new Exception(), + startTagHelperWritingScope: _ => { }, + endTagHelperWritingScope: () => + { + calledEnd = true; + return new DefaultTagHelperContent(); + }); + + // Act & Assert + await Assert.ThrowsAsync( + async () => await executionContext.GetChildContentAsync(useCachedResult: false, encoder: null)); + Assert.True(calledEnd); + } + [Fact] public async Task SetOutputContentAsync_SetsOutputsContent() {