使用强类型模型从Razor视图生成HTML邮件时遇空引用错误
Razor页面生成HTML邮件时模型传递失败问题
我尝试用Razor页面生成HTML邮件,无模型时运行正常,但添加强类型模型WelcomeEmailModel并传递变量后,在@Model.UserName处出现错误:'Object reference not set to an instance of an object.',模型未传递到视图。查看ViewData发现Username字段已填充为“Jane Doe”,但谷歌找到的示例均未涉及模型,请问是否可通过此方式传递模型,或需采用其他方式?
相关代码
Razor View
@page @model WelcomeEmailModel <!DOCTYPE html> <html> <head> <title>Welcome to Our Website!</title> </head> <body> <h2>Welcome, @Model.UserName!</h2> <p>Thank you for signing up to our website. We're excited to have you on board!</p> </body> </html>
EmailService.cs
namespace FlightLog.Services { public class EmailService { private readonly EmailClient _emailClient; private readonly string _senderEmailAddress; private readonly IRazorViewEngine _razorViewEngine; private readonly IServiceProvider _serviceProvider; public EmailService(string connectionString, string senderEmailAddress, IRazorViewEngine razorViewEngine, IServiceProvider serviceProvider) { _emailClient = new EmailClient(connectionString); _senderEmailAddress = senderEmailAddress; _razorViewEngine = razorViewEngine; _serviceProvider = serviceProvider; } public async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model) { var actionContext = GetActionContext(); var viewEngineResult = _razorViewEngine.FindView(actionContext, viewName, false); //var viewEngineResult = _razorViewEngine.GetView("~/Views/EmailTemplates", $"{viewName}.cshtml", false); if (!viewEngineResult.Success) { throw new InvalidOperationException($"Unable to find view '{viewName}'"); } using (var sw = new StringWriter()) { var tempDataSerializer = (TempDataSerializer)_serviceProvider.GetService(typeof(TempDataSerializer)); var tempDataProvider = new SessionStateTempDataProvider(tempDataSerializer); var viewContext = new ViewContext( actionContext, viewEngineResult.View, new ViewDataDictionary<TModel>( metadataProvider: new EmptyModelMetadataProvider(), modelState: new ModelStateDictionary()) { Model = model }, new TempDataDictionary(actionContext.HttpContext, tempDataProvider), sw, new HtmlHelperOptions() ); await viewEngineResult.View.RenderAsync(viewContext); return sw.ToString(); } } private ActionContext GetActionContext() { var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider }; return new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); } public async Task SendEmailAsync(string recipient, string subject, string body) { var emailContent = new EmailContent(subject) { Html = body }; var emailMessage = new EmailMessage( _senderEmailAddress, recipient, emailContent); await _emailClient.SendAsync(WaitUntil.Completed, emailMessage, CancellationToken.None); } public async Task SendWelcomeEmailAsync(string recipient, string userName) { var viewModel = new WelcomeEmailModel { UserName = userName }; string emailBody = await RenderViewToStringAsync("WelcomeEmail", viewModel); await SendEmailAsync(recipient, "Welcome to Our Website!", emailBody); } } }
问题原因及解决方法
问题出在你用了带@page指令的Razor页面,而非普通Razor视图。Razor页面是独立的页面组件,自带路由和模型绑定逻辑,直接用IRazorViewEngine渲染时,不会自动接收你传入的模型。
具体修复步骤
- 把Razor页面改成普通Razor视图
删掉Razor文件顶部的@page指令,因为@page会让它变成独立页面,而非可复用的模板。修改后代码如下:
@model WelcomeEmailModel <!DOCTYPE html> <html> <head> <title>Welcome to Our Website!</title> </head> <body> <h2>Welcome, @Model.UserName!</h2> <p>Thank you for signing up to our website. We're excited to have you on board!</p> </body> </html>
- 调整视图查找逻辑
在RenderViewToStringAsync方法中,用GetView替代FindView,因为普通视图不在Razor页面的默认查找路径里。取消注释原有GetView代码并调整路径到你的模板实际存放位置:
// 替换原来的FindView代码 var viewEngineResult = _razorViewEngine.GetView("~/Views/EmailTemplates", $"{viewName}.cshtml", false);
注意:路径要和你项目里模板的实际位置对应,比如存放在Views/Shared下就改成对应路径。
- 验证模型传递
你原有的ViewDataDictionary初始化逻辑是正确的,只要视图改成普通Razor视图,模型就能正常传递,无需修改其他绑定代码。
额外说明
- Razor页面(带
@page)适合做独立业务页面,不适合邮件模板这种需要复用、接收外部模型的场景,普通Razor视图才是正确选择。 - 如果硬要使用Razor页面,需要额外处理页面的模型绑定逻辑,流程会更复杂,不推荐。
内容的提问来源于stack exchange,提问作者Reafidy
相关产品推荐
相关产品推荐

