在Minimal API中将Razor View渲染为字符串实现邮件发送
在ASP.NET Minimal API中使用Razor视图渲染邮件正文
1. 安装必要的NuGet包
首先安装Razor运行时编译相关依赖,确保Minimal API能编译并渲染Razor视图:
Install-Package Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation
2. 配置Program.cs中的服务
Minimal API默认不包含Razor视图相关服务,需要手动注册:
var builder = WebApplication.CreateBuilder(args); // 注册Razor视图服务及运行时编译 builder.Services.AddControllersWithViews() .AddRazorRuntimeCompilation(); // 注册自定义视图渲染服务 builder.Services.AddScoped<IViewRenderService, ViewRenderService>(); // 注册你的邮件发送服务 builder.Services.AddSingleton<YourEmailService>(); var app = builder.Build(); // 其他中间件配置... app.Run();
3. 实现视图渲染服务
编写一个服务类,通过依赖的Razor引擎组件手动构建视图上下文,将视图渲染为字符串:
public interface IViewRenderService { Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model); } public class ViewRenderService : IViewRenderService { private readonly IRazorViewEngine _razorViewEngine; private readonly ITempDataProvider _tempDataProvider; private readonly IServiceProvider _serviceProvider; public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider) { _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; } public async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model) { // 手动构建HttpContext(无请求上下文时也能运行) var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider }; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); // 查找指定视图 var viewResult = _razorViewEngine.FindView(actionContext, viewName, false); if (!viewResult.Success) { throw new InvalidOperationException($"视图 {viewName} 不存在"); } // 用StringWriter捕获渲染结果 using var sw = new StringWriter(); var viewContext = new ViewContext( actionContext, viewResult.View, new ViewDataDictionary<TModel>( new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model }, new TempDataDictionary(httpContext, _tempDataProvider), sw, new HtmlHelperOptions() ); await viewResult.View.RenderAsync(viewContext); return sw.ToString(); } }
4. 创建Razor邮件视图
在项目根目录下创建Views/Email文件夹,添加RequestDenied.cshtml作为邮件模板:
@model YourNamespace.EmailRequestModel <!DOCTYPE html> <html> <head> <style> .email-box { padding: 24px; font-family: 'Segoe UI', Arial, sans-serif; max-width: 600px; margin: 0 auto; } .system-title { color: #2d3748; font-size: 19px; font-weight: 600; margin-bottom: 16px; } .content-text { color: #4a5568; line-height: 1.6; } </style> </head> <body> <div class="email-box"> <h3>请求已拒绝通知</h3> <div class="system-title">系统名称:@Model.SystemName</div> <div class="content-text">您提交的请求已被系统拒绝,请联系管理员了解详细原因。</div> </div> </body> </html>
5. 修改邮件发送方法
注入视图渲染服务,替换原有的硬编码邮件正文:
private readonly IViewRenderService _viewRenderService; private readonly string _eMailFrom; private readonly string _mailServer; // 构造函数注入视图渲染服务 public YourEmailService(IViewRenderService viewRenderService, IConfiguration configuration) { _viewRenderService = viewRenderService; _eMailFrom = configuration["EmailSettings:From"]; _mailServer = configuration["EmailSettings:Server"]; } public async Task<bool> SendRequestDenied(string systemName) { try { var model = new EmailRequestModel { SystemName = systemName }; // 渲染视图为HTML字符串 string emailBody = await _viewRenderService.RenderViewToStringAsync("Email/RequestDenied", model); MailMessage message = new MailMessage(); message.From = new MailAddress(_eMailFrom); message.Subject = $"[{systemName}] 请求已拒绝"; message.Body = emailBody; message.IsBodyHtml = true; List<string> emailRequests = GetListOfEmails(); foreach (string email in emailRequests) { message.To.Add(email); } using SmtpClient smtpClient = new SmtpClient(_mailServer); smtpClient.Send(message); return true; } catch (Exception ex) { // 可添加日志记录逻辑 return false; } }
注意事项
- 视图路径需对应实际文件位置:
Email/RequestDenied对应Views/Email/RequestDenied.cshtml,共享视图可使用Shared/ViewName格式。 - 确保视图文件的"生成操作"设置为"内容",避免编译时被忽略。
- 该方案支持无请求上下文的场景(如后台任务触发邮件),无需依赖HttpContext。
内容的提问来源于stack exchange,提问作者Abdullah Ergun
相关产品推荐
相关产品推荐

