将ASP.NET MVC视图作为HTML文件返回,以便在电子邮件模板中使用
本文关键字:电子邮件 返回 MVC NET ASP 视图 文件 HTML | 更新日期: 2023-09-27 18:20:09
我正在构建一个应用程序,该应用程序将向最终用户发送自定义电子邮件。
我已经构建了一个HTML模板,电子邮件将从中构建。
我目前已经用标签填充模板作为自定义内容的占位符。。。
|Text-Placeholder|
我一直将html文件作为字符串返回到我的CreateEMail方法:
string html = System.IO.File.ReadAllText(Server.MapPath("~/EmailTemplates/emailTemplate.html"));
然后使用String.Replace在自定义文本/内容中进行替换
html = html.Replace("|Name-Placeholder|", username);
我很好奇是否有一种方法可以让我将模板构造为RazorView,强类型为ViewModel,它将对自定义文本/内容进行建模,并将视图作为HTML文件或直接作为字符串返回,以传递到我的SMTPClient实例的主体属性中,发送给用户?
有人完成过这样或类似的事情吗?
看看这些库:
有ActionMailer。灵感来自Ruby的ActionMailer。
ActionMailer.Net旨在成为从ASP.Net MVC应用程序发送电子邮件的一种简单且相对无痛的方式。这个概念很简单。我们通过使用一些非常时髦的视图引擎来渲染HTML,那么为什么我们不能对电子邮件做同样的事情呢?
http://nuget.org/packages/ActionMailer
我认为支持许多视图引擎,当然包括Razor。并允许您将模型传递到视图中。请参阅:https://bitbucket.org/swaj/actionmailer.net/wiki/Home
代码:
public class MailController : MailerBase
{
public EmailResult VerificationEmail(User model)
{
To.Add(model.EmailAddress);
From = "no-reply@mycoolsite.com";
Subject = "Welcome to My Cool Site!";
return Email("VerificationEmail", model);
}
}
视图:
@using ActionMailer.Net
@model User
@{
Layout = null;
}
Welcome to My Cool Site, @Model.FirstName. We need you to verify your email.
Click this nifty link to get verified!
还有另一个库:
MvcMailer允许您使用MVC视图生成令人惊叹的电子邮件
http://nuget.org/packages/MvcMailer
https://github.com/smsohan/MvcMailer
您可以使用此帮助程序从视图中剥离Html。方法也接受一个模型,视图以编程方式呈现,其输出以字符串形式返回。或多或少与Asp.net中LoadControl的概念相同:
public static string RenderPartialToString(ControllerContext context, string partialViewName, ViewDataDictionary viewData, TempDataDictionary tempData)
{
var viewEngineResult = ViewEngines.Engines.FindPartialView(context, partialViewName);
if (viewEngineResult.View != null)
{
var stringBuilder = new StringBuilder();
using (var stringWriter = new StringWriter(stringBuilder))
{
using (var output = new HtmlTextWriter(stringWriter))
{
ViewContext viewContext = new ViewContext(context, viewEngineResult.View, viewData, tempData, output);
viewEngineResult.View.Render(viewContext, output);
}
}
return stringBuilder.ToString();
}
//return string.Empty;
throw new FileNotFoundException("The view cannot be found", partialViewName);
}
以下是检索视图内容的位置
//The welcome email is in the Shared/Email folder
string partialViewHtml = EmailHelpers.RenderPartialToString(this.ControllerContext, "Email/Welcome", new ViewDataDictionary(modelForPartialView), new TempDataDictionary());
上面所有解决方案的问题是它们不是线程安全的!。
如果要从其他线程渲染视图,该怎么办?(用于电子邮件)
在这种情况下,ControllerContext不再相关,控制器也不再相关
对于这些情况,我建议以下解决方案:
ThreadPool.QueueUserWorkItem(_ =>
{
var model = new TestMailModel() { Sender = "yakirmanor", Recipient = "yakirmanor@notrealmail.com", Description = "some desc" };
string test1 = ControllerExtensions.RenderView("Mail", "TestMail", model);
string test2 = this.RenderView("TestMail", model);
string test3 = this.RenderView(model);
// now send the mail
//MailHelper.SendEmail("yakirmanor@notrealmail.com", "subject", test1, "username", "password");
});
在这里,您可以看到我在Mail控制器中调用TestMail方法,也在当前控制器中调用TestMail
创建文本
public static class ControllerExtensions
{
public static string RenderView(this Controller controller, object model)
{
string viewName = controller.ControllerContext.RouteData.Values["action"].ToString();
string controllerName = controller.ControllerContext.RouteData.Values["controller"].ToString();
return RenderView(controllerName, viewName, model);
}
public static string RenderView(this Controller controller, string viewName, object model)
{
string controllerName = controller.ControllerContext.RouteData.Values["controller"].ToString();
return RenderView(controllerName, viewName, model);
}
public static string RenderView(string controllerName, string viewName, object viewData)
{
//Create memory writer
var writer = new StringWriter();
var routeData = new RouteData();
routeData.Values.Add("controller", controllerName);
//Create fake http context to render the view
var fakeRequest = new HttpRequest(null, "http://tempuri.org", null);
var fakeResponse = new HttpResponse(null);
var fakeContext = new HttpContext(fakeRequest, fakeResponse);
var fakeControllerContext = new ControllerContext(new HttpContextWrapper(fakeContext), routeData, new FakeController());
var razorViewEngine = new RazorViewEngine();
var razorViewResult = razorViewEngine.FindView(fakeControllerContext,viewName,"",false);
var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, new ViewDataDictionary(viewData), new TempDataDictionary(), writer);
razorViewResult.View.Render(viewContext, writer);
return writer.ToString();
}
}
要使用您需要添加模型和伪控制器的代码
public class TestMailModel
{
public string Sender { get; set; }
public string Recipient { get; set; }
public string Description { get; set; }
}
class FakeController : ControllerBase
{
protected override void ExecuteCore() { }
}
视图可能是这样的:
@model Phytech.PhyToWeb.Controllers.TestMailModel
@{
Layout = null;
}
<table cellpadding="8" cellspacing="0" style="width: 100%!important; background: #ffffff; margin: 0; padding: 0" border="0">
<tbody><tr><td valign="top">
Hi @Model.Recipient youve got mail from @Model.Sender about @Model.Description
</td></tr></tbody>
</table>
作为一个小建议,使用资源而不是占位符。你创建了一个资源文件,比如在名为EMail.resx的~/Content目录中,并将你的令牌添加到其中。在视图中,你可以像@EMail.Name
和@EMail.Address
一样引用它们。好处是,如果明天你需要用法语发送邮件,你可以用所有相同的令牌创建一个EMail.fr.resx,这样你就完成了