Structure Your Project With Areas and Services in ASP.NET MVC
Structure Your Project With Areas and Services in ASP.NET MVC
In this blog post I want to show you one possible way to structurize your project with areas and services in ASP.NET MVC.
This is the first part of several architecture posts I will publish in the next time.
The idea to this came up because I noticed that if you are implementing ASP.NET mvc-code you always come to a point where you have to invest some time in the architecture. With a growing project it’s always good to keep an overview of who is doing what, when and where. Also the first question after implementing your first mvc-project lines of code is exactly the participation of the different concerns, which means: How to give your project a structure.
After some tries I came up with a solution of using some patterns and stuff. So this is the first post of two (or three) where I want to give you an idea how to get along with the problems giving your solution a system.
Viewmodels and Submitmodels
I don’t want to get into this further because I already did a blog post on this (here and here). You can see an example of how to get along with viewmodels and submitmodels.
VMs and SMs are one essential part (of many 😉 ) of your mvc-application. They give you more control and they help you to figure out what’s going on. Not only in case of an error.
Areas
Do work with areas. Ever. I know in the beginning it seems useless to you because you “want to get a little thing done”. But do use areas (and thank me later). This is the second step of getting structure into your project from the beginning.
When I started to do this I got problems sharing my partial views from the top-level “Shared”-Folder which is given to me from the MVC-Template.
http://brockallen.com/2012/08/31/sharing-a-single-_viewstart-across-areas-in-asp-net-mvc/
Has a solution for this. So this should not be a problem for you anymore.
Areas are adding a separate “room” for a special part of your website with its own controller, models and views.
Note: You can of course add areas and name them as you want. But I think it’s always good to have a first point where the user first “sees” your application. So remind to have an Area which is giving you this information on the first sight. So name it like “Home” (which is standard). But also “Start” or anything like this would be okay.
Area-Models
So we see that an area is giving your project more structure, also you are summarizing the possibilities and “rooms” of your application and of what it is able to do.
In point 1 I mentioned the view- and submitmodels you have to give your view the information it needs.
You can lay them down in the models-folder. But do not do this on the top-level. Well, you can do this. But I am a fan of namespaces. So I do add a folder for each action I have in the controller (if they have own view-and submitmodels) and add them into this folder.
In this screenshot you see an area called “Projects” because it’s only handling everything which is connected to a project-object which can be handled in this web-application. For every action I added a namespace. In this namespace every single viewmodel and submitmodel can be found.
So you are hiding all information here for someone who is looking at your solution. Only if he is really interested in the code of your models he has to open one. If not he gets a perfect overview of what you can do with your project-object in your web-application without getting into the code of the controller. (Imagine here that this “someone” could be you looking into your code after some time. You will be thankful to have a good structure).
Conclusion so far: Keep your models in the given “models”-folder the area is offering to you. Do add namespaces to actions you can to and summarize all view- and submitmodels in these folders. This gets a perfect overview of what your controller offers and you can find immediately what you are searching for, if you are searching for it. And *only* this. Nothing confusing.
Area-Views
If you added the folders like mentioned in the point before you should also have the views folder looking like the folder structure of your “models”-Folder
This is good so far. Nothing confusing and everybody gets the idea of what is offered here. Every view has exactly the name of what it offers to the user. Here nothing has to be done so far. Looks clean and nice.
Here you can see again the clean folder structure which fits perfectly to the views. For each view you or someone else finds the information immediately. And it presents the fact, that every viewmodels is connected to a view.
Conclusion so far: We have now a clean models-folder and views which represent the models and the functionality of the application in this area part. You know the connections between them because of a clean naming and concern-separation.But their relations is also clear because of a clean naming.
So now we have touched areas, views and models inside an area. Okay…the controller is missing. But before I go into this I have to get a step back:
Controller Services and the controller
We know that the controller receives the requests from your client and handles them. But I was never happy with this many lines of code in my controller. What I mean: He is the interface for your requests, he receives them. He is also responsible for giving the client back what he deserves. And that should be all. All the logic in between should not be into the controller, so why do not separate it and let the controller do what he is made for?
That is why I am using Services inside areas. Such a service works really near the area and has an interface, which is only providing all the methods the controller needs. Nothing more and nothing less. This service also knows view- and submitmodels. This is why the folder is placed beside the models-Folder.
Here on the first sight you only have the interface of the controller service without seeing the real implementation on it. The service is offering everything to the controller what the controller really needs.
Example:
Controller Code:
Service-Interface:
Here you see that in the controller you have only one call to the service which is doing all the work for you. So the controller has only to get the requests, call the method and gives back the result. He does not care about what is in your viewmodel (like errormessages, sucessmessages, etc.)
As I said: I am a fan of namespaces, so I encapsulate the implementation in a namespace (“Impl”), separating it from the interface (because the interface is the first thing that interests me when I am looking at code. “What does the service give me?” comes before “How does he do it?”).
So here the real work is done. Here my UnitOfWork is used (which I inject once per Request, so every request gets one UnitOfwork. Ninject has this feature for you: RequestScope ;))
If you look at the code, you see the next thing I am doing to get a separation of concerns: Factories!
Factories
Every(!) viewmodel gets a factory which gets the viewmodel everything it needs. This is why I have another folder in my service-namespace called “Factories”. I hide this information inside the service namespace because the factories are only used inside this service and nowhere else.
All the factories are getting injected everything they need to build up the requested viewmodel and every viewmodel has its own factory. So you can test the viewmodels perfectly and one is not related to the other.
I won’t get in detail HOW exactly to create viewmodels, because this really depends on what you want to show in your view.
To summarize, this is how an area could look like:
You have your view which is presenting everything it needs from the viewmodel, which is stored in the models-namespace. The controller has only a minimum of logic in it: Getting requests, calling his service and giving the result back. The controller service is handling everything for the controller by using factories to create viewmodels etc.
Your separation of concerns is fulfilled, you can apply this “template” on every area you build and you are working with clean view, and submitmodels which I mentioned earlier in this post.
In the next blog post I will present you the sense of Area-Services and Business-services and why I separate them explicitly. After this I will present you the Generic UnitOfWork-Pattern to get your repositories on a clean way.
Thanks for reading.
Regards
Fabian