I am trying to find the best way to layout my MVC 3 project. When searching online I came across a suggestion that basically said right click on project and add area. What this did was create an area folder with same controller/view/model structure in the same project. This is not what I want. I want the flexibility of having separate projects. I will keep only the views in the main web project. Everything else in a separate project.
Towards that attempt I created a separate project for my controllers. Now I am stuck with pointing a controller action to a view. In all the online examples it was right click and add view. This being a class library project I don't have that flexibility. Where am I going wrong?
All examples that I have found including the ones I have gone through on Asp.net basically explain how to create study applications, which is only good for learning purposes. A large commercial application can't possibly have all the views/models/controllers in one project. Or is that the way it is supposed to go in MVC? I am not sure if doing everything with mouse clicks is also a good idea. In the webforms world also there were a lot of study-for-beginners applications that used mouse clicks to create basic CRUD applications, but in real commercial projects, we never used those methods.
What are your thoughts, guidance on this?
Thanks for your time...
MVC is based on a convention; the convention is you put all the views on /views, the models in /models and the controllers in /controllers. You can change the convention but it will not make your life easier.
From a conceptual point of view this does make sense. If you keep all domain logic and data access in separate projects all you are left with is the web related stuff, your controllers, view models and views. That's your MVC project.
Note that if you want to split off parts into separate projects you may find portable areas useful.
I don't see why you can't use the built in generators as a base for your views and controllers? Nothing says that you have to leave them as generated. I personally thinks that's it's really nice to get a base generated for me (with mouse clicks).
The MVC project is just a UI layer. It's madness to put logic in it for large scale applications. It's therefore usually fine to have one project for all the UI. It actually makes it easier to get an overview of the UI.
That said, there are ways to get a plugin based solution where you can move the controllers (, models and views) to class libraries. But it's not easy.
You need to create a virtual path provider (to find the views)
Make all views embedded
Modify the project file to get the "Add view" dialog etc.
Use areas (makes it easier)
Tell the BuildManager that your plugin DLL exists.
You also need to modify the virtual path provider to access the views from your plugin folders if you want to be able to modify the views during runtime in visual studio. Any change would otherwise require a rebuild of the plugin DLL.
Update
Video for MVC2 (MVC3 areas works the same): http://www.asp.net/mvc/videos/mvc-2/how-do-i/aspnet-mvc-2-areas
Do note that that video is for areas in the same project. Having areas in separate class libraries are more complex. The easiest solution is to use the portable areas as suggested by someone else.
Why keep only your views in the 'main web project' - I think you are missing the point with MVC.
It's the controllers that are your 'main web' part. They are what your users request and post back to, not the view.
The view is only there to provide a means to layout HTML for the controller to push to the browser.
The Models which I think should really be ViewModels, are there to provide substance (i.e. real data) for your views.
So you can see that the MVC layout really wants all three of these to be grouped sensibly together. Controllers interact with your user, get the view (the layout) and populate it with your ViewModel/Model (the data). This is your user interface, all three parts of MVC (if you go with the ViewModel anyway) are only for UI.
Where the data comes from, your real models and whatever you want to do with it can easily reside in a dll somewhere or on the other side of a set of web services or whatever.
Related
I come from an Asp.Net background and I'm evaluating Asp.Net MVC for a new project. I can't see how to structure a large project adequately.
I'm happy with the Model/View/Controller architecture and I'm presently trying to get Areas to work (which seems quite complicated for what it is).
Can you have Areas within Areas?
Can you put Views in dlls?
I really need a starting point here, are there are resources which show how to structure large MVC projects, assume that eventually there will be 100+ views in the project, I don't want them all in the same folder and ideally I'd like sub folders
thanks for any help
Edit:
I can see that each controller maps to a View folder, what I want is something more like this
Areas
Mail
Absence
SimpleAbsenceController.cs
ComplexAbsenceController.cs
Overtime
SimpleOvertimeController.cs
ComplexOvertimeController.cs
Etc
Edit2: Perhaps this is more of a routing question, can I map from:
http://www.mystuff.com/SimpleAbsence/Index
to Mail/Absence/SimpleAbsenceController
Fundamentally I want a way of structuring my project into folders
I hate answering my own question as I feel it undermines the work of others who try to help, at the same time others may look at this later and these really are newbie questions, so...
(this is all from reading Pro ASP.Net MVC5, good book)
I wanted to know how much flexibility there is in Asp.Net MVC with regard to using subfolders or dlls. This answer address the subfolders question.
Answers
You can put controllers where-ever you like in terms of folders on the disk, these are compiled, but...
When you use areas the MapRoute in the AreaRegistration.cs file automatically limits
the routes to the namespace for the area. So if for example you move a controller to an area you -must- change the namespace or methods like Url.Action will fail
Views must stay where they are, so for a controller called Fred there must be this structure:
View
- Fred
- Action1
- Action2
- etc
You can work around all of this using your own routing system, you could probably work around the namespace issue with a custom route, but my view is as a newbie you should work with the system until you know enough to fully understand the consequences of breaking the rules
So this means you could have a large project with a few hundred Views all lumped together in one folder. It's not quite as bad as it seems as the controllers can be in sub folders and you can directly map from them to the Views.
You also have flexibility in the routing system, so regardless where controller are on disk you can have any urls you like!
e.g. this route maps from
http://www.example.com/App/DoSomething to
http://www.example.com/Home/Something with no changes necessary
routes.MapRoute("NewRoute", "App/Do{action}", new { controller = "Home" });
NB If you do this make sure to use Html.ActionLink or Url.Action (or equivilents) as opposed to direct links, these are clever enough to generate the correct urls based on the routing.
As I say, complete newbie issues but I'm sure others will have the same questions, thanks to MiniRagnarok for his example of a real life project
What we're talking about here is very opinion based. I've seen people that prefer to have lots of Controllers with a mapping of every object to a Controller. I've also seen people that prefer to have tons of Views. So my example is what our team has decided to do and not necessarily the same as you would see in sample tutorials.
Take a project we did that has 200+ Views for example. The site is an auction and retail site.
Controllers
AccountController.cs
AdminController.cs
AuctionController.cs
HomeController.cs
PhotoController.cs
StoreController.cs
SupportController.cs
Views
Account
DisplayTemplates
EditorTemplates
ChangePassword.cshtml
_Favorites.cshtml
Settings.cshtml
Admin
Auction
Home
Photo
Shared
Store
Support
For us, we name all partial views with an underscore first. We also utilize DisplayTemplates and EditorTemplates. All of this really helps us keep things separate. You'll notice that our controllers are split by role or function. We were never bothered by the fact that there are many ActionResults within our controller since all of our logic is really in the models.
I have a standard MVC 5 project created from the VS Template. Now I want to move the Account related controller and views to different project so it becomes a module. (That way it can easily be include/excluded from the site.)
I have been able to put the Controller in another project and reference the project, but the account views are not located at runtime.
How do I tell the View Engine to look in the other project for the account views?
After a lot of working with this, it seems that having views in a different DLL may not be the best pattern. First, while it can be done, it requires some extra plumbing. Second, it seems to violate the MVC pattern in that now you have two MVC patterns working side by side. What has worked for me is simply moving the Model part to a different dll. In other words, the plugin becomes a Model provider which is simply used by the Controller and then combined with the view. This is very easy to work with, requires nothing special, and yet separates the responsibilities.
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?
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
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.
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.
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.
You need to use portable areas see http://www.lostechies.com/blogs/hex/archive/2009/11/02/asp-net-mvc-portable-areas-part-2.aspx
We're building about 10 ASP.NET MVC sites which have a common set of features (and corresponding URLs, Routes, Controllers, Actions, and Views). The sites will also all share a base set of domain objects (e.g. users, companies) and base attributes on those objects (e.g. name, address, etc.).
But each site will also be highly customized and extended from the base. For example, our site for large, public companies will have "Subsidiary" and "Stock Symbol" fields on the Company domain object, while our site for startups will have a "Venture Firm" and and "Funding" attributes. Look and feel will also vary considerably, although we're trying to keep HTML as consistent as possible (modulo extra form fields for extra domain object attributes, etc.). We'll also be overriding images sparingly, so we can, for example, re-use the same button graphics across sites.
Anyway, we're trying to figure out how best to factor and architect things so that we can reuse as much code and as many tests as possible without limiting our freedom to add per-app attributes and vary the UI between apps.
I'm familiar with how to handle limited-customization multi-tenancy like you find in StackOverflow/SuperUser/ServerFault (or MSDN/TechNet for that matter), where the UI is a little different and the data model is more-or-less identical. But when the models and UI are very different (but inherit from a common base), I'm less sure how to proceed.
I'm less worried about operational issues, since we'll probably be running each site in a separate appdomain and hosting them on separate databases. I'm more worried about reducing long-term code maintenance costs, increasing agility (e.g. easy to add new features to the base without breaking derived apps), and realizing short-term dev-/test-cost savings as we build our 2nd, 3rd, 4th, etc. site.
I'm looking both for high-level guidance and suggestions, but also concrete suggestions for how to make that guidance real using modern ASP.NET MVC practices.
I realize this is a very general question, but for starters I'm looking for both high-level guidance as well as concrete tips-n-tricks for how to apply that guidance with ASP.NET MVC, including things like:
recommendations where to split base/derived across Visual Studio projects
source control tips to avoid forking
database schema tips (FWIW, our databases are all small-- under 10K rows per table, so dev/test cost is more of an issue than DB perf)
tips about re-using Controllers/Views/etc. corresponding to the "base" model attributes, especially re-using UI for things like "new customer" forms which will have a mix of base and derived attributes.
Anyone have good advice for how to architect a multi-tenant app like this?
Here's what we do, and it works pretty well for about 8 sites currently.
Define a core MVC project for your Controllers, ViewModels, HttpApplication, routes, etc. This will compile into a DLL and compromise the bulk of your site.
Create a basic set of default views, scripts, images, etc. for your site. These will server as defaults for your individual sites.
Per client, create any custom controllers, routes, etc that you'll need in a project that compiles to another dll.
Also per client, recreate any views, scripts, images that you'll want to use.
To make the above steps work together you'll need to write a little glue. The first piece of glue is a custom view engine. You'll want to customize the standard view engine to first look for views in your client-specific folder, and then the default folder. This lets you easily override the default layout per client.
The second method of getting everything working is to have your core application load the routes, controllers, etc from your client specific assembly. To do this I use the Managed Extensibility Framework (MEF) to expose a single Register method. Calling this method on my client assembly code registers the routes and any other client-specific needs.
Here's a general view of what my site folder structure looks like, with SiteContent being checked for views first:
- AppContent
- AppContent/Static
- AppContent/Static/Images
- AppContent/Static/Scripts
- AppContent/Static/Styles
- AppContent/Views
- AppContent/Views/Shared
- SiteContent
- SiteContent/Static
- SiteContent/Static/Images
- SiteContent/Static/Scripts
- SiteContent/Static/Styles
- SiteContent/Views
- SiteContent/Views/Shared
- web.config
- Global.asax
I have helpers that I can use like SiteImage and AppImage for use in my views. Also, I make each of my client sites use certain specific names for their master pages, that I don't ever define in my AppContent defaults.
I realize this is a rough overview, but it is working well enough for us right now.
I'm involved in a similar type of "suite" of projects currently which is focused on allowing customers to apply for products online but have very similar requirements for what information to collect, where the only differences are around product specific pieces of information or slightly different legislative requirements.
One thing that we have tried to do is create pages (model, view and controller combinations) that are reusable in themselves, so any application can use the page to capture information but redirect to the next page which may be different depending on what type of product is being applied for. To achieve this we are using abstract base controllers in the form of the template method pattern that contain basically all the required controller logic (including action methods with their applied action filters) but then use abstract methods to do the specific stuff such as redirecting to the next page in the process. This means that the concrete implementation of the controller used by specific application page flows may contain only one method which returns a RedirectToActionResult corresponding to the next page in the flow.
There is also quite a bit of other stuff that handles going backwards and those kinds of navigational things, but with the help of action filters you can get it set up that you don't have to worry about it once you get it up and working.
There are also base model objects which contains common functionality, be it validation logic or state persistence logic.
The data captured during the application process is persisted in database as xml serialized model objects which can then be pulled out and de-serialised once the application is completed and spat out in whatever format to whatever system the backend operations staff use to process applications.
The implications of this is that we have a project structure that consists of a base dll that contains top level abstract classes, interfaces and utility classes as well as html helpers, action filters etc. Then we have mvc projects which contain the concrete implementations of the base controllers, models etc as well as the views and masterpages.
The hardest thing is sharing views and I don't think we have properly got this sorted yet. Although with MVC 2.0 containing Areas I think this will become less of an issue but I haven't had a good play with it yet. (see Scott Gu's post on 2.0: http://weblogs.asp.net/scottgu/archive/2009/07/31/asp-net-mvc-v2-preview-1-released.aspx)
One thing I have POCed that looks like it will work is using a base MVC project to contain common views and then extending the default view engine to search that project on the web server when looking for a view to render (which is quite easy to do). Areas though is a far nicer solution.
As for source control, we are using svn and I think you are reasonable in being concerned about branches. It is not something that we have had to deal with yet, but we are probably going to go with git as it seems to make the process of branching and merging much less painful.
Not sure whether this helps you much but I would definitely recommend keep in mind abstract controllers and models, and also look at how you can use html helpers and and partial views to group similar pieces of functionality.
Mike Hadlow goes into good detail on how to accomplish this:
http://mikehadlow.blogspot.com/2008/11/multi-tenancy-part-1-strategy.html
One way to do this is to use branching in a source control system.
The main branch is for the common functionality. You then have a branch for customization and can merge changes out to the customization or back to the main branch.
We will be developing a very large vertical market web application, and are leaning toward the MVC approach.
It will have 1 Master Page common to all views in the application.
The master will provide a navigation/search framework for the entire application
that will allow users to search and select entities and then navigate to a function to perform.
The database model will have 700 to 1000 tables.
The application will have hundreds of controllers.
Controllers and their views could be grouped together into one of the many (20-50) subsystems in the application.
(We are looking at an areas approach to aide in organization).
We want to be able to deliver enhancements/updates in small functional pieces.
These might me a new function, a bug fix, customer dependent functionality, or optional modules separately purchased by the enduser.
We spent too many years developing/supporting and delivering one large windows vb app exe.
We would like to take another approach.
Management does not want to deliver one large application. They want to be able to deliver
small incremental pieces when necessary.
We may want to create a deliverable that contains one controller, and only a couple views, and a portion of the model.
To deliver it, we want to copy a dll to a bin folder, and create a View folder and copy in the new view(s). As simple as possible!
I have spent many days researching this and haven't come up with a clear path to proceed.
(Every tutorial and article I found assumed a single project.)
How do we structure the application to accomplish this?
How do we break up the application into separate projects/assemblies to do this?
Can you build a base project that contains the Master Page, authentication, and Global routing,
and then reference this in each of the potentially hundreds of other projects for each of the modules?
In development, does each sub-project need to contain the entire base project, or just the shared views folder, Global routing,
and web.config and a reference to the base project dll?
Any detail documents explaining this approach?
Any development/Testing issues?
Thanks for all input, we have to get this going soon.
Update:
Followed the example here link text
It is a great starting point!
I think this is exactly the case where DLR would help. Your Controllers and Views can be stored as scripts in the database. It will be very easy to deliver your application as a set of "small functional pieces". You could start from reading Haacked - Scripting ASP.NET MVC Views Stored In The Database
Absolutely, break the project up into sub-projects / modules containing your controllers. You can use an IoC container like Unity, Spring.Net, or Castle Windsor to locate your appropriate controllers in the child projects.
Implement your own IControllerFactory to do the Controller lookups in the IoC container based on the controller name passed to it. You're looking to put in place an IControllerFactory.CreateController method that looks something like:
public IController CreateController(RequestContext requestContext, string controllerName)
{
return (IController)IoCContainer.GetObjectByName(controllerName);
}
Then you should be able to simply modify your IoC configuration file to define your new controllers as they are deployed.
Google for MVC with MEF. There is an example by one of the MEF team that will suit your needs exactly.