Loading...
Loading...
Guides conversion of a pre-.NET 8 Blazor Server app into a .NET 8+ Blazor Web App. USE FOR: migrating apps that use AddServerSideBlazor and MapBlazorHub to the AddRazorComponents/MapRazorComponents model, converting _Host.cshtml to an App.razor root component, replacing blazor.server.js with blazor.web.js, migrating CascadingAuthenticationState to a service, adopting new Blazor Web App features like enhanced navigation and streaming rendering. DO NOT USE FOR: apps that are already Blazor Web Apps (already use AddRazorComponents and MapRazorComponents), Blazor WebAssembly or hosted Blazor WebAssembly apps (different migration path), apps that should stay on the Blazor Server hosting model without converting, or apps still targeting .NET Framework.
npx skill4agent add dotnet/skills convert-blazor-server-to-webappAddServerSideBlazorMapBlazorHub_Host.cshtmlAddRazorComponentsMapRazorComponentsApp.razorInteractiveServerAddServerSideBlazor()MapBlazorHub()Program.csStartup.csPages/_Host.cshtml_Host.razorAddRazorComponentsMapRazorComponents| Input | Required | Description |
|---|---|---|
| Blazor Server project | Yes | The |
| Target framework | Yes | .NET 8 or later (e.g., |
| Yes | The app's service and middleware configuration |
| Recommended | Usually |
Commit strategy: Commit after each logical step so the migration is reviewable and bisectable.
.csproj<TargetFramework>net8.0</TargetFramework>Microsoft.AspNetCore.*Microsoft.EntityFrameworkCore.*Microsoft.Extensions.*System.Net.Http.JsonRoutes.razorApp.razorApp.razor<Router>Routes.razorApp.razorRoutes.razorApp.razorRoutes.razor<CascadingAuthenticationState>App.razorRoutes.razor<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router><AuthorizeRouteView><RouteView>_Host.cshtmlApp.razorPages/_Host.cshtmlApp.razor@page "/"@using Microsoft.AspNetCore.Components.Web@namespace@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers@inject IHostEnvironment Env<base href="~/" /><base href="/" /><component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" /><HeadOutlet @rendermode="InteractiveServer" /><component type="typeof(App)" render-mode="ServerPrerendered" /><Routes @rendermode="InteractiveServer" /><environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>@if (Env.IsDevelopment())
{
<text>
An unhandled exception has occurred. See browser dev tools for details.
</text>
}
else
{
<text>
An error has occurred. This app may no longer respond until reloaded.
</text>
}<script src="_framework/blazor.server.js"></script><script src="_framework/blazor.web.js"></script>_Imports.razor@using static Microsoft.AspNetCore.Components.Web.RenderModePages/_Host.cshtmlPages/_Host.cshtml.csrender-mode="Server""ServerPrerendered"new InteractiveServerRenderMode(prerender: false)InteractiveServerHeadOutletRoutesProgram.csProgram.csStartup.csbuilder.Services.AddServerSideBlazor();builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();AddServerSideBlazorAddInteractiveServerComponents// Old:
builder.Services.AddServerSideBlazor(options =>
{
options.DetailedErrors = true;
options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromMinutes(10);
});
// New:
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents(options =>
{
options.DetailedErrors = true;
options.DisconnectedCircuitRetentionPeriod = TimeSpan.FromMinutes(10);
});app.MapBlazorHub();app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();usingAppApp.razorapp.MapFallbackToPage("/_Host");app.UseRouting();UseRouting()UseAuthenticationUseAuthorizationapp.UseAntiforgery();AddRazorComponentsCascadingAuthenticationState<CascadingAuthenticationState><CascadingAuthenticationState>Program.csbuilder.Services.AddCascadingAuthenticationState();Task<AuthenticationState>UseStaticFilesMapStaticAssetsapp.MapStaticAssets()@attribute [StreamRendering]OnInitializedAsync<link>_Host<link href="{AssemblyName}.styles.css" rel="stylesheet" />AddServerSideBlazorMapBlazorHubMapFallbackToPageblazor.server.js_Host.cshtmlAddServerSideBlazorMapBlazorHubMapFallbackToPage("/_Host")blazor.server.jsPages/_Host.cshtmlApp.razorRoutes.razor<Router>Program.csAddRazorComponents().AddInteractiveServerComponents()Program.csMapRazorComponents<App>().AddInteractiveServerRenderMode()app.UseAntiforgery()<CascadingAuthenticationState>AddCascadingAuthenticationState()| Pitfall | Solution |
|---|---|
Missing | |
Forgetting to replace | The old script does not work with the Blazor Web App model. Replace all references to |
Not removing | The component wrapper does not work across render mode boundaries in Blazor Web Apps. Use |
Leaving | Explicit |
Using | If the original app used |
Not migrating | If circuit options, hub options, or detailed error settings were configured, migrate them to |
| The antiforgery middleware must be placed after |
| CSS isolation bundle link has wrong assembly name | If the |
@attribute [StreamRendering]