Trust is earned, not given

A different perspective

2026-09-29 · Projects

AccessToBlazer: converting a classic Access database to a Blazor Server app

Plenty of small businesses still run on a Microsoft Access database nobody wants to touch and nobody can replace. AccessToBlazer is a complete, self-contained demonstration of what that replacement looks like: the same application ported to ASP.NET Core Blazor Server on .NET 10, with EF Core against SQL Server LocalDB. Both halves of the conversion live in the repository, so you can open the .accdb and the Blazor app side by side and compare every screen.

Both halves, side by side

BeforeAfter
CodeAn Access application (.accdb)A Blazor Server project
DataAccess tablesSQL Server tables, created by an EF Core migration
UIAccess bound formsRazor components
RuntimeThe Access desktop appA normal web app in a browser

Nothing in the repo is proprietary: the .accdb is generated from scratch by tools/New-SampleAccessDb.ps1, and the domain is deliberately generic — a small product catalogue with customers and orders, three tables and three forms, with real referential integrity on the Orders relationships so the interesting failure modes exist.

How the forms were converted

This is the heart of the port, and it is not a find-and-replace: every Access concept has to be re-expressed in Razor. The form's RecordSource query becomes an explicit EF Core query in OnInitializedAsync. The single-record form with its navigation bar becomes a two-column layout — all rows in a table on the left, one <EditForm> on the right — which is Access's record navigation made visible, and the one place the port deliberately is not a pixel copy. Bound text boxes became InputText/InputNumber controls mapped control by control; the two combo boxes on the Orders form became <InputSelect> dropdowns that preserve the original ORDER BY and eager-load the related rows so the list shows names instead of raw ids.

Validation moved from field properties to DataAnnotations on the model, so the same rules will serve a future API. Referential integrity got an explicit, friendly message — “Cannot delete ‘Acme Corp’: 2 order(s) still reference it” — instead of Access's raw error dialog. And because the original app has zero VBA modules and no macros, there was no event logic to translate at all, which is exactly why this port is small; a real Access app with macros is where the effort goes.

The data survives unchanged

Each Access type has a mapped destination — COUNTER becomes IDENTITY(1,1), CURRENCY becomes decimal(18,2), DATETIME becomes datetime2 — and the migration inserts the same rows with the same ids as the .accdb. Open both halves and the content is identical; docs/conversion-notes.md maps every Access object to its Blazor equivalent type by type.

Repository: github.com/bobhuang1/AccessToBlazer