TagHelper Structure

This is some rendered output in the browser.

In HTML that looks like this.

<p>PreElement.SetHtmlContent(string)  
<ul class="small text-primary">  
   <li>PreContent.SetHtmlContent(string)
   <li>Content.SetHtmlContent(string)
   <li>Content.AppendHtml(string)
   <li>
      This is the original Inner HTML from the *.cshtml file.
   <li>My Property Value
   <li>Monday, January 1, 0001
   <li>PostContent.SetHtmlContent(string)
</ul>  
<p>PostElement.SetHtmlContent(string)  

The following TagHelper code is what generated that HTML.

Index.cshtml

<my-first  
    my-string-property="My Property Value" 
    my-date-time-property="new DateTime()">
    This is the original Inner HTML from the *.cshtml file.
</my-first>  

MyFirstTagHelper.cs

public class MyFirstTagHelper : TagHelper
{
    public string MyStringProperty { get; set; }

    public DateTime MyDateTimeProperty { get; set; }

    public override async Task ProcessAsync(
        TagHelperContext context,
        TagHelperOutput output)
    {
        ModifyTag(output);
        ModifyAttributes(output);
        ModifyContents(output);

        // get the markup content from the .cshtml file
        var childContent = await output.GetChildContentAsync();
        var innerHtml = childContent.GetContent();

        output.Content
            .AppendHtml($"<li>{innerHtml}")
            .AppendHtml($"<li>{MyStringProperty}")
            .AppendHtml($"<li>{MyDateTimeProperty.ToString("D")}");
    }

    public void ModifyTag(TagHelperOutput output)
    {
        // wrap the PreContent, Content, and PostContent in a list.
        output.TagName = "ul";
        output.TagMode = TagMode.StartTagAndEndTag; // optional
    }

    public void ModifyAttributes(TagHelperOutput output)
    {
        output.Attributes.Add("class", "small text-primary");
    }

    public void ModifyContents(TagHelperOutput output)
    {
        // outside of the TagName tag
        output.PreElement
            .SetHtmlContent("<p>PreElement.SetHtmlContent(string)");
        output.PostElement
            .SetHtmlContent("<p>PostElement.SetHtmlContent(string)");

        // inside the TagName tag
        output.PreContent
            .SetHtmlContent("<li>PreContent.SetHtmlContent(string)");
        output.PostContent
            .SetHtmlContent("<li>PostContent.SetHtmlContent(string)");
        output.Content
            // Set... replaces existing content
            .SetHtmlContent("<li>Content.SetHtmlContent(string)")
            .AppendHtml("<li>Content.AppendHtml(string)");
    }
}