我正在尝试从 Razor 页面生成 HTML 电子邮件。这对于没有任何模型的 HTML 非常有效。但是,当我添加模型“WelcomeEmailModel”并尝试传递变量时,我在“@Model.UserName”参数上收到以下错误。
“未将对象引用设置为对象的实例。”
模型未传递到视图。
我可以在 ViewData 中看到(见下图),模型“用户名”填充有“Jane Doe”。
我通过谷歌找到的例子不包含模型。是否可以通过这种方式发送模型,还是应该通过其他方式传递模型?
剃刀视图
@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>
电子邮件服务.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);
}
}
}
请务必删除 razor 视图中的
@page
,因为您的自定义 RenderViewToStringAsync
方法用于渲染 razor 视图,而不是渲染 razor 页面到字符串。
razor 视图和 razor 页面的区别:
Razor Pages 可以使以页面为中心的场景编码比使用控制器和视图更容易、更高效。它的不同之处在于
@page
指令。 @page
使文件成为 MVC 操作,这意味着它直接处理请求,而不通过控制器。 @page
必须是页面上的第一个 Razor 指令。 @page
影响其他 Razor 构造的行为。