В компоненте представления, вызываемом как помощник тега, как мы можем получить доступ к внутреннему HTML?

В помощниках по тегам мы можем получить доступ к тегам внутри HTML.

<!-- Index.cshtml -->  
<my-first>
    This is the original Inner HTML from the *.cshtml file.
</my-first>

// MyFirstTagHelper.cs > ProcessAsync
var childContent = await output.GetChildContentAsync();
var innerHtml = childContent.GetContent();

Если мы вызовем компонент представления в качестве помощника по тегам, как мы можем получить доступ к внутреннему HTML?

<vc:my-first>
    This is the original Inner HTML from the *.cshtml file.
</vc:my-first>

// MyFirstViewComponent.cs > InvokeAsync()
var innerHtml = DoMagic();

Несколько дальнейших мыслей:

Я ценю, что мы можем передавать произвольный контент компоненту представления через атрибуты HTML. Это может стать непрактичным, однако, в случае очень большого количества текста, и в этом случае внутренний HTML будет более читабельным и будет иметь лучшую поддержку инструментов.

Некоторые могут также сказать: "Почему бы тогда просто не использовать помощник по тегам?" Что ж, мы хотим связать представление с помощником тега, а помощники тега не поддерживают представления; вместо этого, помощники по тегам требуют, чтобы мы строили весь HTML программно.

Так что мы застряли в тесноте. С одной стороны, нам нужен помощник по тегам, но они не поддерживают представления; с другой стороны, мы можем использовать компонент представления в качестве помощника по тегам, но компоненты представления могут не позволить нам получить доступ к внутреннему HTML.

2 ответа

Решение

Извините, но ответ "Просто используйте помощник по тегам"

Смотрите следующую проблему: https://github.com/aspnet/Mvc/issues/5465

Будучи в состоянии призвать ViewComponent из помощника тега это просто другой способ вызвать его вместо использования @Component.Invoke(),

Я вижу, где это вводит в заблуждение, и я вспоминаю, как видел в руководствах по ASP.NET Core 2.1 заявление о том, что "View Components похожи на Tag Helpers, но более мощны".

Наконец-то появился способ получить наш торт и съесть его! Разрешить вспомогательному тегу использовать представление Razor в качестве источника HTML, но по-прежнему обертывать разметку при использовании на странице Razor.

Используйте помощник тегов, чтобы получить внутренний HTML в виде строки. Затем напрямую задействуйте механизм представления Razor для рендеринга частичного представления в строку. Наконец, используйте замену строки, чтобы поместить внутреннюю строку HTML в нужное место в строке частичного представления.

Ключевым моментом является использование высококачественных ответов StackOverflow, доступных при рендеринге представления Razor в виде строки. См. службу IRazorViewToStringRenderer здесь (здесь написано ASP.NET Core 3.1, но у меня работало в версии 2.2) или в другом месте как Mvc.RenderViewToString.

Тег-помощник:

      // RazorViewTagHelper.cs
using Microsoft.AspNetCore.Razor.TagHelpers;

namespace GetSafetyCone.TagHelpers
{
    public class RazorViewTagHelper : TagHelper
    {
        private IRazorViewToStringRenderer RazorViewToStringRenderer { get; }
        
        public ViewName { get; set; }


        public RazorViewedTagHelperBase(
            IRazorViewToStringRenderer razorViewToStringRenderer)
        {
            this.RazorViewToStringRenderer = razorViewToStringRenderer;
        }

        public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
        {
            var childContent = await output.GetChildContentAsync();

            var childContentString = childContent.GetContent();
        
            var viewHtmlTemplateString = await this.RazorViewToStringRenderer.Render<object>(this.ViewName, null);
            
            var viewHtmlString = viewHtmlTemplateString.Replace("BODY_GOES_HERE", childContentString);

            output.Content.SetHtmlContent(viewHtmlString); // Set the content.
        }
    }
}

Частичное представление, которое вы хотите использовать в качестве источника HTML для вспомогательного тега:

      // ViewXYZ.cshtml
@*
    ViewXYZ to be rendered to string.
*@
// No model specified, so ok model was a null object.
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
    <div class="max-w-3xl mx-auto">
        BODY_GOES_HERE
    </div>
</div>

И вот tag-helper в использовании:

      // YourPage.cshtml
<razor-view view-name="ViewXYZ">
    <p>You should see this content wrapped in the ViewXYZ divs.</p>
</razor-view>

Если вы хотите, вы можете упростить замену строки и использовать тег childContent TagHelperContent непосредственно в качестве модели представления:

      // RazorViewTagHelper.cs
...
var childContent = await output.GetChildContentAsync();

var viewHtmlString = await this.RazorViewToStringRenderer.Render("viewName", childContent);
...

// ViewXYZ.cshtml
...
@model Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContent;
...
<div class="max-w-3xl mx-auto">
    @(this.Model)
</div>
...
Другие вопросы по тегам