是否可以在控制器内执行 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.
}
}
我目前有几个在许多不同地方使用的视图组件。我希望能够将调用视图组件时生成的结果 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.
}
}