MVC6 TagHelpers с одноразовыми

В старых помощниках HTML MVC можно было использовать IDisposable для переноса содержимого — например, помощник BeginForm автоматически оборачивал *stuff* закрывающим тегом form.

<% using (Html.BeginForm()) {%>
   *stuff*
<% } %> 

Поддерживается ли такая упаковка содержимого с помощью TagHelpers MVC6? Например, я хотел бы это

<widget-box title="My Title">Yay for content!</widget-box>

для расширения в поле виджета начальной загрузки с оберткой div:

<div class="widget-box">
    <div class="widget-header">
        <h4 class="widget-title">My Title</h4>
    </div>
    <div class="widget-body">
        <div class="widget-main">
            Yay for content!
        </div>
    </div>
</div>

Возможно ли это с помощью TagHelpers?

Решение: я превратил ответ @DanielJG в рабочее демо на github, которое потребляет WidgetBoxTagHelper.cs (будет обновляться вместе с Beta/RC/RTM, поскольку я использую библиотеку в своем рабочем приложении)


person fiat    schedule 22.07.2015    source источник


Ответы (1)


Вспомогательные функции тегов должны реализовать интерфейс ITagHelper (как указал @NTaylorMullen, класс TagHelper — это просто вспомогательный класс, который вы можете использовать при его реализации), что заставляет вас использовать методы Process и ProcessAsync, поэтому вы нельзя полагаться на добавление содержимого в метод Dispose.

Однако у вас есть полный контроль над выходным содержимым, поэтому вы можете заменять/изменять его по мере необходимости. Например, краткое приближение к вашему вспомогательному тегу виджета (Использование версии 1.0 фреймворка):

[HtmlTargetElement("widget-box")]
public class WidgetTagHelper : TagHelper
{
    public string Title { get; set; }

    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        var outerTag = new TagBuilder("div");
        outerTag.Attributes.Add("class", output.TagName);
        output.MergeAttributes(outerTag);
        output.TagName = outerTag.TagName;

        //Create the header
        var header = new TagBuilder("div");
        header.Attributes.Add("class", "widget-header");
        header.InnerHtml.Append(this.Title);
        output.PreContent.SetHtmlContent(header);

        //Create the body and replace original tag helper content
        var body = new TagBuilder("div");
        body.Attributes.Add("class", "widget-body");
        var originalContents = await output.GetChildContentAsync();
        body.InnerHtml.Append(originalContents.GetContent());
        output.Content.SetHtmlContent(body);
    }
}

В вашей бритве будет:

<widget-box title="My Title">Yay for content!</widget-box>

Что будет отображаться как:

<div class="widget-box">
    <div class="widget-header">My Title</div>
    <div class="widget-body">Yay for content!</div>
</div>

Не забудьте зарегистрировать вспомогательные функции тегов в своей сборке, добавив директиву @addTagHelper в файл _ViewImports.cshtml. Например, это зарегистрирует всех помощников в моем приложении:

@addTagHelper *, WebApplication2

СТАРЫЙ код бета7

  • В beta7 вам приходилось использовать атрибут [TargetElement].
  • У класса TagBuilder был метод SetInnerText, который вы могли использовать для установки его контекста в виде текста.

Код выглядел так:

[TargetElement("widget-box")]
public class WidgetTagHelper : TagHelper
{
    private IHtmlEncoder encoder;
    public WidgetTagHelper(IHtmlEncoder encoder)
    {
        this.encoder = encoder;
    }

    public string Title { get; set; }

    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        var outerTag = new TagBuilder("div");
        outerTag.Attributes.Add("class", output.TagName);
        output.MergeAttributes(outerTag);
        output.TagName = outerTag.TagName;

        //Create the header
        var header = new TagBuilder("div");
        header.Attributes.Add("class", "widget-header");
        header.SetInnerText(this.Title);
        output.PreContent.SetContent(header);

        //Create the body and replace original tag helper content
        var body = new TagBuilder("div");
        body.Attributes.Add("class", "widget-body");
        var originalContents = await context.GetChildContentAsync();           
        using (var writer = new StringWriter())
        {
            body.TagRenderMode = TagRenderMode.StartTag;
            body.WriteTo(writer, encoder);
            originalContents.WriteTo(writer, encoder);
            body.TagRenderMode = TagRenderMode.EndTag;
            body.WriteTo(writer, encoder);
            output.Content.SetContent(writer.ToString());
        }                            
    }
}

СТАРЫЙ код beta5

  • В помощниках тегов было свойство InnerHtml.
  • В хелперах тегов был метод ToHtmlString, используемый для рендеринга их как html.

Код выглядел так:

[TargetElement("widget-box")]
public class WidgetTagHelper: TagHelper
{
    public string Title { get; set; }

    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        var outerTag = new TagBuilder("div");
        outerTag.Attributes.Add("class", output.TagName);
        output.MergeAttributes(outerTag);
        output.TagName = outerTag.TagName;

        //Create the header
        var header = new TagBuilder("div");
        header.Attributes.Add("class", "widget-header");
        header.InnerHtml = this.Title;
        output.PreContent.SetContent(header.ToHtmlString(TagRenderMode.Normal).ToString());

        //Create the body and replace original tag helper content
        var body = new TagBuilder("div");
        body.Attributes.Add("class", "widget-body");
        var originalContents = await context.GetChildContentAsync();
        body.InnerHtml = originalContents.GetContent();
        output.Content.SetContent(body.ToHtmlString(TagRenderMode.Normal).ToString());
    }
}
person Daniel J.G.    schedule 22.07.2015
comment
Пожалуйста, @fiat. Интересно поиграться с asp .net 5 :). Кстати, я только что видел ваш репозиторий на github, хорошая идея! - person Daniel J.G.; 22.07.2015
comment
Дополнительное примечание: чтобы быть действительным TagHelper, вам просто нужно реализовать интерфейс ITagHelper. Класс TagHelper — это просто хорошая базовая реализация :) - person N. Taylor Mullen; 05.08.2015
comment
В BETA 8 TagBuilder больше не имеет метода SetInnerText, поэтому код не работает. Вы получаете только внутренний текст - person devfric; 12.11.2015
comment
@firste, у меня наконец-то появилось время попробовать версию RC1 ASP 5 и обновить код - person Daniel J.G.; 18.11.2015