You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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环境下需要手动补充缺失的依赖:

  1. 安装System.CodeDom NuGet包:
    在NuGet包管理器中搜索并安装System.CodeDom,或使用命令行:
    Install-Package System.CodeDom
    
  2. 如果项目是.NET 5+,需确保项目文件(.csproj)中包含以下引用:
    <ItemGroup>
      <PackageReference Include="System.CodeDom" Version="7.0.0" />
    </ItemGroup>
    

方案二:替换为ASP.NET Core原生Razor视图渲染(推荐)

RazorEngine对.NET Core的兼容性较差,官方原生的Razor视图引擎更稳定可靠,步骤如下:

  1. 创建邮件模板视图
    在项目中创建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>
    
  2. 封装视图渲染服务
    创建一个服务类用于渲染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();
        }
    }
    
  3. 注册服务并使用
    在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 03:10:06