diff --git a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Rendering/TagBuilder.cs b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Rendering/TagBuilder.cs index d97c6785e2..e3e4edfbb8 100644 --- a/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Rendering/TagBuilder.cs +++ b/src/Microsoft.AspNetCore.Mvc.ViewFeatures/Rendering/TagBuilder.cs @@ -298,37 +298,69 @@ namespace Microsoft.AspNetCore.Mvc.Rendering throw new ArgumentNullException(nameof(encoder)); } - switch (TagRenderMode) + WriteTo(this, writer, encoder, TagRenderMode); + } + + /// + /// Returns an that renders the body. + /// + /// An that renders the body. + public IHtmlContent RenderBody() => _innerHtml; + + /// + /// Returns an that renders the start tag. + /// + /// An that renders the start tag. + public IHtmlContent RenderStartTag() => new RenderTagHtmlContent(this, TagRenderMode.StartTag); + + /// + /// Returns an that renders the end tag. + /// + /// An that renders the end tag. + public IHtmlContent RenderEndTag() => new RenderTagHtmlContent(this, TagRenderMode.EndTag); + + /// + /// Returns an that renders the self-closing tag. + /// + /// An that renders the self-closing tag. + public IHtmlContent RenderSelfClosingTag() => new RenderTagHtmlContent(this, TagRenderMode.SelfClosing); + + private static void WriteTo( + TagBuilder tagBuilder, + TextWriter writer, + HtmlEncoder encoder, + TagRenderMode tagRenderMode) + { + switch (tagRenderMode) { case TagRenderMode.StartTag: writer.Write("<"); - writer.Write(TagName); - AppendAttributes(writer, encoder); + writer.Write(tagBuilder.TagName); + tagBuilder.AppendAttributes(writer, encoder); writer.Write(">"); break; case TagRenderMode.EndTag: writer.Write(""); break; case TagRenderMode.SelfClosing: writer.Write("<"); - writer.Write(TagName); - AppendAttributes(writer, encoder); + writer.Write(tagBuilder.TagName); + tagBuilder.AppendAttributes(writer, encoder); writer.Write(" />"); break; default: writer.Write("<"); - writer.Write(TagName); - AppendAttributes(writer, encoder); + writer.Write(tagBuilder.TagName); + tagBuilder.AppendAttributes(writer, encoder); writer.Write(">"); - if (_innerHtml != null) + if (tagBuilder._innerHtml != null) { - _innerHtml.WriteTo(writer, encoder); + tagBuilder._innerHtml.WriteTo(writer, encoder); } - writer.Write(""); break; } @@ -343,6 +375,23 @@ namespace Microsoft.AspNetCore.Mvc.Rendering } } + private class RenderTagHtmlContent : IHtmlContent + { + private readonly TagBuilder _tagBuilder; + private readonly TagRenderMode _tagRenderMode; + + public RenderTagHtmlContent(TagBuilder tagBuilder, TagRenderMode tagRenderMode) + { + _tagBuilder = tagBuilder; + _tagRenderMode = tagRenderMode; + } + + public void WriteTo(TextWriter writer, HtmlEncoder encoder) + { + TagBuilder.WriteTo(_tagBuilder, writer, encoder, _tagRenderMode); + } + } + private static class Html401IdUtil { public static bool IsAsciiLetter(char testChar) diff --git a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/TagBuilderTest.cs b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/TagBuilderTest.cs index 55a37da7e4..ce76a6c786 100644 --- a/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/TagBuilderTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.ViewFeatures.Test/Rendering/TagBuilderTest.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.TestCommon; using Microsoft.Extensions.WebEncoders.Testing; using Xunit; @@ -169,5 +170,89 @@ namespace Microsoft.AspNetCore.Mvc.Core.Rendering Assert.False(tagBuilder.HasInnerHtml); Assert.NotNull(innerHtml); } + + [Fact] + public void RenderStartTag_RendersExpectedStartTag() + { + // Arrange + var tagBuilder = new TagBuilder("p"); + + // Act + var tag = tagBuilder.RenderStartTag(); + + // Assert + Assert.Equal("

", HtmlContentUtilities.HtmlContentToString(tag)); + } + + [Fact] + public void RenderStartTag_RendersExpectedStartTag_TagBuilderRendersAsExpected() + { + // Arrange + var tagBuilder = new TagBuilder("p"); + tagBuilder.TagRenderMode = TagRenderMode.EndTag; + + // Act + var tag = tagBuilder.RenderStartTag(); + + // Assert + Assert.Equal("

", HtmlContentUtilities.HtmlContentToString(tag)); + Assert.Equal("

", HtmlContentUtilities.HtmlContentToString(tagBuilder)); + } + + [Fact] + public void RenderEndTag_RendersExpectedEndTag() + { + // Arrange + var tagBuilder = new TagBuilder("p"); + + // Act + var tag = tagBuilder.RenderEndTag(); + + // Assert + Assert.Equal("

", HtmlContentUtilities.HtmlContentToString(tag)); + } + + [Fact] + public void RenderEndTag_RendersExpectedEndTag_TagBuilderRendersAsExpected() + { + // Arrange + var tagBuilder = new TagBuilder("p"); + tagBuilder.TagRenderMode = TagRenderMode.Normal; + + // Act + var tag = tagBuilder.RenderEndTag(); + + // Assert + Assert.Equal("

", HtmlContentUtilities.HtmlContentToString(tag)); + Assert.Equal("

", HtmlContentUtilities.HtmlContentToString(tagBuilder)); + } + + [Fact] + public void RenderSelfClosingTag_RendersExpectedSelfClosingTag() + { + // Arrange + var tagBuilder = new TagBuilder("p"); + + // Act + var tag = tagBuilder.RenderSelfClosingTag(); + + // Assert + Assert.Equal("

", HtmlContentUtilities.HtmlContentToString(tag)); + + } + + [Fact] + public void RenderBody_RendersExpectedBody() + { + // Arrange + var tagBuilder = new TagBuilder("p"); + tagBuilder.InnerHtml.AppendHtml("Hello"); + + // Act + var tag = tagBuilder.RenderBody(); + + // Assert + Assert.Equal("Hello", HtmlContentUtilities.HtmlContentToString(tag)); + } } } \ No newline at end of file