J'utilise le moteur Razor https://github.com/Antaris/RazorEngine pour analyser le corps de mes modèles de courrier électronique. Est-il possible de définir une mise en page et d'inclure d'autres fichiers .cshtml? par exemple un en-tête commun et un pied de page.
J'ai obtenu des modèles communs et une mise en page fonctionnant à l'aide de ces deux messages:
RazorEngine dispositions et sections de chaîne?
Ceci est ma solution:
Solution 1: Mise en page
Utilisé en définissant _Layout
@{
_Layout = "Layout.cshtml";
ViewBag.Title = Model.Title;
}
Bas de page
@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
Étendre TemplateBase avec une méthode 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);
}
}
Config Razor
Définissez BaseTemplateType sur votre classe TemplateBaseExtensions
TemplateServiceConfiguration templateConfig = new TemplateServiceConfiguration
{
BaseTemplateType = typeof(TemplateBaseExtensions<>)
};
Razor.SetTemplateService(new TemplateService(templateConfig));
Edit Solution 2:
Si vous utilisez un TemplateResolver. RenderPart n'est pas nécessaire, utilisez plutôt @Include
Bas de page
@section Footer
{
@Include("Footer.cshtml")
}
Résolveur
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);
}
}
Config
TemplateServiceConfiguration templateConfig = new TemplateServiceConfiguration
{
Resolver = new TemplateResolver()
};
Razor.SetTemplateService(new TemplateService(templateConfig));
Mise à jour par The Muffin Man Spécifiez un modèle et restituez une chaîne
var templateResolver = Razor.Resolve("Registration.cshtml");
return templateResolver.Run(new ExecuteContext());
De plus, avec d'autres personnes sur ce lien https://github.com/Antaris/RazorEngine/issues/61 , je rencontrais des problèmes pour utiliser _Layout
alors que Layout
fonctionnait.
'_Layout' est l'ancienne syntaxe. Il a été mis à jour en "Mise en page" dans une prochaine version.
Le moyen le plus simple d'implémenter une présentation avec RazorEngine est de remplacer ce que votre modèle renvoie dans la @RenderBody () de la présentation:
var finalHtml = layout.Replace(@"@RenderBody()", templateHtml);
Par exemple.:
Votre _Layout.cshtml avec le type typique @RenderBody ()
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html>
<head>
</head>
<body>
<div>
@RenderBody()
</div>
</body>
</html>
Votre modèle RazorEngine MyTemplate.cshtml
@using RazorEngine.Templating
@inherits TemplateBase<myviewmodel>
<h1>Hello People</h1>
<p>@Model</p>
Et partout où vous appelez le modèle 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);
Vous pouvez facilement faire beaucoup de choses avec Razor; Cependant, ce projet particulier semble faire abstraction de tout ce que vous pourriez faire avec le moteur Razor (ce qui est à la fois bon et mauvais). Dans votre cas, il semblerait que vous feriez bien mieux de mettre en œuvre votre propre solution Razor (ce n'est en fait pas si mal) et ensuite, vos modèles jetteront des exceptions ou extrairont facilement du contenu.
Par exemple; faire rouler votre propre solution vous permet de créer une classe de base pour vos modèles de rasoir, ce qui peut vous permettre d’obtenir des "vues partielles" en appelant d’autres modèles. De plus, vous pouvez vérifier les modèles et générer des exceptions si certaines propriétés sont nulles.
Solution entièrement personnalisée d'implémentation de la fonctionnalité Mail.
Ajouter le paquet de pépites de RazorEngine
Créer un modèle de mise en forme (.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>
Créer un modèle ConfirmEmail (.cshtml):
@using yourProjectnamespace.LanguageResources.Mail
@model ConfirmEmail
@MailTemplateResource.YouHaveLoggedIn
<a href="@Url(string.Format("/User/Confirmemail?EmailId={0}", Model.UserId))">@MailTemplateResource.ClickHere</a>
Créer une classe CustomTemplateBase:
public class CustomTemplateBase<T> : TemplateBase<T>
{
public string Url(string url)
{
return MailConfiguration.BaseUrl + url.TrimStart('/');
}
}
Créer une classe EmbeddedTemplateManager:
classe interne EmbeddedTemplateManager: ITemplateManager { private readonly string 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("");
}
}
Créer une classe de courrier:
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;
}
}
Créer une classe 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; }
}
Créer une classe 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"));
}
Classe MailSender:
Implémentez votre méthode dans la classe MailSerder et appelez la méthode MailSerder dans votre référentiel ou contrôleur.
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);
}
}