Presentations : Blazor WebAssembly

The Presentation Blazor WebAssembly layer templates generate a complete Blazor WebAssembly client application for each bounded context. The generator produces the project file, application entry point, dependency injection configuration, layout and menu components, home and error pages, resource files for localization, static web assets, and a full CRUD UI for each entity — including list, details, create, edit, and delete dialogs — all driven by the entity and bounded context definitions configured in the Scaffolder.net UI. Unlike the BlazorServer variant, this layer communicates with the backend via HTTP proxies and runs entirely in the browser.

Project File

The {{Solution.Name}}.Presentation.BlazorWebAssembly.{{BoundedContext.Name}}.csproj file defines the Blazor WebAssembly project using the Microsoft.NET.Sdk.BlazorWebAssembly SDK. It enables HTML asset placeholder overriding and loads all globalization data for client-side localization. It includes project references to the Application project (for shared command/query contracts) and the Shared.Presentation.Blazor and Shared.Presentation.BlazorWebAssembly projects, providing access to shared UI controls and BlazorWebAssembly-specific extensions. It also references the Microsoft.AspNetCore.Components.WebAssembly and Microsoft.AspNetCore.Components.WebAssembly.DevServer packages.

Imports

The _Imports.razor file declares global Razor directives for the presentation project. It imports ASP.NET Core Components routing and web namespaces, MudBlazor, the error and layout component namespaces, and all shared Blazor UI control namespaces (Button, CheckBox, DataGrid, DatePicker, Dialog, ErrorManager, Loading, NavMenu, NumericField, Select, SimpleTable, TextField, etc.). It injects shared services (IDialogService, IJSRuntime, NavigationManager) and string localizers for both the Domain and PresentationBlazorWebAssembly resources. The generator appends entity-specific @inject directives for each entity's query and command service proxies via {PresentationBlazorWebAssemblyGenerator.GetImports}. Finally, it inherits from ApplicationComponentBaseControl to provide shared component base functionality.

Global Usings

The GlobalUsings.cs file declares global using directives for the presentation project. It includes standard .NET namespaces, Microsoft ASP.NET Core Components and WebAssembly hosting namespaces, dependency injection, localization, JS interop, MudBlazor, and Serilog. The generator dynamically appends global usings for each entity's Application layer namespaces (commands, queries, errors, services) and Presentation BlazorWebAssembly namespaces (components, dependency injection, resources) via {PresentationBlazorWebAssemblyGenerator.GetGlobalUsings}, ordered alphabetically by entity name.

Program

The Program.cs file contains the application entry point. It creates the WebAssemblyHostBuilder using the default configuration, calls ConfigureWebAssemblyHostBuilder to register all client-side services, builds the WebAssemblyHost, logs startup information using Serilog, calls ConfigureWebApplicationAsync to apply culture and validation configuration, and runs the host. A global try-catch-finally block ensures fatal exceptions are logged and the logger is properly flushed on shutdown.

Components

The Components directory contains all Razor components for the Blazor WebAssembly application, organized into subdirectories for errors, entity features, home, layouts, menus, and the root routes file.

Components : Errors : NotFound

The NotFoundErrorPage.razor and NotFoundErrorComponent.razor files generate a @page "/NotFound" route with the MainLayoutComponent layout. The page renders the NotFoundErrorComponent, which displays a localized "Page not found" heading and content. Both files have partial code-behind classes declaring the namespace.

Components : Errors : Unknown

The UnknownErrorPage.razor and UnknownErrorComponent.razor files generate a @page "/UnknownError" route. The page renders the UnknownErrorComponent, which displays a localized "Unknown error" heading and content. Both files have partial code-behind classes declaring the namespace.

Components : Features : Entity Commands : Create

