Search code examples
c#asp.net-core.net-coreasp.net-core-mvctag-helpers

Net Core: Use a Tag Helper in a Custom Tag Helper that returns Html?


I am trying to conduct this question except in .Net Core 2.

Can I use a Tag Helper in a custom Tag Helper that returns html?

" I would like to use a tag helper within a tag helper. I looked around and couldn't find anyone else trying to do this, am I using a poor convention or am I missing documentation?

Ex. Tag Helper A outputs HTML that contains another tag helper."

How would I resolve the compilation error below?

[HtmlTargetElement("tag-name")]
public class RazorTagHelper : TagHelper
{
    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("<a asp-action=\"Home\" ");
        output.Content.SetHtmlContent(sb.ToString());
    }
}

Is there a way for me to process the tag helper from C#? Or to reprocess the output HTML with tag helpers? "

Tried this marked Solution from Taylor Mullen:

var anchorTagHelper = new AnchorTagHelper
{
    Action = "Home",
};

var anchorOutput = new TagHelperOutput("a", new TagHelperAttributeList(), (useCachedResult, encoder) => new HtmlString());
var anchorContext = new TagHelperContext(
    new TagHelperAttributeList(new[] { new TagHelperAttribute("asp-action", new HtmlString("Home")) }),
    new Dictionary<object, object>(),
    Guid.NewGuid());
await anchorTagHelper.ProcessAsync(anchorContext, anchorOutput);
output.Content.SetHtmlContent(anchorOutput);

Receiving Error Below

There is no argument given that corresponds to the required formal parameter 'value' of 'HtmlString.HtmlString(string)'

Solution

  • Now this is has been one of my favorite question on here. Thankfully I've dealt with tag helpers enough. Here is the code.

    [HtmlTargetElement(ParentAnchorTag)]
    public class ParentActionTagHelper : TagHelper
    {
        private const string ParentAnchorTag = "p-a";
    
        [HtmlAttributeNotBound]
        [ViewContext]
        public ViewContext viewContext { get; set; }
    
        private readonly IHtmlGenerator _htmlGenerator;
    
        public ParentActionTagHelper(IHtmlGenerator htmlGenerator)
        {
            _htmlGenerator = htmlGenerator;
        }
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = "div";
    
            var anchorTagHelper = new AnchorTagHelper(_htmlGenerator)
            {
                Action = "Privacy",
                ViewContext = viewContext,
    
            };
            var anchorOutput = new TagHelperOutput("a", new TagHelperAttributeList(),
                (useCachedResult, encoder) =>  Task.Factory.StartNew<TagHelperContent>(
                     () => new DefaultTagHelperContent()));
            anchorOutput.Content.AppendHtml("Privacy Link");
            var anchorContext = new TagHelperContext(
                new TagHelperAttributeList(new[]
                {
                    new TagHelperAttribute("asp-action", new HtmlString("Privacy"))
                }),
                    new Dictionary<object, object>(),
                    Guid.NewGuid().ToString());
    
            anchorTagHelper.ProcessAsync(anchorContext, anchorOutput).GetAwaiter().GetResult();
            output.Content.SetHtmlContent(anchorOutput);
        }
    }
    

    First, to generate the href attribute using the action name, you need action name, you need to provide ViewContext to the AnchorTagHelper(it will throw an error otherwise), you can't inject that as a dependency. Lines 6-8 explain that, you also need the IHtmlGenerator which you need to pass only the AnchroTagHelper constructor. Then you create the context TagHelperOutput and TagHelperContext needed to call the processAsync method on anchor tag helper you instantiated. (Note - I am using GetAwaiter().GetResult() because this method is not async in my case, you can totally put this code in the ProcessAsync overriden method). So I help this solves your problem. I have tested it and it works.

    My cshtml file. enter image description here My output.

    This is the output