Base solution for your next web application
Open Closed

Domain Services (Manager), Repositories and Dynamic Web API #3347


User avatar
0
hugol created

Hi,

Just a quick question following up a post that I did regarding the "Update Person" example in another thread. Following your recommendations I was able to implement the Update but I have a doubt after reading the recommended documentation: [https://aspnetboilerplate.com/Pages/Documents/Domain-Services]) [https://aspnetboilerplate.com/Pages/Documents/Repositories])

You have the following text on the Domain Services: Why Not Only Application Services? You can say that why application service does not implement the logic in the domain service? We can simply say that it's not application service task. Because it's not a use-case, instead, it's a business operation. We may use same 'assign a task to a user' domain logic in a different use-case. Say that we may have another screen to somehow update the task and this updating can include assigning the task to another person.So, we can use same domain logic there. Also, we may have 2 different UI (one mobile application and one web application) that shares same domain or we may have a web API for remote clients that includes a task assign operation.

Shouldn't we use always Domain Services and Managers instead of using repositories directly in the Application Services? Because even for simple CRUD operations, they will be most likely repeated for each, for example, different UIs.

Kind regards, Hugo


4 Answer(s)
  • User Avatar
    0
    hikalkan created
    Support Team

    Hi,

    Documentation says the best practice for a product have different use cases, different applications based on it. However, we haven't implemented it in AspNet Zero like that. This can be criticized, I know :) We wanted to keep it a bit simpler to address more developers and more projects since most of them has not such a rich domain. Implementing it for every bit of your code can be hard, but we suggest you to implement it for critical entities of your business.

    This article tries to implement it: <a class="postlink" href="https://www.codeproject.com/Articles/1043326/A-Multi-Tenant-SaaS-Application-With-ASP-NET-MVC-A">https://www.codeproject.com/Articles/10 ... -NET-MVC-A</a>

    BTW, Application service can always safely query data from repositories.

  • User Avatar
    0
    hugol created

    Hello there,

    I wasn't criticising, far from that. Your work is very appreciated and after working for 20 years in the software industry I know that there isn't such a thing as a perfect solution and that "theory" and "practice" don't always walk together :D

    The reason is related to the fact that I was giving a deep reading to the documentation, checking the examples and I wasn't being able to have a clear view. On my mind I had questions like: (note: (you don't need to answer the next questions), they are here just to show you the type of questions that someone reading the documentation and seeing the examples may have.

    • Why do I need a manager while using this framework since it creates a WebApi automatically from the Application Service?
    • Should I keep everything in the manager, including the repository and make the ApplicationService just a "proxy"?
    • Should I have a Repository and the Manager in the Application Service and if so which operations should I have. something similar to the example that you provided [https://www.codeproject.com/Articles/1043326/A-Multi-Tenant-SaaS-Application-With-ASP-NET-MVC-A#ArticleAppServices])

    So perhaps I would ask you to answer just the last question. Why in your example you decided to have the repository and the manager at the application service? Why "Get" operations use the repository and the C,U,D operations are just a proxy to the manager? (again I'm not criticising, I'm just trying to brainstorm the decisions behind an architecture).

    Keep up the good work ;) Cheers H

  • User Avatar
    0
    hikalkan created
    Support Team

    Hi,

    Thank you for your additional comments :)

    We are trying to implement and follow principals of Domain Driven Design. You can read to Eric Evan's and book (<a class="postlink" href="https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215">https://www.amazon.com/Domain-Driven-De ... 0321125215</a>) Martin Fowler's articles to have a deep understanding it. For instance, <a class="postlink" href="https://martinfowler.com/bliki/AnemicDomainModel.html">https://martinfowler.com/bliki/AnemicDomainModel.html</a> is a good article to understand why you have domain layer.

    We are constantly reading books and investigating source code to understand and implement DDD better day by day. But it's very hard to follow all principles and every implementation have differences than other.

    You don't have to code DDD, but following SOLID principles is important for a scaleable code base.

    Application layer (and app services) have an important role in DDD. They are not only proxies. If they were, we would automatically create them just like dynamic web api proxies. But, it's impossible to make anyone understand DDD in this post or in our documentation :) Even after reading books on it, I have many questions :)

    For a few pratical sentece;

    If you have a few application service methods working on same domain objects (entities) and perform similar business rules, then you may consider to create a domain service (manager) to unify them (do not duplicate domain logic / business logic).

    Querying is safe because it generally does not have business rules and it does not effect state of the database.

    In an ideal design, an application service should work like that to implement a use case of the application:

    1. Get related entities from repositories
    2. Use domain layer (domain services or entity methods) to manipulate them (perform business logic) - But do not implement business logic inside app service, just delegate the work to domain layer and orchestrate them.
    3. Save changed entities via repositories (actually Unit Of Work pattern (EF DbContext)) already does it when you SaveChanges).

    So, this simple method implement it:

    public async Task Cancel(EntityRequestInput<Guid> input)
        {
            var @event = await _eventManager.GetAsync(input.Id);
            _eventManager.Cancel(@event);
        }
    

    Gets entity from manager (could get it from repository - it would be better) and uses domain layer to perform the operation: It does not just set event.Cancelled = true; because maybe we want to force to perform additional business logic on event cancellation.

    In brief; ABP's Documentation's goal is not to tech DDD with all aspects and make reader write applications with best practices. But it provides a good start point for anyone to learn these concepts.

    Have a nice day.

  • User Avatar
    0
    hugol created

    Hi,

    First of all thank you very much your reply, it's much appreciated specially because I know that you are busy man :D

    Just a quick reply, you mentioned:

    In an ideal design, an application service should work like that to implement a use case of the application:

    1. Get related entities from repositories
    2. Use domain layer (domain services or entity methods) to manipulate them (perform business logic) - But do not implement business logic inside app service, just delegate the work to domain layer and orchestrate them.
    3. Save changed entities via repositories (actually Unit Of Work pattern (EF DbContext)) already does it when you SaveChanges).

    So, this simple method implement it:

    public async Task Cancel(EntityRequestInput<Guid> input)
       {
           var @event = await _eventManager.GetAsync(input.Id);
           _eventManager.Cancel(@event);
       }
    

    Gets entity from manager (could get it from repository - it would be better) and uses domain layer to perform the operation: It does not just set event.Cancelled = true; because maybe we want to force to perform additional business logic on event cancellation.

    This is perfect, this is precisely what I was trying to say. When I was following the Examples and Step by Steps guides I got confused because they were not following the DDD principles (some parts were and some parts weren't). I know now that you used that approach to make the examples a little bit simpler.

    Once more thanks for the reply. Cheers, H