diff --git a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs index 3477137d76..a4ad2047bc 100644 --- a/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs +++ b/src/Microsoft.AspNet.Mvc.Razor.Host/MvcRazorHost.cs @@ -103,9 +103,6 @@ namespace Microsoft.AspNet.Mvc.Razor StartTagHelperWritingScopeMethodName = "StartTagHelperWritingScope", EndTagHelperWritingScopeMethodName = "EndTagHelperWritingScope", - WriteTagHelperAsyncMethodName = "WriteTagHelperAsync", - WriteTagHelperToAsyncMethodName = "WriteTagHelperToAsync", - // Can't use nameof because IHtmlHelper is (also) not accessible here. MarkAsHtmlEncodedMethodName = HtmlHelperPropertyName + ".Raw", BeginAddHtmlAttributeValuesMethodName = "BeginAddHtmlAttributeValues", @@ -113,6 +110,9 @@ namespace Microsoft.AspNet.Mvc.Razor AddHtmlAttributeValueMethodName = "AddHtmlAttributeValue", HtmlEncoderPropertyName = "HtmlEncoder", TagHelperContentGetContentMethodName = nameof(TagHelperContent.GetContent), + TagHelperOutputIsContentModifiedPropertyName = nameof(TagHelperOutput.IsContentModified), + TagHelperOutputContentPropertyName = nameof(TagHelperOutput.Content), + TagHelperOutputGetChildContentAsyncMethodName = nameof(TagHelperExecutionContext.GetChildContentAsync) }) { BeginContextMethodName = "BeginContext", diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs index 5e224193df..af6f9c3677 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs @@ -310,106 +310,6 @@ namespace Microsoft.AspNet.Mvc.Razor return tagHelperContentWrapperTextWriter.Content; } - /// - /// Writes the content of a specified . - /// - /// The execution context containing the content. - /// - /// A that on completion writes the content. - /// - public Task WriteTagHelperAsync(TagHelperExecutionContext tagHelperExecutionContext) - { - if (tagHelperExecutionContext == null) - { - throw new ArgumentNullException(nameof(tagHelperExecutionContext)); - } - - return WriteTagHelperToAsync(Output, tagHelperExecutionContext); - } - - /// - /// Writes the content of a specified to the specified - /// . - /// - /// The instance to write to. - /// The execution context containing the content. - /// - /// A that on completion writes the content - /// to the . - /// - public async Task WriteTagHelperToAsync( - TextWriter writer, - TagHelperExecutionContext tagHelperExecutionContext) - { - if (writer == null) - { - throw new ArgumentNullException(nameof(writer)); - } - - if (tagHelperExecutionContext == null) - { - throw new ArgumentNullException(nameof(tagHelperExecutionContext)); - } - - var tagHelperOutput = tagHelperExecutionContext.Output; - var isTagNameNullOrWhitespace = string.IsNullOrWhiteSpace(tagHelperOutput.TagName); - - WriteTo(writer, tagHelperOutput.PreElement); - - if (!isTagNameNullOrWhitespace) - { - writer.Write('<'); - writer.Write(tagHelperOutput.TagName); - - foreach (var attribute in tagHelperOutput.Attributes) - { - writer.Write(' '); - writer.Write(attribute.Name); - - if (!attribute.Minimized) - { - writer.Write("=\""); - WriteTo(writer, HtmlEncoder, attribute.Value, escapeQuotes: true); - writer.Write('"'); - } - } - - if (tagHelperOutput.TagMode == TagMode.SelfClosing) - { - writer.Write(" /"); - } - - writer.Write('>'); - } - - if (isTagNameNullOrWhitespace || tagHelperOutput.TagMode == TagMode.StartTagAndEndTag) - { - WriteTo(writer, tagHelperOutput.PreContent); - if (tagHelperOutput.IsContentModified) - { - WriteTo(writer, tagHelperOutput.Content); - } - else if (tagHelperExecutionContext.ChildContentRetrieved) - { - var childContent = await tagHelperExecutionContext.GetChildContentAsync(useCachedResult: true); - WriteTo(writer, childContent); - } - else - { - await tagHelperExecutionContext.ExecuteChildContentAsync(); - } - - WriteTo(writer, tagHelperOutput.PostContent); - } - - if (!isTagNameNullOrWhitespace && tagHelperOutput.TagMode == TagMode.StartTagAndEndTag) - { - writer.Write(string.Format(CultureInfo.InvariantCulture, "", tagHelperOutput.TagName)); - } - - WriteTo(writer, tagHelperOutput.PostElement); - } - /// /// Writes the specified with HTML encoding to . /// @@ -437,7 +337,7 @@ namespace Microsoft.AspNet.Mvc.Razor throw new ArgumentNullException(nameof(writer)); } - WriteTo(writer, HtmlEncoder, value, escapeQuotes: false); + WriteTo(writer, HtmlEncoder, value); } /// @@ -446,21 +346,13 @@ namespace Microsoft.AspNet.Mvc.Razor /// The instance to write to. /// The to use when encoding . /// The to write. - /// - /// If true escapes double quotes in a of type . - /// Otherwise writes values as-is. - /// /// /// s of type are written using /// . /// For all other types, the encoded result of is written to the /// . /// - public static void WriteTo( - TextWriter writer, - HtmlEncoder encoder, - object value, - bool escapeQuotes) + public static void WriteTo(TextWriter writer, HtmlEncoder encoder, object value) { if (writer == null) { @@ -480,28 +372,6 @@ namespace Microsoft.AspNet.Mvc.Razor var htmlContent = value as IHtmlContent; if (htmlContent != null) { - if (escapeQuotes) - { - // In this case the text likely came directly from the Razor source. Since the original string is - // an attribute value that may have been quoted with single quotes, must handle any double quotes - // in the value. Writing the value out surrounded by double quotes. - // - // This is really not optimal from a perf point of view, but it's the best we can do for right now. - using (var stringWriter = new StringWriter()) - { - htmlContent.WriteTo(stringWriter, encoder); - - var stringValue = stringWriter.ToString(); - if (stringValue.Contains("\"")) - { - stringValue = stringValue.Replace("\"", """); - } - - writer.Write(stringValue); - return; - } - } - var htmlTextWriter = writer as HtmlTextWriter; if (htmlTextWriter == null) { diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/TagHelperContentExtensions.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/TagHelperContentExtensions.cs index 8604fb30e8..8264cd9067 100644 --- a/src/Microsoft.AspNet.Mvc.TagHelpers/TagHelperContentExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.TagHelpers/TagHelperContentExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.IO; using System.Text; using System.Text.Encodings.Web; using Microsoft.AspNet.Mvc.Razor; @@ -23,7 +24,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers /// The to write. /// after the write operation has completed. /// - /// s of type are written using + /// s of type are written using /// . /// For all other types, the encoded result of /// is written to the . @@ -51,7 +52,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers using (var writer = new TagHelperContentWrapperTextWriter(encoding, content)) { - RazorPage.WriteTo(writer, encoder, value, escapeQuotes: true); + using (var stringWriter = new StringWriter()) + { + RazorPage.WriteTo(stringWriter, encoder, value); + + // In this case the text likely came directly from the Razor source. Since the original string is + // an attribute value that may have been quoted with single quotes, must handle any double quotes + // in the value. Writing the value out surrounded by double quotes. + var stringValue = stringWriter.ToString().Replace("\"", """); + writer.Write(stringValue); + } } return content; diff --git a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Output/Runtime/ModelExpressionTagHelper.cs b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Output/Runtime/ModelExpressionTagHelper.cs index 294c59fc49..b267f58e5b 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Output/Runtime/ModelExpressionTagHelper.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Host.Test/TestFiles/Output/Runtime/ModelExpressionTagHelper.cs @@ -54,7 +54,7 @@ __Microsoft_AspNet_Mvc_Razor_InputTestTagHelper.For = CreateModelExpression(__mo __tagHelperExecutionContext.AddTagHelperAttribute("for", __Microsoft_AspNet_Mvc_Razor_InputTestTagHelper.For); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); BeginContext(120, 24, false); - await WriteTagHelperAsync(__tagHelperExecutionContext); + Write(__tagHelperExecutionContext.Output); EndContext(); __tagHelperExecutionContext = __tagHelperScopeManager.End(); BeginContext(144, 2, true); @@ -73,7 +73,7 @@ __Microsoft_AspNet_Mvc_Razor_InputTestTagHelper.For = CreateModelExpression(__mo __tagHelperExecutionContext.AddTagHelperAttribute("for", __Microsoft_AspNet_Mvc_Razor_InputTestTagHelper.For); __tagHelperExecutionContext.Output = await __tagHelperRunner.RunAsync(__tagHelperExecutionContext); BeginContext(146, 27, false); - await WriteTagHelperAsync(__tagHelperExecutionContext); + Write(__tagHelperExecutionContext.Output); EndContext(); __tagHelperExecutionContext = __tagHelperScopeManager.End(); } diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageTest.cs index 2197bffd21..20417bb812 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageTest.cs @@ -1222,767 +1222,6 @@ namespace Microsoft.AspNet.Mvc.Razor Assert.Equal("Hello world", HtmlContentUtilities.HtmlContentToString(((IHtmlContent)buffer[0]))); } - public static TheoryData WriteTagHelper_InputData - { - get - { - // parameters: TagHelperOutput, expectedOutput - return new TheoryData - { - { - // parameters: TagName, Attributes, SelfClosing, PreContent, Content, PostContent - GetTagHelperOutput( - tagName: "div", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "
Hello World!
" - }, - { - GetTagHelperOutput( - tagName: string.Empty, - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "Hello World!" - }, - { - GetTagHelperOutput( - tagName: " ", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "Hello World!" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList() { { "test", "testVal" } }, - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "

