@Include and @Layout - adoconnection/RazorEngineCore GitHub Wiki
Maintainer strongly believes implementing @include
and @Layout
is unnecessary complexity for standalone RazorEngine.
-
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
-
It is easily implementable outside of RazorEngine
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
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();
}
}
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
}
}