Domain Layer + Repository Layer with asp.net mvc question - c#

Just a quick question about my Domain Layer/ Domain Service... Should I allow this layer to have read only access to the database? i.e. hook up a IReadOnlySession and only allow the Repository Layer to have access to CRUD i.e. Persistence? Or should the Repository Layer do both the ReadOnly and CRUD with the service layer making a call to the Repository layer?
One thing I find rather strange is why most of the time the Service Layer is only making a direct call to the Repo, hence the question - move out ReadOnly to the Domain Service Layer.
EDIT:
I have decided to have 3 layers in my app (for anyone who is interested in what I have done), the first layer is the WebUI (I will have 3 in total, business requiement), below this is the Domain Service i.e. All business rules, validation, checking if user can do action x, user is valid user, calling the repo for the data. The final layer is the Repository Layer i.e. the layer that talks to the database iteself, I am using LinqToSql, all my CRUD and ReadOnly logic resides here. As a side note I created another project called Model, this is the actual LinqToSql model entities i.e. Product, Item, Shop, Customer etc. This very project is referenced by the UI, Domain Service and Repo, saving me from writing DTO, and from unecessary complexity hopefully.

In your application, only one 'layer' should talk to the database.
In the Repository pattern, it's the Repository.
It doesn't matter if it's CRUD or ReadOnly, it should go through the repository to the database.

I see the discussion as what are the responsibilities of these layers. The repository is clearly to provide an abstraction over the db. Done correctly and the users of the repository cannot tell if you are using SQL server, mysql or files for persistence. This layer must have all the necessary crud operations.
The service layer is another abstraction. It may depend upon the repository for persistence. There is usually a bit more business logic. Maybe cross repository concerns or another stream of data (gps for instance).
Some apps don't need a service layer. Don't add it until you need it. If you do have the need for the service layer, letting it be a thin rapper around the repo exposing read/write allows your models to only have one direct dependency.

Related

Where do I place the entity framework queries in layered architecture?

I have .net core api project with following folders:
Models contains the database table classes and dbcontext
Services contain logic to send email, and business logic (example calculate student grade based on marks)
Controller contains the controllers with respective actions (api endpoints). The dbcontext is injected into the controller and the endpoints contain the LINQ queries (example: _ctx.Students.Where.....)
I want to organize this into layered architecture.
UI layer will contain the api project (controllers) and reference the business layer dll.
Business layer will contain the send email logic, and business logic (grading based on marks). I think this must reference the data layer to be able to fetch data.
Data layer will contain the table classes and db context.
Where do I place my entity framework queries which were previously in the controller action method?
I usually recommend people to use the repository pattern to structure Asp.net application in a monolithic fashion. At a high level, there are usually three-layer
Repository/Data Layer
Service/Business layer
Controller/API (Web Project)
In Repository Layer, we define all our models and database call(Your Entity framework will be here).
In the Service Layer, We perform all the business logic.
And in the web project, we define all the API endpoints and other client-side interaction services.
The followings are some of the articles related to the Repository pattern:
https://www.linkedin.com/pulse/repository-pattern-c-pawan-verma/
https://medium.com/net-core/repository-pattern-implementation-in-asp-net-core-21e01c6664d7
https://codewithmukesh.com/blog/repository-pattern-in-aspnet-core/
Some articles, here use the same project to define all the layers but you can simply separate all layers into a separate project (class library).
I usually layer my application like this:
APIs - EndPoints
Application Layer - All glueing code, mapping, orchestra code, utilities, and other application-level code comes here
Domain Layer - Purely contains domains, sub-domains, validations, interfaces for repositories and unit of work, and commands.
Data Layer - This layer contains the implementation of all the repositories and unit of work interfaces. And this is the layer where I keep all my queries and database-specific code.

Is it a good practice to inject DB context directly into the service layer (without a repository layer)?

