PhotoAtomic.BlazorTemplater 1.7.0

dotnet add package PhotoAtomic.BlazorTemplater --version 1.7.0                
NuGet\Install-Package PhotoAtomic.BlazorTemplater -Version 1.7.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PhotoAtomic.BlazorTemplater" Version="1.7.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add PhotoAtomic.BlazorTemplater --version 1.7.0                
#r "nuget: PhotoAtomic.BlazorTemplater, 1.7.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install PhotoAtomic.BlazorTemplater as a Cake Addin
#addin nuget:?package=PhotoAtomic.BlazorTemplater&version=1.7.0

// Install PhotoAtomic.BlazorTemplater as a Cake Tool
#tool nuget:?package=PhotoAtomic.BlazorTemplater&version=1.7.0                

BlazorTemplater

A library that generates HTML (e.g. for emails) from Razor Components.

Build Nuget

Examples

The ComponentRenderer uses a fluent interface.

Let's render MyComponent.razor as a HTML string.

string html = new ComponentRenderer<MyComponent>().Render();

<details> <summary><code>MyComponent.razor</code></summary>

<p>Hello from BlazorTemplater!</p>

</details>

Parameters

You can set parameters on a component:

var model = new Model() { Value = "Test" };
var title = "Test";
string html = new ComponentRenderer<MyComponent>()
            .Set(c => c.Model, model)
            .Set(c => c.Title, title)
            .Render();

MyComponent has a Model parameter and a Title parameter. The fluent interface uses a lambda expression to specify the property and ensures the value matches the property type.

<details> <summary><code>MyComponent.razor</code></summary>

<h1>@Title</h1>
<p>Your model value is @Model.Value</p>
@code
{
 [Parameter] public Model Model { get; set; }
 [Parameter] public string Title { get; set; }
}

</details>

Dependency Injection

You can specify services to be provided to a component that uses @inject, e.g.:

string html = new ComponentRenderer<MyComponent>()
            .AddService<ITestService>(new TestService())
            .Render();

<details> <summary><code>MyComponent.razor</code></summary>

@inject ITestService MyService
<p>Use service: @MyService.SomeFunction()</p>

Add Service Provider

New for version 1.5 is the ability to add your own IServiceProvider rather than adding services individually. This is useful if you need to re-use the same services repeatedly. Many thanks to @PhotoAtomic for this feature!

IServiceProvider myServiceProvider = GetServiceProvider();
string html = new ComponentRenderer<MyComponent>()
            .AddServiceProvider(myServiceProvider)
            .Render();

</details>

Layouts

If a top-level component has a @layout attribute it will be applied. Alternatively you can apply a template explicitly:

string html = new ComponentRenderer<MyComponent>()
            .UseLayout<MyLayout>()
            .Render();

You can also specify via a type:

void Example(Type layout)
{
    string html = new ComponentRenderer<MyComponent>()
            .UseLayout(layout)
            .Render();
}

See Layouts for more information

The 'kitchen sink'

You can chain them all together in any order, provided .Render() is last:

var model = new Model() { Value = "Test" };
var title = "Test";
string html = new ComponentRenderer<MyComponent>()
            .Set(c => c.Title, title)
            .AddService<ITestService>(new TestService())
            .Set(c => c.Model, model)
            .UseLayout<MyLayout>()
            .Render();

<details> <summary><code>MyComponent.razor</code></summary>

@inject ITestService MyService
<h1>@Title</h1>
<p>Your model value is @Model.Value</p>
<p>Use service: @MyService.SomeFunction()</p>
@code
{
 [Parameter] public Model Model { get; set; }
 [Parameter] public string Title { get; set; }
}

</details>

Template Method

You can also use the older templater method (retained for compatability). See Templater

Getting Started

Add the BlazorTemplater NUGET package to your library.

Usage

See the usage guide.

Supported Project Types

BlazorTemplater can be used in

  • .NET Standard 2.0
  • .NET Standard 2.1
  • .NET Core 3.1
  • .NET 5
  • .NET 6

Libraries or applications using BlazorTemplator need to have the Razor SDK enabled to provide compilation and intellisense for .razor files. If you have an existing .NET Standard class library that does not have Razor Component support, follow this guide to upgrade the library. I did have issues retrofitting Razor support into the .NET Core 3.1 unit test app, so I moved the .razor classes into a .NET Standard library Templater.Library. This should not be an issue for a Blazor WASM or Blazor Server application using .NET Core 3.1 since they already support.

Background

Historically developers have used Razor Views (.cshtml files) to create easy-to-edit email templates with model-based data binding.

This was not a simple process as the .cshtml format wasn't always supported in non-web applications or libraries, and getting the syntax-highlighting and tooling to work with Razor Views was sometimes difficult. Two examples of this approach are RazorLight and RazorEngine.

With the introduction of Razor Component Libraries that can contain .razor files, it's now much easier to create class libraries which include Razor-based markup than using using Razor Views (.cshtml files).

Technical Differences

A .cshtml file was normally a text file or resource in a project that had to be parsed, validated, and a class generated at runtime to create code that could be used with a model to create the HTML required. The meant that RazorView-based libraries had to "compile" the template before it could be used, often at runtime.

In comparison, a Razor Component is a class created at compile time so using this is much faster and simpler! Razor Components also support binding of multiple properties (not just a single Model), so provides more flexibility in design and usage.

Supported Features

BlazorRenderer supports using:

Limitations

The following are not supported/tested:

  • JavaScript
  • EventCallbacks
  • Rerendering
  • CSS and CSS isolation
CSS and Html Emails

CSS support in HTML emails is a complicated area. Many email clients (Outlook, GMail, Hotmail etc) have differing levels of what is supported. You can't often reference an external CSS file from the email as external references are often blocked.

A good idea is to use a utility library to pre-process and inline the CSS before creating the email body. A good example of this is PreMailer.NET.

Credits and Acknowledgements

The basis of the rendering system is adapted from Steve Sanderson's BlazorUnitTestingPrototype repo which was written as very simple component test library for Blazor.

This was never developed into a functioning product or library. For unit testing Razor Components I recommend Egil Hansen's bunit.

Version History

Version Changes
v1.0.0 Inital Release (to Nuget)
v1.1.0 Breaking change: renamed BlazorTemplater class to Templater #4
v1.2.0 Added multi-targetting for .NET Std/.NET 5 to fix bug #12
v1.3.0 Added ComponentRenderer<T> for fluent interface and typed parameter setting
v1.4.0 Added support for Layouts
v1.5.0 Added support already existing IServiceProvider
v1.6.0 Added support AsyncRender
v1.7.0 Added better support AsyncRender using Drake53 code, marked old AsyncRender introduce in 1.6.0 Obsolete
Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.7.0 5,909 10/17/2022
1.6.0 2,668 9/21/2022
1.4.1-PR.26 147 4/28/2022

Incorporated better async generation from Drake53 code, marked old async render method obsolete