Introducing RazorSharpener
Introduction
Sharpener: a person or device that makes something sharp (Cambridge Dictionary).
RazorSharpener is a Razor compiler and renderer. It can load a .razor file and compile it into a .NET class that implements IComponent, the base interface for Razor components.
This can be used, for example, to build a template engine, as Razor allows us to combine contents and code.
Usage
RazorSharpener is composed of just two classes:
- RazorCompiler: used to compile a .razor source file (Razor component) into a .NET class
- RazorRenderer: renders a Razor component type into a string
Razor Compiler
To compile a .razor file is very simple:
var compiler = new RazorCompiler();
var asm = compiler.Compile("RenderMessage.razor");
As you can see, the Compile method takes a file from the current folder and produces an assembly, which is how .NET "wraps" generated code. If there is any compilation error, an exception is thrown. The generated assembly will have a single .NET type that implements IComponent.
There are overloads for passing arbitrary .NET assemblies, that will be used for linked references, and also compiler options. The defaults should be enough, at least, for simple cases and I won't cover more complex scenarios here.
Razor Renderer
The renderer is only slightly more complex, but the class itself is called RazorRenderer:
var renderer = new RazorRenderer();
Now, there are two overloads of its Render method:
1) One that takes a .razor class:
var html = await renderer.Render<RenderMessage>();
Note: the .csproj must have this .razor file configured as Content and Copy if newer so that it is available on the output folder:
var componentType = asm.GetTypes().First();
var html = await renderer.Render(componentType);
As you can see, both overloads are asynchronous and have to be awaited. Also, both have an overload that takes a parameter dictionary:
var parameters = new Dictionary<string, object?>
{
["Message"] = "Hello, world!"
};
var html = await renderer.Render<RenderMessage>(parameters);
//or
var html = await renderer.Render(componentType, parameters);
Parameters must match any parameters defined on the .razor file, for example, here is my sample RenderMessage.razor:
@if (string.IsNullOrWhiteSpace(Message))
{
<p>No message provided</p>
}
else
{
<p>@Message</p>
}
@code {
[Parameter]
public string? Message { get; set; }
}
Of course, any parameters passed to Render must match the declared parameter type - the property to which [Parameter] is applied.
And this is it! Render will render the component as HTML (or whatever it produces) and return the generated output.
Conclusion
I hope you find this useful, as always, looking forward for your comments or questions. You can expect some more features and improvements in the future.
The need to target .Net Web Sdk is kind of restrictive, since an interesting use case for this library would be on application layers dispatching templated emails, for instance.
ReplyDeleteRight, let me explain that: in order to automatically compile the RenderMessage.razor file into a RenderMessage .NET class you need this, but that is all. You can use the library without it. Thanks for your comment!
DeleteActually, it seems that it is not needed, I was wrong! :-)
Delete