This is a .NET 8 web application built with a Blazor Server frontend and a Web API backend. It provides a SPA experience and supports multi-tenancy. Data access is via Entity Framework Core against SQL Server. The UI is built with Radzen Blazor components.
Key Technologies:
- .NET 8: Core framework for the application.
- ASP.NET Core: For the web server and API.
- Blazor Server: Reactive frontend UI.
- Entity Framework Core: Data access (migrations generated from DDL pipeline).
- SQL Server: Relational database.
- Radzen.Blazor: UI component library.
- Docker: Used for dev containers (app + database).
Architecture:
Program.cs: Entry point and service registration.Components/: Blazor UI components.Controllers/: API controllers.Data/:AppDbContext, tenancy helpers, and dynamic model wiring.Models/: Entity models (includingModels/Generated).Services/: Business logic and DI services.Migrations/: Generated EF Core migration files (ignored in repo).
The app uses SQL DDL as the source of truth, generating app.yaml that drives:
- app branding + theme
- dynamic model generation (
ModelGenerator) - API and UI entity navigation
Generated entities live in Models/Generated and are wired into AppDbContext via reflection. Table names are pluralized (e.g., Product -> Products) to align with existing SQL tables.
- DDL-driven metadata and model definitions are generated into
app.yaml. ModelGeneratorcreatesModels/Generated; optional value types are nullable to avoid forced defaults.AppDictionaryServiceexposes YAML metadata to the UI and navigation.- UI uses Radzen panel menu components and includes a dynamic "Data" section.
- Generic entity pages load data via
GenericEntityPage.razorwith the routeapi/{entity.Name}and singular controllers.
Migrations are generated by make run-ddl-pipeline from the SQL DDL schema. If you see errors like:
Invalid object name 'dbo.Category'Invalid column name 'CategoryId'
the database schema does not match the current DDL. Run make db-start, make run-ddl-pipeline, then make migrate.
The project uses a Makefile to simplify common development tasks.
- Install SQL Server: Run
./setup.shto install SQL Server via Docker or on the host machine. - Install .NET EF Tools:
dotnet tool install --global dotnet-ef --version 8.* - Use the wrapper:
maketargets call./dotnet-build.sh, which setsDOTNET_ROOTfor global tools and bypassesglobal.jsonlocally.
-
Check and Restore Dependencies:
make check
-
Generate Schema Migration:
make run-ddl-pipeline make migrate
-
Build the Application:
make build
-
Run in Development Mode (with hot reload):
make dev
-
Run in Production-like Mode:
make run
-
Run Tests:
make test -
Build Docker Image:
make docker-build
- Dependency Injection: Services are registered in
Program.csand injected into constructors. This is the standard pattern for .NET Core applications. - Async/Await: Asynchronous programming is used for I/O operations, particularly in the service layer and controllers when interacting with the database.
- Separation of Concerns: The project is organized into distinct layers (UI, API, Services, Data) to keep the codebase clean and maintainable.
- Configuration: Application settings are managed in
appsettings.jsonandappsettings.Development.json. Secrets are managed using the .NET User Secrets manager (seeSECRETS.md). - Multi-Tenancy: The
Data/Tenancyfolder and theAppDbContextshow a mechanism for supporting multiple tenants with different database schemas.
make checkrunsshellcheckonsetup.shanddotnet-build.shbefore the build.- Do not modify or reinstall the system .NET runtime; use the
dotnet-build.shwrapper viamake. - Keep Radzen UI wiring intact (NavMenu and theme CSS).
- Ensure the DDL pipeline and migration are applied before debugging 500s in entity pages.