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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 04:06:02