Organizing ASP.NET MVC solutions
Recently, a question came up on Twitter around your favorite project structure/solution organizing for ASP.NET MVC projects. I’ve toyed around with quite a few different strategies for structuring projects, and I’m currently settled around one that gives me the most flexibility. It’s extremely simple:
That’s it, two projects. So what goes in each project? Let’s first look at the UI project. The UI project contains only website content and contains no code. And I mean no code. This includes:
- No controllers
- No models
- No Global.asax.cs
- NO CODE AT ALL
Why no code? Because when the UI project contains only UI content and no code, my UI project now matches the deployment structure. It contains:
- Views
- CSS
- Images
- Global.asax
- Web.config
- Reference to the Core project
Since my UI project structure matches my deployment structure, it makes it a lot easier to figure out how the deployment should work. With controllers, models and so on in the mix, it becomes more difficult to see what gets included for deployment (the Content, Scripts and Views folder) versus what is left out. We can then organize two different concerns separately: our content and our code.
So where does code go? That’s the other project. I call it “Core”, but it can be anything. All code goes in one project, that includes our persistence model, view model, controllers, repositories, ORM mapping definitions, EVERYTHING.
Organizing the code
As far as organizing the code – I prefer keeping things simple. If I had my druthers, the UI project wouldn’t compile at all – it would just be a folder, holding content. Its “bin” folder would merely get populated by the output of the Core project.
Otherwise, I use folders to organize code. Projects are okay for organization, but they’re pretty rigid and tend to lock you in to layers and structure that are quite, quite difficult to change. I’ve already been burned a couple of times on large projects making a mistake in my project structure, and found that this approach tends not to scale. I’ve even run into teams with upwards of 100 projects, with only a half-dozen actual deploy targets! Remember, compile time is largely a function of the number of projects. 1000 files in a single project will compile much much faster than 100 files in 10 projects. At least an order of magnitude faster in cases I’ve seen.
Another issue I ran into was the difficulty in re-organizing code if you’re locked into a project structure. Besides just a sloooooooow Ctrl+F5 experience, it can be quite frustrating to realize you’re going to hose your entire source control log history because you want to move a file to a different project. In one recent hair-pulling re-organization experience, we basically lost our entire log history because we couldn’t do basic source control commands for a re-organization. This is exacerbated with source control systems like TFS which embed source control information in the actual project files. In our case, we had to delete all of our projects and re-create them by hand. Moving folders is waaaaaaay easier than dealing with projects and dependencies. You will want to re-organize your code, in a major, major way at some point.
If you’re having problems with layering your codebase – projects are a great way of dealing with this problem. It enforces dependencies quite nicely, basically forcing you to follow certain rules. However, once you get to the point where you’re starting to create a “Common” project, a “Configuration” project, a “Mappings” project and so on, consider rolling things back up into one project. Continuing down the project path will introduce friction in just basic everyday coding tasks, so at some point, it’s just not worth it.
So why not just do one UI project? Put all the code in there, and get the absolute fastest and the most flexible experience? Content structure is a completely different concern with completely different reasons for change than organizing code. However you decide to organize your code, keeping the code out of the UI project ensures that you don’t mix code and content organization.