是否可以在控制器内执行 ViewComponent 并将 HTML 存储为字符串

Is it possible to execute a ViewComponent inside a controller and store the HTML as a string

我目前有几个在许多不同地方使用的视图组件。我希望能够将调用视图组件时生成的结果 HTML 存储到字符串变量中,以便我可以将 HTML 用于其他目的(例如电子邮件)。

我查看了一些问题和帖子,但没能找到符合我要求的内容。我目前存储了 ViewComponentResult 以供使用,但 ExecuteResult() return无效,因此无法使用它。

我希望能够操纵要执行的视图组件结果,然后 return 将 HTML 发送到浏览器进行显示。然后我可以将其用作电子邮件正文。但是,在不知道结果视图

的完整路径的情况下,我目前离获得 HTML 还差得很远

好吧,你可以做到,

一种方法是创建 "your own" html 标记(更像是现有的扩展方法)并实现 TagHelper

您可以在重写时访问或更改内容,我有一个 class 扩展了几个 html 标签来管理客户全球化,看看代码,看看这个帮助你。

在您的页面中,您可以通过添加您的属性来 "take ownership" html,就像我在此处使用我的属性 cats-language-key 演示的那样:

<div cats-language-key="Home-S2-h1-p1">

</p>

[HtmlTargetElement("p",Attributes = CatsLanguageKey)]
[HtmlTargetElement("span", Attributes = CatsLanguageKey)]
[HtmlTargetElement("a", Attributes = CatsLanguageKey)]
[HtmlTargetElement("li", Attributes = CatsLanguageKey)]
[HtmlTargetElement("h1", Attributes = CatsLanguageKey)]
[HtmlTargetElement("h2", Attributes = CatsLanguageKey)]
[HtmlTargetElement("h3", Attributes = CatsLanguageKey)]
[HtmlTargetElement("h4", Attributes = CatsLanguageKey)]
[HtmlTargetElement("div", Attributes = CatsLanguageKey)]
public class LanguageTagHelper: TagHelper
{
    private const string CatsLanguageKey= "cats-language-key";

    private readonly ILanguageRepository _repository;
    private readonly ClaimsPrincipal _user;
    private readonly IMemoryCache _memoryCache;

    public LanguageTagHelper(ILanguageRepository repository, IHttpContextAccessor context, IMemoryCache memoryCache)
    {
        _repository = repository;
        _user = context.HttpContext.User;
        _memoryCache = memoryCache;
    }

    [HtmlAttributeName(CatsLanguageKey)]
    public string Key { get; set; }



    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {




        var childContent = await output.GetChildContentAsync();
        if (!childContent.IsEmptyOrWhiteSpace)
        {
            var textItem = _repository.GetHtml(Key, childContent.GetContent().Trim());
            if (_user.Identity.IsAuthenticated && _user.IsInRole(MagicStrings.ROLE_TEXTER))
            {
                output.Attributes.Add("data-language-target", textItem.Language);
                output.Attributes.Add("data-language-key", textItem.Key);
                var html = new HtmlString(textItem.Text);
                output.Content.SetHtmlContent(html);

                _memoryCache.Remove(Key);
            }
            else
            {
                string text = string.Empty;
                if (!_memoryCache.TryGetValue(Key, out text))
                {
                    text = Regex.Replace(textItem.Text, @">\s+<", "><", RegexOptions.Compiled | RegexOptions.Multiline);
                    text = Regex.Replace(text, @"<!--(?!\s*(?:\[if [^\]]+]|<!|>))(?:(?!-->)(.|\n))*-->", "", RegexOptions.Compiled | RegexOptions.Multiline);
                    text = Regex.Replace(text, @"^\s+", "", RegexOptions.Compiled | RegexOptions.Multiline);
                    text = Regex.Replace(text, @"\r\n?|\n", "", RegexOptions.Compiled | RegexOptions.Multiline);
                    text = Regex.Replace(text, @"\s+", " ", RegexOptions.Compiled | RegexOptions.Multiline);
                    _memoryCache.Set(Key, text, new MemoryCacheEntryOptions() { Priority= CacheItemPriority.Low, SlidingExpiration= new TimeSpan(hours:1,minutes:0,seconds:0) });
                }
                var html = new HtmlString(text);
                output.Content.SetHtmlContent(html);

            }


        }
    }
}

在更改整个页面时我必须做的另一件事是向我的 MidleWare 添加一些功能。我们注意到我们的页面返回的 HTML 相当臃肿,在不需要的地方有空字符串和填充,然后我缩小了页面(在 JavaScript 中保留空格和换行符)

public static class BuilderExtensions
{
    public static IApplicationBuilder UseHTMLMinification(this IApplicationBuilder app)
    {
        return app.UseMiddleware<HtmlMinificationMiddleware>();
    }
    public static IApplicationBuilder UseHTMLMinification(this IApplicationBuilder app,
        string excludeFilter)
    {
        var options = new HtmlMinificationOptions() { ExcludeFilter = excludeFilter };
        return app.UseMiddleware<HtmlMinificationMiddleware>(options);
    }
    public static IApplicationBuilder UseHTMLMinification(this IApplicationBuilder app,
        HtmlMinificationOptions minificationOptions)
    {
        return app.UseMiddleware<HtmlMinificationMiddleware>(minificationOptions);
    }
///so other options
}

