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

namespaceConsoleApp11{classProgram{staticvoidMain(string[]args){stringtemplate=@" @{ Layout = ""MyLayout""; } <h1>@Model.Title</h1> @Include(""outer"", Model) ";IDictionary<string,string>parts=newDictionary<string,string>(){{"MyLayout",@" LAYOUT HEADER @RenderBody() LAYOUT FOOTER "},{"outer","This is Outer include, <@Model.Title>, @Include(\"inner\")"},{"inner","This is Inner include"}};IRazorEnginerazorEngine=newRazorEngine();MyCompiledTemplatecompiledTemplate=razorEngine.Compile(template,parts);stringresult=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

publicclassMyTemplateBase:RazorEngineTemplateBase{publicFunc<string,object,string>IncludeCallback{get;set;}publicFunc<string>RenderBodyCallback{get;set;}publicstringLayout{get;set;}publicstringInclude(stringkey,objectmodel=null){returnthis.IncludeCallback(key,model);}publicstringRenderBody(){returnthis.RenderBodyCallback();}}

RazorEngine extension

publicstaticclassRazorEngineCoreExtensions{publicstaticMyCompiledTemplateCompile(thisRazorEnginerazorEngine,stringtemplate,IDictionary<string,string>parts){returnnewMyCompiledTemplate(razorEngine.Compile<MyTemplateBase>(template),parts.ToDictionary(
k =>k.Key,
v =>razorEngine.Compile<MyTemplateBase>(v.Value)));}}
publicclassMyCompiledTemplate{privatereadonlyIRazorEngineCompiledTemplate<MyTemplateBase>compiledTemplate;privatereadonlyDictionary<string,IRazorEngineCompiledTemplate<MyTemplateBase>>compiledParts;publicMyCompiledTemplate(IRazorEngineCompiledTemplate<MyTemplateBase>compiledTemplate,Dictionary<string,IRazorEngineCompiledTemplate<MyTemplateBase>>compiledParts){this.compiledTemplate=compiledTemplate;this.compiledParts=compiledParts;}publicstringRun(objectmodel){returnthis.Run(this.compiledTemplate,model);}publicstringRun(IRazorEngineCompiledTemplate<MyTemplateBase>template,objectmodel){MyTemplateBasetemplateReference=null;stringresult=template.Run(instance =>{if(!(modelisAnonymousTypeWrapper)){model=newAnonymousTypeWrapper(model);}instance.Model=model;instance.IncludeCallback=(key,includeModel)=>this.Run(this.compiledParts[key],includeModel);templateReference=instance;});if(templateReference.Layout==null){returnresult;}returnthis.compiledParts[templateReference.Layout].Run(instance =>{if(!(modelisAnonymousTypeWrapper)){model=newAnonymousTypeWrapper(model);}instance.Model=model;instance.IncludeCallback=(key,includeModel)=>this.Run(this.compiledParts[key],includeModel);instance.RenderBodyCallback=()=>result;});}publicvoidSave(){/* TODO this.compiledTemplate.SaveToFile(); this.compiledTemplate.SaveToStream(); foreach (var compiledPart in this.compiledParts) { compiledPart.Value.SaveToFile(); compiledPart.Value.SaveToStream(); } */}publicvoidLoad(){// TODO}}

Clone this wiki locally