我正在编写一组ASP.Net Core标记帮助器,这些辅助器以<form>
和<input>
标签为目标(以及其他标签)。我的<form>
标签帮助程序定义了一个自定义属性,该属性希望将其值传递给子元素。
我读过的所有文章都听起来很简单:父标记助手将值存储在context.Items
字典中,而子项则从同一字典中读取它。
这意味着子标记助手在父标记助手之后执行。但是,我发现,对于<form>
和<input>
标记助手, FormTagHelper
在InputTagHelper
之后执行。
通过示例,请考虑以下HTML:
<form my-attr='Hello'>
<input asp-for='SomeProperty' />
</form>
我的表单标签助手:
public class FormTagHelper : TagHelper
{
public string MyAttr { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
Debug.WriteLine("<form>");
context.Items.Add("my-attr", MyAttr ?? "");
}
}
输入标签助手:
public class InputTagHelper : TagHelper
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
Debug.WriteLine("<input>");
var valueFromParentForm = context.Items["my-attr"].ToString();
}
}
我希望valueFromParentForm
是"Hello"
,但实际上它会引发异常,因为context.Items字典为空。
这是什么一回事,我应该怎么做才能解决这种奇怪的,由内而外的执行顺序?
答案 0 :(得分:0)
除了Process()
方法外,基本标记帮助程序还提供了Init()
方法。摘要:
使用给定的上下文初始化
Microsoft.AspNetCore.Razor.TagHelpers.ITagHelper
。Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext.Items
的添加应在此方法内完成,以确保在执行子代之前将其添加。
只需重写此方法并添加所需的内容:
public override void Init(TagHelperContext context)
{
context.Items.Add(1, "Init FormTagHelper");
}
对于您的html代码:
<form my-attr='Hello'>
<input asp-for='SomeProperty' />
</form>
我们有两个标签助手:
[HtmlTargetElement("form")]
public class FormTagHelper : TagHelper
{
public override void Init(TagHelperContext context)
{
context.Items.Add(1, "Init FormTagHelper");
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
context.Items.Add(4, "Process FormTagHelper");
}
}
[HtmlTargetElement("input")]
public class InputTagHelper : TagHelper
{
public override void Init(TagHelperContext context)
{
context.Items.Add(2, "Init InputTagHelper");
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
context.Items.Add(3, "Process InputTagHelper");
}
}
为了更好地理解按什么顺序调用方法,让我们看一下该图:
我认为执行顺序是不言自明的。但是红色的No access
部分呢?让我们从建立确切的Items
字典及其工作开始。它的编号为IDictionary<object, object>
,但不是常规词典。这是CopyOnWriteDictionary
,非常特殊。它有两个基础字典ReadDictionary
和WriteDictionary
,并根据当前执行的操作类型(读/写)来调用其中的一个。
尽管您可以从1
添加FormTagHelper.Init()
,但是尽管您可以根据以下条件访问2
中的键3
和FormTagHelper.Process()
到他们应该已经在图中的位置:
这是因为InputTagHelper
的值被添加到_innerDictionary
而不是_sourceDictionary
中,然后在FormTagHelper
中使用。这种行为会创建对Items
字典的单向访问。儿童标签助手可以访问父母添加的值,但不能相反。
执行Items
的{{1}}方法后Init()
字典的状态:
答案 1 :(得分:0)
我现在运行以下标记助手(父母和孩子)
<sp-row>
<sp-col>Child 1</sp-col>
<sp-col>Child 2</sp-col>
</sp-row>
,它按以下顺序运行(而不是预览答案的顺序):