Migrate Blazor Server to Blazor WebAssembly – .NET Aspire Starter App.
Introduction:
We recently undertook an exciting project to migrate our .NET Aspire Starter application from a Blazor Server setup to Blazor WebAssembly (WASM). This move aimed to enhance our application’s performance, scalability, and user experience by leveraging the client-side capabilities of WebAssembly. In this blog post, we’ll walk you through the steps we took, the challenges we faced, and the benefits we gained from this migration.
Why Migrate to Blazor WebAssembly?
Blazor Server and Blazor WebAssembly are both powerful frameworks, but they cater to different needs:
Blazor Server
It runs on the server and uses SignalR to communicate with the client. It offers faster initial load times and better SEO support but relies on a constant server connection, which can be a bottleneck for large-scale applications.
Blazor WebAssembly
It runs directly on the client’s browser using WebAssembly. It offers better scalability and offline capabilities since it doesn’t rely on a constant server connection. This can significantly enhance the user experience by reducing latency and server load.
Given these advantages, we decided to transition our .NET Aspire Starter Web app to Blazor WebAssembly.
Step-by-Step Migration Process
First, we created a new Blazor WebAssembly project. This involved setting up the basic structure of our new Blazor WebAssembly app using Visual Studio:
Initial Setup
Create a New Blazor WebAssembly Project
- Open Visual Studio and select `Create a new project`.
- Choose `Blazor WebAssembly App` and click `Next`.
- Configure the project name, location, and solution name, then click `Create`.
Configure for .Net Aspire Orchestration
- During project creation, select the `Enlist in .NET Aspire orchestration` option.
Migrate Project Files
Next, we migrated our project files from the Blazor Server app to the new Blazor WebAssembly app:
Copy `wwwroot` Folder
— Copy the entire `wwwroot` folder from the Blazor Server project to the Blazor WebAssembly project. This folder contains static assets such as CSS, JavaScript, and images.
Note: In Blazor Server app we will have App.razor which serves as the main entry point for loading and running the application. But In Blazor WASM app index.html file serves as the main entry point for loading and running the application.
Here’s what the index.html file typically does in a WebAssembly app:
Structure and Basic HTML
It provides the basic structure of an HTML document, including <html>, <head>, and <body> tags. This structure allows the browser to render the content correctly.
Loading the WebAssembly Module
Inside the <body> section, there is usually a script tag (<script>), which is responsible for loading the WebAssembly module. This script sets up the necessary environment for the module to be loaded and executed.
This JavaScript code typically uses fetch() to load the .wasm file and then instantiates the WebAssembly module using WebAssembly.instantiate() or WebAssembly.instantiateStreaming()
CSS and Styling
It can include CSS styles or link to external stylesheets (<link rel=”stylesheet” href=”styles.css”>) to define the visual appearance of the application.
Scripts and Dependencies
It might include additional JavaScript files or libraries that are needed to support the application logic or interact with the WebAssembly module.
Fallbacks and Error Handling
Optionally, it can provide fallbacks or error handling mechanisms in case the browser does not support WebAssembly or encounters errors during module loading.
Transfer Components and Pages
Copy all Razor components (`.razor` files) and their code-behind files (`.razor.cs`) from the Blazor Server project to the Blazor WebAssembly project.
Update `_Imports.razor`
Ensure the `_Imports.razor` file in the Blazor WebAssembly project includes all necessary namespaces used by the components and pages.
Update Program.cs.
In Blazor WebAssembly, the Program.cs file handles the app’s startup configuration. We needed to update this file to configure services and other settings appropriately:
Configure Dependency Injection
Register services and configure dependency injection in the Program.cs file of the Blazor WebAssembly project:

Remove Blazor Server-Specific Code
Remove any Blazor Server-specific code from Program.cs, as it is not needed in Blazor WebAssembly. This includes SignalR configurations and server-side services.
Handle Authentication and Authorization
Add Authentication
Use the “Microsoft.AspNetCore.Components.WebAssembly.Authentication” package to add authentication support. This package includes OAuth and OIDC authentication mechanisms.
Update App.razor

Modify the App.razor file to include authentication logic:
<CascadingAuthenticationState>
This component provides the current authentication state (such as user identity and claims) to all descendant components. It’s required when using components that need to access authentication state, such as AuthorizeRouteView.
<Router AppAssembly=”@typeof(App).Assembly”>
The Router component enables routing in the Blazor application. It looks for routes in the specified assembly, which in this case is the assembly containing the App class.
<Found Context=”routeData”>
The Found component specifies what to render when a route is successfully matched. The Context parameter provides the matched route data (routeData).
<AuthorizeRouteView RouteData=”@routeData” DefaultLayout=”@typeof(MainLayout)” />
The AuthorizeRouteView component is similar to RouteView, but it includes authorization support. It renders the component specified by the route if the user is authorized. If the user is not authorized, it will typically render an Authorizing or NotAuthorized message. The DefaultLayout parameter specifies the default layout to use for the component (in this case, MainLayout).
<FocusOnNavigate RouteData=”@routeData” Selector=”h1″ />
The FocusOnNavigate component sets the focus to the element specified by the Selector parameter (in this case, an h1 element) whenever navigation occurs. This helps improve accessibility by ensuring that screen readers and keyboard users are aware of navigation changes.
<NotFound>
The NotFound component specifies what to render when no route matches the requested URL.
<LayoutView Layout=”@typeof(MainLayout)”>
The LayoutView component renders content inside a specified layout. Here, it uses the MainLayout and displays a message indicating that the requested address is not found.
Migrate API Calls
In Blazor WebAssembly, API calls are made directly from the client using HttpClient. Ensure all API calls are correctly configured and secured:
Update API Base URL
Configure the base URL for HttpClient to point to your backend API:
![]()
Secure API Endpoints
Ensure your API endpoints are secured and can only be accessed by authenticated users. Use JWT tokens or other secure methods to authorize API requests.
Conclusion
Migrating our .NET Aspire Starter app from Blazor Server to Blazor WebAssembly was a significant step forward. The move has enabled us to leverage the benefits of WebAssembly, including improved performance, better scalability, and a more responsive user experience. By following the steps outlined in this blog post, we hope you can achieve a similar successful migration in your own projects.
If you have any questions or need further assistance, feel free to reach out to me. Thank you & Happy coding!
Written by Kamal Kiran Nethala