views:

419

answers:

5

I've been puzzled by what I consider a contradiction in terms: ASP.NET MVC claims to be furthering and supporting the "separation of concern" motto, which I find a great idea.

However, it seems there's no way of separating out controllers, model or views into their own assembly, or separating areas into assemblies.

With the fixed Controller, Model and View folders in your ASP.NET MVC, you're actually creating a huge hodge podge of things. Is that the separation of concerns, really?? Seems like quite the contrary to me.

So what I'm wondering:

  • how can I create an ASP.NET MVC solution that will either separate out controllers, the model, and the folders full of views, into separate assemblies?

  • how can I put areas of ASP.NET MVC 2 into separate assemblies?

  • or how else do you manage a large ASP.NET MVC app - which has several dozen or even over a hundred controllers, lots of model and viewmodel classes, and several hundred views?

+5  A: 

I think you're looking for Areas in ASP.Net MVC 2. There are some things to uncomment in the CSProj files, but after that it will copy the views over when you build. I don't think there is any requirement that the Controller or Model classes be in the same assembly as the views.

Walkthrough: Creating an ASP.NET MVC Areas Application Using Multiple Projects

Mark
@Mark: thanks - does that work across assembly boundaries, though? E.g. can I put my "Admin" and my "Superuser" areas into separate class libraries and reference them from the main ASP.NET MVC2 app?? I never see any hints or screencasts or demo on how to do this.... it's always just subfolders in your single, monolithic ASP.NET MVC2 app...
marc_s
@marc_s I know you can have different assemblies for each MVC area. We do that here. I don't know for a fact that you can put the controller and model in their own assembly, but I see no reason why that wouldn't work. I think the areas build task just copies the views to the main project and provides a mechanism to register the routes. ...but that is just an assumption. We don't actually use the build task and copy the views manually and it works.
Mark
@marc_s I added the link to the walk through that I followed.
Mark
@Mark: great walkthrough - thanks so much!
marc_s
+5  A: 

Controllers: AFAIK you shouldn't have to do anything special to throw controllers into their own assembly. At the very most all you'd have to do is override the GetControllerType method of your ControllerFactory.

Models: Zero restrictions on where you put your models. Although this is frowned upon I regularly use persistent objects from an Nhibernate/other ORM layer or WCF/service layer DTO thats are located in a separate assembly as my views. This works the same way using WebForms.

Views: Views in a separate assembly must be marked as embedded resource and then you must use a custom VirtualPathProvider that knows how to get the views from an resource instead of the file system. views from an resource instead of the file system. Again this is the exact same technique you would use for WebForm development.

Regarding mcintyre321 and his Portable Areas answer: The linked project does barely anything custom and simply wraps up the existing MVC 2 extensibility points into an easier to use abstraction. Its barely "custom" and more syntactic sugar.

You manage a large MVC app just like you'd manage any other large app. I dread opening up a 500 page WebForms project because you never quite know whats in each of those code behinds. With MVC distinct functionality is mostly within its right place. Its not contrary at all.

jfar
@jfar: thanks for your input! Highly appreciated!
marc_s
@marc_s, my pleasure, I'm sure get deeper with MVC you'll see all the extensibility points really make managing a large app really easy. :D
jfar
I've never really thought about putting the views as embedded assembly resources. I can see where that would be nice if you had to package an application for delivery.
Mark
@Mark, its really nice if you have custom input implementations, like for a DateTime field with a javascript caldendar widget and you need to share that across projects. The viewengine is pretty smart and will also let you override your embedded view with a local one if they share the same path.
jfar
@jfar I can see that too. It makes carrying around those partial views for types really easy, but I think doing that for every view is overkill. You loose the ability to see and/or change the markup without compiling. Areas feels more natural to me.
Mark
+1  A: 

MVC is very extensible and does not require to adhere to the Controller, View, and Model folder structure. You can place the controllers anywhere you would like, however if they are located in another assembly you will need to implement your own controller factory that knows how to locate them. Here is an example for locating your controllers with Windsor.

Your models/view models can be where ever you want. You simply need to reference their namespace in the web.config so views know where to look. (At least I know this is true with the Spark view engine.)

You put your views in any web project. My usual strategy is to create a plain web (non-mvc) project that contains the views folder. (This could even be a legacy web app!) Then all my controllers go in a separate class library. My view models and services go in another.

As far as structuring folders, I usually center my hierarchy around domain concepts. I'd have a folder in each project for Users, Products, Orders, etc. I never have a Models or Controllers folder anywhere.

Ryan
@Ryan: anything in particular I need to be careful about if I choose *not* to use the convention (Controller, Model, View folders)? It's convention-over-configuration - so do I need to configure something if I am not adhering to the standard convention?
marc_s
Really the only point is implementing your own controller factory. Be sure to set the correct factory in your global.asax file.
Ryan
+2  A: 

Separating code into separate assemblies is orthogonal to separation of concerns. Where the code lives is not a "concern". Separation of concerns has to do with responsibilities and direction of dependencies of various components. For example, Views are responsible for rendering the output, and the controller knows about the views, but the views don't really have intimate knowledge of the controller.

Likewile, Models don't know anything about either views or controllers, but both views and controllers will know about the model.

However, back to your question. As jfar points out, moving controllers and models into another assembly is trivially easy and will work. Moving views into another assembly is trickier. Embedded resources with a custom virtual path provider is one way, but not one we generally recommend for a high performance site. But if it meets your needs, go for it.

Haacked
thanks for your insights, Phil. So to move controllers and/or the model into separate assemblies, no extra config or preliminary steps are needed, right?
marc_s
That is correct. You just need to make sure your MVC project references the other project/assembly where you moved you models and controllers into.
Haacked