在作为标签助手调用的视图组件中,我们如何访问内部 HTML?

In a view component invoked as a tag helper, how can we access the inner 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();

如果我们invoke a view component as a tag helper,我们如何访问内部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 将更具可读性并且具有更好的工具支持。

也有人会说,"Why not just use a tag helper, then?"好吧,我们要关联一个view和tag helper,tag helper不支持view;相反,标签助手要求我们以编程方式构建所有 HTML。

所以我们陷入了困境。一方面,我们想要一个标签助手,但它们不支持视图;另一方面,我们可以使用视图组件作为标签助手,但视图组件可能不允许我们访问内部 HTML。

抱歉,答案是 "Just use a tag helper"

请参阅以下问题:https://github.com/aspnet/Mvc/issues/5465

能够从标签助手调用 ViewComponent 只是一种不同的调用方式,而不是使用 @Component.Invoke()

我能看出这是误导的地方,我确实记得在 ASP.NET 核心 2.1 教程中看到过关于 "View Components are like Tag Helpers, but more powerful."

效果的声明

终于有办法既吃蛋糕又吃蛋糕了!允许标签助手使用 Razor 视图作为其 HTML 的来源,但在 Razor 页面中使用时仍然包装标记。

使用标签助手将内部 HTML 作为字符串获取。然后直接操作Razor视图引擎将分部视图渲染成字符串。最后,使用字符串替换将内部 HTML 字符串放入局部视图字符串中的正确位置。

关键是在将 Razor 视图呈现为字符串时使用高质量的 Whosebug 答案。请参阅 IRazorViewToStringRenderer 服务 (it says ASP.NET Core 3.1 but worked for me in 2.2), or elsewhere as 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>

这是正在使用的标签助手:

// 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>
...