I am trying to follow the Onion Architecture to design my application where I have the following layers -
- Domain Layer: is the inner-most layer and defines repository interfaces
- Infrastructure Layer: forms the outer-most layer peered with the Web/UI layer and implements the repository interfaces
- Service Layer: is the middle layer where business logic resides and repository interfaces are injected
- Web/UI Layer: forms the outer-most layer peered with the Infrastructure layer and handles DI configurations
Things are working. No issues so far.
I've come across several Stack Overflow answers and online articles that recommend not to implement Repository pattern when using Entity Framework and Entity Framework Core, because the DbContext
itself is implemented to provide the functionality of the Unit of Work pattern while the each IDbSet<T>
acts as a repository. I do understand the point and that’s very good. Because, less code to write. So, I thought let’s see if I can find a way to structure my application avoiding the repositories and using the DbContext
only.
Some recommendations I've found suggests use of the DbContext
directly in my Controllers, which I didn’t like. I don’t want my Controller code to get all messy with queries. I prefer them slim, and delegate the business processing and database operations to somebody else, like I currently do with the Service classes.
I've read this article Ditch the Repository Pattern Already and in the comment section in response to one comment the writer said he uses Onion Architecture and -
If an Application Layer exists as a discrete layer then it is injected with the DbContext and possibly other dependencies. For a Web application, a UI layer sets up all the DI, translates request to calls to the Application layer, and maps responses onto view models to be sent back to the browser. Other infrastructure layers like the persistence layer I define the DbContext in sit at the outside layer with the UI layer as "peer" layers.
Since according to Onion Architecture the dependency should only go inward what I really don't understand is how can you get a reference of DbContext
(defined in Infrastructure Layer) in Application Layer through DI.
For those who prefer not to implement Repository and Unit of Work patterns with EF/EF Core could you suggest how can I do the same and still structure my application using Onion Architecture?
EDIT - Feb 03 2020
Thanks to Flater for his answer. I've gone through each and every link everyone provided. Thanks to all.
But it seems I failed to properly express my problem. I'll try once again. My application can be represented with the following diagram of Onion Architecture
-
Each layer is implemented as a separate project for convenience. Since Onion Architecture
dictates that dependencies go only inward -
Domain - has no dependency on any other project. Defines models and interfaces.
Service - has dependency only on Domain. Contains the Service classes which implements the Service interfaces. Service classes are injected with Repository interfaces.
Infrastructure - has dependency on Domain. It defines the DbContext. It contains the Repository classes which implements the Repository interfaces. Repository classes are injected with the DbContext.
Web/UI - has dependency on Service and Domain. It contains the Controller classes which are injected with Service interfaces and/or Repository interfaces. (This project also has a dependency on Infrastructure, but that is solely for DI configuration purpose).
Onion Architecture
puts persistence operations at the outer most layer as part of Infrastructure and use Dependency Inversion to access them. This results in a loosely coupled design where the Application Core (comprised of Application + Services + Domain Layer) doesn't have any dependency on data access layer/technologies.
When I said -
what I really don't understand is how can you get a reference of DbContext (defined in Infrastructure Layer) in Application Layer through DI.
what I meant is, if I'm to discard the Repositories and use DbContext only, then I must use the DbContext from my Service classes, but DbContext is defined in Infrastructure and Service doesn't have a reference to Infrastructure.
To use the DbContext, the Service Layer it needs a direct reference to Infrastructure. Adding this reference violates the most fundamental concept required by Onion Architecture
- dependencies should always go inward.
This requirement forces us to use DIP to resolve outward dependency and thus achieve the loose coupling.
So, if Service Layer have a reference to the Infrastructure, the Application Core is directly dependent on the Data Access Layer, and I don't think we can call it an Onion
anymore.
That's where my question comes - how can I avoid the Repositories, use DbContext only but still adhere to Onion Architecture
?
I'm just trying to implement something that I can use with smaller applications, because clearly Repo/UoW approach is overkill for some scenarios and not to mention more code to write.