Render Razor components outside of ASP.NET Core

Note

This isn't the latest version of this article. For the current release, see the .NET 9 version of this article.

Important

This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.

For the current release, see the .NET 9 version of this article.

Razor components can be rendered outside of the context of an HTTP request. You can render Razor components as HTML directly to a string or stream independently of the ASP.NET Core hosting environment. This is convenient for scenarios where you want to generate HTML fragments, such as for generating email content, generating static site content, or for building a content templating engine.

In the following example, a Razor component is rendered to an HTML string from a console app:

In a command shell, create a new console app project:

dotnet new console -o ConsoleApp1
cd ConsoleApp1

In a command shell in the ConsoleApp1 folder, add package references for Microsoft.AspNetCore.Components.Web and Microsoft.Extensions.Logging to the console app:

dotnet add package Microsoft.AspNetCore.Components.Web
dotnet add package Microsoft.Extensions.Logging

In the console app's project file (ConsoleApp1.csproj), update the console app project to use the Razor SDK:

- <Project Sdk="Microsoft.NET.Sdk">
+ <Project Sdk="Microsoft.NET.Sdk.Razor">

Add the following RenderMessage component to the project.

RenderMessage.razor:

<h1>Render Message</h1>

<p>@Message</p>

@code {
    [Parameter]
    public string Message { get; set; }
}

Update the Program file:

Any calls to RenderComponentAsync must be made in the context of calling InvokeAsync on a component dispatcher. A component dispatcher is available from the HtmlRenderer.Dispatcher property.

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using ConsoleApp1;

IServiceCollection services = new ServiceCollection();
services.AddLogging();

IServiceProvider serviceProvider = services.BuildServiceProvider();
ILoggerFactory loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();

await using var htmlRenderer = new HtmlRenderer(serviceProvider, loggerFactory);

var html = await htmlRenderer.Dispatcher.InvokeAsync(async () =>
{
    var dictionary = new Dictionary<string, object?>
    {
        { "Message", "Hello from the Render Message component!" }
    };

    var parameters = ParameterView.FromDictionary(dictionary);
    var output = await htmlRenderer.RenderComponentAsync<RenderMessage>(parameters);

    return output.ToHtmlString();
});

Console.WriteLine(html);

Note

Pass ParameterView.Empty to RenderComponentAsync when rendering the component without passing parameters.

Alternatively, you can write the HTML to a TextWriter by calling output.WriteHtmlTo(textWriter).

The task returned by RenderComponentAsync completes when the component is fully rendered, including completing any asynchronous lifecycle methods. If you want to observe the rendered HTML earlier, call BeginRenderingComponent instead. Then, wait for the component rendering to complete by awaiting HtmlRootComponent.QuiescenceTask on the returned HtmlRootComponent instance.