【问题标题】:Is it possible to execute a ViewComponent inside a controller and store the HTML as a string是否可以在控制器内执行 ViewComponent 并将 HTML 存储为字符串
【发布时间】:2019-08-28 10:43:14
【问题描述】:

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

我查看了一个问题和帖子,但无法找到符合我要求的内容。我目前存储了 ViewComponentResult 以供使用,但 ExecuteResult() 返回 void 所以无法使用它。

我希望能够操纵要执行的视图组件结果,然后返回将发送到浏览器显示的 HTML。然后我可以将其用作电子邮件正文。但是,在不知道结果视图的完整路径的情况下,我目前还没有接近获取 HTML

【问题讨论】:

    标签: c# asp.net-core-mvc asp.net-core-viewcomponent


    【解决方案1】:

    this post 中的一个答案中所述,我能够找到一种完全满足我需要的方法(将返回的 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.
      }
    }
    

    【讨论】:

      【解决方案2】:

      你可以这样做,

      一种方法是制作“你自己的”html 标签(更像是现有的扩展方法)并实现TagHelper

      您可以在覆盖时访问或更改内容,我有一个扩展几个 html 标记的类来管理客户全球化,看看代码,看看这是否对您有帮助。

      在您的页面中,您可以通过添加您的属性来“拥有”一个 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 在没有所有隐私法公开的情况下更详细带有谷歌的 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,另一个基本上是你喜欢的大小。

      【讨论】:

      • 感谢您的帖子。我不确定它是否完全回答了我的问题,但我设法找到了另一个我之前忽略的堆栈溢出帖子。再次感谢。
      猜你喜欢
      • 2022-12-20
      • 2019-09-14
      • 1970-01-01
      • 2021-02-02
      • 2016-09-21
      • 2021-03-27
      • 1970-01-01
      • 1970-01-01
      • 2010-11-03
      相关资源
      最近更新 更多