针对同一元素的多个标记助手

时间:2021-04-19 10:02:44

I have just noticed that if I have 2 tag helpers targeting the same element, both can be executed. The order in which they are executed depends on the order in which they are registered in _ViewImports.cshtml.

我刚刚注意到,如果我有2个标记助手,它们都是针对同一个元素的,那么两者都可以执行。它们的执行顺序取决于它们在_ViewImports.cshtml中的注册顺序。

For example, I can create another tag helper for the anchor element:

例如,我可以为anchor元素创建另一个标记助手:

[HtmlTargetElement("a", Attributes = "foo")]
public class FooTagHelper : TagHelper
{
    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        //Get the url from href attribute generated in the default AnchorTagHelper
        var url = output.Attributes["href"].Value.ToString();

        ...
    }
}

Use it as follows (notice I am also adding attributes of the default anchor helper like asp-controller):

使用如下(注意我还添加了默认锚点助手的属性,如asp-controller):

<a class="menu" asp-controller="Home" asp-action="Index" foo>Foo</a>

If this helper is registered in _ViewImports.cshtml after the default ASP ones:

如果在默认的ASP之后在_ViewImports.cshtml中注册了这个帮助器:

  • Whenever Process is called, the TagHelperOutput already contains the href generated by the default AnchorTagHelper. I could also update the anchor generated by the default tag helper in any way I like.
  • 每当调用Process时,TagHelperOutput都已包含默认的AnchorTagHelper生成的href。我也可以用我喜欢的任何方式更新默认标签助手生成的锚点。

Is there any degree of control over this behavior?

对这种行为有任何程度的控制吗?

You might want to decide whether or not to execute further helpers targeting the same element (As if sealing your output). You might also want to allow other helpers, but make sure some attribute wasn't modified.

您可能想要决定是否执行针对同一元素的其他帮助程序(如同密封输出一样)。您可能还希望允许其他帮助程序,但请确保未修改某些属性。

1 个解决方案

#1


7  

Reading the source code of the TagHelperRunner class, I realized that the same TagHelperContext and TagHelperOutput will be shared for all the tag helpers found for the same element, which will be processed orderd by the ITagHelper.Order property.

阅读TagHelperRunner类的源代码,我意识到将为同一元素找到的所有标记助手共享相同的TagHelperContext和TagHelperOutput,它们将由ITagHelper.Order属性处理。

So you can control the order in which they are executed by assigning appropriated values to the Order property. As a reference, this is the TagHaelperRunner.RunAsync method:

因此,您可以通过为Order属性分配适当的值来控制它们的执行顺序。作为参考,这是TagHaelperRunner.RunAsync方法:

public async Task<TagHelperOutput> RunAsync([NotNull] TagHelperExecutionContext executionContext)
{
    var tagHelperContext = new TagHelperContext(
        executionContext.AllAttributes,
        executionContext.Items,
        executionContext.UniqueId,
        executionContext.GetChildContentAsync);
    var tagHelperOutput = new TagHelperOutput(
        executionContext.TagName,
        executionContext.HTMLAttributes)
    {
        SelfClosing = executionContext.SelfClosing,
    };
    var orderedTagHelpers = executionContext.TagHelpers.OrderBy(tagHelper => tagHelper.Order);

    foreach (var tagHelper in orderedTagHelpers)
    {
        await tagHelper.ProcessAsync(tagHelperContext, tagHelperOutput);
    }

    return tagHelperOutput;
}
  • The default Order if you extend the class TagHelper is 0.

    如果扩展TagHelper类,则默认顺序为0。

  • The MVC tag helpers like AnchorTagHelper or InputTagHelper seem to have the order defined as -1000.

    像AnchorTagHelper或InputTagHelper这样的MVC标记助手似乎将顺序定义为-1000。

So far, I have also found that you can query some of the properties in TagHelperOutput to check if a previous tag helper has modified the output. Although you cannot know if a tag helper with higher order (executed after yours) modifies the output:

