Instantiating and Invoking TagHelpers Manually

2019-08-20 22:31发布

问题:

This is a follow up question to this question, which seems to be for an older ASP.NET Core version (I'm using 2.1).

I'm trying to call a TagHelper manually from within a TagHelper. Applying the Answer in the linked question above, the TagHelper.Process looks like so:

public override async void Process(TagHelperContext context, TagHelperOutput output)
{
    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);
}

Several compiler errors occur at this point.

cannot convert from 'System.Guid' to 'string'

No problem, I can cast to a String.

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

Checking the MSDN page for the TagHelperOutput constructor, it seems it doesn't take an HtmlString anymore.

I changed that argument to a delegate fuction:

new TagHelperOutput("a", new TagHelperAttributeList(),
    (useCachedResult, encoder) => Task.Factory.StartNew<TagHelperContent>(
         () => new DefaultTagHelperContent()));

The last compiler error:

There is no argument given that corresponds to the required formal parameter 'generator' of 'AnchorTagHelper.AnchorTagHelper(IHtmlGenerator)

Hoping its an optional parameter, I passed in null:

var anchorTagHelper = new AnchorTagHelper(null);

It finally compiled - but this led to a null pointer exception on runtime:

Microsoft.AspNetCore.Mvc.TagHelpers.InputTagHelper.Process(TagHelperContext context, TagHelperOutput output)

My question is thus: how can I instantiate AnchorTagHelper so I can manually invoke TagHelpers in C#?

EDIT: I've DI'd IHtmlGenerator and got a more meaningful error message:

private IHtmlGenerator htmlGenerator;
public myAnchorTagHelper(IHtmlGenerator htmlGenerator) {
    this.htmlGenerator = htmlGenerator;
}

Value cannot be null. Parameter name: viewContext>

Microsoft.AspNetCore.Mvc.ViewFeatures.DefaultHtmlGenerator.GenerateActionLink(ViewContext viewContext, String linkText, String actionName, String controllerName, String protocol, String hostname, String fragment, Object routeValues, Object htmlAttributes) at Microsoft.AspNetCore.Mvc.TagHelpers.AnchorTagHelper.Process(TagHelperContext context, TagHelperOutput output) at EAGLEweb2020.Models.EAGLEinputTagHelper.Process(TagHelperContext context, TagHelperOutput output) in C:\Users\1135937\source\repos\EAGLEweb2020\EAGLEweb2020\Models\TagHelpers\EAGLEinputTagHelper.cs:line 66 at Microsoft.AspNetCore.Razor.TagHelpers.TagHelper.ProcessAsync(TagHelperContext context, TagHelperOutput output) at Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.d__0.MoveNext()

But how can I DI a ViewContext?

EDIT 2:

Turns out ViewContext is a public property in AnchorTagHelper:

AnchorTagHelper inputTagHelper = new AnchorTagHelper(htmlGenerator);
inputTagHelper.ViewContext = viewContext;

But now the content is empty...

回答1:

Hi I was going through this and you got stuck at the ViewContext and the Output. I have done a similar project. Here's the code, hope it helps.

[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);
    }
}