Adding a simple TagHelper causes this error: "RenderBody has not been called for the page "
Adding a simple TagHelper causes this error: "RenderBody has not been called for the page "
在 ASP.NET Core 3.0 网络应用程序中,我添加了以下简单的标签助手:
[HtmlTargetElement("submit-button")]
public class SubmitButtonTagHelper : TagHelper
{
public string Title { get; set; } = "Submit";
public string Classes { get; set; }
public string Id { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Content.SetHtmlContent(
$@"<span class=""btn btn-primary {Classes}"" id=""{Id}"">{Title}</span>");
}
}
我打算这样使用:
<submit-button></submit-button>
但是,添加 SubmitButtonTagHelper 而没有尝试使用它的行为会导致以下运行时异常:
InvalidOperationException: RenderBody has not been called for the page
at '/Views/Shared/_Layout.cshtml'. To ignore call IgnoreBody().
我通过将此行添加到 Pages/_ViewImports.cshtml 文件来导入标签助手:
@addTagHelper *, Web
我的 _Layout.cshtml 页面如下所示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><vc:product-name></vc:product-name> @ViewData["Title"]</title>
@RenderSection("Styles", required: false)
<partial name="_FrameworkStyles" />
</head>
<body class="top-navigation">
<div id="wrapper">
<div id="page-wrapper" class="gray-bg">
<div class="">
<vc:Navigation></vc:Navigation>
@RenderBody()
<div class="footer"></div>
</div>
</div>
</div>
<partial name="_FrameworkScripts" />
@RenderSection("Scripts", required: false)
</body>
</html>
我这里哪里出错了?在调试时,我可以看到在 SubmitButtonTagHelper 中遇到了断点,但我还没有在任何地方引用它?据我了解,[HtmlTargetElement] 属性意味着它仅适用于元素标记为 "submit-button" 的位置。那不对吗?
我的项目中还有另一个标记助手,我还注意到 class 中的断点也在我没有引用它的地方被击中。
我肯定在做一些愚蠢的事情,但是什么?
ASP.NET Core MVC有Tag Helper Components的概念:
A Tag Helper Component is a Tag Helper that allows you to conditionally modify or add HTML elements from server-side code.
...
Tag Helper Components don't require registration with the app in _ViewImports.cshtml.
...
Two common use cases of Tag Helper Components include:
同样来自文档,这里是 Tag Helper 组件的实现:
public class AddressStyleTagHelperComponent : TagHelperComponent
{
private readonly string _style =
@"<link rel=""stylesheet"" href=""/css/address.css"" />";
public override int Order => 1;
public override Task ProcessAsync(TagHelperContext context,
TagHelperOutput output)
{
if (string.Equals(context.TagName, "head",
StringComparison.OrdinalIgnoreCase))
{
output.PostContent.AppendHtml(_style);
}
return Task.CompletedTask;
}
}
一旦注册(如下所示),AddressStyleTagHelperComponent
将 运行 两次:一次用于 head
元素;一次用于 body
元素。这是它在 DI 中的注册方式:
services.AddTransient<ITagHelperComponent, AddressScriptTagHelperComponent>();
此时(或更早),您可能认为我疯了。这与 SubmitButtonTagHelper
有什么关系?
通过其继承树,SubmitButtonTagHelper
最终实现了 ITagHelperComponent
。如果您要添加以下 DI 注册,SubmitButtonTagHelper
将 运行 作为 Tag Helper 组件,一次用于 head
,一次用于 body
:
services.AddTransient<ITagHelperComponent, SubmitButtonTagHelper>();
SubmitButtonTagHelper
是破坏性的,会替换它操作的元素的全部内容。如果要替换 body
元素的内容,正文当然会丢失其 RenderBody
指令。
所以,如果 SubmitButtonTagHelper
被注册为标签助手组件, 可能 会发生什么,这是一个很长的解释。您上传到 GitHub (source):
的示例中确实发生了这种情况,这不足为奇
private static void WebRegistration(ContainerBuilder builder)
{
builder.RegisterAutowiredAssemblyInterfaces(Assembly.Load(Web));
builder.RegisterAutowiredAssemblyTypes(Assembly.Load(Web));
}
我对 Autofac 了解不多,但很明显,上面显示的对 RegisterAutowiredAssemblyInterfaces
的调用会找到 SubmitButtonTagHelper
并将其注册到其所有接口,包括 ITagHelperComponent
。
同样,我对 Autofac 了解不多,但最终,不打算 运行 作为标签助手组件的标签助手应该被排除在这个自动注册过程之外。这是一个关于如何进行这种过滤的建议,尽管我认为这是一种糟糕的 Autofac 方法:
builder.RegisterAutowiredAssemblyInterfaces(Assembly.Load(Web))
.Where(x => !x.Name.EndsWith("TagHelper"));
在 ASP.NET Core 3.0 网络应用程序中,我添加了以下简单的标签助手:
[HtmlTargetElement("submit-button")]
public class SubmitButtonTagHelper : TagHelper
{
public string Title { get; set; } = "Submit";
public string Classes { get; set; }
public string Id { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.Content.SetHtmlContent(
$@"<span class=""btn btn-primary {Classes}"" id=""{Id}"">{Title}</span>");
}
}
我打算这样使用:
<submit-button></submit-button>
但是,添加 SubmitButtonTagHelper 而没有尝试使用它的行为会导致以下运行时异常:
InvalidOperationException: RenderBody has not been called for the page at '/Views/Shared/_Layout.cshtml'. To ignore call IgnoreBody().
我通过将此行添加到 Pages/_ViewImports.cshtml 文件来导入标签助手:
@addTagHelper *, Web
我的 _Layout.cshtml 页面如下所示:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><vc:product-name></vc:product-name> @ViewData["Title"]</title>
@RenderSection("Styles", required: false)
<partial name="_FrameworkStyles" />
</head>
<body class="top-navigation">
<div id="wrapper">
<div id="page-wrapper" class="gray-bg">
<div class="">
<vc:Navigation></vc:Navigation>
@RenderBody()
<div class="footer"></div>
</div>
</div>
</div>
<partial name="_FrameworkScripts" />
@RenderSection("Scripts", required: false)
</body>
</html>
我这里哪里出错了?在调试时,我可以看到在 SubmitButtonTagHelper 中遇到了断点,但我还没有在任何地方引用它?据我了解,[HtmlTargetElement] 属性意味着它仅适用于元素标记为 "submit-button" 的位置。那不对吗?
我的项目中还有另一个标记助手,我还注意到 class 中的断点也在我没有引用它的地方被击中。
我肯定在做一些愚蠢的事情,但是什么?
ASP.NET Core MVC有Tag Helper Components的概念:
A Tag Helper Component is a Tag Helper that allows you to conditionally modify or add HTML elements from server-side code.
...
Tag Helper Components don't require registration with the app in _ViewImports.cshtml.
...
Two common use cases of Tag Helper Components include:
同样来自文档,这里是 Tag Helper 组件的实现:
public class AddressStyleTagHelperComponent : TagHelperComponent { private readonly string _style = @"<link rel=""stylesheet"" href=""/css/address.css"" />"; public override int Order => 1; public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { if (string.Equals(context.TagName, "head", StringComparison.OrdinalIgnoreCase)) { output.PostContent.AppendHtml(_style); } return Task.CompletedTask; } }
一旦注册(如下所示),AddressStyleTagHelperComponent
将 运行 两次:一次用于 head
元素;一次用于 body
元素。这是它在 DI 中的注册方式:
services.AddTransient<ITagHelperComponent, AddressScriptTagHelperComponent>();
此时(或更早),您可能认为我疯了。这与 SubmitButtonTagHelper
有什么关系?
通过其继承树,SubmitButtonTagHelper
最终实现了 ITagHelperComponent
。如果您要添加以下 DI 注册,SubmitButtonTagHelper
将 运行 作为 Tag Helper 组件,一次用于 head
,一次用于 body
:
services.AddTransient<ITagHelperComponent, SubmitButtonTagHelper>();
SubmitButtonTagHelper
是破坏性的,会替换它操作的元素的全部内容。如果要替换 body
元素的内容,正文当然会丢失其 RenderBody
指令。
所以,如果 SubmitButtonTagHelper
被注册为标签助手组件, 可能 会发生什么,这是一个很长的解释。您上传到 GitHub (source):
private static void WebRegistration(ContainerBuilder builder) { builder.RegisterAutowiredAssemblyInterfaces(Assembly.Load(Web)); builder.RegisterAutowiredAssemblyTypes(Assembly.Load(Web)); }
我对 Autofac 了解不多,但很明显,上面显示的对 RegisterAutowiredAssemblyInterfaces
的调用会找到 SubmitButtonTagHelper
并将其注册到其所有接口,包括 ITagHelperComponent
。
同样,我对 Autofac 了解不多,但最终,不打算 运行 作为标签助手组件的标签助手应该被排除在这个自动注册过程之外。这是一个关于如何进行这种过滤的建议,尽管我认为这是一种糟糕的 Autofac 方法:
builder.RegisterAutowiredAssemblyInterfaces(Assembly.Load(Web))
.Where(x => !x.Name.EndsWith("TagHelper"));