Hello World!

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList() { { "test", "testVal" }, { "something", " spaced " } }, - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "

Hello World!

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList() - { - ["test"] = new TagHelperAttribute - { - Name = "test", - Minimized = true - }, - }, - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "

Hello World!

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList() - { - ["test"] = new TagHelperAttribute - { - Name = "test", - Minimized = true - }, - ["test2"] = new TagHelperAttribute - { - Name = "test2", - Minimized = true - }, - }, - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "

Hello World!

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList() - { - ["first"] = "unminimized", - ["test"] = new TagHelperAttribute - { - Name = "test", - Minimized = true - }, - }, - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "

Hello World!

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList() - { - ["test"] = new TagHelperAttribute - { - Name = "test", - Minimized = true - }, - ["last"] = "unminimized", - }, - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "

Hello World!

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList() { { "test", "testVal" } }, - tagMode: TagMode.SelfClosing, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList() { { "test", "testVal" }, { "something", " spaced " } }, - tagMode: TagMode.SelfClosing, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList() { { "test", "testVal" } }, - tagMode: TagMode.StartTagOnly, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList() { { "test", "testVal" }, { "something", " spaced " } }, - tagMode: TagMode.StartTagOnly, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: "Hello World!", - content: null, - postContent: null, - postElement: null), - "

