From 852ad8df87e27fd9a39bf4def70742f7832b7240 Mon Sep 17 00:00:00 2001 From: "N. Taylor Mullen" Date: Wed, 29 Aug 2018 15:45:44 -0700 Subject: [PATCH] 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 --- .../TagHelpers/TagHelperExecutionContext.cs | 20 ++++++-- .../TagHelperExecutionContextTest.cs | 47 +++++++++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) 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() {