I want to keep my controllers as clean as possible, so I want to put all the business logic inside the service layer, where I want to inject the DB context. It's worth clarifying that I am going to use EF Core.
Knowing that EF Core already implements the repository pattern and unit of work. I would directly inject the DB context into my services. I wouldn't want to create unnecessary abstractions such as a repository layer.
It is a common practice to inject DbContext into the service layer, it is however not instantaneously a GOOD practice on its own.
I want to keep my controllers as clean as possible, so I want to put all the business logic inside the service layer
That statement can be contradictory, you want everything in one place and you want to keep it clean as possible... This is the major driving argument behind implementing your own repository.
Repository and Unit of Work
A key goal of the Repository Pattern is to try and encapsulate data transformation and query logic so that it can be reused and separated from the database design itself
Unit Of Work is concerned with tracking changes and coordinating how and when those changes are committed to the database, perhaps across multiple repositories.
EF DbContext manages a Unit Of Work implementation over a Repository of Business Domain Entities that are mapped to Database Schema Tables. EF therefore represents both UOW and Repo.
When Is EF A good Repo?
Just because EF is A Repo, does not mean it is THE Repo for your solution, EF can be the perfect repo for the business domain logic has direct access to it, disconnected service architectures can however get in the way of this, unless your entire business logic is encapsulated in the service layer, so every button click and decision point in your client/UI is mapped back to the API, then there some of the business logic spills over into the client side, so an EF based service layer requires a lot of plumbing if you were to expose all of the functionality that the client needs in a meaningful way.
If you end up mapping all or the majority of EF model classes into DTOs or have an entirely different business model that you want to expose to clients, then to do all of this in your API Controller classes can easily become a huge management and maintenance issue, with APIs Controllers you really need to separate the routing and De/Serialization of requests and responses from the actual logic, using another Repo to encapsulate the logic implementation from the transport (the controllers) is a good thing, this usually means that you would NOT inject the DbContext, unless it was simply to pass through to the Repo for that controller.
If the EF Model is not being exposed by the controller, then it is better to avoid injecting the DbContext into the controller, as it will encourage you to do too much in the controller itself.
Lets consider when it IS a good practice to inject the DbContext into the service layer:
In a tiered solution with a Service Layer, if the EF Model represents the main DTOs that will be transferred between the Service and the Client, then EF is a good choice to use in the controllers directly. In fact if that is your goal, then you should consider OData as a service framework as it does this and provides an additional layer of abstraction (the OData Model) that is initially mapped to the EF model but you can easily extend elements to implement custom business logic or structures with theadded benefit of exposing a convention based standard interface for querying data from the clients.
OData basically maps HTTP queries to deferred EF queries, which are in turn mapped to SQL queries (or whatever your chosen backend is). If you use the Simple or Connected OData Client frameworks then Client-side linq statements can be passed through (albeit indirectly) to the database for execution.
When your EF Model represents the bulk of the DTOs exposed from the service and consumed by the clients, then it is a standard practise to inject the DbContext into the Controller definitions, OData is an Implementation that does this with minimal effort and provides a client-side implementation to manage UOW on the client as well!
Why do I need another abstraction layer
As mentioned above, due to the disconnected nature of things, the service layer almost always ends up forming its own abstraction layer, whether you choose to identify or implement them or not, the service layer imposes security and structure constraints on the calls to our business logic. Sometimes we transform data on the service side for efficency or reduction in bandwith, other times to deliberately hide or withold confidential or process critical data, or prevent the client from updating certain fields.
There is also the question of protocols, most modern APIs even add Content Negotiation such that the service can be consumed by different formats as specified by the client. Your controller code will get extremely heavy and dare I say dirty whne you start to tweak some of these factors.
You can gain a great deal of flexibility and interoperability from creating your own repo to manage these interactions, to separate transport and bindings from your business logic.
I wouldn't want to create unnecessary abstractions such as a repository layer.
In a small project or with a very small team it may seem unnecessary, but many of the benefits to creating your own repo will be realized later, either when on-boarding new developers, extending your project to more or new types of clients or perhaps importantly, when the underlying frameworks or operating systems change and you need to adapt to them.
Another abstraction layer shouldn't mean that you are introducing another performance bottleneck, in most cases there are ways to abstract the business logic in a way that either improves the throughput or is effectively pass through. Any performance loss, if observed should either be fixed or it should be easily justified in the net gains to the user or SDLC.
With service based architecture it is normal to see these abstractions:
Database
Data Model
ORM
Business Logic
API Transport (Server)
(HTTP)
API Transport (Client)
ViewModel
View
If you utilise SQL Server, EF and OData, then the only elements you need to explicitly code yourself are:
Data Model
Business Logic
(HTTP)
ViewModel
View
In the end, it is not a question of should the DbContext be injected into the controller, its more of a question about why? Its the Business Logic side of things that matters, this usually requires your DbContext, if you choose to merge your business logic with the API controllers, then you are still managing the business logic, its just harder to identify the boundaries between what is transport related and what is actual business logic.
If the business logic needs to be a separately defined repository or can be an extension of the DbContext is up to you, It will depend greatly as reasoned above on whether you expose the EF Data Model objects through to the client at all, or if all interactions need to be transformed to and from DTO structures. If its ALL DTOs and Zero EF model being exposed, then this falls 100% into the realm of a Repo. Your controllers can be the repo implementation, but everything said before this suggests that is not the best idea for the long term stability of your development team or the solution itself.
As an example, I often write my business logic as extension methods to the EF Model. I use the EF as the repo in this case, this allows many other server side processes to access the business logic without having to go through the HTTP activation pipeline when it makes sense to do so.
T4 templates are used to generate the service layer including OData Controllers from the EF model and the extension methods that are specifically decorated with attributes to identify those moethds that should be available to external clients.
In this implementation, the DbContext is injected to the controllers, because that is the entry point to the business logic!
The client-side projects use the OData Connected Service to generate clien-side proxies providing a strongly typed and linq enabled context that is similar to the DbContext but with the business logic carefully constrained within it.

