When working with a layered or Clean Architecture in .NET, one of the key aspects for maintaining cohesion and separation of concerns is understanding how the Application Layer communicates with the API Layer (or Web Layer in the case of an ASP.NET Core application).
In this article, weβll explore:
π The Role of Each Layer (API vs Application)
π§ How to Structure Communication Between Them
π‘ Examples Using Handlers, DTOs, and MediatR
π§ͺ Best Practices for Testability and Decoupling
ποΈ Architectural Layers Overview
βββββββββββββββββββββββ
β API Layer β β HTTP Interface (Controllers, Endpoints)
βββββββββββββββββββββββ
β
βββββββββββββββββββββββ
β Application Layer β β Use Cases, DTOs, Handlers
βββββββββββββββββββββββ
β
βββββββββββββββββββββββ
β Domain Layer β β Entities, Business Rules, Interfaces
βββββββββββββββββββββββ
β
βββββββββββββββββββββββ
β Infrastructure Layerβ β Implementations, Persistence, Services
βββββββββββββββββββββββ
π€ 1. Who Calls Whom?
The API Layer is responsible for receiving HTTP requests and forwarding them to use cases (Application Layer). The business logic does not live in the controller β it's encapsulated inside the Application Handlers.
π¦ 2. Creating a Use Case (Command Handler)
// Application/Orders/Commands/CreateOrderCommand.cs
public record CreateOrderCommand(string CustomerEmail, List<string> Items) : IRequest<Guid>;
// Application/Orders/Handlers/CreateOrderHandler.cs
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, Guid>
{
public async Task<Guid> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
{
// Business rules, validations, persistence via interface
var orderId = Guid.NewGuid(); // Simulated example
return await Task.FromResult(orderId);
}
}
π§ We are using MediatR to orchestrate the flow between layers without direct coupling.
π 3. Calling Application from API
// API/Controllers/OrdersController.cs
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
private readonly IMediator _mediator;
public OrdersController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost]
public async Task<IActionResult> Create([FromBody] CreateOrderCommand command)
{
var orderId = await _mediator.Send(command);
return CreatedAtAction(nameof(GetById), new { id = orderId }, orderId);
}
[HttpGet("{id}")]
public IActionResult GetById(Guid id)
{
// You could use another query/handler here
return Ok(new { Id = id, Status = "Mocked Order" });
}
}
π 4. Summary Flow
[HTTP Request]
β
[API Controller] β Receives and validates
β
[Mediator.Send(command)]
β
[Application Handler]
β
[Domain + Business Rules]
β
[Persistence Interface]
π 5. DTO Separation
Avoid exposing domain models directly from the API. Use specific DTOs for input and output.
// API.DTOs
public record CreateOrderRequest(string CustomerEmail, List<string> Items);
[HttpPost]
public async Task<IActionResult> Create([FromBody] CreateOrderRequest request)
{
var command = new CreateOrderCommand(request.CustomerEmail, request.Items);
var orderId = await _mediator.Send(command);
return Ok(orderId);
}
π§ͺ 6. Testability & Benefits
β
Easily test Handlers independently of the API
β
No ASP.NET Core dependency in Application Layer
β
Each layer with a single responsibility
β
Flexible for other interfaces (Blazor, Console, CLI, etc.)
π§ 7. Suggested Project Structure
/API
βββ Controllers/
βββ DTOs/
βββ Program.cs
/Application
βββ Orders/
βββ Commands/
βββ Queries/
βββ Handlers/
βββ Validators/
/Domain
βββ Entities/
βββ Interfaces/
/Infrastructure
βββ Persistence/
βββ Services/
β Conclusion
The communication between the API and the Application Layer in modern .NET should be clean, decoupled, and testable. By using MediatR, DTOs, and layered separation of responsibilities, you can:
Apply Clean Architecture in practice
Scale your application with confidence
Maintain readability and cohesion across layers
Perfeito! VocΓͺ pode adicionar esses links de contato no final do artigo traduzido em inglΓͺs com o seguinte bloco:
π€ Connect with Me
If you work with modern .NET and want to master architecture, C#, DevOps, or interoperability, letβs talk:
πΌ LinkedIn
π» Dev.to
βοΈ Medium
π¬ contato@dopme.io