Clean Architecture and API Contracts in .NET 10 [closed]

2 weeks ago 31
ARTICLE AD BOX

I'm building an ASP.NET Core 10 Web API. I'm trying my best to follow the Clean Architecture principles along with CQRS (MediatR).

The layer structure:

API (dependencies: application, and infrastructure for DI purposes only) Infrastructure (dependencies: application) Application (dependencies: domain) Domain (independent)

There is a trend of putting contracts (requests and responses) into a separate independent project or layer to share with other systems. I've encountered several problems with this approach, and would like to hear someones opinion about it.

Problem 1: considering the fact that the contracts layer is independent, working with files is hell. I can't use IFormFile in request DTOs because the layer itself is a simple class library.

Problem 2: the contracts layer can't depend on the domain layer because it could expose domain logic, causing DRY issue. I have a simple Sex enumeration in my domain layer:

namespace MovieStore.Domain.Users; public enum Sex { Male = 0, Female = 1 }

When I want to define a request DTO to create a user, I have to create a duplicate of my domain enumeration, which requires further mapping. The duplication can be fixed by defining sex as int in request and then mapping it to Sex in my handler, but such approach causes API documentation problems (enums are nicely documented by OpenAPI, while int doesn't say anything about options).

Problem 3: it makes sense to distinct the API layer request and the application layer CQRS command objects because API might accept a file as IFormFile, while the application layer command expects Stream. I'm not sure if the separation of the API and Application response objects makes sense because they are mostly identical (I can't think imagine the case when they are differnet). Duplication will require mapping again. Is it worth it?

Separating contracts has more cons than pros. I think that keeping requests/responses in the API layer is far easier to maintain, but it doesn't solve problem #3 because the application layer doesn't see the API layer response DTOs, resulting in duplicates.

Read Entire Article