Skip to content

@Include and @Layout

Alexander edited this page Jul 1, 2020 · 6 revisions

Maintainer strongly believes implementing @include and @Layout is unnecessary complexity for standalone RazorEngine.

  1. Since RazorEngine.Compile accept template as a string, one will need also to accept a Dictionary (key, template) to be able to resolve @Include and @Layout

  2. It is easily implementable outside of RazorEngine

Extension

Usage

We would like to have code like this: Supply primary template, parts, and model and see the result as a string

namespace ConsoleApp11 { class Program { static void Main(string[] args) { string template = @"  @{  Layout = ""MyLayout"";  }   <h1>@Model.Title</h1>   @Include(""outer"", Model)  "; IDictionary<string, string> parts = new Dictionary<string, string>() { {"MyLayout", @"  LAYOUT HEADER  @RenderBody()  LAYOUT FOOTER  "}, {"outer", "This is Outer include, <@Model.Title>, @Include(\"inner\")"}, {"inner", "This is Inner include"} }; IRazorEngine razorEngine = new RazorEngine(); MyCompiledTemplate compiledTemplate = razorEngine.Compile(template, parts); string result = compiledTemplate.Run(new {Title = "Hello"}); Console.WriteLine(result); Console.ReadKey(); } } }

Output

LAYOUT HEADER <h1>Hello</h1> This is Outer include, <Hello>, This is Inner include LAYOUT FOOTER

Custom template base

Lets make custom template base with Include function. It will be available as @Include("footer") in template. We will inialize IncludeCallback just before running template

public class MyTemplateBase : RazorEngineTemplateBase { public Func<string, object, string> IncludeCallback { get; set; } public Func<string> RenderBodyCallback { get; set; } public string Layout { get; set; } public string Include(string key, object model = null) { return this.IncludeCallback(key, model); } public string RenderBody() { return this.RenderBodyCallback(); } }

RazorEngine extension

public static class RazorEngineCoreExtensions { public static MyCompiledTemplate Compile(this RazorEngine razorEngine, string template, IDictionary<string, string> parts) { return new MyCompiledTemplate( razorEngine.Compile<MyTemplateBase>(template), parts.ToDictionary( k => k.Key, v => razorEngine.Compile<MyTemplateBase>(v.Value))); } }
public class MyCompiledTemplate { private readonly IRazorEngineCompiledTemplate<MyTemplateBase> compiledTemplate; private readonly Dictionary<string, IRazorEngineCompiledTemplate<MyTemplateBase>> compiledParts; public MyCompiledTemplate(IRazorEngineCompiledTemplate<MyTemplateBase> compiledTemplate, Dictionary<string, IRazorEngineCompiledTemplate<MyTemplateBase>> compiledParts) { this.compiledTemplate = compiledTemplate; this.compiledParts = compiledParts; } public string Run(object model) { return this.Run(this.compiledTemplate, model); } public string Run(IRazorEngineCompiledTemplate<MyTemplateBase> template, object model) { MyTemplateBase templateReference = null; string result = template.Run(instance => { if (!(model is AnonymousTypeWrapper)) { model = new AnonymousTypeWrapper(model); } instance.Model = model; instance.IncludeCallback = (key, includeModel) => this.Run(this.compiledParts[key], includeModel); templateReference = instance; }); if (templateReference.Layout == null) { return result; } return this.compiledParts[templateReference.Layout].Run(instance => { if (!(model is AnonymousTypeWrapper)) { model = new AnonymousTypeWrapper(model); } instance.Model = model; instance.IncludeCallback = (key, includeModel) => this.Run(this.compiledParts[key], includeModel); instance.RenderBodyCallback = () => result; }); } public void Save() { /*  TODO   this.compiledTemplate.SaveToFile();  this.compiledTemplate.SaveToStream();   foreach (var compiledPart in this.compiledParts)  {  compiledPart.Value.SaveToFile();  compiledPart.Value.SaveToStream();  }  */ } public void Load() { // TODO } }

Clone this wiki locally