.NET Core Mvc application using Layered architecture

Gergő Nagygyörgy
5 min readJul 14, 2019

--

This story is going to show you a basic .Net Core Mvc application architecture with Entity Framework 6 which uses Windows Authentication to identify the application user.

This project structure is suitable in small to medium sizes projects which uses simple Windows Authentication, but could be used in corporate environment too with Microsoft’s Active Directory services.

We are going to use a project template, which helps us in starting a project from scratch, and it sure as hell saves us a lot of time and effort (also got some item templates too, which helps even further in implementing the application).

Throughout the project, we are going to keep SoC in our head, as our main priority while coding. (MVC itself actually complies to that)

Earlier i mention that this structure is for small to medium sized projects. The reason for that is because every layer(view/data models, services, repositories, etc.) of the application is going to be in one project. If you are planning on making a big project, you should separate these layers into different class libraries, and than set up the references accordingly (example: the client project, which in our case is going to be a web application, should not have access to the database model layer, but should have to the view models).

As Layered Architecture implies, we are going to separate everything into layers. Every one of them got (mostly)one distinct purpose. For example, the Repository behaves like a gateway to our database. It speaks to the database, selects the data we want, and than maps the results into a more convenient object or objects. Also does the querying with parameters passed to it from the service, whether we are writing LINQ or using Lambda.

Rought structure of the architecture

The service layer is the place where we do all the business logic. As every layer should have access only to the immediate lower layer, the repository should only be accessed from the service layer. This layer’s methods parameter type is an input(or request) class. And the return type is an output(or response) class type. This way the controller only has to return the output object(so we can use it as a Web Api for our client side JavaScript based application writing in for example React), or use it as a View Model and return a View with it. In the given example, we’be using the former option.

Starting with model example:

User object model.

We are gone need a Repository for the model. Utilizing C#’s type parameters here with the Interfaces.Repositories.Repository abstract class. It is possible to add more methods to the repository(this is the reason the class has a Context property). We can write new methods, extending our repository with new capabilities.

The generic Repository which is the base class of our repositories abstracts the database interface for us, for CRUD operations and querying (not included in here, search for Interfaces.Repositories.Repository).

Repository for User object model.

As mentioned before, the service layer is going to use immediate lower layer, which is in this case is a repository.

And the controller uses the service as follows. For validation, we use the built in functionality Mvc provides, and if it fails, the action returns a BadRequest response type. This can be the right place to do error handling, we can call more than one service method and than summarize its results and handle routing based on the output of the services for example.

When adding new properties to the data and view model, automapper can help us a lot. If we use the same name for the new properties in both classes, than we don’t have to do anything else, because the mapper automatically maps those properties if the properties name’s are identical. Which means that we can assign value to the newly added property when creating(CreateUser in our instance) a new instance of the db model, and also get back the new property and its value when calling the appropriate controller action(UserAvarage action).

We separate a lot of thing not only because of re-usability, but because we can understand it better, read it easier.

“Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code. …[Therefore,] making it easy to read makes it easier to write.”

― Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship

By applying these well known principles, we will get a common pattern, which can be followed. Instead of using our own abstractions, we developed during out programming career.

The end product is testable because we applied IoC. Making all those classes (repository, services, etc) might look like a lot of work. It does take away some time, but its neglegable compared to the time spent figuring out (and making changes to) what is happening in the code, if all the logic would be in one controller method.

If we skip service layer, we can write a pretty straight forward RESTful Api. Its pretty easy to write a RESTful Api, all we have to do is skip the service layer, and access the repository directly from controller.

RESTful Api controller example

The example code is accessible from here. The template for the database project here and web project template here.

Postman collection for the example is available here. And collection for testing out the initial controllers those are in the web template is here. And the projects made out of the templates should look like this solution here.

What is missing here is to write an appropriate exception handling middleware, for custom and system exceptions, return with some fancy view(MVC case), or with a predefined detailed error object(Web API).

I haven’t talked about SecurityRepository which is a custom implementation of row level security. There is another concept in the Core.Rules.rules.* namespace, we can define rules specific to database entities and extend the default validations we can define with data annotations. Its really close to what IValidatableObject lets you do. We could also apply optional decorators tfor the layers for example if we’d like some custom caching, or more logging, etc…

--

--

No responses yet