ministrymason ministrymason - 2 months ago 46
C# Question

RazorEngine layouts

I am using the Razor engine https://github.com/Antaris/RazorEngine to parse the body of my email templates. Is it possible to define a layout and include other .cshtml files? for example a common header and a footer.

Answer

I got common templates and a layout working, with the help of these two posts:

RazorEngine string layouts and sections?

http://blogs.msdn.com/b/hongyes/archive/2012/03/12/using-razor-template-engine-in-web-api-self-host-application.aspx

This is my solution:

Solution 1: Layout

Used by setting _Layout

@{
    _Layout = "Layout.cshtml";
    ViewBag.Title = Model.Title;
 }

Footer

@section Footer 
{
   @RenderPart("Footer.cshtml")
}

Layout.cshtml

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html>
    <head>
    </head>
    <body>
        <div id="content">
            @RenderBody()
        </div> 
        @if (IsSectionDefined("Footer"))
        { 
            <div id="footer">
                @RenderSection("Footer")
            </div>
        }
    </body> 
</html>

TemplateBaseExtensions

Extend TemplateBase with a RenderPart Method

public abstract class TemplateBaseExtensions<T> : TemplateBase<T>
{
    public string RenderPart(string templateName, object model = null)
    {
        string path = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "Templates", templateName);
        return Razor.Parse(File.ReadAllText(path), model);
    }
}

Razor Config

Set BaseTemplateType to your TemplateBaseExtensions class

TemplateServiceConfiguration templateConfig = new TemplateServiceConfiguration
{
     BaseTemplateType = typeof(TemplateBaseExtensions<>)
};

Razor.SetTemplateService(new TemplateService(templateConfig));

Edit Solution 2:

If you are using a TemplateResolver. RenderPart isn't needed use the @Include instead

Footer

@section Footer 
{
   @Include("Footer.cshtml")
}

Resolver

public class TemplateResolver : ITemplateResolver
{
    public string Resolve(string name)
    {
        if (name == null)
        {
            throw new ArgumentNullException("name");
        }

        string path = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "Templates", name);
        return File.ReadAllText(path, System.Text.Encoding.Default);
    }
}

Config

TemplateServiceConfiguration templateConfig = new TemplateServiceConfiguration
{
     Resolver = new TemplateResolver()
};
Razor.SetTemplateService(new TemplateService(templateConfig));

Update by The Muffin Man Specify a template and render a string

var templateResolver = Razor.Resolve("Registration.cshtml");
return templateResolver.Run(new ExecuteContext());

Also I, along with others at this link https://github.com/Antaris/RazorEngine/issues/61 had issues with using _Layout whereas Layout worked.

'_Layout' is the old syntax. It was updated to 'Layout' in a future release.