Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

733 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

RazorLight

Important

This repository is an independently maintained continuation of toddams/RazorLight. It is no longer maintained as a contribution fork, so compatibility and release policy may diverge. See UPSTREAM.md for provenance and the upstream synchronization policy.

Note

The maintained release line targets .NET 10 and is published as Dijgrid.RazorLight, beginning with version 3.0.0. The RazorLight 2.3.1 package is the historical upstream build rather than this continuation.

Use Razor to build templates from files, embedded resources, strings, databases, or a custom source outside ASP.NET MVC. The maintained source and samples support .NET 10. See framework support, the dependency policy, and testing guidance for the current maintenance baseline.

Build Status NuGet

Table of contents

Quickstart

Install the .NET 10 SDK selected by global.json, then add the independently maintained package:

dotnet add package Dijgrid.RazorLight --version 3.0.0

Do not use the historical RazorLight 2.3.1 package as evidence of this continuation's framework or dependency baseline.

The simplest scenario creates a template from a string. Each template has a templateKey, allowing RazorLight to cache and reuse its compiled form. String templates do not require a project; layouts, includes, and project-based template lookup do.

var engine = new RazorLightEngineBuilder()
	.UseMemoryCachingProvider()
	.Build();

string template = "Hello, @Model.Name. Welcome to RazorLight repository";
ViewModel model = new ViewModel {Name = "John Doe"};

string result = await engine.CompileRenderStringAsync("templateKey", template, model);

snippet source | anchor

To render a compiled template:

var cacheResult = engine.Handler.Cache.RetrieveTemplate("templateKey");
if(cacheResult.Success)
{
	var templatePage = cacheResult.Template.TemplatePageFactory();
	string result = await engine.RenderTemplateAsync(templatePage, model);
}

snippet source | anchor

Compatibility and support

  • Maintained source, tools, tests, and samples target .NET 10 only.
  • Moving from the historical 2.3.1 package is a framework-breaking migration; read docs/framework-support.md before upgrading.
  • The public API and historical behavior baseline are recorded in docs/compatibility-baseline.md.
  • Current model, import, LINQ, and template-cache behavior is recorded in the template language compatibility matrix.
  • Azure Functions v4 is build-validated by the maintained sample. AWS Lambda and other hosting environments are not part of CI and should be treated as community-supported until a focused integration fixture is added.
  • For support and security reporting, follow SUPPORT.md and SECURITY.md.

Template sources

RazorLight has built-in providers for file-system and embedded-resource templates. Implement RazorLightProject to load templates from another source, such as a database.

Project-backed templates receive RazorLight's built-in imports and namespaces configured with AddDefaultNamespaces. String templates currently require explicit @using directives. See the template language compatibility matrix for the tested behavior and known dynamic-model limitations.

File source

For a file-system project, the template key is a path relative to the root directory passed to RazorLightEngineBuilder.

var engine = new RazorLightEngineBuilder()
	.UseFileSystemProject("C:/RootFolder/With/YourTemplates")
	.UseMemoryCachingProvider()
	.Build();

var model = new {Name = "John Doe"};
string result = await engine.CompileRenderAsync("Subfolder/View.cshtml", model);

snippet source | anchor

Embedded-resource source

For an embedded resource, the template key combines the resource namespace and template file name.

The examples below use this project structure:

Project/
  Model.cs
  Program.cs
  Project.csproj
Project.Core/
  EmailTemplates/
    Body.cshtml
  Project.Core.csproj
  SomeService.cs

var engine = new RazorLightEngineBuilder()
	.UseEmbeddedResourcesProject(typeof(SomeService).Assembly)
	.UseMemoryCachingProvider()
	.Build();

var model = new Model();
string html = await engine.CompileRenderAsync("EmailTemplates.Body", model);

snippet source | anchor

Setting the root namespace lets you omit that prefix from the template key:

var engine = new RazorLightEngineBuilder()
	.UseEmbeddedResourcesProject(typeof(SomeService).Assembly, "Project.Core.EmailTemplates")
	.UseMemoryCachingProvider()
	.Build();

var model = new Model();
string html = await engine.CompileRenderAsync("Body", model);

snippet source | anchor

Custom source

To store templates in a database or another custom location, implement RazorLightProject. The project resolves template content and imports, and RazorLight also uses it to find layouts and included templates.

var project = new EntityFrameworkRazorProject(new AppDbContext());
var engine = new RazorLightEngineBuilder()
    .UseProject(project)
    .UseMemoryCachingProvider()
    .Build();

// For key as a GUID
string guidResult = await engine.CompileRenderAsync(
    "6cc277d5-253e-48e0-8a9a-8fe3cae17e5b",
    new { Name = "John Doe" });

// Or integer
int templateKey = 322;
string integerResult = await engine.CompileRenderAsync(
    templateKey.ToString(),
    new { Name = "John Doe" });

