Добавление простого TagHelper вызывает эту ошибку: «RenderBody не был вызван для страницы» - PullRequest
3 голосов
/ 26 января 2020

Код доступен здесь

В веб-приложении 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 не был вызван для страницы в /Views/Shared/_Layout.cshtml. Чтобы игнорировать вызов IgnoreBody ().

Я импортировал помощники тегов, добавив эту строку в файл Pages / _ViewImports.cs html:

@addTagHelper *, Web

My _Layout. cs html страница выглядит так:

<!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». Это не правильно?

У меня есть еще один помощник по тегам в моем проекте, и я также заметил, что точка останова в этом классе также используется в тех местах, где я на нее не ссылался.

Я, конечно, делаю что-то глупое, но что?

1 Ответ

4 голосов
/ 02 февраля 2020

ASP. NET Ядро MVC имеет концепцию Компоненты помощника по тегам :

Компонент помощника по тегам - это помощник по тегам, который позволяет вам условно изменить или добавить HTML элементов из серверного кода.

...

Tag Helper Компоненты не требуют регистрации в приложении в _ViewImports.cs html.

...

Два распространенных варианта использования компонентов-помощников тегов:

  1. Ввод в .
  2. Внедрение в .

Также из документов приведена реализация тега Вспомогательный компонент:

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 будет работать как компонент поддержки тегов, один раз для head и один раз для body:

services.AddTransient<ITagHelperComponent, SubmitButtonTagHelper>();

SubmitButtonTagHelper разрушительный, заменяя все содержимое элемента, на котором он работает. Если бы он заменил содержимое элемента body, тело, конечно, потеряло бы свою директиву RenderBody.

Итак, это длинное объяснение того, что может произойти если SubmitButtonTagHelper были зарегистрированы в качестве компонента Tag Helper. Не должно быть слишком удивительно, что именно это происходит в примере, который вы загрузили на GitHub ( source ):

private static void WebRegistration(ContainerBuilder builder)
{
    builder.RegisterAutowiredAssemblyInterfaces(Assembly.Load(Web));
    builder.RegisterAutowiredAssemblyTypes(Assembly.Load(Web));
}

Не знаю Я знаю много об Autofa c, но ясно, что вызов RegisterAutowiredAssemblyInterfaces, показанный выше, находит SubmitButtonTagHelper и регистрирует его для всех его интерфейсов, включая ITagHelperComponent.

Опять же, я не много знаю об Autofa c, но, в конечном итоге, помощники по тегам, которые не предназначены для работы в качестве компонентов-помощников по тегам, должны быть исключены из процесса автоматической регистрации. Вот предложение о том, как сделать эту фильтрацию, хотя я ожидаю, что это ужасный подход Autofa c:

builder.RegisterAutowiredAssemblyInterfaces(Assembly.Load(Web))
    .Where(x => !x.Name.EndsWith("TagHelper"));
...