Build a RazorEngine template by specifying a layout in the calling code rather than the template?

StackOverflow https://stackoverflow.com/questions/22308142

  •  12-06-2023
  •  | 
  •  

Question

Using Antaris RazorEngine, given two strings:

  • a Razor template without a layout specified

    <h1>My template</h1>
    
  • and a layout in which it should be rendered

    <html>RenderBody()</html>
    

I would like to be able to parse/compile the strings and set the layout in the code performing the parsing. Something like:

ParseWithTemplate(templateAsString, layoutAsString, model, etc.);

How might I implement this ParseWithTemplate(String, String, ...) method?

Background: I'm building a static site generator and want a way to provide a default layout so I don't have to specify it in every single one of my many site pages. It should be possible to override the default if a Layout = "layoutName" is provided in the template.

Was it helpful?

Solution

If you pre-compile the layout template, you should be able to set the Layout directly by casting the template to TemplateBase. If you later specify the Layout in the template markup, this will override the value in the code as you require when the template executes.

ITemplateService templateService = ...;

// Ensure layout template is cached with layoutCacheName
templateService.GetTemplate(layoutAsString, model, layoutCacheName);

ITemplate template = templateService.GetTemplate(templateAsString, model, templateCacheName);
var templateBase = template as TemplateBase;
if (templateBase != null) templateBase.Layout = layoutCacheName;

OTHER TIPS

Though I ultimately decided to switch to RazorMachine for this and many other reasons, here is a hacky fix for anyone who needs it:

var finalHtml = layoutHtml.Replace(@"@RenderBody()", templateHtml);

(Thanks to aviatrix on Github.)

Expanding the of Ryan Norbauer's answer, the easiest way to implement a layout is:

Your _Layout.cshtml with the typical @RenderBody()

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html>
    <head>
    </head>
    <body>
        <div>
            @RenderBody()
        </div> 
    </body> 
</html>

Your RazorEngine template MyTemplate.cshtml

@using RazorEngine.Templating
@inherits TemplateBase<myviewmodel>

<h1>Hello People</h1>
<p>@Model</p>

And wherever you call the RazorEngine template:

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);

As you can see is very simple, just place what MyTemplate.cshtml return in @RenderBody()

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top