Blazor WebAssembly
Learn the structure of the Blazor WebAssembly project template.
The Blazor WebAssembly project template is used to create a stand-alone Blazor WebAssembly application. In this lesson, we will look at its structure. Let’s look at the complete project setup below:
<Router AppAssembly="@typeof(App).Assembly"> <Found Context="routeData"> <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /> <FocusOnNavigate RouteData="@routeData" Selector="h1" /> </Found> <NotFound> <PageTitle>Not found</PageTitle> <LayoutView Layout="@typeof(MainLayout)"> <p role="alert">Sorry, there's nothing at this address.</p> </LayoutView> </NotFound> </Router>
The complete project structure is demonstrated in the following diagram:
Project file structure and core libraries
In the above example, our project folder is called Blazor
, and the project file is Blazor.csproj
. It has the following content:
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly"><PropertyGroup><TargetFramework>net7.0</TargetFramework><Nullable>enable</Nullable><ImplicitUsings>enable</ImplicitUsings></PropertyGroup><ItemGroup><PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.0" /><PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.0" PrivateAssets="all" /></ItemGroup></Project>
A Blazor WebAssembly project file is based on the Microsoft.NET.Sdk.BlazorWebAssembly
SDK. This is defined inside the opening Project
tag on line 1.
Every Blazor WebAssembly project relies on the Microsoft.AspNetCore.Components.WebAssembly
NuGet package, which we have on line 10 in the project file. We also have a reference to Microsoft.AspNetCore.Components.WebAssembly.DevServer
NuGet package on line 11. This package enables us to launch and host the application in the development environment.
Application entry point
As with most .NET applications, a Blazor WebAssembly application has the Program.cs
file as its entry point. In the example above, this file has the following content.
using Blazor;using Microsoft.AspNetCore.Components.Web;using Microsoft.AspNetCore.Components.WebAssembly.Hosting;var builder = WebAssemblyHostBuilder.CreateDefault(args);builder.RootComponents.Add<App>("#app");builder.RootComponents.Add<HeadOutlet>("head::after");builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });await builder.Build().RunAsync();
On line 5, we create a default Blazor WebAssembly host builder. On line 6, we determine which class will represent our application. In the example above, this class is called App
. We associate this class with an HTML element that has the id
attribute app
. On line 7, we define the template for the header, which is represented by the HeadOutlet
class and is mapped to the head::after
CSS selector. On line 9, we are adding a scoped reference to a HttpClient
instance. Finally, on line 11, we are building and running our application.
Other files in the project root folder
The remaining files in the root folder of our project have a .razor
extension. This is the file extension used by individual Blazor units, such as pages, layouts, and reference files. These are collectively called Razor components. These files are _Imports.razor
and App.razor
.
The _Imports.razor
file contains shared namespaces used by other files with .razor
extensions inside the application. If we define any specific namespace in this file, we don't need to explicitly define them in any other Razor components.
The App.razor
file is the container object for our application and its user interfaces. In the example above, this file has the following structure.
<Router AppAssembly="@typeof(App).Assembly"><Found Context="routeData"><RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" /><FocusOnNavigate RouteData="@routeData" Selector="h1" /></Found><NotFound><PageTitle>Not found</PageTitle><LayoutView Layout="@typeof(MainLayout)"><p role="alert">Sorry, there's nothing at this address.</p></LayoutView></NotFound></Router>
Router
is the root element defined by the markup. If we point at a path that maps to a valid Razor page, the content inside the Found
element will be used that is defined on lines 2–5. The RouteView
element on line 3 represents the placeholder for the layout, which will then contain the actual page.
If there is no Razor page associated with the URL path provided, the NotFound
element will be used, which is defined on lines 6–11. We still use a layout defined by the LayoutView
element on lines 8–10. Instead of populating it with a Razor page, we populate it with a message telling the user that the page has not been found.
Shared components
The Shared
folder contains Razor components that are shared by the application. Examples of these shared resources include layouts and navigational menus. For example, let’s examine the MainLayout.razor
file, which has the following content:
@inherits LayoutComponentBase<div class="page"><div class="sidebar"><NavMenu /></div><main><article class="content px-4">@Body</article></main></div>
In Blazor, a layout component inherits from the LayoutComponentBase
class, as we have defined on line 1. It can then have a combination of HTML and Razor components. The NavMenu
reference on line 5 is an example of a Razor component reference. The body of the Razor page gets inserted into the @Body
placeholder directive that we have on line 10.
Individual pages
Individual pages are located inside the Pages
folder of the project. When a specific page is requested, a layout is displayed with the content of this page inside of it.
Static resources
Static recourses, such as HTML, CSS, and JavaScript files, are inside the wwwroot
folder. The Blazor application is hosted inside an HTML page. By default, we have the index.html
file for this purpose. The default structure of this file is as follows:
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /><title>BlazorWebAssemblyExample</title><base href="/" /><link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" /><link href="css/app.css" rel="stylesheet" /><link rel="icon" type="image/png" href="favicon.png" /><link href="BlazorWebAssemblyExample.styles.css" rel="stylesheet" /></head><body><div id="app"><svg class="loading-progress"><circle r="40%" cx="50%" cy="50%" /><circle r="40%" cx="50%" cy="50%" /></svg><div class="loading-progress-text"></div></div><div id="blazor-error-ui">An unhandled error has occurred.<a href="" class="reload">Reload</a><a class="dismiss">🗙</a></div><script src="_framework/blazor.webassembly.js"></script></body></html>
The Blazor application is inserted into the div
element with the id
attribute of app
, as we have defined on line 16. This is the element we pointed to when we configured our application in the Program.cs
file.