Hello World!

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: "Hello World!", - postContent: null, - postElement: null), - "

Hello World!

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: null, - postContent: "Hello World!", - postElement: null), - "

Hello World!

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: null), - "

HelloTestWorld!

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.SelfClosing, - preElement: null, - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: null), - "

" - }, - { - GetTagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagOnly, - preElement: null, - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: null), - "

" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: null), - "HelloTestWorld!" - }, - { - GetTagHelperOutput( - tagName: "random", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.SelfClosing, - preElement: null, - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: null), - "" - }, - { - GetTagHelperOutput( - tagName: "random", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagOnly, - preElement: null, - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: null), - "" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: "Before", - preContent: null, - content: null, - postContent: null, - postElement: null), - "Before" - }, - { - GetTagHelperOutput( - tagName: string.Empty, - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: "Before", - preContent: null, - content: null, - postContent: null, - postElement: null), - "Before" - }, - { - GetTagHelperOutput( - tagName: string.Empty, - attributes: new TagHelperAttributeList { { "test", "testVal" } }, - tagMode: TagMode.SelfClosing, - preElement: "Before", - preContent: null, - content: null, - postContent: null, - postElement: null), - "Before" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList { { "test", "testVal" } }, - tagMode: TagMode.SelfClosing, - preElement: "Before", - preContent: null, - content: null, - postContent: null, - postElement: null), - "Before" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.SelfClosing, - preElement: "Before", - preContent: null, - content: null, - postContent: null, - postElement: null), - "Before" - }, - { - GetTagHelperOutput( - tagName: string.Empty, - attributes: new TagHelperAttributeList { { "test", "testVal" } }, - tagMode: TagMode.StartTagOnly, - preElement: "Before", - preContent: null, - content: null, - postContent: null, - postElement: null), - "Before" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList { { "test", "testVal" } }, - tagMode: TagMode.StartTagOnly, - preElement: "Before", - preContent: null, - content: null, - postContent: null, - postElement: null), - "Before" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagOnly, - preElement: "Before", - preContent: null, - content: null, - postContent: null, - postElement: null), - "Before" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: null, - postContent: null, - postElement: "After"), - "After" - }, - { - GetTagHelperOutput( - tagName: string.Empty, - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: null, - preContent: null, - content: null, - postContent: null, - postElement: "After"), - "After" - }, - { - GetTagHelperOutput( - tagName: string.Empty, - attributes: new TagHelperAttributeList { { "test", "testVal" } }, - tagMode: TagMode.SelfClosing, - preElement: null, - preContent: null, - content: null, - postContent: null, - postElement: "After"), - "After" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList { { "test", "testVal" } }, - tagMode: TagMode.SelfClosing, - preElement: null, - preContent: null, - content: null, - postContent: null, - postElement: "After"), - "After" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.SelfClosing, - preElement: null, - preContent: null, - content: null, - postContent: null, - postElement: "After"), - "After" - }, - { - GetTagHelperOutput( - tagName: string.Empty, - attributes: new TagHelperAttributeList { { "test", "testVal" } }, - tagMode: TagMode.StartTagOnly, - preElement: null, - preContent: null, - content: null, - postContent: null, - postElement: "After"), - "After" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList { { "test", "testVal" } }, - tagMode: TagMode.StartTagOnly, - preElement: null, - preContent: null, - content: null, - postContent: null, - postElement: "After"), - "After" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagOnly, - preElement: null, - preContent: null, - content: null, - postContent: null, - postElement: "After"), - "After" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: "Before", - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: "After"), - "BeforeHelloTestWorld!After" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList { { "test", "testVal" } }, - tagMode: TagMode.StartTagAndEndTag, - preElement: "Before", - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: "After"), - "BeforeHelloTestWorld!After" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.SelfClosing, - preElement: "Before", - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: "After"), - "BeforeAfter" - }, - { - GetTagHelperOutput( - tagName: string.Empty, - attributes: new TagHelperAttributeList(), - tagMode: TagMode.SelfClosing, - preElement: "Before", - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: "After"), - "BeforeHelloTestWorld!After" - }, - { - GetTagHelperOutput( - tagName: "custom", - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagOnly, - preElement: "Before", - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: "After"), - "BeforeAfter" - }, - { - GetTagHelperOutput( - tagName: string.Empty, - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagOnly, - preElement: "Before", - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: "After"), - "BeforeHelloTestWorld!After" - }, - { - GetTagHelperOutput( - tagName: string.Empty, - attributes: new TagHelperAttributeList(), - tagMode: TagMode.StartTagAndEndTag, - preElement: "Before", - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: "After"), - "BeforeHelloTestWorld!After" - }, - { - GetTagHelperOutput( - tagName: string.Empty, - attributes: new TagHelperAttributeList { { "test", "testVal" } }, - tagMode: TagMode.StartTagAndEndTag, - preElement: "Before", - preContent: "Hello", - content: "Test", - postContent: "World!", - postElement: "After"), - "BeforeHelloTestWorld!After" - }, - }; - } - } - - [Theory] - [MemberData(nameof(WriteTagHelper_InputData))] - public async Task WriteTagHelperAsync_WritesFormattedTagHelper(TagHelperOutput output, string expected) - { - // Arrange - var writer = new StringCollectionTextWriter(Encoding.UTF8); - var context = CreateViewContext(writer); - var tagHelperExecutionContext = new TagHelperExecutionContext( - tagName: output.TagName, - tagMode: output.TagMode, - items: new Dictionary(), - uniqueId: string.Empty, - executeChildContentAsync: () => Task.FromResult(result: true), - startTagHelperWritingScope: () => { }, - endTagHelperWritingScope: () => new DefaultTagHelperContent()); - tagHelperExecutionContext.Output = output; - - // Act - var page = CreatePage(p => - { - p.HtmlEncoder = new HtmlTestEncoder(); - p.WriteTagHelperAsync(tagHelperExecutionContext).Wait(); - }, context); - await page.ExecuteAsync(); - - // Assert - Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(writer.Content)); - } - - [Theory] - // This is a scenario where GetChildContentAsync is called. - [InlineData(true, "HelloWorld!", "

