In this article we will discuss how to design ASP.NET MVC applications using SQL Server and Entity Framework.
Last weekend I got a chance to visit one of my friend's workplace. These guys wanted some unofficial help on starting up a new project. Their company has been developing Web Forms based applications since many years. Now they wanted to switch to ASP.NET MVC for new projects. Everybody in the organization was pretty excited and studying ASP.NET MVC. But they had some concerns on how to kick start their project with this new technology. How should concerns like n-tier architecture, data access, and unit testing be planned and implemented. I spent almost a day with them and most of it was in front of the white board with a projector showing diagrams and texts of the ASP.NET MVC architecture. At the end of the day we came up with a plan to design
an ASP.NET MVC application from scratch. It was not a perfect plan but it was a decent plan. Later that day I thought why not document all my discussion in the form of an article so that someone else could also read this information and perhaps find it useful too.
In this article, I will assume that the reader has some basic knowledge and awareness of ASP.NET MVC and has some background working with ASP.NET Web Forms. I will also provide links to helpful texts wherever needed so that the reader can read them to understand the context fully.
Using the code
One of the best things about a good application architecture is the Separation of Concerns (SoC).
One of the evident features of an ASP.NET MVC application is the ability to provide this separation of concerns out of the box. The Model will represent the business objects needed to implement the solution. The view is the part that is visible to the user. The user can simply consume the data using views or act upon the data, i.e., CRUD operations. The controller is the one that provides the mechanism for interaction between models and views. It is the controller's responsibility to orchestrate the show/application using models and views. The Models and Views remain loosely coupled, i.e., the Models don't know anything about
the View and the View has a Model object (association) to extract information and display it to the user.
Note: For those who don't know about ASP.NET MVC:
Selecting the Data Layer
For any business application, data access is a very crucial part. Whenever we are designing our application we should give some thought on the data access methodologies that the application will use. The first issue to tackle here is the type of data store that we will use for our application. We can choose
- A relational database like SQL Server
- Or a NoSql database like RavenDb which is a document based database.
If we choose a NoSql database then the mapping of our Models, i.e., domain objects, is relatively easy. This mapping will vary based on the database selection but it will just be a matter of having a mechanism to persist our models using the selected NoSql database mechanism. On the other hand if we select a relational database then we need to device a mechanism to perform object relational mapping. For this, we have two alternatives. Either we can go ahead and create our own data access layer using classic ADO.NET. This way the data access layer will communicate in the form of a domain model and will in turn do the database interactions
for the application. The second alternative to this is to have a data access layer that will use some Object Relational Mapper (ORM) and will ease the data access process. This is relatively easy and less time consuming but this could have some impact on the performance as ORMs tend to be a little slow compared to raw ADO.NET calls.
Note: The choice of using a relational database or a NoSql database is mostly governed by whether we need to scale up the database or scale out the database in future. Relational databases are relatively easy to scale up whereas NoSql databases are easier to scale out.
Designing our Data Access Layer
Let's say we select SQL Server as our database (like most enterprise applications) and choose Entity Framework as the ORM. We need to now devise a strategy to use Entity Framework effectively. Entity Framework provides us with three different ways of working with data.
- Database First: This should be used when the database schema will be created and/or is already pre-existing and matured.
- Code First: This should be used when we are developing a new application incrementally and we will work with our model classes primarily (POCOs) and these models need not worry about the persistence mechanism.
Later they can be saved in a database using Entity Framework.
- Model First: This should be used when we want to design the database schema before starting application development. But our schema is persistence ignorant, i.e., we can define a schema (model) and then work with this model.
Later using Entity Framework we can persist this model in a database like SQL Server.
Note: Please refer to the following articles to know more on the Data access layer design guidelines and entity framework:
Using the Data Access Layer
Once we have our data layer (say SQL Server) and Data Access Layer (using Entity Framework) ready, it's time to work on the layers that will work on top of these layers and use these layers. Typically this is the point where we would want to have our ASP.NET MVC application come in to the picture. What we need to do now is have an ASP.NET MVC application on top of the data access layer. With this, we need to first work on how to access the data access layer from our MVC application. One simple way of accessing the data access layer is to have DBContext classes directly in our controllers and use them. This approach is fine till each controller is only acting upon on only one Model. But if we need to use multiple models and perform database operations on multiple database entities from our controller, this approach will not work. Why? The answer to this is that the
DBContext relies on some internal mechanism
to implement the Unit of Work and perform the database operations. ASP.NET MVC being stateless,
does not let Entity Framework work properly with this internal mechanism.
To circumvent this problem, we need to introduce an abstract layer between our Controllers and the data access layer so that all the data and control flowing in/out of our data access layer are controlled by this abstract intermediate layer. This abstract layer can easily be implemented using Repository and Unit of Work patterns. These patterns provide a better abstraction between the business logic layer and data access layer so that these two can change independently.
Note: To know more on this, please read:
Another benefit of using this pattern is that it makes our ASP.NET MVC application and business logic unit testable. Since our MVC application is using a repository class for data access, out test projects can easily pass in Mock repositories to act to mock data.
Note: To know more on this, please read:
Diving Deep into ASP.NET MVC
Before we jump into the beautiful world of ASP.NET MVC, let us talk about Separation of Concerns once again. Separation of Concerns is a concept that dictates that software components should be designed in such a way that each one of them addresses only one concern. Each of these concerns are independent of each other, i.e., they can be updated independently without affecting any other. In fact in most cases these can be developed independently too. N-tier architecture is the perfect example of separation of concerns. Whatever we have discussed so far in this article also adheres to the SoC concept. Where Data Access Layer is independent of Data Layer, the Business Logic Layer is independent of the Data Access Layer. And the use of Repository pattern further reduces the coupling and each of them can be changed independently.
Note: This is one of the benefits of ASP.NET MVC among others. The best part about ASP.NET MVC is the loose coupling it provides between Views, Models, and Controllers. This enables the application developer to develop more maintainable, testable, and flexible applications. With this in mind let us see what should be put where to get the best out of the ASP.NET MVC application architecture.
Models are typically C# classes representing domain entities. In any application we might need different kinds of models.
- Data Model: Data model is the object representation of the relational entity. This Model will contain properties corresponding to the database entity and the data validation rules for this data model. This model is typically used when we are talking to the data access layer.
- Domain Model: The domain model is the model that will contain the business logic of the application. This model handles all business rule validations and then gets converted to a data model so that it can be passed to the data access layer. The application's top layers use the domain model and when we need to communicate to the data access layer, this domain model is mapped to a data model and then passed to the data access layer. This mapping can be done manually or by using tools like AutoMapper. [The Data model can be used as a domain model if the models only contain data rule validations and CRUD operations. Using Entity Framework we can use the entities or POCO classes both as a data model and a domain model.]
- View Model: A view model is typically a containment of two or more Domain models. It is mainly created because the presentation layer expects data from multiple domain models. In ASP.NET MVC, if we need to show data from multiple domain models then a view model can be created which will contain these two models. The controller can then create this view model and associate it with a view. A view model is an aggregate of multiple domain models.
Controllers are classes that facilitate interaction between models and views. Typically the controller will get invoked by the routers on any user action and then an action method of the controller will get called. Which will then create some model object and then pass it on to some view. So we can say that the Action method is what contains the real logic. For every user action there will be one action method and these action methods will be wrapped inside a controller class so that they can be invoked via the routing engine.
Now one might say that we can have a big controller containing all the action methods inside it. This will work but we will be compromising the Single Responsibility principle. Typically, one way to create controllers is one controller per Model (Domain Model or View Model).
This way only the actions related to one model will be inside individual controllers.
(User view here means one use case like "Manage Accounts"). Either of the approaches is fine but what we need to keep in mind is that we are creating our controllers in such a way that they are providing sensible separation of concerns and catering to only a single responsibility.
Views are the screens that the user will see and use to take actions on the application. For a normal view, data can be passed in a
ViewDataDictionary from the controller to the view. Alternatively we can use strongly typed views to bind the view to a specific model or view model. A partial view comes in handy when we need to reuse a part of the UI across multiple pages. Master views or Layouts can be used to create a consistent layout across multiple views.
We can also create views which will themselves be single page applications, i.e., the view
Points of interest
Separation of concerns is perhaps the major benefit of ASP.NET MVC. But the ASP.NET MVC framework
is flexible enough to violate the rules and deviate from the separation of concerns principle. While designing an ASP.NET application we should keep SoC in mind from the beginning. We started our discussion by talking about achieving SoC at the application architecture level by designing a proper data layer, data access layer, business logic layer, and presentation layer. We then saw how we can have a loosely coupled business logic layer and data access layer by implementing the Repository pattern. Finally we looked at some pointers on how to create models, controllers, and views in an ASP.NET MVC application.
This article is mostly on the theoretical front and it shows one way of approaching application design. There are others and probably better approaches for the same. This is something I came up with while having a discussion with MVC newbies who have worked mostly with web forms. I hope this has been a little informative.
- 03 December 2013: First version.