使用RazorEngine生成HTML邮件模板时遇System.CodeDom加载失败问题
解决ASP.NET Core MVC中RazorEngine调用时找不到System.CodeDom的问题
问题描述
在ASP.NET Core MVC项目中使用RazorEngine的Engine.Razor.RunCompile()或TemplateService.Parse()方法生成HTML邮件模板时,触发以下运行时错误:
System.IO.FileNotFoundException: 'Could not load file or assembly 'System.CodeDom, Version=0.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.'
即使是极简示例也会触发错误:
using RazorEngine; using RazorEngine.Templating; string template = "Hello @Model.Name, welcome to RazorEngine!"; var result = Engine.Razor.RunCompile(template, "templateKey", null, new { Name = "World" });
用户已安装RazorEngine包,参考官方文档及相关方案未解决,测试代码如下:
using Microsoft.AspNetCore.Mvc; using OperationalForecast.Models; using OperationalForecast.Models.EmailTemplateModels; using OperationalForecast.Services; using RazorEngine; using RazorEngine.Configuration; using RazorEngine.Templating; using System.Diagnostics; using System.Reflection; using System.Text; namespace OperationalForecast.Controllers { public class HomeController : Controller { private readonly ILogger<HomeController> _logger; private IDistrictServices districtlist { get; set; } private IEmailServices emailservices { get; set; } public HomeController(ILogger<HomeController> logger, IDistrictServices dataservice, IEmailServices emailservices) { _logger = logger; districtlist = dataservice; this.emailservices = emailservices; } public IActionResult Index() { return View(districtlist.GetAllDistricts()); } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } public string SendTestEmail2() // 测试模板渲染的方法 { string template = "Hello @Model.Name, welcome to RazorEngine!"; var result = Engine.Razor.RunCompile(template, "templateKey", null, new { Name = "World" }); var approvaltemplate = new ApprovalEmailTemplate {district_name ="Akron", hire_date=new DateTime(2024,1,1), class_size=10, forecasted_need=5 }; string forparsing = @"class size is @Model.class_size"; var templateService = new TemplateService(); var emailhtmlbody = Engine.Razor.RunCompile(forparsing, "CreatedNewHireClassApproval", null, approvaltemplate); EmailModel newEmail = new EmailModel { ToEmail = "tristenhannah@usicllc.com", Subject = "test", Body = emailhtmlbody, IsHtml = true }; return emailservices.SendEmail(newEmail).ToString(); } } }
解决方案
方案一:修复RazorEngine依赖问题
RazorEngine是针对.NET Framework开发的旧库,在.NET Core环境下需要手动补充缺失的依赖:
- 安装
System.CodeDomNuGet包:
在NuGet包管理器中搜索并安装System.CodeDom,或使用命令行:Install-Package System.CodeDom - 如果项目是.NET 5+,需确保项目文件(.csproj)中包含以下引用:
<ItemGroup> <PackageReference Include="System.CodeDom" Version="7.0.0" /> </ItemGroup>
方案二:替换为ASP.NET Core原生Razor视图渲染(推荐)
RazorEngine对.NET Core的兼容性较差,官方原生的Razor视图引擎更稳定可靠,步骤如下:
创建邮件模板视图
在项目中创建Views/EmailTemplates目录,添加ApprovalEmail.cshtml模板文件:@model ApprovalEmailTemplate <html> <body> <p>地区:@Model.district_name</p> <p>入职日期:@Model.hire_date.ToString("yyyy-MM-dd")</p> <p>班级规模:@Model.class_size</p> <p>预计需求:@Model.forecasted_need</p> </body> </html>封装视图渲染服务
创建一个服务类用于渲染Razor视图为字符串:using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Razor; using System.IO; using System.Threading.Tasks; public class RazorViewRenderer { private readonly IRazorViewEngine _viewEngine; private readonly ITempDataProvider _tempDataProvider; private readonly IServiceProvider _serviceProvider; public RazorViewRenderer(IRazorViewEngine viewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider) { _viewEngine = viewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; } public async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model) { var actionContext = new ActionContext(new DefaultHttpContext { RequestServices = _serviceProvider }, new System.Routing.RouteData(), new ActionDescriptor()); using var sw = new StringWriter(); var viewResult = _viewEngine.FindView(actionContext, viewName, false); if (!viewResult.Success) { throw new FileNotFoundException("视图未找到", viewName); } var viewDictionary = new ViewDataDictionary<TModel>(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model }; var viewContext = new ViewContext( actionContext, viewResult.View, viewDictionary, new TempDataDictionary(actionContext.HttpContext, _tempDataProvider), sw, new HtmlHelperOptions() ); await viewResult.View.RenderAsync(viewContext); return sw.ToString(); } }注册服务并使用
在Program.cs中注册服务:builder.Services.AddScoped<RazorViewRenderer>();在HomeController中修改测试方法:
private readonly RazorViewRenderer _razorViewRenderer; // 构造函数注入 public HomeController(ILogger<HomeController> logger, IDistrictServices dataservice, IEmailServices emailservices, RazorViewRenderer razorViewRenderer) { _logger = logger; districtlist = dataservice; this.emailservices = emailservices; _razorViewRenderer = razorViewRenderer; } public async Task<string> SendTestEmail2() { var approvaltemplate = new ApprovalEmailTemplate { district_name = "Akron", hire_date = new DateTime(2024,1,1), class_size = 10, forecasted_need = 5 }; // 渲染原生Razor视图 var emailhtmlbody = await _razorViewRenderer.RenderViewToStringAsync("EmailTemplates/ApprovalEmail", approvaltemplate); EmailModel newEmail = new EmailModel { ToEmail = "tristenhannah@usicllc.com", Subject = "test", Body = emailhtmlbody, IsHtml = true }; return emailservices.SendEmail(newEmail).ToString(); }
内容的提问来源于stack exchange,提问作者Tristen Hannah
相关产品推荐
相关产品推荐