For each entity, the generator produces a Create{{Entity.NameSingular}}Dialog with a Razor file and a code-behind file :
  • Create{{Entity.NameSingular}}Dialog.razor : Renders a DialogControl with a localized title, a loading state, form input controls generated by {PresentationBlazorWebAssemblyGenerator.GetControls.WithId} (which produces TextFieldControl, NumericFieldControl, DatePickerControl, CheckBoxControl, or SelectEnumControl based on each property's type), and Cancel / Create action buttons.
  • Create{{Entity.NameSingular}}Dialog.razor.cs : A sealed partial class implementing IAsyncDisposable that holds a Create{{Entity.NameSingular}}CommandRequest, initializes non-nullable enum properties to their default values via {PresentationBlazorWebAssemblyGenerator.GetEnumsDefaultValue}, calls the command service proxy to create the entity, and closes the dialog with the result. Errors are displayed via ErrorManagerControl.

Components : Features : Entity Commands : Delete

For each entity, the generator produces a Delete{{Entity.NameSingular}}Dialog with a Razor file and a code-behind file :
  • Delete{{Entity.NameSingular}}Dialog.razor : Renders a DialogControl with a localized title, a loading state, a read-only SimpleTableControl displaying the entity's property values generated by {PresentationBlazorWebAssemblyGenerator.GetTableRows.WithId}, and Cancel / Delete action buttons.
  • Delete{{Entity.NameSingular}}Dialog.razor.cs : A sealed partial class implementing IAsyncDisposable that receives the entity Id as a parameter, loads the delete confirmation data via the query service proxy's GetDelete{{Entity.NameSingular}}Async method (navigating to /NotFound if the entity does not exist), shows a ConfirmDeleteDialogControl before deletion, calls the command service proxy to delete the entity, and closes the dialog with the result.

Components : Features : Entity Commands : Edit

For each entity, the generator produces an Edit{{Entity.NameSingular}}Dialog with a Razor file and a code-behind file :
  • Edit{{Entity.NameSingular}}Dialog.razor : Renders a DialogControl with a localized title, a loading state, form input controls generated by {PresentationBlazorWebAssemblyGenerator.GetControls} (without the Id field, since the Id is not editable), and Cancel / Save action buttons.
  • Edit{{Entity.NameSingular}}Dialog.razor.cs : A sealed partial class implementing IAsyncDisposable that receives the entity Id as a parameter, loads the edit data via the query service proxy's GetEdit{{Entity.NameSingular}}Async method (navigating to /NotFound if the entity does not exist), populates the Edit{{Entity.NameSingular}}CommandRequest, calls the command service proxy to edit the entity, and closes the dialog with the result.

Components : Features : Entity Queries : GetDetails

For each entity, the generator produces a details page and component :
  • Get{{Entity.NameSingular}}DetailsPage.razor : Defines a @page "/{{Entity.NamePlural}}/{{{Entity.NameSingular}}Id:{{Entity.IdType.ToLower}}}" route, renders a localized page title, and passes the route parameter to the Get{{Entity.NameSingular}}DetailsComponent.
  • Get{{Entity.NameSingular}}DetailsPage.razor.cs : A sealed partial class declaring the {{Entity.IdType}} {{Entity.NameSingular}}Id parameter with [EditorRequired].
  • Get{{Entity.NameSingular}}DetailsComponent.razor : Displays a localized heading, a loading state, a read-only SimpleTableControl with the entity's property values generated by {PresentationBlazorWebAssemblyGenerator.GetTableRows.WithId}, and an Edit button that opens the Edit{{Entity.NameSingular}}Dialog.
  • Get{{Entity.NameSingular}}DetailsComponent.razor.cs : A sealed partial class implementing IAsyncDisposable that loads the entity details via the query service proxy, handles the NotFound error by redirecting to /NotFound, and opens the edit dialog with the entity Id.

Components : Features : Entity Queries : GetList

For each entity, the generator produces a list page and component :
  • Get{{Entity.NameSingular}}ListPage.razor : Defines a @page "/{{Entity.NamePlural}}" route, renders a localized page title, and delegates rendering to the Get{{Entity.NameSingular}}ListComponent.
  • Get{{Entity.NameSingular}}ListPage.razor.cs : A sealed partial class declaring the namespace.
  • Get{{Entity.NameSingular}}ListComponent.razor : Displays a localized heading, a loading state, a DataGridControl with property columns generated by {PresentationBlazorWebAssemblyGenerator.GetDataGridPropertyColumns.WithId}, a details hyperlink icon column, and a delete icon button column. An Add button opens the Create{{Entity.NameSingular}}Dialog.
  • Get{{Entity.NameSingular}}ListComponent.razor.cs : A sealed partial class implementing IAsyncDisposable that loads the entity list via the query service proxy, orders the results by Id, and provides methods to open the create and delete dialogs. After a successful dialog action, the list is reloaded.

Components : Home

The HomePage.razor and HomeComponent.razor files generate the application landing page. The page defines a @page "/" route with a localized page title and renders the HomeComponent, which displays a localized heading and a welcome message using the solution name. Both files have partial code-behind classes declaring the namespace.

Components : Layouts

The MainLayoutComponent.razor and its code-behind generate the main application layout. The layout uses MudBlazor's MudLayout with a cascading dark-mode value, a MudAppBar containing a menu toggle button (with localized show/hide titles), the project name, a LanguageSelectorControl, and a dark/light mode toggle button. A MudDrawer hosts the MainMenuComponent, and MudMainContent renders the page body. The code-behind class manages the menu open state and dark mode preference via localStorage through JS interop, and configures a custom MudTheme with dark palette colors.

Components : Menus

The MainMenuComponent.razor and its code-behind generate the application navigation menu. The menu renders a NavMenuControl with a Home link and one NavLinkControl per entity, generated by {PresentationBlazorWebAssemblyGenerator.GetMenu}, which produces links to the /{{Entity.NamePlural}} route with localized display names. Each link uses NavLinkMatch.Prefix matching.

Components : Routes

The Routes.razor file defines the Blazor Router component, wrapped in an ErrorManagerControl. The router uses the presentation assembly (referenced via the {{Solution.Name}}PresentationBlazorWebAssembly{{BoundedContext.Name}}AssemblyReference marker type), sets the MainLayoutComponent as the default layout, and routes to the NotFoundErrorPage when no route matches.

Dependency Injection

The DependencyInjection directory contains two extension classes that configure the Blazor WebAssembly host :
  • WebAssemblyHostBuilderExtension : A static class with a ConfigureWebAssemblyHostBuilder method that registers Serilog, localization, HttpClient, Application service proxies (for HTTP-based command/query communication), MudBlazor services, and the Blazor WebAssembly root component (Routes).
  • WebAssemblyHostExtension : A static class with a ConfigureWebApplicationAsync method that applies the stored localStorage culture for client-side localization and configures the FluentValidation display name resolver using the Application and Domain resource types.

Properties

The launchSettings.json file defines the HTTPS launch profile for the development environment, with the application URL set to https://localhost:7200, ASPNETCORE_ENVIRONMENT set to Development, the browser launch option enabled, and a debug inspect URI for Blazor WebAssembly debugging via the WebSocket proxy.

Resources

The Resources directory contains the localization resource class and its associated .resx file :
  • {{Solution.Name}}PresentationBlazorWebAssembly{{BoundedContext.Name}}Resource.cs : A sealed marker class used by the IStringLocalizer infrastructure to resolve localized strings for the presentation layer.
  • {{Solution.Name}}PresentationBlazorWebAssembly{{BoundedContext.Name}}Resource.resx : The resource file containing localized strings for the layout (project name, menu toggle titles, dark/light mode titles), main menu (Home link, entity plural names generated by {PresentationBlazorWebAssemblyGenerator.GetResources}), home page, error pages, and entity-specific page titles, headings, and dialog labels for list, details, create, edit, and delete operations — all humanized from the entity names.

wwwroot

The wwwroot directory contains the static web assets for the Blazor WebAssembly application :
  • index.html : The root HTML document that hosts the Blazor application. It loads MudBlazor CSS, the project-specific CSS, Roboto fonts, the favicon, the Blazor WebAssembly JavaScript bootstrapper, MudBlazor JavaScript, and the custom Default.js. It includes a loading spinner placeholder displayed while the WebAssembly payload downloads.
  • appsettings.json : Configures the WebApi base address for HTTP proxy calls, the default and supported localization cultures, and Serilog console logging with minimum levels for the production environment.
  • appsettings.Development.json : Overrides the WebApi base address to https://localhost:7300 and Serilog minimum levels to Information for the Development environment.
  • Default.css : Defines custom CSS styles for headings, the language selector control (with dark and light mode variants), dialog control title and content styling, and the loading container and spinner animation displayed during initial load.
  • Default.js : Contains JavaScript helper functions for client-side culture management, including getCultureFromCookie to read the culture from the ASP.NET Core culture cookie and cultureHelper to get/set the culture in localStorage.
  • favicon.png : The binary favicon image served as the browser tab icon. This file is copied as binary content without tag replacement.

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please reload the page.