gpt4 book ai didi

c# - 在 ASP.NET MVC 项目中使用 Razor 生成电子邮件 HTML

转载 作者:太空宇宙 更新时间:2023-11-03 12:20:50 25 4
gpt4 key购买 nike

我有一个 ASP.NET MVC 项目,它使用 Razor 通过内置引擎呈现 HTML。

我想使用相同的过程创建电子邮件模板。通常,这些模板是作为 Action Context 的一部分创建的(例如,当用户完成购买时,将发送通知)。但是,有些情况下没有可用的上下文。例如,在应用程序重新启动时发送日志。

这是我到目前为止的想法:

public static string RenderRazor(ViewTemplateType TemplateType, string ViewName, PageController Controller = null, object Model = null)
{
try
{
ControllerContext Context;

if (Controller != null)
{
Context = Controller.ControllerContext;
}
else
{
if (HttpContext.Current == null)
{
throw new InvalidOperationException("Cannot render a razor template if the current context is null (See DEV-1669).");
}
var RouteData = new RouteData();
RouteData.Values.Add("controller", "Pseudo");
Controller = new PseudoController(Model);
Context = new ControllerContext(new HttpContextWrapper(HttpContext.Current), RouteData, Controller);
// If this isn't set, an error occurs when calling FindView/FindViewPartial.
Controller.ControllerContext = Context;
}

// I'm not really sure what the point of this is...
// Further, it was actually causing an exception to occur since the Controller may not actually be populated?
// Without this, the Notification Debug wasn't working - so apparently it is required in some circumstances for notifications.
if (Controller != null && Controller.ViewData != null && Model != null) { Controller.ViewData.Model = Model; }

var ViewResult = ViewName.StartsWith("_")
? ViewEngines.Engines.FindPartialView(Context, string.Format("~/Views/Template/{0}/{1}.cshtml", TemplateType, ViewName))
: ViewEngines.Engines.FindView(Context, string.Format("~/Views/Template/{0}/{1}.cshtml", TemplateType, ViewName), string.Format("~/Views/Template/{0}/_Shared/{1}.cshtml", TemplateType, "_Layout"));

if (ViewResult.View == null)
{
StringBuilder LocationBuilder = new StringBuilder();
string[] SearchedLocations = ViewResult.SearchedLocations.ToArray();
for (int i = 0; i < SearchedLocations.Length; i++)
{
LocationBuilder.Append(string.Format("({0}) {1} ", i, SearchedLocations[i]));
}

throw new InvalidOperationException(string.Format("Could not find the {0} Template named {1} using the {2} Master. Locations Searched: {3}", TemplateType, ViewName, "_Layout", LocationBuilder));//
}
using (var Writer = new StringWriter())
{
//ViewResult.View.Render(new ViewContext(
// Context,
// ViewResult.View,
// (Controller != null) ? Controller.ViewData : (Model != null) ? new ViewDataDictionary(Model) : new ViewDataDictionary(),
// (Controller != null) ? Controller.TempData : new TempDataDictionary(), Writer), Writer);

ViewResult.View.Render(new ViewContext(
Context,
ViewResult.View,
Controller.ViewData,
Controller.TempData, Writer), Writer);

ViewResult.ViewEngine.ReleaseView(Context, ViewResult.View);

// This must remove Tabs (\t) Returns (\r) and Newlines (\n)
// Always making the quotes single makes sense for statically generated stuff - the only time when it wouldn't make sense is for more complex stuff or if it includes JS which i don't think
// a statically generated one should ever?

string result = Regex.Replace(Writer.GetStringBuilder().ToString().Replace("\"", "\'"), "(\\t|\\r|\\n)", string.Empty);

// Currently, this process does not work well when initiated outside of a request (e.g. in the startup method or purely within a
// hangfire task). This serves as a warning if it ever is (since it will return an empty string).

if (result.Blank()) { throw new InvalidOperationException("There was an error rendering the " + ViewName + " template. This can happen if the template was initialized outside of the context of an actual request."); }
else
{
return result;
}
}
}
catch (Exception ex)
{
// This could indicate an error in the underlying template
// If there is an error on any of the underlying templates in a given class,
// this can be called.
Logging.Error(ex);
return string.Empty;
}
}

这工作得很好,除非我在没有对 Controller 的引用时尝试生成模板。

我也开始考虑应用第三方 RazorEngine ( https://antaris.github.io/RazorEngine ) - 但这是不是有点矫枉过正?在同样使用内置 Razor 引擎的项目中实现这一点是否可行?

最佳答案

我用过 ActionMailer在过去。它不再维护,但有一个 fork https://github.com/crossvertise/ActionMailerNext .

您设置一个 Controller 来绑定(bind)模板,但可以像调用另一个服务类一样调用它。

public class EmailController : MailerBase, IEmailService
{
public EmailResult PasswordRecovery(PasswordRecoveryModel model)
{
To.Add(model.Email);
From = "noreply@example.com";
Subject = "Password Recovery";
return Email("PasswordRecovery", model);
}
}

我用我自己的接口(interface)设置它,所以我可以在任何地方注入(inject)它

public interface IEmailService
{
EmailResult PasswordRecovery(PasswordRecoveryModel model);
}


public class Foo
{
private readonly IEmailService emailService;

public Foo(IEmailService emailService)
{
this.emailService = emailService;
}

public void DoSomething()
{
this.emailService.PasswordRecovery(new PasswordRecoveryModel { ... });
}
}

模板看起来就像常规 View

密码恢复.html.cshtml

@using ActionMailer.Net.Mvc
@model PasswordRecoveryModel

<p>@Model.UserName</p>
<div> ... </div>

我还没有尝试过 fork ,所以我只能假设它在用法上是相似的。

关于c# - 在 ASP.NET MVC 项目中使用 Razor 生成电子邮件 HTML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47403086/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com