HelloWorld!

")] - // This is a scenario where ExecuteChildContentAsync is called. - [InlineData(false, "HelloWorld!", "

")] - public async Task WriteTagHelperAsync_WritesContentAppropriately( - bool childContentRetrieved, string input, string expected) - { - // Arrange - var defaultTagHelperContent = new DefaultTagHelperContent(); - var writer = new StringCollectionTextWriter(Encoding.UTF8); - var context = CreateViewContext(writer); - var tagHelperExecutionContext = new TagHelperExecutionContext( - tagName: "p", - tagMode: TagMode.StartTagAndEndTag, - items: new Dictionary(), - uniqueId: string.Empty, - executeChildContentAsync: () => - { - defaultTagHelperContent.AppendHtml(input); - return Task.FromResult(result: true); - }, - startTagHelperWritingScope: () => { }, - endTagHelperWritingScope: () => defaultTagHelperContent); - tagHelperExecutionContext.Output = new TagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList(), - getChildContentAsync: (_) => Task.FromResult(new DefaultTagHelperContent())); - if (childContentRetrieved) - { - await tagHelperExecutionContext.GetChildContentAsync(useCachedResult: true); - } - - // Act - var page = CreatePage(p => - { - p.HtmlEncoder = new HtmlTestEncoder(); - p.WriteTagHelperAsync(tagHelperExecutionContext).Wait(); - }, context); - await page.ExecuteAsync(); - - // Assert - Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(writer.Content)); - } - - [Fact] - public async Task WriteTagHelperToAsync_WritesToSpecifiedWriter() - { - // Arrange - var writer = new StringCollectionTextWriter(Encoding.UTF8); - var context = CreateViewContext(new StringWriter()); - var tagHelperExecutionContext = new TagHelperExecutionContext( - tagName: "p", - tagMode: TagMode.StartTagAndEndTag, - items: new Dictionary(), - uniqueId: string.Empty, - executeChildContentAsync: () => { return Task.FromResult(result: true); }, - startTagHelperWritingScope: () => { }, - endTagHelperWritingScope: () => new DefaultTagHelperContent()); - tagHelperExecutionContext.Output = new TagHelperOutput( - tagName: "p", - attributes: new TagHelperAttributeList(), - getChildContentAsync: (_) => Task.FromResult(new DefaultTagHelperContent())); - tagHelperExecutionContext.Output.Content.AppendHtml("Hello World!"); - - // Act - var page = CreatePage(p => - { - p.HtmlEncoder = new HtmlTestEncoder(); - p.WriteTagHelperToAsync(writer, tagHelperExecutionContext).Wait(); - }, context); - await page.ExecuteAsync(); - - // Assert - Assert.Equal("