See the custom project sample for a complete implementation.

Includes and partial templates

Includes let templates share smaller, reusable components. They reduce duplication and keep complex templates manageable.

Includes require a RazorLight project so the engine can locate the referenced template.

@model MyProject.TestViewModel
<div>
    Hello @Model.Title
</div>

@{ await IncludeAsync("SomeView.cshtml", Model); }

The first argument is the template key; the second is the model passed to the included template and may be null.

Encoding

RazorLight HTML-encodes model values by default. Use Raw when a specific value is already safe to render without encoding.

/* With encoding (default) */

string encodedTemplate = "Render @Model.Tag";
string encodedResult = await engine.CompileRenderStringAsync(
    "encoded",
    encodedTemplate,
    new { Tag = "<html>&" });

Console.WriteLine(encodedResult); // Output: &lt;html&gt;&amp;

/* Without encoding */

string rawTemplate = "Render @Raw(Model.Tag)";
string rawResult = await engine.CompileRenderStringAsync(
    "raw",
    rawTemplate,
    new { Tag = "<html>&" });

Console.WriteLine(rawResult); // Output: <html>&

To disable encoding for an entire template, set DisableEncoding to true:

@model TestViewModel
@{
    DisableEncoding = true;
}

<html>
    Hello @Model.Tag
</html>

Enable IntelliSense support

Visual Studio assumes a Razor file is an ASP.NET MVC view. Add an explicit base class to help IntelliSense understand a RazorLight template:

@using RazorLight
@inherits TemplatePage<MyModel>

<html>
    Your awesome template goes here, @Model.Name
</html>

Intellisense

FAQ

Coding Challenges (FAQ)

How to use templates from memory without setting a project?

String templates work without configuring a project. The builder supplies NoRazorProject by default, and the memory cache can store the compiled template:

var razorEngine = new RazorLightEngineBuilder()
                .UseMemoryCachingProvider()
                .Build();

string html = await razorEngine.CompileRenderStringAsync(
    "welcome",
    "Hello, @Model.Name!",
    new { Name = "Ada" });

Configure a file, embedded-resource, or custom project when templates use layouts, includes, or project keys. This behavior is covered by the quickstart smoke tests.

How to embed an image in an email?

This isn't a RazorLight question, but please see this Stack Overflow answer.

How to embed CSS in an email?

This isn't a RazorLight question, but please look into PreMailer.Net.

Compilation and Deployment Issues (FAQ)

Runtime compilation depends on metadata from the entry application. If rendering works during local development but fails after deployment, review the following common configuration issues.

Additional metadata references

RazorLight normally discovers metadata references from the entry assembly. When a required assembly is not discoverable, pass its metadata reference explicitly:

var metadataReference = MetadataReference.CreateFromFile("path-to-your-assembly");

var engine = new RazorLightEngineBuilder()
    .UseMemoryCachingProvider()
    .AddMetadataReferences(metadataReference)
    .Build();

I'm getting "Cannot find compilation library" when I deploy this library on another server

RazorLight discovers metadata from the entry-point project's dependency context. Add this property to the entry-point project (for example, the web app, worker, or console app), not just a class library that wraps RazorLight:

<PropertyGroup>
    <PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>

I'm getting "Can't load metadata reference from the entry assembly" exception

Set PreserveCompilationContext to true in the entry-point project's .csproj file:

<PropertyGroup>
    <PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>

Self-contained, trimmed, and single-file deployments can remove assemblies required by runtime compilation. Preserve the dependency context, avoid trimming template dependencies, and use AddMetadataReferences when the host cannot expose a required reference automatically.

Does RazorLight work in serverless or ASP.NET Core integration-test hosts?

The repository build-validates a .NET 10 Azure Functions v4 isolated-worker sample. AWS Lambda, trimmed deployment, and dedicated ASP.NET Core integration-test hosting are not currently exercised in CI, so they are community-supported rather than declared broken. Keep template rendering behind an application service when you need to substitute it in broader host tests, and open a reproducible issue for host-specific failures.

Project maintenance

  • Read CONTRIBUTING.md before proposing or implementing changes.
  • Report vulnerabilities privately according to SECURITY.md.
  • Use SUPPORT.md to choose the appropriate issue type and diagnostic information.
  • Review CHANGELOG.md for independent-maintenance changes.
  • Follow the protected release process when preparing package artifacts or tags.
  • Track accepted roadmap work in .planfs, with working conventions documented in AGENTS.md.

README.md is generated from this file and the compile-checked snippets in tests/RazorLight.Tests/Snippets. Regenerate it with:

dotnet build tests/RazorLight.Tests/RazorLight.Tests.csproj --configuration Release

Commit README.source.md, the snippet source, and the resulting README.md together. CI rebuilds the documentation and fails if the generated file differs.

About

Independently maintained continuation of RazorLight for .NET

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages