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:

image

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.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in ASP.NET MVC. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://twitter.com/jakescott Jake Scott

    How do get around the default page issue? This nasty code:

    string originalPath = Request.Path; HttpContext.Current.RewritePath(Request.ApplicationPath, false);
    IHttpHandler httpHandler = new MvcHttpHandler();
    httpHandler.ProcessRequest(HttpContext.Current);
    HttpContext.Current.RewritePath(originalPath, false);

  • http://paulbatum.com Paul Batum

    “NO CODE AT ALL”

    What about JavaScript?

    • Manuel Hernandez

      That was my first question

  • Arnis L.

    I’m not structuring it this way (UI project) but I agree fully about preferring folders. That’s the same reason why tests shouldn’t ‘mirror’ project structure. Saw recently security assembly which had 2 tiny classes. I could live with managing dependencies but i can’t peacefully watch how build get’s damn slow with no good reason.

    What are reasons you use internal development server instead of IIS?
    I see IIS more ‘production environment’ like. And there is no need for waiting on firing up dev server.

  • http://www.learnaholic.me Kornelije Sajler

    And how about Controllers from MVC2 Area, how they could be added to Core, maybe with same structure, I could try!
    Nice post!

  • David

    Its not big deal, but doing that, you lose some of the asp.net mvc tools

  • http://shadowcoding.blogspot.com Erik

    “If I had my druthers” — Who took your druthers, Jimmy?

  • West

    Deciding on your project structure just so if you need to change it in the future you can get round TFS loosing the history seems a bit odd.

    You can keep the history of files in TFS between projects you just have to exclude them from the project itself, move it in source control view and then include it in the new project (if I remember correctly).

    Hope this helps.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Jake

    Ah yes, the default.aspx. MVC2 has a way of handling this, I’ll post about in the future.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Paul

    lol, yes, scripts go in UI. Managed code, no.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Arnis

    No reason for not using IIS, other than it’s one less thing to configure on everyone’s boxes

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @David

    Meh. I never use those tools anyway.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @West

    That’s a good tip, thanks! It’s not just that, though. Folders are just easier to deal with than projects. Project explosion leads to dependency management problems, as well as slower compile times.

  • http://simpleprogrammer.com John Sonmez

    Thanks for this simple solution. I will use it in my next project!

  • http://blechie.com/wpierce/ Bill Pierce

    I would generalize the advice as one project per appdomain, plus one. In your example you have one appdomain (UI) and Core is your plus one.

    -Bill

  • http://derans.blogspot.com Deran

    I’m curious how you structure your folders in the Core project. Do you do something like below?

    Helpers
    – Configuration
    – Extensions
    – Filters

    UI
    – Controllers
    – Models

    Domain
    – Models

    Impl
    – Mappers

    or something like this:

    Controllers
    Helpers
    – Configuration
    – Extensions
    – Filters
    Models
    – Domain
    – UI
    Mappers

  • Kevin Radcliffe

    Jimmy, do you have a sample project like this available somewhere?
    I get the feeling I’m just missing the link, so apologies in advance.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Bill

    YES – exactly. yagni until you need to share code between deployed appdomains

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Deran

    Either one of those is fine. Ours is something like:

    Core
    – Domain
    – Common
    UI
    – Controllers
    – Filters
    Infrastructure
    – Repositories

    etc.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Kevin

    No, unfortunately. I can whip something up though!

  • AdamA

    Thanks for the article! I would appreciate a sample project as well, as I am a bit confused on how to return views from controllers which are in a different assembly. It seems like this would cause an unwanted dependency on UI from Core.

  • http://nocturne.net.nz Bayard Randel

    Are you making use of the new areas feature in MVC.Net 2 yet? They look like an excellent way of making the organisation of views and controllers more granular.

  • http://www.mgroves.com mgroves

    I like that the approach really highlights the separation of concerns, especially if you’re dealing with separate developer(s) and designer(s).

    That being said, I’m not sure I like the “everything” in the “Core” project approach–I’d like to see some more layering and separation expressed by separate projects.

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Bayard

    We’re in the process of migrating our project over. Since we use Haack’s areas prototype, it’s not as quick and easy as we would like.

    @mgroves

    That’s cool, I just prefer the flexibility folders gives me.

  • chad

    I think your ideas have merit, but like AdamA and Kevin suggested…an example would be nice.

    Thanks.

  • http:///www.fathisever.com Fatih Sever

    Hi,

    I absolutely agree with you. This approach is necessary for “separation of concern” (http://en.wikipedia.org/wiki/Separation_of_concerns).

    I’m using another name for code layer. There is “UI Process Components” for this in Microsoft’s Application Architecture Guide (http://www.codeplex.com/AppArchGuide). I think it’s for this purpose ha? If I’m wrong, please warn me. Anyway, my structure of asp.net mvc presentation layer is:

    - ProjectName.Web.Process
    – ActionFilters
    – Controllers
    – Extensions
    – Helpers
    – ViewModels
    - ProjectName.Web.UI
    – Assets
    – image
    – flash
    – video
    – icon
    – Scripts
    – Styles
    – Views

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Faith

    Yep, looks good to me! Basically, the web’s content (images, scripts, css, views, etc) are separated from code.

  • Klenne

    Problem I see is if you are developing a distributed app where your business components need to run on a different server.

    This structure does not allow this…

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @Klenne

    Then you have multiple deployment targets. Multiple deployment targets = more projects. This example is a 1 deployment target solution.

  • CareySon

    Hi,bogardj,great post..
    and i had translated it into chinese and published it on chinese .net community.hope u don’t mind~~

  • CareySon

    hi,bogardj,great post…
    i had translated it into chinese and post it on a chinese .net community.hope u don’t mind..

    the URL is:http://www.cnblogs.com/CareySon/archive/2009/12/12/1622679.html

  • RichB

    You never move files in Solution Explorer between projects. You move them in TFS Source Control Explorer, then re-add them back into the project using Solution Explorer. That way you keep your history.

  • nachid

    What’s the secret to have global.asax and global.asax.cs in two differents projects.

    I tried your solution putting them into two separate projects but my solution didn’t compile
    I got this error
    Could not load type ‘myProjectl.Web.Global’

    I need global.asax to regster my routes

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @nachid

    Our global.asax looks like this:

    < %@ Application Inherits="MyApp.UI.GlobalApplication" Language="C#" %>

    Just make sure that that “Inherits” is correct and that the UI project has a reference to the other project, that should be it.

  • nachid

    Thanks Jimmy
    I realized that and it is working perfecly well now

  • http://howom.com/ 哈哈笑

    有一个问题,Core项目生成的DLL是不是很大?

    • man

      这不是一个问题 

  • http://howom.com/ jinseyd

    There is a problem, Core generated DLL project is not big?

  • Peter

    RenderAction does not work if moved outside the web project

  • Peter

    Please disregard my comment. It was my mistake, didn’t have latest referenced dll

  • Nikodem

    Hi. Is there any way to get helper menus work ?
    I mean Visual Stiodio contextual actions like Add View… when clicking on controller action header.Resharper does it, but views lands in Core project instead of UI.. Thanks in advance

  • http://www.shrinkrays.net Chris

    It’s a nice clean project/folder structure – but how do you handle the site master and its designer?

  • https://openid.stackexchange.com/user/2fb90c2f-d8ba-4aa1-8ffd-f09c14cdcb88 Dale Burrell

    I like this approach, however 2 details I was unable to resolve, my UI project files (.csproj, .csproj.user) and still in the UI directory – and don’t need to be deployed. I can live with that unless there is a way around it.

    But the annoying thing is the UI project DLL’s are still created despite there being nothing to compile. I tried this with a bare bones web application containing nothing and it still created a 3KB DLL.

    Is there anyway around this? 

  • Pingback: My ASP.NET MVC 4 solution set up | Mapping the territory

  • Moe DeLawn

    Love your blog posts, and sorry so late to this post party, but….

    I am reorganizing my MVC app – new business requirements are causing it to grow beyond early expectations and was wondering what kind of “gotcha”s I need to avoid.

    It looks like I just need to create a “Core” project and a “UI” project, copy all the files into their respective projects, delete the original files, and add a reference to the Core project in the UI project. Highlighted folders in the uploaded PNG would go in the UI project.
    Is there anything I am missing?

    Edit: oops, I think Scripts should go to UI too.