When I initially switched from using ASP.Net Web Forms to MVC as my standard technology for building web sites on the Microsoft stack I really liked the clean separation of the models, views and controllers. No more messy code-behind files with scattered business logic all over the place!
After a while though, I started to get kind of frustrated when editing the different parts of the code. I often find that a change in one type of file (e.g. the model) tend to result in corresponding changes in other related files (the view or the controller) and for any reasonably large project you’ll start to spend considerable time in the Solution Explorer trying to find the files that are affected by your modifications. It turns out that the default project structure of ASP.Net MVC actually does a pretty poor job of limiting change propagation between the files used by a certain feature. It’s still much better than Web Forms, but it’s by no means perfect.
The problem is that the default project structure separates the files by file type first and then by controller. This image shows the default project structure for ASP.Net MVC:
Default ASP.Net MVC project structure
Wouldn’t it be much better to group files by feature instead? Yes, of course it would, when you think about it. Fortunately it’s quite easy to reconfigure ASP.Net MVC a bit to accomplish this. This is the goal:
Grouping by feature
Instead of the Controllers, Models and Views folders, we now have a Features folder. Each controller now has a separate sub-folder and each action method has a sub-folder of their own:
What we accomplish by doing this is the following:
All the files that are likely to be affected by a modification are stored together and are therefore much easier to find.
- It’s also easier to get an overview of the implementation of a feature and this in turn makes it easier to understand and work with the code base.
- It’s much easier to delete a feature and all related files. All that has to be done is to delete the action folder for the feature, and the corresponding controller action.
After that rather long motivation, I’ll now show how to implement the group by feature structure. Luckily, it’s not very hard once you know the trick. This is what has to be done:
Create a new folder called Features, and sub-folders for the controllers.
- Move the controller classes into their respective sub-folders. They don’t need to be changed in any way for this to work (although it might be nice to adjust their namespaces to reflect their new locations). It turns out that MVC does not assume that the controllers are located in any specific folder, they can be placed anywhere we like.
Create sub-folders for each controller action and move their view files there. Rename the view files to
View.html as there’s no need to reflect the action name in the file name anymore.
If you try to run your application at this point, you’ll get an error saying that the view cannot be found:
The view 'Index' or its master was not found or no view engine supports the searched locations. The following locations were searched:
This is exactly what we’d expect, as we just moved the files.
What we need to do is to tell MVC to look for the view files in their new locations and this can be accomplished by creating a custom view engine. That sounds much harder than it is, since we can simply inherit the standard Razor view engine and override its folder setup:
/// Modified from the suggestion at
public class FeatureViewLocationRazorViewEngine : RazorViewEngine
var featureFolderViewLocationFormats = new
// First: Look in the feature folder
// If needed: standard locations
ViewLocationFormats = featureFolderViewLocationFormats;
MasterLocationFormats = featureFolderViewLocationFormats;
PartialViewLocationFormats = featureFolderViewLocationFormats;
The above creates a view engine that searches the following folders in order (assuming the Url is
The last two are just used for backward compatibility so that it isn’t necessary to refactor all controllers at once.
To use the new view engine, do the following on application startup:
The view will now load and the application will work as before, but with better structure.
Once everything is up and running, the project becomes much easier to work with and when you get used to working like this you really start to wonder why Microsoft is not doing it by default in their Visal Studio templates. Maybe in a future version?
2014-11-21 Updated the images to clarify the concept