An ASP.NET Core solution that calculates net salary for a UK-style progressive income tax system: annual tax is the sum of the tax paid within each band — 0% on the first £5,000, 20% on £5,000–£20,000, 40% above £20,000 — and monthly figures are the annual ones divided by 12.
The tax model is deliberately simple. The point of the project is the architecture around it: a layered multi-project solution with a clean dependency flow, dependency injection, EF Core with migrations, ASP.NET Core Identity, Swagger, and a test suite that runs without any external infrastructure.
⚠️ The calculation is intentionally simplified (no personal allowance, National Insurance or other deductions). It is a demo, not tax advice.
| Project | Role |
|---|---|
TaxCalculator (Web) |
MVC app — the UI (Razor + Bootstrap + jQuery + toastr) that calls the API |
TaxCalculator.Api (WebApi) |
REST API — POST /api/salary, Swagger UI in Development |
TaxCalculator.Services |
Business logic — tax calculation and salary breakdown |
TaxCalculator.Repositories |
Data access — tax band repository behind an interface |
TaxCalculator.Db |
EF Core model, DbContext, migrations, ASP.NET Core Identity user store |
TaxCalculator.UnitTests |
Unit tests for the services |
TaxCalculator.IntegrationTests |
API integration tests (in-memory TestServer + EF InMemory) |
Dependency flow: Web → WebApi → Services → Repositories → Db. Services depend only on repository interfaces, so the calculation logic is unit-testable in isolation.
Requires the .NET 8 SDK.
dotnet build
dotnet test # all tests, no SQL Server needed
dotnet run --project TaxCalculator.Api # API + Swagger UI
dotnet run --project TaxCalculator # MVC UIThe MVC UI expects the API at the address configured in TaxCalculator/appsettings.json (ApiSettings:ApiUrl).
Tax bands live in SQL Server (ConnectionStrings:DefaultConnection in TaxCalculator.Api/appsettings.json). Apply the EF Core migrations to create and seed the database:
dotnet ef database update --project TaxCalculator.Db --startup-project TaxCalculator.ApiPOST /api/salary with { "grossAnnualSalary": 27000 } returns:
| Annual | Monthly | |
|---|---|---|
| Gross salary | 27,000.00 | 2,250.00 |
| Tax paid | 5,800.00 | 483.33 |
| Net salary | 21,200.00 | 1,766.67 |
Tax breakdown: 0% × 5,000 + 20% × 15,000 + 40% × 7,000 = 5,800.
- Unit tests cover
TaxCalculatorServiceandSalaryService, including edge cases (salary inside a single band, salary spanning all bands, negative input). - Integration tests boot the full API in a
WebApplicationFactory, swap SQL Server for the EF Core InMemory provider with seeded tax bands, and verify the endpoint end-to-end.