Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/dotnet-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Setup DotNet ✨
uses: actions/setup-dotnet@v5
with:
dotnet-version: "9.0.x"
dotnet-version: "10.0.x"

- name: Install dependencies 📦️
run: dotnet restore
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish-nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
- name: Setup DotNet ✨
uses: actions/setup-dotnet@v5
with:
dotnet-version: "9.0.x"
dotnet-version: "10.0.x"

- name: Install dependencies 📦️
run: dotnet restore
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All"/>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>
</ItemGroup>

<ItemGroup>
Expand Down
129 changes: 55 additions & 74 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ To change this file edit the source file and then run MarkdownSnippets.

# RazorLight

Use Razor to build templates from Files / EmbeddedResources / Strings / Database or your custom source outside of ASP.NET MVC. No redundant dependencies and workarounds in pair with excellent performance and **.NET 8.0 and .NET 9.0** support.
Use Razor to build templates from Files / EmbeddedResources / Strings / Database or your custom source outside of ASP.NET MVC. No redundant dependencies and workarounds in pair with excellent performance and **.NET 8.0, 9.0 and 10.0** support.

Forked from original by [@toddams](https://github.com/toddams/RazorLight/)
Forked from original by [@toddams](https://github.com/toddams/RazorLight/).

My packages are the same names, but prefixed with jcamp. to differentiate them.
My packages are the same names, but prefixed with `jcamp.` to differentiate them.

The original repo has not been updated in two years and I needed some updates to the package that were provided by various PRs. I've tried to give all credit where due.

Expand All @@ -32,18 +32,16 @@ The original repo has not been updated in two years and I needed some updates to

# Quickstart

Install the nuget package using following command:
Install the NuGet package using following command:

```
```powershell
Install-Package RazorLight -Version 3.0.0
```

The simplest scenario is to create a template from string. Each template must have a `templateKey` that is associated with it, so you can render the same template next time without recompilation.

<!-- snippet: simple -->

<a id='snippet-simple'></a>

<!-- snippet: Simple -->
<a id='snippet-Simple'></a>
```cs
var engine = new RazorLightEngineBuilder()
// required to have a default RazorLightProject type,
Expand All @@ -58,17 +56,13 @@ ViewModel model = new ViewModel {Name = "John Doe"};

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

<sup><a href='/tests/RazorLight.Tests/Snippets/Snippets.cs#L18-L32' title='Snippet source file'>snippet source</a> | <a href='#snippet-simple' title='Start of snippet'>anchor</a></sup>

<sup><a href='/tests/RazorLight.Tests/Snippets/Snippets.cs#L18-L32' title='Snippet source file'>snippet source</a> | <a href='#snippet-Simple' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

To render a compiled template:

<!-- snippet: RenderCompiledTemplate -->

<a id='snippet-rendercompiledtemplate'></a>

<a id='snippet-RenderCompiledTemplate'></a>
```cs
var cacheResult = engine.Handler.Cache.RetrieveTemplate("templateKey");
if(cacheResult.Success)
Expand All @@ -77,9 +71,7 @@ if(cacheResult.Success)
string result = await engine.RenderTemplateAsync(templatePage, model);
}
```

<sup><a href='/tests/RazorLight.Tests/Snippets/Snippets.cs#L39-L46' title='Snippet source file'>snippet source</a> | <a href='#snippet-rendercompiledtemplate' title='Start of snippet'>anchor</a></sup>

<sup><a href='/tests/RazorLight.Tests/Snippets/Snippets.cs#L39-L46' title='Snippet source file'>snippet source</a> | <a href='#snippet-RenderCompiledTemplate' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

# Template sources
Expand All @@ -91,9 +83,7 @@ RazorLight can resolve templates from any source, but there are a built-in provi
When resolving a template from filesystem, templateKey - is a relative path to the root folder, that you pass to RazorLightEngineBuilder.

<!-- snippet: FileSource -->

<a id='snippet-filesource'></a>

<a id='snippet-FileSource'></a>
```cs
var engine = new RazorLightEngineBuilder()
.UseFileSystemProject("C:/RootFolder/With/YourTemplates")
Expand All @@ -103,9 +93,7 @@ var engine = new RazorLightEngineBuilder()
var model = new {Name = "John Doe"};
string result = await engine.CompileRenderAsync("Subfolder/View.cshtml", model);
```

<sup><a href='/tests/RazorLight.Tests/Snippets/Snippets.cs#L51-L60' title='Snippet source file'>snippet source</a> | <a href='#snippet-filesource' title='Start of snippet'>anchor</a></sup>

<sup><a href='/tests/RazorLight.Tests/Snippets/Snippets.cs#L51-L60' title='Snippet source file'>snippet source</a> | <a href='#snippet-FileSource' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## EmbeddedResource source
Expand All @@ -114,7 +102,7 @@ For embedded resource, the key is the namespace of the project where the templat

The following examples are using this project structure:

```
```text
Project/
Model.cs
Program.cs
Expand All @@ -127,9 +115,7 @@ Project.Core/
```

<!-- snippet: EmbeddedResourceSource -->

<a id='snippet-embeddedresourcesource'></a>

<a id='snippet-EmbeddedResourceSource'></a>
```cs
var engine = new RazorLightEngineBuilder()
.UseEmbeddedResourcesProject(typeof(SomeService).Assembly)
Expand All @@ -139,17 +125,13 @@ var engine = new RazorLightEngineBuilder()
var model = new Model();
string html = await engine.CompileRenderAsync("EmailTemplates.Body", model);
```

<sup><a href='/tests/RazorLight.Tests/Snippets/Snippets.cs#L65-L74' title='Snippet source file'>snippet source</a> | <a href='#snippet-embeddedresourcesource' title='Start of snippet'>anchor</a></sup>

<sup><a href='/tests/RazorLight.Tests/Snippets/Snippets.cs#L65-L74' title='Snippet source file'>snippet source</a> | <a href='#snippet-EmbeddedResourceSource' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

Setting the root namespace allows you to leave that piece off when providing the template name as the key:

<!-- snippet: EmbeddedResourceSourceWithRootNamespace -->

<a id='snippet-embeddedresourcesourcewithrootnamespace'></a>

<a id='snippet-EmbeddedResourceSourceWithRootNamespace'></a>
```cs
var engine = new RazorLightEngineBuilder()
.UseEmbeddedResourcesProject(typeof(SomeService).Assembly, "Project.Core.EmailTemplates")
Expand All @@ -159,9 +141,7 @@ var engine = new RazorLightEngineBuilder()
var model = new Model();
string html = await engine.CompileRenderAsync("Body", model);
```

<sup><a href='/tests/RazorLight.Tests/Snippets/Snippets.cs#L79-L88' title='Snippet source file'>snippet source</a> | <a href='#snippet-embeddedresourcesourcewithrootnamespace' title='Start of snippet'>anchor</a></sup>

<sup><a href='/tests/RazorLight.Tests/Snippets/Snippets.cs#L79-L88' title='Snippet source file'>snippet source</a> | <a href='#snippet-EmbeddedResourceSourceWithRootNamespace' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

## Custom source
Expand All @@ -171,9 +151,9 @@ If you store your templates in database - it is recommended to create custom Raz
```CSharp
var project = new EntityFrameworkRazorProject(new AppDbContext());
var engine = new RazorLightEngineBuilder()
.UseProject(project)
.UseMemoryCachingProvider()
.Build();
.UseProject(project)
.UseMemoryCachingProvider()
.Build();

// For key as a GUID
string result = await engine.CompileRenderAsync("6cc277d5-253e-48e0-8a9a-8fe3cae17e5b", new { Name = "John Doe" });
Expand All @@ -183,16 +163,17 @@ int templateKey = 322;
string result = await engine.CompileRenderAsync(templateKey.ToString(), new { Name = "John Doe" });
```

You can find a full sample [here](https://github.com/toddams/RazorLight/tree/master/samples/RazorLight.Samples)
You can find more at the [RazorLight.Samples](samples/RazorLight.Samples).

# Includes (aka Partial views)

Include feature is useful when you have reusable parts of your templates you want to share between different views. Includes are an effective way of breaking up large templates into smaller components. They can reduce duplication of template content and allow elements to be reused. _This feature requires you to use the RazorLight Project system, otherwise there is no way to locate the partial._

```CSharp
```cshtml
@model MyProject.TestViewModel

<div>
Hello @Model.Title
Hello @Model.Title
</div>

@{ await IncludeAsync("SomeView.cshtml", Model); }
Expand Down Expand Up @@ -222,7 +203,7 @@ Console.WriteLine(result); // Output: <html>&

In order to disable encoding for the entire document - just set `"DisableEncoding"` variable to true

```html
```cshtml
@model TestViewModel @{ DisableEncoding = true; }

<html>
Expand All @@ -234,12 +215,12 @@ In order to disable encoding for the entire document - just set `"DisableEncodin

Visual Studio tooling knows nothing about RazorLight and assumes, that the view you are using - is a typical ASP.NET MVC template. In order to enable Intellisense for RazorLight templates, you should give Visual Studio a little hint about the base template class, that all your templates inherit implicitly

```CSharp
```cshtml
@using RazorLight
@inherits TemplatePage<MyModel>

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

Expand All @@ -258,21 +239,21 @@ The short answer is, you have to set a project to use the memory caching provide
:x:
You used to be able to write:

```c#
```CSharp
var razorEngine = new RazorLightEngineBuilder()
.UseMemoryCachingProvider()
.Build();
.UseMemoryCachingProvider()
.Build();
```

... but this now throws an exception, saying, "`_razorLightProject cannot be null`".

:heavy_check_mark:

```c#
```CSharp
var razorEngine = new RazorLightEngineBuilder()
.UseEmbeddedResourcesProject(typeof(AnyTypeInYourSolution)) // exception without this (or another project type)
.UseMemoryCachingProvider()
.Build();
.UseEmbeddedResourcesProject(typeof(AnyTypeInYourSolution)) // exception without this (or another project type)
.UseMemoryCachingProvider()
.Build();
```

Affects: RazorLight-2.0.0-beta1 and later.
Expand All @@ -296,21 +277,21 @@ Most problems with RazorLight deal with deploying it on a new machine, in a dock
When RazorLight compiles your template - it loads all the assemblies from your entry assembly and creates MetadataReference from it. This is a default strategy and it works in 99% of the time. But sometimes compilation crashes with an exception message like "Can not find assembly My.Super.Assembly2000". In order to solve this problem you can pass additional metadata references to RazorLight.

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

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

### I'm getting errors after upgrading to ASP.NET Core 3.0 when using runtime compilation

Please see: https://docs.microsoft.com/en-us/aspnet/core/razor-pages/sdk?view=aspnetcore-3.1#use-the-razor-sdk
Please see [the warning in the Microsoft documentation](https://learn.microsoft.com/en-us/aspnet/core/razor-pages/sdk?view=aspnetcore-3.1#properties-1):

> Starting with ASP.NET Core 3.0, MVC Views or Razor Pages aren't served by default if the `RazorCompileOnBuild` or `RazorCompileOnPublish` MSBuild properties in the project file are disabled. Applications must add an explicit reference to the `Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation` package if the app relies on runtime compilation to process .cshtml files.
> Starting with ASP.NET Core 3.0, MVC Views or Razor Pages aren't served by default if the `RazorCompileOnBuild` or `RazorCompileOnPublish` MSBuild properties in the project file are disabled. Applications must add an explicit reference to the [Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation](https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation) package if the app relies on runtime compilation to process `.cshtml` files.

### I'm getting a Null Reference Exception after upgrading to RazorLight-2.0.0-beta2 or later.
### I'm getting a Null Reference Exception after upgrading to RazorLight-2.0.0-beta2 or later

The most common scenario is that some people were using RazorLight's ability to render raw strings as templates. While this is still somewhat supported (you can't use advanced features like partial views), what is not supported (right now) is using the caching provider with raw strings. A workaround is to use a dummy class.

Expand All @@ -319,23 +300,23 @@ The most common scenario is that some people were using RazorLight's ability to
Add these property groups to your **entry point csproj**.
It has to be the entry point project. For example: ASP.NET Core web project, .NET Core Console project, etc.

```XML
<PropertyGroup>
<!-- This group contains project properties for RazorLight on .NET Core -->
<PreserveCompilationContext>true</PreserveCompilationContext>
<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
</PropertyGroup>
```xml
<PropertyGroup>
<!-- This group contains project properties for RazorLight on .NET Core -->
<PreserveCompilationContext>true</PreserveCompilationContext>
<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish>
</PropertyGroup>
```

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

Set PreserveCompilationContext to true in your \*.csproj file's PropertyGroup tag.

```XML
```xml
<PropertyGroup>
...
<PreserveCompilationContext>true</PreserveCompilationContext>
...
<PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>
```

Expand All @@ -346,10 +327,10 @@ Additionally, RazorLight allows you to specifically locate any `MetadataReferenc
By default, the 3.0 SDK avoids copying references to the build output.
Set `PreserveCompilationReferences` and `PreserveCompilationContext` to true in your \*.csproj file's PropertyGroup tag.

```XML
```xml
<PropertyGroup>
<PreserveCompilationReferences>true</PreserveCompilationReferences>
<PreserveCompilationContext>true</PreserveCompilationContext>
<PreserveCompilationReferences>true</PreserveCompilationReferences>
<PreserveCompilationContext>true</PreserveCompilationContext>
</PropertyGroup>
```

Expand Down
Loading