到目前为止,我还发现您可以查询TagHelperOutput中的一些属性,以检查先前的标记帮助程序是否已修改输出。虽然您无法知道具有更高顺序的标签助手(在您之后执行)是否会修改输出:

  • TagHelperOutput.IsContentModified will return true only when the Content is modified (Not when the attributes or the PreElement, PreContent, PostElement, PostContent are modified)

    只有在修改内容时,TagHelperOutput.IsContentModified才会返回true(不是在修改属性或PreElement,PreContent,PostElement,PostContent时)

  • TagHelperOutput.PreElement.IsModified and similar for PreContent, PostElement and PostContent will return true when those have been modified.

    PreContent,PostElement和PostContent的TagHelperOutput.PreElement.IsModified和类似将在修改后返回true。

  • Content set by a previous tag helper could be removed by calling TagHelperOutput.Content.Clear() and similar for Pre/Post Element/Context properties.

    可以通过调用TagHelperOutput.Content.Clear()以及类似的Pre / Post Element / Context属性来删除先前标记帮助程序设置的内容。

  • Content can be completely suppressed by calling TagHelperOutput.SuppressOutput() which calls clear on every of those properties and set TagName as null. If you want the tag helper to render something you will then need to assign them again.

    通过调用TagHelperOutput.SuppressOutput()可以完全抑制内容,该函数在每个属性上调用clear并将TagName设置为null。如果您希望标记帮助器呈现某些内容,则需要再次分配它们。

Finally, if you had to share some data between multiple tag helpers for the same element, you can use the TagHelperContext.Items dictionary.

最后,如果您必须在同一元素的多个标记助手之间共享一些数据,则可以使用TagHelperContext.Items字典。

#1


7  

Reading the source code of the TagHelperRunner class, I realized that the same TagHelperContext and TagHelperOutput will be shared for all the tag helpers found for the same element, which will be processed orderd by the ITagHelper.Order property.

阅读TagHelperRunner类的源代码,我意识到将为同一元素找到的所有标记助手共享相同的TagHelperContext和TagHelperOutput,它们将由ITagHelper.Order属性处理。

So you can control the order in which they are executed by assigning appropriated values to the Order property. As a reference, this is the TagHaelperRunner.RunAsync method:

因此,您可以通过为Order属性分配适当的值来控制它们的执行顺序。作为参考,这是TagHaelperRunner.RunAsync方法:

public async Task<TagHelperOutput> RunAsync([NotNull] TagHelperExecutionContext executionContext)
{
    var tagHelperContext = new TagHelperContext(
        executionContext.AllAttributes,
        executionContext.Items,
        executionContext.UniqueId,
        executionContext.GetChildContentAsync);
    var tagHelperOutput = new TagHelperOutput(
        executionContext.TagName,
        executionContext.HTMLAttributes)
    {
        SelfClosing = executionContext.SelfClosing,
    };
    var orderedTagHelpers = executionContext.TagHelpers.OrderBy(tagHelper => tagHelper.Order);

    foreach (var tagHelper in orderedTagHelpers)
    {
        await tagHelper.ProcessAsync(tagHelperContext, tagHelperOutput);
    }

    return tagHelperOutput;
}
  • The default Order if you extend the class TagHelper is 0.

    如果扩展TagHelper类,则默认顺序为0。

  • The MVC tag helpers like AnchorTagHelper or InputTagHelper seem to have the order defined as -1000.

    像AnchorTagHelper或InputTagHelper这样的MVC标记助手似乎将顺序定义为-1000。

So far, I have also found that you can query some of the properties in TagHelperOutput to check if a previous tag helper has modified the output. Although you cannot know if a tag helper with higher order (executed after yours) modifies the output:

到目前为止,我还发现您可以查询TagHelperOutput中的一些属性,以检查先前的标记帮助程序是否已修改输出。虽然您无法知道具有更高顺序的标签助手(在您之后执行)是否会修改输出:

  • TagHelperOutput.IsContentModified will return true only when the Content is modified (Not when the attributes or the PreElement, PreContent, PostElement, PostContent are modified)

    只有在修改内容时,TagHelperOutput.IsContentModified才会返回true(不是在修改属性或PreElement,PreContent,PostElement,PostContent时)

  • TagHelperOutput.PreElement.IsModified and similar for PreContent, PostElement and PostContent will return true when those have been modified.

    PreContent,PostElement和PostContent的TagHelperOutput.PreElement.IsModified和类似将在修改后返回true。

  • Content set by a previous tag helper could be removed by calling TagHelperOutput.Content.Clear() and similar for Pre/Post Element/Context properties.

    可以通过调用TagHelperOutput.Content.Clear()以及类似的Pre / Post Element / Context属性来删除先前标记帮助程序设置的内容。

  • Content can be completely suppressed by calling TagHelperOutput.SuppressOutput() which calls clear on every of those properties and set TagName as null. If you want the tag helper to render something you will then need to assign them again.

    通过调用TagHelperOutput.SuppressOutput()可以完全抑制内容,该函数在每个属性上调用clear并将TagName设置为null。如果您希望标记帮助器呈现某些内容,则需要再次分配它们。

Finally, if you had to share some data between multiple tag helpers for the same element, you can use the TagHelperContext.Items dictionary.

最后,如果您必须在同一元素的多个标记助手之间共享一些数据,则可以使用TagHelperContext.Items字典。