On this page

Final project: complete product catalog API

25 min read TextCh. 5 — Production

Final project: product catalog API

This project integrates all the course concepts into a functional, well-structured API. You will implement:

  • Related entities with EF Core (Product, Category, Tag — N:M relationship)
  • Immutable DTOs with records and DataAnnotations validation
  • Advanced search and filtering with LINQ (multiple chained filters, pagination)
  • JWT authentication with Admin/User roles
  • Request logging middleware
  • Unit and integration tests

Project structure

CatalogApi/
├── Domain/
│   ├── Entities/
│   │   ├── Product.cs
│   │   ├── Category.cs
│   │   └── Tag.cs
│   └── Interfaces/
│       └── IProductRepository.cs
├── Infrastructure/
│   ├── Data/
│   │   ├── CatalogDbContext.cs
│   │   └── Configurations/
│   │       └── ProductConfiguration.cs
│   └── Repositories/
│       └── ProductRepository.cs
├── Application/
│   ├── DTOs/
│   │   └── ProductDtos.cs
│   └── Services/
│       ├── IProductService.cs
│       └── ProductService.cs
├── API/
│   ├── Controllers/
│   │   ├── AuthController.cs
│   │   └── ProductsController.cs
│   └── Middleware/
│       └── RequestLogMiddleware.cs
├── Tests/
│   ├── Unit/
│   │   └── ProductServiceTests.cs
│   └── Integration/
│       └── ProductsApiTests.cs
└── Program.cs

Implementation milestones

Milestone 1: Data and DB (30 min)

Implement the entities, DbContext with Fluent API, and the N:M relationship between Product and Tag using UsingEntity. Generate the initial migration and apply it to SQLite:

dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet ef migrations add InitialCreate
dotnet ef database update

Milestone 2: Repository and LINQ (30 min)

Implement SearchAsync with chained filters, pagination, and DTO projection. Write at least 5 unit tests with InMemory DB to verify the filters.

Milestone 3: Controllers and JWT (30 min)

Create the AuthController with POST /auth/login and POST /auth/register. Protect the create, update, and delete endpoints with [Authorize].

Milestone 4: Middleware and integration tests (20 min)

Add RequestLogMiddleware with response times. Write integration tests with WebApplicationFactory for the main endpoints.

Bonus features

Once you complete the main milestones, add:

// 1. Export products to CSV
[HttpGet("export")]
[Authorize(Roles = "Admin")]
public async Task<FileResult> ExportCsv()
{
    var products = await _repo.GetAllAsync();
    var csv      = new StringBuilder();
    csv.AppendLine("Id,Name,Price,Stock,Category");

    foreach (var p in products)
        csv.AppendLine($"{p.Id},{p.Name},{p.Price},{p.Stock},{p.Category}");

    var bytes = Encoding.UTF8.GetBytes(csv.ToString());
    return File(bytes, "text/csv", "products.csv");
}

// 2. Statistics endpoint with LINQ GroupBy
[HttpGet("stats")]
public async Task<ActionResult<object>> Statistics()
{
    var stats = await _db.Products
        .Where(p => p.Active)
        .GroupBy(p => p.Category.Name)
        .Select(g => new
        {
            Category       = g.Key,
            Count          = g.Count(),
            InventoryValue = g.Sum(p => p.Price * p.Stock),
            AverageStock   = g.Average(p => p.Stock),
        })
        .ToListAsync();

    return Ok(stats);
}

// 3. Full-text search suggestions with LINQ
[HttpGet("suggestions")]
public async Task<ActionResult<IEnumerable<string>>> Suggestions([FromQuery] string q)
{
    var names = await _db.Products
        .Where(p => p.Active && p.Name.Contains(q))
        .OrderBy(p => p.Name)
        .Take(10)
        .Select(p => p.Name)
        .ToListAsync();

    return Ok(names);
}

Delivery checklist

Verify that your project:

  • Compiles without errors or warnings (dotnet build)
  • All migrations are applied
  • All tests pass (dotnet test)
  • Swagger correctly documents all endpoints
  • Protected endpoints return 401 without a token
  • Search with combined filters works correctly
  • Pagination returns the correct total and page counts
  • Middleware logs all requests with timing

Resources to continue

With these solid fundamentals, natural next steps are:

  • gRPC with .NET — for efficient communication between microservices
  • SignalR — for real-time communication (WebSockets)
  • Blazor — for interactive web applications with C# in the browser
  • MAUI — for cross-platform mobile and desktop applications
  • Orleans — for distributed systems and the actor model
  • Clean Architecture — for scalable enterprise projects

Congratulations on completing the .NET with C# course!

Recommended workflow
Start with entities and DbContext, generate the migration and verify the schema in the DB. Then implement the repository with unit tests. Only after that create the controller and integration tests. This bottom-up flow ensures each layer works before building on top of it.
Simplified Clean Architecture
For larger projects, separate into layers: Domain (entities), Application (services + DTOs), Infrastructure (EF Core + repositories), API (controllers). This structure makes testing, maintenance, and long-term extensibility much easier.
Never expose EF Core entities directly
Always return DTOs from your endpoints, never EF Core entities directly. Entities have circular references (Product → Category → Products → ...) that break JSON serialization. You could also accidentally expose sensitive fields.