remarks generate example c# embedded-resource razorengine

c# - generate - RazorEngine cadenas de diseños y secciones?



params comments c# (3)

Necesitaba proporcionar mi propio diseño como una cadena o un nombre de archivo. Aquí es cómo resolví esto (basado en esta entrada de blog )

public static class RazorEngineConfigurator { public static void Configure() { var templateConfig = new TemplateServiceConfiguration { Resolver = new DelegateTemplateResolver(name => { //no caching cause RazorEngine handles that itself var emailsTemplatesFolder = HttpContext.Current.Server.MapPath(Properties.Settings.Default.EmailTemplatesLocation); var templatePath = Path.Combine(emailsTemplatesFolder, name); using (var reader = new StreamReader(templatePath)) // let it throw if doesn''t exist { return reader.ReadToEnd(); } }) }; RazorEngine.Razor.SetTemplateService(new TemplateService(templateConfig)); } }

Luego llamo a RazorEngineConfigurator.Configure () en Global.asax.cs y está listo.

La ruta a mis plantillas se encuentra en Propiedades.Configuración.Default.EmailTemplatesLocation

En mi opinión tengo esto:

@{ Layout = "_layout.html";}

_layout.html está en emailsTemplatesFolder

Es un HTML bastante estándar con una llamada @RenderBody () en el medio.

Según tengo entendido, RazorEngine usa el nombre de la plantilla ("_layout.html" en este caso) como clave de su caché, por lo que se llama al delegado de mi configurador solo una vez por plantilla.

Creo que usa esa resolución para cada nombre de plantilla que aún no conoce.

Yo uso el motor de afeitar de esta manera:

public class EmailService : IService { private readonly ITemplateService templateService; public EmailService(ITemplateService templateService) { if (templateService == null) { throw new ArgumentNullException("templateService"); } this.templateService = templateService; } public string GetEmailTemplate(string templateName) { if (templateName == null) { throw new ArgumentNullException("templateName"); } Assembly assembly = Assembly.GetAssembly(typeof(EmailTemplate)); Stream stream = assembly.GetManifestResourceStream(typeof(EmailTemplate), "{0}.cshtml".FormatWith(templateName)); string template = stream.ReadFully(); return template; } public string GetEmailBody(string templateName, object model = null) { if (templateName == null) { throw new ArgumentNullException("templateName"); } string template = GetEmailTemplate(templateName); string emailBody = templateService.Parse(template, model, null, null); return emailBody; } }

El servicio de plantillas que uso se inyecta, aunque solo es una implementación predeterminada:

internal ITemplateService InstanceDefaultTemplateService() { ITemplateServiceConfiguration configuration = new TemplateServiceConfiguration(); ITemplateService service = new TemplateService(configuration); return service; }

Dado que en este caso en particular, estaré creando correos electrónicos a partir de estas plantillas. Quiero poder usar @section s para el asunto del correo electrónico, y diferentes secciones del cuerpo del correo electrónico, mientras uso un diseño en el que especifico los estilos que son comunes a toda la estructura del correo electrónico (que se verá como uno de MailChimp Probablemente).

La pregunta es entonces doble:

  • ¿Cómo puedo especificar diseños en RazorEngine ?
  • ¿Cómo puedo especificar estos diseños desde cadenas (o una secuencia)? ya que como puede ver, uso recursos incrustados para almacenar las plantillas de correo electrónico de afeitar.

Actualizar

Tal vez no estaba claro, pero me refiero a la biblioteca RazorEngine .


Parece que alguien más lo resolvió por ti.

https://github.com/aqueduct/Appia/blob/master/src/Aqueduct.Appia.Razor/RazorViewEngine.cs

El código que desea está en el segundo método ExecuteView. A pesar de que están creando su propio motor de visualización, puede crear su propia solución de plantillas personalizada y usar algo similar. Básicamente, están buscando la propiedad Diseño de la plantilla y, si existe, realizan una búsqueda y reemplazan el contenido del diseño.

Aquí hay un enlace a las plantillas personalizadas de RazorEngine:

http://razorengine.codeplex.com/wikipage?title=Building%20Custom%20Base%20Templates&referringTitle=Documentation

Aquí es donde encontré tu solución:

.NET Razor engine - Implementando diseños


Resulta que después de algunas excavaciones que los diseños son compatibles, solo tenemos que declararlos con _Layout lugar de Layout

En cuanto al problema de los recursos incrustados, implementé el siguiente ITemplateResolver

using System; using System.IO; using System.Reflection; using Bruttissimo.Common; using RazorEngine.Templating; namespace Website.Extensions.RazorEngine { /// <summary> /// Resolves templates embedded as resources in a target assembly. /// </summary> public class EmbeddedTemplateResolver : ITemplateResolver { private readonly Assembly assembly; private readonly Type type; private readonly string templateNamespace; /// <summary> /// Specify an assembly and the template namespace manually. /// </summary> /// <param name="assembly">The assembly where the templates are embedded.</param> /// <param name="templateNamespace"></param> public EmbeddedTemplateResolver(Assembly assembly, string templateNamespace) { if (assembly == null) { throw new ArgumentNullException("assembly"); } if (templateNamespace == null) { throw new ArgumentNullException("templateNamespace"); } this.assembly = assembly; this.templateNamespace = templateNamespace; } /// <summary> /// Uses a type reference to resolve the assembly and namespace where the template resources are embedded. /// </summary> /// <param name="type">The type whose namespace is used to scope the manifest resource name.</param> public EmbeddedTemplateResolver(Type type) { if (type == null) { throw new ArgumentNullException("type"); } this.assembly = Assembly.GetAssembly(type); this.type = type; } public string Resolve(string name) { if (name == null) { throw new ArgumentNullException("name"); } Stream stream; if (templateNamespace == null) { stream = assembly.GetManifestResourceStream(type, "{0}.cshtml".FormatWith(name)); } else { stream = assembly.GetManifestResourceStream("{0}.{1}.cshtml".FormatWith(templateNamespace, name)); } if (stream == null) { throw new ArgumentException("EmbeddedResourceNotFound"); } string template = stream.ReadFully(); return template; } } }

Entonces simplemente lo cableas así:

internal static ITemplateService InstanceTemplateService() { TemplateServiceConfiguration configuration = new TemplateServiceConfiguration { Resolver = new EmbeddedTemplateResolver(typeof(EmailTemplate)) }; ITemplateService service = new TemplateService(configuration); return service; }

El tipo que pasa es solo para hacer referencia al conjunto y al espacio de nombres donde están incrustados los recursos.

namespace Website.Domain.Logic.Email.Template { /// <summary> /// The purpose of this class is to expose the namespace of razor engine templates in order to /// avoid having to hard-code it when retrieving the templates embedded as resources. /// </summary> public sealed class EmailTemplate { } }

Una última cosa, para que las plantillas se resuelvan con nuestro resolutor, tenemos que resolverlas así:

ITemplate template = templateService.Resolve(templateName, model); string body = template.Run(); return body;

.Run es solo un método de extensión simple, ya que no puedo encontrar ningún uso para un ViewBag .

public static class ITemplateExtensions { public static string Run(this ITemplate template) { ExecuteContext context = new ExecuteContext(); string result = template.Run(context); return result; } }

ACTUALIZAR

Aquí están las extensiones que faltan

public static string FormatWith(this string text, params object[] args) { return string.Format(text, args); } public static string ReadFully(this Stream stream) { using (StreamReader reader = new StreamReader(stream)) { return reader.ReadToEnd(); } }