Should controllers in an ASP.NET MVC web app call repositories, services, or both?

后端 未结 7 1426
生来不讨喜
生来不讨喜 2021-01-30 09:22

The controllers in my ASP.NET MVC web app are starting to get a bit bloated with business logic. The examples on the web all show simple controller actions that simply pull dat

7条回答
  •  温柔的废话
    2021-01-30 10:26

    I'm not sure about using services for this.

    As I understand it, one of the principles of DDD (which I'm reading up on at the moment) is that the Domain Objects are organised into Aggregates and that when you create an instance of the Aggregate root, it can only directly deal with the objects within the Aggregate (to help maintain a clear sense of responsibility).

    Creating the Aggregate should enforce any invariants etc.

    Taking an example of a Customer class, the Customer might be the Aggregate root and another class within the Aggregate might be Address.

    Now if you want to create a new Customer, you should be able to do this using either the Customer constructor or a factory. Doing this should return an object which is fully functional within the Aggregate boundary (so it can't deal with Products as these are not part of the Aggregate but it can handle Addresses).

    The database is a secondary concern and only comes into play for persisting the Aggregate to the database, or retrieving it from the database.

    To avoid interfacing with the database directly you can create a Repository interface (as discussed) which given an instance of Customer (which includes a reference to Address) should be able to persist the Aggregate to the database.

    The point is that the Repository interface IS part of your domain model/layer (the Implementation of the Repository is not). The other factor is that the repository probably should end up calling the same "create" method as if you were creating a new object (to maintain invariants etc). If you're using a constructor this is simple enough as you will end up calling the constructor when the repository "creates" the object from data anyway.

    The application layer can directly communicate with the domain (including the repository interface).

    So if you want to create a new instance of an object you can e.g.

    Customer customer = new Customer();
    

    If the app needs to retrieve an instance of the customer from the repository, there's no particular reason I can think of for it not to call...

    Customer customer = _custRepository.GetById(1)
    

    or...

    Customer customer = _custRepository.GetByKey("AlanSmith1")
    

    Ultimately it will end up with an instance of the Customer object which functions within it's own limits and rules just as it would if it created the new Customer object directly.

    I think services should be reserved for when the "thing" you are trying to work with just isn't an object. Most rules (constraints etc) can be written as part of the Domain Object itself.

    A good example is in the DDD Quickly pdf I'm reading at the moment. In there they have a constraint on a Bookshelf object, whereby you can only add as many books as the shelf can contain.

    Calling the AddBook method on the BookShelf object checks that space is available before adding the book to the BookShelf's collection of Book objects. A simple example but the business rule is enforced by the Domain Object itself.

    I'm not saying any of the above is correct by the way! I'm trying to get my head around all this at the moment!

提交回复
热议问题