How to structure Service and Business Layer with Entity Framework, Repository, Unit of Work and Transactions

I have a service layer which makes requests of business layers to perform some functions.
The business layers access a repository which uses Entity Framework.
The service layer has a Unit Of Work object that maintains references to the ObjectContexts of EF.
When the business layers have been called, the service layer tells the Unit of Work to save the changes which it does inside of a transaction.
This is all working fine, I'm able to have multiple repositories talking to multiple edmx files all in a transaction.
One of the rules in the system is that the EF stuff has to stay the repository layer (apart from the Contexts in the UoW).
But my design has a major flaw.
In a function in the business layer I want to call a respository function to create a new record in the database. Then, in the same function in the business layer, i want to point another record at the new record. The EF entity isn't available to the business layer and because it hasn't returned to the service layer yet I don't have an id for the new record which I could then update the other record with.
Any suggestions on how I should change my design to support this?

In which layer should i put my repository?

Scenario
Data Access Layer
EF's generated .edmx and classes
Used only to access the SQL Database and pass the data forward to the business layer
Business Layer
Business entities : contain all validation logic, marked with the [DataContract] attribute so that they can be passed as parameters to my web service
Problem
I want to use the repository pattern with this approach. The repository would contain all CRUD operations to be performed on the database, accepting and returning business layer entities. This means that the repository will reside in the business layer, because only the business layer can reference the data layer, not the other way round. I'm also planning to use the data layer assembly in other projects, that's why I would like to have the repository in the data layer, not the business layer (which is particular for this project).
What do you recommend? Should I keep the repository in the business layer and write one for each different business layer? Or should I keep the repository inside the data layer, not accepting or returning business entities.
Or, as an alternative, can anyone recommend a different approach, that would yield a more logical, scalable architecture?
Thanks for reading, waiting for answers
A repository is an abstraction over the data layer - to afford persistence ignorance to your application. It should only deal with data access and nothing more. It should not have any business logic.
The repository can and should accept and return DTOs (Data Transfer Objects) - these are simple objects that do not have behavior of their own and are used to transfer data between layers.
I would put it between the DAL and the BLL and only use it for data access from the BLL.
I like the accepted answer. Ideally, having a completely layer dedicated to the Repositories sounds right.
But I think, in a traditional 3-tier only application (e.g. "Data->Business->UI"), I would stick the Repositories in the Data layer. The reason I would put them in the Data Layer, is because they deal strictly with data access. The reason I would NOT put them in the Business Layer, is because they should NOT have any business logic to them.
I think repository interface should be in business layer, but implementation of this interface should be in data layer. Interface enable unit testing, but repository implementation is not responsibility of business layer.

How do I deal with a bidirectional dependency between my business and data access layers?

I have an application with three layers (Presentation, Business Logic, and Data Access). In the data access layer, I have an object called Unit, and I have another object called Unit in the business layer.
When Insert() is called on the Unit object in the business layer, it calls the Insert() method on the corresponding object in the data access layer, and passes itself as the parameter. The problem I have is that the data access layer does not reference the business layer, and allowing it to do so would cause circular dependencies.
Is my approach flawed? If so, what would be a good solution to my problem?
You're right when you state that the way you're doing it would require a bidirectional dependency between layers, and that's almost always a bad thing. The reason for this dependency is that your business logic layer takes on some of the responsibility of the persistence layer (by implementing Insert() in the business logic layer).
It seems like you're mixing two incompatible concepts here.
First, you state that you have three layers in your code: presentation, business, and data access. The problem with this statement is that you also claim to be using an active record like pattern (unit.Insert()). If you truly have a distinct domain (business) layer and persistence (data access) layer, then the domain objects would not know how to Insert().
Take a look at the repository pattern. This pattern is better suited for establishing a distinct persistence layer. If you use this pattern, you can define an "Entity" in the persistence layer, and map your Unit object in the domain layer to the Unit object in the persistence layer. AutoMapper should save you from the pain of manually mapping the domain model to the entity.

Categories