Briefly about where to put Repository in Onion Architeckture and DDD


Hello, Habr. I want to talk about where, in the figure above, put the repository. A little more about DIP, IoC and project structure. There is a standard approach according to which the IRepository interfaces must be interfered with in the domain layer to DomainServices and the implementation in Infrastructure. Here we are talking about standard Repositories which are just an abstract collection of objects that does not know about transactions and UnitOfWork and so on (for example, IList and its generic version are the typical interface of an abstract repository). I personally disagree with him because usually repositories are overgrown with behavior specific to a particular application, so I put their interfaces to ApplicationServices. The implementation of course remains in the Infrastructure layer. If you are interested, then welcome to cat.

Often many are confused by the old picture from Robert Martin:

He has the words in the article
Entities encapsulate Enterprise wide business rules. An entity can be an object with methods, or it can be a set of data structures and functions. It doesn't matter so long as the entities could be used by many different applications in the enterprise.

Therefore, it turns out that it simply assigns DomainServices to the Entities layer. Well, UseCases == ApplicationServices. Gateways == UserPepository, EmailService, Logger. Read more here .

  1. Serivice is any stateless class. InfrastructureService is an anti-corruption laer that isolates you from the file system, the library for working with SMTP and, of course, from ORM or the library for working with the Database, etc.
  2. Repository . . List Repository T[] ValueObject Entities. Repository InfrastructureService InfrastructureService Repository. : Logger, EmailSender.
  3. Repository InfrastructureService - EmailSender EmailService, FileService ( File.Open(… ) . .) .


To understand where to place abstractions, we need to remember Dependency Inversion and Inversion of Control. According to them, our ApplicationService can use Infrastructure, I don’t know what its implementation is in such ways as:
  1. Define the interface that will implement the Infrastructure and interact with it.
  2. Just accept delegates like Action and Func.


Via interfaces:

    interface IRepository
    {
        int Get();
    }

    class ApplicationService
    {
        private readonly IRepository _repository;

        public ApplicationService(IRepository repository)
        {
            _repository = repository;
        }

        public int GetInt() => _repository.Get();
    }

Through delegates:

    class ApplicationService
    {
        private readonly Func<int> _getIntFromDb;

        public ApplicationService(Func<int> getIntFromDb)
        {
            _getIntFromDb = getIntFromDb;
        }

        public int GetInt() => _getIntFromDb();
    }

Now about how to structure the code. There are two cases to consider:
  1. Everything is divided into folders.
  2. Everything is divided into libraries.

Details of the terminology can be found here .

Folders within the same application


SnakeGame Code Example


By libraries


We put the InfrastructureServices (IRepository) interfaces in the ApplicationServices library, and the implementation (Repository) in the Infrastructure library.



The final picture from an article by a person with much more development experience than mine and who also thinks that IRepository should be placed in the Application Layer to ApplicationServices (the Repository implementations themselves also have Infrastructure).


findings


The infrastructure services interface (IRepository, IEmailSender) can be placed in the ApplicationServices.dll library, and their specific implementation (Repository, EMailSender) in the Infrastructure.dll library.

All Articles