Aeroverra.RazorToString
1.0.1
dotnet add package Aeroverra.RazorToString --version 1.0.1
NuGet\Install-Package Aeroverra.RazorToString -Version 1.0.1
<PackageReference Include="Aeroverra.RazorToString" Version="1.0.1" />
<PackageVersion Include="Aeroverra.RazorToString" Version="1.0.1" />
<PackageReference Include="Aeroverra.RazorToString" />
paket add Aeroverra.RazorToString --version 1.0.1
#r "nuget: Aeroverra.RazorToString, 1.0.1"
#:package Aeroverra.RazorToString@1.0.1
#addin nuget:?package=Aeroverra.RazorToString&version=1.0.1
#tool nuget:?package=Aeroverra.RazorToString&version=1.0.1
AeroRazorToString
Render Razor views to HTML strings from anywhere. No web host required.
Purpose
Razor is the best templating engine .NET has, and ASP.NET Core will only run it for you inside a web request. The moment you want an HTML string instead of a response body, from a worker service sending an email, a console tool generating a report, a queue consumer building a PDF, you are on your own.
The pieces to do it by hand are all public, which is why every codebase ends up with the same
copy of the same fifteen year old sample: fake an HttpContext, fake an ActionContext, point a
StringWriter at the view engine. That sample stops working the moment there is no web host,
because MVC quietly assumes one: no IWebHostEnvironment, no diagnostic listener, no object pool
provider, and no application parts to harvest compilation references from. What you get instead is
a namespace 'Hosting' does not exist error from a Razor compiler with nothing to compile against.
This package is that problem solved once, tested against a worker service, a web app, and a bare
ServiceCollection.
- One line of registration, one method to call, works the same in every host
- Layouts, partials,
_ViewStart,_ViewImports, tag helpers, andViewDataall behave normally @injectresolves against a fresh DI scope per render, so a scopedDbContextin a view is a scopedDbContextand not a process lifetime singleton shared across concurrent renders- Views are read from the output folder, and the package's build targets put them there for you
- Views can also come from any other folder, from a file provider with no disk behind it, or from a Razor class library where they are already compiled
- A view that will not compile, or a view name that matches nothing, says so in a way you can act on
Install
dotnet add package Aeroverra.RazorToString
Requires .NET 10. Your .cshtml files are copied next to the built app automatically; no csproj
changes needed.
Use it
Register once, in any host:
builder.Services.AddRazorToString();
Inject IRazorToStringRenderer anywhere and render:
public class OrderCompleteEmailBuilder(IRazorToStringRenderer razor)
{
public async Task<string> BuildAsync(Order order)
{
return await razor.RenderAsync("/Emails/OrderComplete.cshtml", new OrderCompleteModel
{
CustomerName = order.CustomerName,
SerialCodes = order.SerialCodes
});
}
}
That is the whole API in a worker service, a console app, an Azure Function, or a web app. The view
is an ordinary .cshtml file with an ordinary @model directive.
What it does for you
AddRazorToString() looks at the service collection and decides what is missing:
| In a web app | In a worker service, console app, or bare container |
|---|---|
Uses the host's IWebHostEnvironment, application parts, and compilation references |
Registers a stand in IWebHostEnvironment rooted at the output folder |
| Adds the output folder as an extra view location, so views shipped inside a class library resolve | Registers the DiagnosticListener and ObjectPoolProvider MVC assumes a web host provided |
| Leaves the app's own content root at higher priority, so its views stay editable at run time | Hands the runtime compiler a reference set built from the loaded assemblies, the output folder, and the shared frameworks |
Either way you get the same singleton renderer, safe to call concurrently.
Views that are not on disk
Runtime compilation is the default because it lets a template be edited without a rebuild. It is not the only source:
builder.Services.AddRazorToString(options =>
{
options.AdditionalViewRoots.Add("/etc/myapp/templates"); // an operator editable folder
options.FileProviders.Add(new ManifestEmbeddedFileProvider(assembly));
options.ApplicationParts.Add(typeof(EmailTemplates).Assembly); // compiled into a Razor class library
});
Set options.UseRuntimeCompilation = false to render only views compiled into application parts,
which trades editability for never shipping a .cshtml file.
Documentation
Full documentation, including host modes, how view names resolve, every option, precompiled views, and the gotchas worth knowing about, lives in the wiki.
License
MIT. See LICENSE.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation (>= 10.0.11)
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.0.1 | 110 | 8/17/2026 |