12 KiB
sessionId
| sessionId |
|---|
| session-260909-131140-mwcu |
Requirements
Overview & Goals
The objective of this task is to rename the Website project to Web and migrate it from an ASP.NET Core server-hosted Blazor model to a Blazor Standalone (client-side WebAssembly) application.
Converting the resume website to a standalone WebAssembly client maximizes practical utility:
- Zero Server Overhead: Eliminates the ongoing cost, server compute requirements, and connection state management of Blazor Server.
- Reliability & Availability: Removes SignalR disconnection fragility for users viewing the resume, ensuring seamless offline and low-bandwidth reading.
- Static Hostability: Allows the build output to be deployed to any high-efficiency static storage or CDN provider (e.g., GitHub Pages, Cloudflare Pages, Azure Static Web Apps, AWS S3).
- Naming Consistency: Unifies the repository naming conventions around
Web.
Scope
In Scope
- Rename folder
WebsitetoWeband project fileWebsite.csprojtoWeb.csproj. - Update solution configuration
Resume.slnx. - Refactor all namespaces from
Website.*toWeb.*. - Change project SDK to
Microsoft.NET.Sdk.BlazorWebAssembly. - Replace server package dependencies with
Microsoft.AspNetCore.Components.WebAssemblyandMicrosoft.AspNetCore.Components.WebAssembly.DevServer. - Add
wwwroot/index.htmlas the host document. - Migrate
Program.cstoWebAssemblyHostBuilder. - Convert
App.razorto client router structure and purge server-only components (ReconnectModal, server-boundError.razor). - Update scoped CSS stylesheet references to
Web.styles.css.
Out of Scope
- Altering the resume data models (
Overview.cs,PersonalInfo.cs,Skills.cs,WorkExperience.cs) or resume content. - Visual restyling of
Home.razororMainLayout.razor.
User Stories
- As a recruiter or hiring manager viewing the resume, I want instant page load and resilient navigation without connection drops or server lag so that I can evaluate candidate qualifications smoothly.
- As a developer maintaining the site, I want a lightweight static client structure with clean
Webnaming so that deployment pipelines and local iteration are simple, cheap, and efficient.
Functional Requirements
- The project must build and run successfully via
dotnet buildanddotnet run. - Navigating to
/must render the resume content (Home.razor) throughMainLayout.razor. - Navigating to undefined routes must display the not-found view (
NotFound.razor/<NotFound>). - Client asset loading (Bootstrap,
app.css, scoped CSS, favicon) must resolve properly without 404 errors.
Non-Functional Requirements
- Efficiency: The published output must consist strictly of static assets (WASM binaries, HTML, CSS, JS) suitable for edge distribution.
- Compatibility: Targets .NET 10.0 runtime with modern browser support.
Technical Design
Current Implementation
The application currently resides in directory Website/ with project file Website/Website.csproj using Microsoft.NET.Sdk.Web on net10.0. It utilizes server-side interactive Razor Components with WebApplication builder, server routing, and ReconnectModal for SignalR circuit reconnections.
Key Decisions
- SDK & Package Strategy: Transition from
Microsoft.NET.Sdk.WebtoMicrosoft.NET.Sdk.BlazorWebAssembly. RemoveMicrosoft.AspNetCore.Components.WebAssembly.Serverand installMicrosoft.AspNetCore.Components.WebAssemblywithMicrosoft.AspNetCore.Components.WebAssembly.DevServerfor seamless local debugging. - Client Host Document (
index.html): In standalone Blazor, the host page iswwwroot/index.htmlrather thanApp.razor.index.htmlwill contain#appmount point, fallback loader, and script reference to_framework/blazor.webassembly.js. - Component Hierarchy: Convert
App.razorto contain the root<Router>component, delegating page rendering toMainLayoutand pages. - Server Artifact Deletion: Cleanly delete
ReconnectModal.razor/.css/.js(SignalR circuit reconnects) and ASP.NET Core server-dependentError.razor(HttpContext.TraceIdentifier).
Proposed Changes
C:\Users\jonmc\Resume
├── Resume.slnx (Updated project path to Web/Web.csproj)
└── Web/ (Renamed from Website/)
├── Components/
│ ├── Layout/
│ │ ├── MainLayout.razor
│ │ └── MainLayout.razor.css
│ ├── Pages/
│ │ ├── Home.razor (Updated namespace Web.Data)
│ │ ├── Home.razor.css
│ │ └── NotFound.razor
│ ├── App.razor (Converted to client Router root)
│ └── _Imports.razor (Updated usings to Web.*)
├── Data/ (Updated namespaces to Web.Data)
│ ├── Overview.cs
│ ├── PersonalInfo.cs
│ ├── Skills.cs
│ └── WorkExperience.cs
├── Properties/
│ └── launchSettings.json (Updated profiles for WebAssembly dev server)
├── wwwroot/
│ ├── index.html (Added client host document)
│ ├── app.css
│ ├── favicon.png
│ └── lib/bootstrap/...
├── Program.cs (WebAssemblyHostBuilder startup)
└── Web.csproj (Renamed & converted to BlazorWebAssembly SDK)
Data Models & Contracts
Data classes remain statically available under Web.Data:
Web.Data.Overview.Get()->Overview.DataWeb.Data.PersonalInfo.Get()->PersonalInfo.DataWeb.Data.Skills.Get()->Skills.DataWeb.Data.WorkExperience.Get()->WorkExperience.Data
Entry Point Contract (Web/Program.cs)
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Web;
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();
Root Host Document (Web/wwwroot/index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Jonathan McCaffrey - Resume</title>
<base href="/" />
<link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="app.css" />
<link rel="stylesheet" href="Web.styles.css" />
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet />
</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>
<span class="dismiss">🗙</span>
</div>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>
Project File Contract (Web/Web.csproj)
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Web</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.6" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.6" PrivateAssets="all" />
</ItemGroup>
</Project>
Testing
Validation Approach
Verification focuses on compilation integrity, project file correctness, client asset resolution, and routing fidelity under the standalone execution model.
Key Scenarios
- Build Verification: Run
dotnet buildonResume.slnxandWeb/Web.csprojto confirm zero compilation warnings or errors across the new namespaces. - Startup Execution: Launch the project via
dotnet run --project Web/Web.csprojand verify that the development server starts up cleanly on the configured localhost port. - Root Page Rendering (
/): Verifyindex.htmlloads, WebAssembly runtime bootstrapsApp.razor, andHome.razordisplays Jonathan McCaffrey's overview, contact info, skills, and work experience. - Routing & Not Found (
/invalid-path): Verify that navigating to unmapped routes renders theNotFoundcomponent insideMainLayout. - Static Assets Integrity: Check that Bootstrap,
app.css,Web.styles.css, andfavicon.pngare returned with HTTP 200 responses.
Edge Cases
- Scoped CSS bundle path changes (
Website.styles.css->Web.styles.css) properly reflected inindex.html. - No lingering references to
Websitein usings, project configurations, or solution metadata. - Clean removal of
ReconnectModalandError.razorwithout dangling references inApp.razoror_Imports.razor.
Delivery Steps
✓ Step 1: Rename project files, solution references, and namespace declarations
The project directory, project file, solution definition, and all source namespaces are unified under Web.
- Rename the directory
WebsitetoWeband renameWebsite.csprojtoWeb.csproj. - Update the solution file
Resume.slnxto referenceWeb/Web.csprojinstead ofWebsite/Website.csproj. - Update the
<RootNamespace>inWeb.csprojtoWeb. - Refactor all C# namespace declarations in
Web/Data/Overview.cs,Web/Data/PersonalInfo.cs,Web/Data/Skills.cs, andWeb/Data/WorkExperience.csfromWebsite.DatatoWeb.Data. - Refactor
@using Website.*statements acrossWeb/Components/_Imports.razor,Web/Components/Pages/Home.razor, andWeb/Program.cstoWeb.*. - Update scoped CSS bundle link references from
Website.styles.csstoWeb.styles.css.
✓ Step 2: Convert project SDK and package dependencies to Blazor Standalone
The project file is configured as a standalone Blazor WebAssembly application with client-side runtime packages and tooling.
- Update the project SDK in
Web.csprojfromMicrosoft.NET.Sdk.WebtoMicrosoft.NET.Sdk.BlazorWebAssembly. - Remove the server hosting package
Microsoft.AspNetCore.Components.WebAssembly.Server. - Add
Microsoft.AspNetCore.Components.WebAssembly(version10.0.*) as a runtime package reference. - Add
Microsoft.AspNetCore.Components.WebAssembly.DevServer(version10.0.*,PrivateAssets="all") for local development execution. - Update
Web/Properties/launchSettings.jsonto streamline local development profiles with the WebAssembly debug proxy and browser launch.
✓ Step 3: Restructure client entry point, HTML host, and Blazor component hierarchy
The application boots as a client-side WebAssembly single-page application using index.html and WebAssemblyHostBuilder.
- Create
Web/wwwroot/index.htmlwith root mounting target#app,<HeadOutlet />integration, static stylesheet references, and_framework/blazor.webassembly.js. - Rewrite
Web/Program.csto initializeWebAssemblyHostBuilder.CreateDefault(args), mountAppto#appandHeadOutlettohead::after, configure standard scopedHttpClient, and executeawait builder.Build().RunAsync(). - Update
Web/Components/App.razorto act as the client component router containing<Router>,<Found>, and<NotFound>definitions. - Remove server-specific artifacts that are obsolete in standalone mode:
Web/Components/Layout/ReconnectModal.razor,ReconnectModal.razor.css,ReconnectModal.razor.js, andWeb/Components/Pages/Error.razor. - Clean up
Web/Components/_Imports.razorto remove server render-mode directives and include client WebAssembly namespaces. - Move or verify client configuration files in
Web/wwwroot/if required for client settings.