Я использую механизм Razor https://github.com/Antaris/RazorEngine, чтобы проанализировать тело моих шаблонов электронной почты. Можно ли определить макет и включить другие .cshtml файлы? например, общий заголовок и нижний колонтитул.
Разметка RazorEngine
Ответ 1
Я получил общие шаблоны и рабочий макет, с помощью этих двух постов:
RazorEngine макеты строк и разделы?
Это мое решение:
Решение 1: макет
Используется установкой _Layout
@{
_Layout = "Layout.cshtml";
ViewBag.Title = Model.Title;
}
нижний колонтитул
@section Footer
{
@RenderPart("Footer.cshtml")
}
Layout.cshtml
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html>
<head>
</head>
<body>
<div id="content">
@RenderBody()
</div>
@if (IsSectionDefined("Footer"))
{
<div id="footer">
@RenderSection("Footer")
</div>
}
</body>
</html>
TemplateBaseExtensions
Расширение TemplateBase с помощью метода RenderPart
public abstract class TemplateBaseExtensions<T> : TemplateBase<T>
{
public string RenderPart(string templateName, object model = null)
{
string path = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "Templates", templateName);
return Razor.Parse(File.ReadAllText(path), model);
}
}
Razor Config
Установите BaseTemplateType для вашего класса TemplateBaseExtensions
TemplateServiceConfiguration templateConfig = new TemplateServiceConfiguration
{
BaseTemplateType = typeof(TemplateBaseExtensions<>)
};
Razor.SetTemplateService(new TemplateService(templateConfig));
Изменить решение 2:
Если вы используете TemplateResolver. RenderPart не требуется, используйте вместо этого @Include
нижний колонтитул
@section Footer
{
@Include("Footer.cshtml")
}
Резольвер
public class TemplateResolver : ITemplateResolver
{
public string Resolve(string name)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
string path = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "Templates", name);
return File.ReadAllText(path, System.Text.Encoding.Default);
}
}
конфиг
TemplateServiceConfiguration templateConfig = new TemplateServiceConfiguration
{
Resolver = new TemplateResolver()
};
Razor.SetTemplateService(new TemplateService(templateConfig));
Обновление от Muffin Man Укажите шаблон и визуализируйте строку
var templateResolver = Razor.Resolve("Registration.cshtml");
return templateResolver.Run(new ExecuteContext());
Также у меня, наряду с другими по этой ссылке https://github.com/Antaris/RazorEngine/issues/61, были проблемы с использованием _Layout
тогда как Layout
работал.
"_Layout" - старый синтаксис. Он был обновлен до "Layout" в будущем выпуске.
Ответ 2
Вы можете легко сделать много вещей с помощью Razor; тем не менее, этот конкретный проект, кажется, абстрагирует многие вещи двигателя Razor, которые вы могли бы сделать (что хорошо и плохо). В вашей ситуации звучит так, что вам будет намного лучше реализовать свое собственное решение Razor (это на самом деле не так уж плохо), и тогда вы можете легко заставить свои шаблоны исключать или просто тянуть другой контент.
Например; сворачивание собственного решения позволяет вам создать базовый класс для ваших шаблонов бритвы, которые могут выставить возможность "частично просматривать", вызывая другие шаблоны. Кроме того, вы можете выполнять проверку модели и выдавать исключения, если определенные свойства имеют значение NULL.
Ответ 3
Самый простой способ реализовать макет с помощью RazorEngine - это заменить то, что ваш шаблон возвращается в @RenderBody() макета:
var finalHtml = layout.Replace(@"@RenderBody()", templateHtml);
например:.
Ваш _Layout.cshtml с типичным @RenderBody()
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html>
<head>
</head>
<body>
<div>
@RenderBody()
</div>
</body>
</html>
Ваш шаблон RazorEngine MyTemplate.cshtml
@using RazorEngine.Templating
@inherits TemplateBase<myviewmodel>
<h1>Hello People</h1>
<p>@Model</p>
И везде, где вы вызываете шаблон RazorEngine:
var TemplateFolderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "EmailTemplates");
var template = File.ReadAllText(Path.Combine(TemplateFolderPath,"MyTemplate.cshtml"));
var layout = File.ReadAllText(Path.Combine(TemplateFolderPath, "_Layout.cshtml"));
var templateService = new TemplateService();
var templateHtml = templateService.Parse(template, myModel, null, null);
var finalHtml = layout.Replace(@"@RenderBody()", templateHtml);
Ответ 4
Полностью индивидуальное решение для реализации функциональности Почты.
Добавить пакет nuget RazorEngine
Создайте шаблон _Layout (.cshtml):
<html>
<body style="margin: 0; padding: 0;">
<div style="width:100%; display:block; float:left; height:100%;">
<table cellpadding="0" cellspacing="0" border="0" align="center" width="100%">
<tr>
<td width="37" style="background-color: #ffffff;"></td>
<td width="200" style="background-color: #ffffff">
<a href="@Url("")">Send Mail Logo</a>
</td>
<td style="background-color: #ffffff;">
</td>
<td width="126" style="background-color: #ffffff;">
<img src="@Url("Images/mail/social-media.png")" alt="" width="126" height="73" border="0" usemap="#Map" />
</td>
</tr>
</table>
<table cellpadding="0" cellspacing="0" border="0" align="center" width="100%">
<tr height="7">
<td style="background-color: #ffffff;" colspan="3"></td>
</tr>
<tr height="54">
<td colspan="3"></td>
</tr>
<tr>
<td width="37"> </td>
<td style="font-family: Myriad, 'Helvetica Neue',Arial,Helvetica,sans-serif; font-size: 11pt; color: #6b6c6f; line-height: 24px;">
{{BODY}}
</td>
<td width="37"> </td>
</tr>
<tr height="55">
<td style="line-height: 0;" colspan="3"> </td>
</tr>
<tr height="11">
<td background="@Url("/Images/mail/dotted-line.png")" colspan="3" style="line-height: 0;"> </td>
</tr>
</table>
</div>
<map name="Map" id="Map">
<area shape="rect" coords="28,29,51,51" href="#" alt="Twitter" />
<area shape="rect" coords="56,28,78,52" href="#" alt="Google+" />
<area shape="rect" coords="84,28,104,51" href="#" alt="LinkedIn" />
</map>
</body>
</html>
Создайте шаблон ConfirmEmail (.cshtml):
@using yourProjectnamespace.LanguageResources.Mail
@model ConfirmEmail
@MailTemplateResource.YouHaveLoggedIn
<a href="@Url(string.Format("/User/Confirmemail?EmailId={0}", Model.UserId))">@MailTemplateResource.ClickHere</a>
Создайте класс CustomTemplateBase:
public class CustomTemplateBase<T> : TemplateBase<T>
{
public string Url(string url)
{
return MailConfiguration.BaseUrl + url.TrimStart('/');
}
}
Создайте класс EmbeddedTemplateManager:
внутренний класс EmbeddedTemplateManager: ITemplateManager {закрытая только для чтения строка ns;
public EmbeddedTemplateManager(string @namespace)
{
ns = @namespace;
}
public ITemplateSource Resolve(ITemplateKey key)
{
var resourceName = $"{ns}.{key.Name}.cshtml";
string content;
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
using (var streamReader = new StreamReader(stream))
{
content = streamReader.ReadToEnd();
}
return new LoadedTemplateSource(content);
}
public ITemplateKey GetKey(string name, ResolveType resolveType, ITemplateKey context)
{
return new NameOnlyTemplateKey(name, resolveType, context);
}
public void AddDynamic(ITemplateKey key, ITemplateSource source)
{
throw new NotImplementedException("");
}
}
Создать почтовый класс:
public class Mail
{
private static readonly IRazorEngineService RazorEngine;
static Mail()
{
var config = new TemplateServiceConfiguration
{
BaseTemplateType = typeof(CustomTemplateBase<>),
TemplateManager = new EmbeddedTemplateManager(typeof(Mail).Namespace + ".Templates"),
Namespaces = { "Add CurrentProjectName", "Add CurrentProjectName .Models" },
CachingProvider = new DefaultCachingProvider()
};
RazorEngine = RazorEngineService.Create(config);
}
public Mail(string templateName)
{
TemplateName = templateName;
ViewBag = new DynamicViewBag();
}
public string TemplateName { get; set; }
public object Model { get; set; }
public DynamicViewBag ViewBag { get; set; }
public string GenerateBody()
{
var layout = RazorEngine.RunCompile("_Layout", model: null);
var body = RazorEngine.RunCompile(TemplateName, Model.GetType(), Model);
return layout.Replace("{{BODY}}", body);
}
public MailMessage Send(Guid key, string to, string subject, string cc = null)
{
var email = new MailMessage()
{
From = MailConfiguration.From,
Body = GenerateBody(),
IsBodyHtml = true,
Subject = subject,
BodyEncoding = Encoding.UTF8
};
email.Headers.Add("X-MC-Metadata", "{ \"key\": \"" + key.ToString("N") + "\" }");
foreach (var sendTo in to.Split(' ', ',', ';'))
{
email.To.Add(sendTo);
}
if (cc != null)
{
foreach (var sendCC in cc.Split(' ', ',', ';'))
{
email.CC.Add(sendCC);
}
}
var smtp = new MailClient().SmtpClient;
smtp.EnableSsl = true;
smtp.Send(email);
return email;
}
}
public class Mail<TModel> : Mail where TModel : class
{
public Mail(string templateName, TModel mailModel) : base(templateName)
{
Model = mailModel;
}
}
Создать класс MailClient:
public class MailClient
{
public MailClient()
{
SmtpClient = new SmtpClient(MailConfiguration.Host)
{
Port = MailConfiguration.Port,
Credentials = new NetworkCredential
{
UserName = MailConfiguration.UserName,
Password = MailConfiguration.Password
}
};
}
public SmtpClient SmtpClient { get; }
}
Создать класс MailConfiguration:
public class MailConfiguration
{
private static string GetAppSetting(string key)
{
var element = ConfigurationManager.AppSettings["Mail:" + key];
return element ?? string.Empty;
}
public static string BaseUrl => GetAppSetting("BaseUrl");
public static string Host => GetAppSetting("Host");
public static int Port => Int32.Parse(GetAppSetting("Port"));
public static string UserName => GetAppSetting("Username");
public static string Password => GetAppSetting("Password");
public static MailAddress From => new MailAddress(GetAppSetting("From"));
}
Класс MailSender:
Реализуйте свой метод в классе MailSerder и вызовите метод MailSerder в своем хранилище или контроллере.
Create public class MailSender : IMailSender
{
public MailSender()
{
}
public void SendConfirmEmail(string emailId, Guid userId)
{
var confirmEmail = new ConfirmEmail
{
UserId = userId
};
ConfirmEmail(emailId, MailResource.YourRegistration, confirmEmail);
}
private void ConfirmEmail(string recipient,string subject,ConfirmEmail model)
{
var key = Guid.NewGuid();
var mail = new Mail<ConfirmEmail>("ConfirmEmail", model);
mail.ViewBag.AddValue("Recipient", recipient);
var sentMail = mail.Send(key, recipient, subject);
}
}