HtmlMinificationMiddleware 看起来像这样,请注意您不会有 StatsRepository 但您可以从示例中编辑它或用您自己的替换它,StatsRepository 维护页面统计信息比 google 没有的更详细googles AddSence 或 AWStats 附带的所有隐私法曝光都是实时的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using System.IO;
using System.Threading.Tasks;
using System.Text;
using System.Text.RegularExpressions;
namespace CATS.Web.Shared.Infrastructure.Middleware
{

    using CATS.Web.Shared.Repositories;

    public class HtmlMinificationMiddleware
    {
        private RequestDelegate _next;
        StatsRepository _stats;
        private HtmlMinificationOptions _minificationOptions;
        public HtmlMinificationMiddleware(RequestDelegate next, StatsRepository stats)
            : this(next, null, stats)
        {
        }
        public HtmlMinificationMiddleware(RequestDelegate next, HtmlMinificationOptions minificationOptions, StatsRepository stats)
        {
            _next = next;
            _minificationOptions = minificationOptions;
            _stats = stats;
        }
        public async Task Invoke(HttpContext context)
        {
            var stream = context.Response.Body;
            if (_minificationOptions != null)
            {
                var filter = _minificationOptions.ExcludeFilter;
                if (Regex.IsMatch(context.Request.Path, filter))
                {
                    await _next(context);
                    return;
                }
            }
            long size = 0;
            try
            {
                using (var buffer = new MemoryStream())
                {
                    context.Response.Body = buffer;
                    await _next(context);
                    var isHtml = context.Response.ContentType?.ToLower().Contains("text/html");

                    buffer.Seek(0, SeekOrigin.Begin);
                    using (var reader = new StreamReader(buffer))
                    {
                        string responseBody = await reader.ReadToEndAsync();
                        var backup = string.Copy(responseBody);
                        if (context.Response.StatusCode == 200 && isHtml.GetValueOrDefault())
                        {
                            try
                            {
                                responseBody = Regex.Replace(responseBody, @">\s+<", "><", RegexOptions.Compiled | RegexOptions.Multiline);
                                responseBody = Regex.Replace(responseBody, @"<!--(?!\s*(?:\[if [^\]]+]|<!|>))(?:(?!-->)(.|\n))*-->", "", RegexOptions.Compiled | RegexOptions.Multiline);
                                responseBody = Regex.Replace(responseBody, @"\r\n?|\n", "", RegexOptions.Compiled | RegexOptions.Multiline);
                                responseBody = Regex.Replace(responseBody, @"\s+", " ", RegexOptions.Compiled | RegexOptions.Multiline);
                                if (string.IsNullOrWhiteSpace(responseBody))
                                    responseBody = backup;
                            } catch
                            {
                                responseBody = backup;
                            }
                        }
                        var bytes = Encoding.UTF8.GetBytes(responseBody);
                        using (var memoryStream = new MemoryStream(bytes))
                        {
                            memoryStream.Seek(0, SeekOrigin.Begin);
                            await memoryStream.CopyToAsync(stream);
                        }
                        size = bytes.LongLength;
                        await _stats.UpdateRequestSize(context, size);
                    }

                }
            }
            finally
            {

                context.Response.Body = stream;
            }

        }
    }

}
public class HtmlMinificationOptions
{
    public string ExcludeFilter { get; set; }
}

我做的管道配置是这样的:

namespace CATS.Web.Shared.Infrastructure.Middleware
{
    using Microsoft.AspNetCore.Builder;
    public class HtmlMinificationPipeline
    {
        public void Configure(IApplicationBuilder applicationBuilder)
        {
            applicationBuilder.UseHTMLMinification();
        }
    }

}

所以,我给了你 2 个选项 1 在标签级别说一个 div,另一个基本上和你喜欢的一样大。

我能够找到一种方法,它完全符合我的需要(将返回的 HTML 作为字符串获取),如 中的一个答案所述。

我使用的代码块是..

public async Task<string> RenderViewComponent(string viewComponent, object args) {

  var sp = HttpContext.RequestServices;

  var helper = new DefaultViewComponentHelper(
    sp.GetRequiredService<IViewComponentDescriptorCollectionProvider>(),
    HtmlEncoder.Default,
    sp.GetRequiredService<IViewComponentSelector>(),
    sp.GetRequiredService<IViewComponentInvokerFactory>(),
    sp.GetRequiredService<IViewBufferScope>());

  using (var writer = new StringWriter()) {
    var context = new ViewContext(ControllerContext, NullView.Instance, ViewData, TempData, writer, new HtmlHelperOptions());
    helper.Contextualize(context);
    var result = await helper.InvokeAsync(viewComponent, args);
    result.WriteTo(writer, HtmlEncoder.Default);
    await writer.FlushAsync();
    return writer.
  }
}