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
| Before | After | |
|---|---|---|
| Code | An Access application (.accdb) | A Blazor Server project |
| Data | Access tables | SQL Server tables, created by an EF Core migration |
| UI | Access bound forms | Razor components |
| Runtime | The Access desktop app | A 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