Hello World!

", HtmlContentUtilities.HtmlContentToString(writer.Content)); - } - - [Theory] - [MemberData(nameof(WriteTagHelper_InputData))] - public async Task WriteTagHelperToAsync_WritesFormattedTagHelper(TagHelperOutput output, string expected) - { - // Arrange - var writer = new StringCollectionTextWriter(Encoding.UTF8); - var context = CreateViewContext(new StringWriter()); - var tagHelperExecutionContext = new TagHelperExecutionContext( - tagName: output.TagName, - tagMode: output.TagMode, - items: new Dictionary(), - uniqueId: string.Empty, - executeChildContentAsync: () => Task.FromResult(result: true), - startTagHelperWritingScope: () => { }, - endTagHelperWritingScope: () => new DefaultTagHelperContent()); - tagHelperExecutionContext.Output = output; - - // Act - var page = CreatePage(p => - { - p.HtmlEncoder = new HtmlTestEncoder(); - p.WriteTagHelperToAsync(writer, tagHelperExecutionContext).Wait(); - }, context); - await page.ExecuteAsync(); - - // Assert - Assert.Equal(expected, HtmlContentUtilities.HtmlContentToString(writer.Content)); - } - - private static TagHelperOutput GetTagHelperOutput( - string tagName, - TagHelperAttributeList attributes, - TagMode tagMode, - string preElement, - string preContent, - string content, - string postContent, - string postElement) - { - var output = new TagHelperOutput( - tagName, - attributes, - getChildContentAsync: (_) => Task.FromResult(new DefaultTagHelperContent())) - { - TagMode = tagMode - }; - - output.PreElement.AppendHtml(preElement); - output.PreContent.AppendHtml(preContent); - output.Content.AppendHtml(content); - output.PostContent.AppendHtml(postContent); - output.PostElement.AppendHtml(postElement); - - return output; - } - private static TestableRazorPage CreatePage( Action executeAction, ViewContext context = null)