1

I am learning ASP.NET clean architecture structure. I have an application layer with a query GetAllRestaurants which has to return paginated restaurant objects.

I am using repository pattern, with the structure as shown in this screenshot:

my project structure - underlined files i am asking about

Now, I want to create an endpoint which takes GetRestaurantQuery [FromBody], which is a class in the application layer, then passes this object to the RestaurantRepository and returns PagedResult object.

My problem is that the domain layer has no access to any other layers. So in IRestaurantRepository, I cannot define any method that uses DTOs or objects from the application layer.

This is the Handle method from my application layer:

public async Task<PagedResult<List<RestaurantDto>>> Handle(GetRestaurantQuery request, CancellationToken cancellationToken)
{
    var restaurants = await _restaurantRepository.GetAllRestaurants(request);
    // etc...
}

And my IRestaurantRepository is trying to use those DTOs:

using Domain.Entities;

namespace Domain.Repository
{
    public interface IRestaurantRepository
    {
        Task<PagedResult<List<Restaurant>>> GetAllRestaurants(GetRestaurantQuery query); <----
        Task<Restaurant> GetRestaurantById(int Id);
        Task<int> CreateRestaurant(Restaurant restaurant);
    }
}

which obviously is not working, because the domain layer has no access.

What is the best way to handle such situation?

I thought about:

  • removing repository layer (but I still want to know how I should handle this)
  • passing primitive types to IRestaurantRepository methods, then return primitive types as well and construct objects in application layer. But that seems wrong.

So how should I handle that? Thanks in advance.

2
  • What do you know about mappers? Commented Dec 1, 2024 at 20:37
  • @flackoverstow what do you mean? i know how to use data from one object to map to another object. but i do not know what's the point. you mean to create similar Dto in domain layer, and then in application layer before calling IRestaurantRepository method to map dto from application layer to dto from domain layer? seems weird Commented Dec 1, 2024 at 21:15

3 Answers 3

1

The Dependency Rule tells us:

Source code dependencies can only point inwards

So you have correctly identified that we cannot use elements from the application layer (PagedResult, GetRestaurantQuery) in the domain layer.

  1. To solve this problem, the missing elements should be identified at the domain level and used at the application level.
  2. From a clean architecture perspective, the application layer should not depend on the "delivery channel", so you still need to create a web layer.

Here's what it might look like conceptually (pseudocode):

// Domain layer
public interface IRestaurantRepository
{
   List<IRestaurant> GetRestaurants(IRestaurantFilter filter);
   // etc., IRestaurant and IRestaurantFilter at the domain layer
}

// Application layer
public class GetRestaurantsUseCase : IGetRestaurantsUseCase
{
   private IRestaurantRepository iRestaurantRepository;
   // etc.
   
   List<IUseCaseRestaurant> GetRestaurants(IUseCaseRestaurantFilter useCaseFilter)
   {
       IRestaurantFilter filter = new RestaurantFilterImpl(useCaseFilter);
       List<IRestaurant> restuarants = iRestaurantRepository.GetRestaurants(filter);
       // mapping List<IRestaurant> to List<IUseCaseRestaurant> and return it
       // IUseCaseRestaurant, IUseCaseRestaurantFilter, RestaurantFilterImpl at the application alyer
   }
}

// Web layer
public class RestuarantsResource
{
   private IGetRestaurantsUseCase iGetRestaurantsUseCase;
   // etc.
   
   HttpResponse get(HttpRequest request)
   {
       IUseCaseRestaurantFilter useCaseFilter = new UseCaseRestaurantFilterImpl(request);
       List<IUseCaseRestaurant> restaurants = iGetRestaurantsUseCase.GetRestaurants(useCaseFilter);
       // mapping restaurants to HttpResponse and return it
       // UseCaseRestaurantFilterImpl at the web layer
   }
}
Sign up to request clarification or add additional context in comments.

Comments

0

The Repository interfaces need to be in the application layer and not Domain layer.

The implementation of the interfaces would be in the Infrastructure layer.

The Domain layer is only for application level objects such as 'Entities', 'Constants', 'Application Exception' etc..

This way, you would be able to pass Entity objects to the repo layer and have it returned Entities/ Dtos as you like.

Comments

0

In my opinion, the best solution is to extract the Repositories into a separate Data layer, positioned between the Domain layer and the Application layer. The methods in the Data layer should return objects from the Domain layer, which are typically the entity classes representing your database models.

For example, if your entity is Restaurant, the repository interface might look like this:

public interface IRestaurantRepository
{
    Task<Restaurant> GetRestaurantByIdAsync(string id);
    Task<IEnumerable<Restaurant>> GetAllRestaurantsAsync();
    Task<Restaurant> AddNewRestaurantAsync(Restaurant restaurant);
}

In the Application layer, within a Command or Query, you can map your DTO object to the domain model and interact with the database through the repository.

Here’s an example of a query handler:

public class GetRestaurantByIdQueryHandler
{
    private readonly IRestaurantRepository _restaurantRepository;

    public GetRestaurantByIdQueryHandler(IRestaurantRepository restaurantRepository)
    {
        _restaurantRepository = restaurantRepository;
    }

    public async Task<RestaurantDto> HandleAsync(string id)
    {
        var restaurant = await _restaurantRepository.GetRestaurantByIdAsync(id);
        return restaurant.MapToDto();
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.