
Learn clean architecture in dotnet, emphasizing domain, application, infrastructure, and presentation layers; achieve maintainable, testable, and scalable software with easy dependency switching and CQRS via MediatR.
Learn a clean architecture implementation with agent controllers and property minimal APIs. Explore mediator-based CQRS, fluent validation, global response wrappers, caching with Redis, and pipeline behaviors for validation and caching.
Download and install Visual Studio 2022 (Community Edition) or Visual Studio Code for cross-platform use, then install SQL Server with SQL Server Management Studio (Developer or Express edition).
Install Visual Studio 2022 and create a blank solution named ABC properties, then design a clean architecture solution with a property entity following Uncle Bob.
Create the domain layer to host domain models and business rules, using a C# class library in a dotnet eight solution and define your domain entities.
Create the application layer as a class library named application. Implement the CQRS pattern, and define interfaces and contracts that use domain layer entities to drive application-specific business rules.
Define the infrastructure layer as a class library to host external dependencies, such as database connections and the ORM (Entity Framework), implementing app-layer contracts to decouple core rules from infrastructure.
Create a presentation layer with a web api as the entry and exit point, enabling swagger open api documentation and both controllers and minimal api endpoints in dotnet eight.
Organize a clean architecture as onion-like layers: domain, application, infrastructure, and presentation, with inner layers having no dependencies and outer layers referencing inward.
Create a core folder to group the application layer and the domain layer. Call it core, the core of our application, while infrastructure and the presentation layer—the web API—lie outside.
Turn off nullable warnings in a dotnet project to avoid null-reference warnings, use default values like string.empty, and apply the setting across infrastructure, core, and domain.
Launch the API as a startup, test the weather forecast endpoint, and verify a 200 OK response to ensure the solution works before adding domain entities.
define the property entity in the domain layer for a property management system, including an integer id as primary key, short and long descriptions, price, and listing date.
Define an agent entity with a primary key id, first name, last name, phone number, and email, and link properties to agents through a foreign key agentId for one-to-many listings.
Define the infrastructure layer, choose SQL Server, and connect to the database using Entity Framework Core, installing EF Core packages, design, SQL Server, and Tools for ORM access.
Create an application db context within a context folder, inherit from the ef core db context, and define db sets for agent and property mapped to tables agents and properties.
Register the application db context in the dependency injection container via an infrastructure service, and configure sql server with a connection string from IConfiguration.
Learn how Entity Framework Core tracks database migrations with a default migration history table and rename it to a friendlier migrations table within the EF Core schema.
Add infrastructure to dependency injection in a web API by configuring the DI container in Program.cs, referencing the infrastructure namespace, and passing app configuration to resolve the connection string.
Configures the appsettings.json connection string, using the default connection key with data source, initial catalog, integrated security, and trust server certificate to register the db context for migrations.
Install the design entity framework core package in the web api, then add a migration named initial db gen and update the database to create the agents and property tables.
Implement a global response wrappers pattern in the application layer to standardize api outputs. Define generic and non generic interfaces with messages, isSuccessful, and data for a uniform response shape.
Implement nongeneric and generic response wrappers, and add extension methods like fail and failed to mark outcomes, initialize messages, and propagate success or failure with single or multiple messages.
Implement a generic response wrapper with success and failure states, featuring overloads for a single message or a list of messages, and organize code with regions.
Implement a generic response wrapper in a .NET clean architecture context, defining a data property, supporting failures and successes, and using new to hide inherited methods for specialized behavior.
Introduce a generic success response in a response wrapper, hiding inherited methods, returning data of type T, and handling data, single messages, and a list of messages for API responses.
Demonstrates wrapping the weather forecast controller output in a response wrapper. Shows how to return a weather forecast array inside a standardized object, including success or failure states and messages.
Define request and response models in the application layer for agent and property management, aligning with domain entities, to support incoming client requests and outgoing responses.
Create a dedicated agent creation request model in the application layer, organizing request and response classes under models, with required fields: first name, last name, phone, and email (id auto-generated).
The update agent request model teaches updating an agent, using request and response suffixes, requiring the current primary key and allowing updates to all fields or a subset.
Explore creating and updating property request models in a clean architecture, detailing fields: agent ID, existing agent ID, short and long descriptions, price, listing date, with updates using property ID.
Create agent and property response models to serialize agent details (id, first name, last name, phone, email) and their related property data, enabling eager loading with Entity Framework.
Show how to use request and response DTOs to avoid exposing domain entities in a clean architecture API, and how mapping connects DTOs to domain entities for input and output.
Explore implementing the CQRS pattern with the mediator library to separate command and query responsibilities for agent and property data, enabling clean inter-component communication and CRUD operations.
Organize the application layer into feature folders for agents and properties, and implement crud management with separate commands and queries to structure the domain entities.
Define a public IAgentService interface in the application layer for agent CRUD, with an asynchronous create method returning the new agent's int primary key, implemented in infrastructure.
Update an agent asynchronously and return the updated agent. Delete an agent asynchronously by id and return its primary key, while keeping it available in memory.
Learn how the IAgentService supports async get by id, get all, and does exist queries to fetch agent entities, return collections, and validate existence before updates.
Learn to implement a create agent command using CQRS with mediator, defining a mediator request, an input model create agent request, and a handler that returns a global response wrapper.
Inject the agent service into the create agent command handler and map the create agent request to the domain agent before calling create agent async.
Compare manual mapping with a library-based approach by mapping a create agent request to a new agent, highlighting potential null errors and validation considerations.
Demonstrates mapping a create agent request to a domain agent using Map Star and adapt, includes a manual mapping region, and returns a global response with the new agent id.
Register the mediator library in the application layer by creating a static startup extension for IServiceCollection, configuring mediator with the executing assembly to inject mediation services.
Implement an update agent command with a mediator handler that maps the request to the domain agent, updates via the agent service, and returns an agent response.
Implement a delete agent command via a mediator request that accepts an agent id, and have the handler call the agent service to delete and return a success response.
Create a get agent by id query with a mediator handler that fetches by id, maps to an agent response, and returns success or not found (404).
Implement a GetAgentsQuery that fetches all agents via an AI agent service, returns a list of agent responses through a mediator request, and handles the no-agents-found case as a failure.
Implement the AI agent service in the infrastructure layer, create the agent service class, and implement the required contract and skeletons to enable early testing of agent features.
Create an agent using entity framework by injecting the application db context, adding the agent asynchronously to the agents db set, saving changes, and returning the new agent's id.
Implement the delete agent flow by locating the agent in the database via the context, removing it, saving changes, and returning the deleted id or zero if not found.
AgentService does exist demonstrates checking whether an agent exists by ID and returning a boolean via an asynchronous AnyAsync query against the agents data set in the context.
retrieve all agents using an async list, check if the count is greater than zero, and return a success or failure in the agent service.
Implement get by id in the agent service with async logic, performing a null check on the DB result and returning the agent or a does not exist failure.
Check if the agent exists using a local helper; if it exists, update the agent, save changes asynchronously, and return the updated agent; otherwise return null.
Register the AI agent interface and its implementing class as scoped services in the dependency injection container via startup, within the infrastructure and web application builder DI setup.
Create a base controller that injects mediator and ISender through a constructor, uses lazy initialization to resolve ISender from HttpContext when needed, and lets derived controllers reuse the dependency.
Define a create agent endpoint in an api controller, using mediator to dispatch a create agent command and return a validated response with appropriate http status.
Test the create agent endpoint by launching the API, sending a creation request, and confirming a successful response and database entry, proving end-to-end functionality.
Implement update agent endpoint using http put in .NET clean architecture, with an async action handling update agent request and command, returning ok on success or bad request on failure.
Implement a delete endpoint for agents using http delete, requiring an id query parameter, and route to a mediator delete command that returns ok or bad request.
Implement the get by id endpoint with http get and a query parameter, asynchronously returning an IActionResult via a mediator that sends GetAgentByIdQuery with the incoming id.
Create a get all agents endpoint in a .NET clean architecture app using an async task action result and GetAgentsQuery with no parameters, returning ok or bad request after awaiting.
Test all agent endpoints by creating, updating, retrieving, and deleting agents; verify 200, 404, and 400 responses and not-found handling for consistent API behavior.
Define a public AI property service interface mirroring the AI agent service, create a property commands folder, rename methods to property, and implement async get, get all, update, and delete.
Implement the ai property service in the infrastructure, add async create and delete property operations using the application db context, and return the new property ID.
Implement asynchronous property service methods in a clean architecture, covering does exist, get all, get by id, and update, with a database context and null handling.
create a property command and handler in the application layer, map the create property request to the domain property, and return the new property id in a response wrapper.
Implement the update property command with mediator, inject the property service, map the request to domain property, and return response wrapper of property on success or property does not exist.
Create a delete property command and handler that calls the property service to delete by id, returning the deleted id or zero with a success or failure message.
Implement the get property by ID query with a handler, inject the property service, map to a property response, and return a clear failure when not found.
Implement the get all properties query in a clean architecture setup, returning a response wrapper with a list of property responses, using get all async and handling no properties found.
Implement a new IPropertyService method GetPropertiesByAgentId to asynchronously fetch properties by agent ID using a filter on context.properties and ToListAsync, enabling quick access to properties listed by a specific agent.
Introduce a get properties for agent query using a mediator request to fetch properties for an agent ID, via a handler and property service, returning a list of property responses.
Unlock the full potential of .NET 8 Web API development by mastering Clean Architecture, advanced patterns, and industry best practices. This course is designed for developers who want to build scalable, maintainable, and high-performing APIs using the latest technologies and design principles.
From structuring your projects with Clean Architecture to implementing CQRS with MediatR, this course covers everything you need to build professional-grade APIs. You’ll learn how to manage data persistence with Entity Framework Core, implement caching with Redis, use FluentValidation for request validation, and optimize your API with Hybrid Endpoints (Controllers & Minimal API).
What You'll Learn
Clean Architecture – Build a well-structured and scalable API
Response Wrapper Pattern – Standardize your API responses with global response wrappers
Entity Framework Core – Master migrations, entity relationships, lazy & eager loading
Repository Pattern – Implement abstraction for data access
CQRS & MediatR – Use custom pipeline behaviors to handle commands and queries efficiently
Redis Caching – Improve performance by integrating distributed caching
FluentValidation – Apply powerful request validation techniques
Mapster – Simplify object mapping with high-performance transformations
Hybrid Endpoints – Combine Controllers and Minimal API for optimal flexibility
Configurations & Dependency Injection – Manage app settings and service lifetimes effectively
MSSQL Database – Use SQL Server as your database backend
This course is beginner-friendly for backend developers but assumes basic programming knowledge in C#. If you’re new to some topics like Clean Architecture, CQRS, or Redis, don’t worry—we’ll break them down step by step!