Asp.Net Core 3.1 发送邮件时如何将带模型的cshtml模板转为字符串作为邮件正文
Asp.Net Core 3.1 实现CSHTML模板转字符串方案
实现逻辑
通过Asp.Net Core自带的IRazorViewEngine组件封装通用的视图渲染服务,将绑定了模型的cshtml模板渲染为HTML字符串,直接用作邮件正文。
步骤1:创建视图渲染服务
首先定义服务接口与对应实现:
// 服务接口 public interface IRazorViewRenderer { /// <summary> /// 将cshtml视图渲染为字符串 /// </summary> /// <param name="viewName">视图名称/路径</param> /// <param name="model">视图绑定的模型实例</param> /// <typeparam name="TModel">模型类型</typeparam> Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model); } // 服务实现 public class RazorViewRenderer : IRazorViewRenderer { private readonly IRazorViewEngine _razorViewEngine; private readonly ITempDataProvider _tempDataProvider; private readonly IServiceProvider _serviceProvider; public RazorViewRenderer(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider) { _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; } public async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model) { var httpContext = _serviceProvider.GetRequiredService<IHttpContextAccessor>().HttpContext; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); using var stringWriter = new StringWriter(); // 查找视图,若视图在非标准路径可替换为GetView方法传入完整路径 var viewResult = _razorViewEngine.FindView(actionContext, viewName, false); if (viewResult.View == null) { throw new FileNotFoundException($"未找到指定视图:{viewName}"); } var viewData = new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model }; var tempData = new TempDataDictionary(httpContext, _tempDataProvider); var viewContext = new ViewContext(actionContext, viewResult.View, viewData, tempData, stringWriter, new HtmlHelperOptions()); await viewResult.View.RenderAsync(viewContext); return stringWriter.ToString(); } }
步骤2:注册服务到DI容器
在Startup.cs的ConfigureServices方法中添加服务注册:
public void ConfigureServices(IServiceCollection services) { // 其他服务注册... services.AddControllersWithViews(); // 已注册MVC服务可忽略此行 services.AddHttpContextAccessor(); services.AddScoped<IRazorViewRenderer, RazorViewRenderer>(); }
步骤3:调用服务获取邮件正文
在发邮件的逻辑中注入IRazorViewRenderer,调用方法渲染模板后赋值给MailMessage.Body即可:
// 注入服务 private readonly IRazorViewRenderer _viewRenderer; public 你的业务类名(IRazorViewRenderer viewRenderer) { _viewRenderer = viewRenderer; } // 发邮件逻辑 public async Task SendEmailAsync(string to, string subject) { // 构造cshtml对应的模型实例,和模板声明的@model类型匹配 var emailModel = new 你的模型类 { // 赋值模型属性 }; // 渲染cshtml为字符串,参数为视图名称(如模板放在Views/Shared/EmailTemplate.cshtml则传EmailTemplate) string emailBody = await _viewRenderer.RenderViewToStringAsync("EmailTemplate", emailModel); MailMessage mail = new MailMessage(); mail.To.Add(to); mail.Subject = subject; mail.Body = emailBody; mail.IsBodyHtml = true; // 必须设置为true才能正确解析HTML内容 // 后续发送邮件逻辑... }
注意事项
- cshtml模板顶部必须声明
@model 你的模型类全路径,传入的模型实例类型要和声明一致 - 如果模板不在
Views目录的标准子路径下,调用RenderViewToStringAsync时需要传入完整相对路径,例如/Views/Emails/OrderNotice.cshtml - 视图渲染报错优先排查视图路径是否正确、模型属性是否和模板调用一致
内容的提问来源于stack exchange,提问作者KasraRS
相关产品推荐
相关产品推荐

