ASP.NET MVC2 Routing / Folder structure - c#

In ASP.NET MVC2,
How do I change routing/folder structure so I can have
Views\FOLDER\Account\ChangePass.aspx
Rather than:
Views\Account\ChangePass.aspx
I don't actually want to do it for the account, but I'd like to structure things like that, e.g.
SO I can have two different views like:
Views\Categories\
Views\Admin\Categories\
These would display completely differently.
All I want to do is to be able to create my own subfolders to push the views into, not a seperate folder for each different controller...............................................................

Sounds to me like you need to look into using areas... Have a look at this article for more info:
Walkthrough: Organizing an ASP.NET MVC Application using Areas
Excerpt:
However, some applications can have a large number of controllers, and each controller can be associated with several views. For these types of applications, the default ASP.NET MVC project structure can become unwieldy.
To accommodate large projects, ASP.NET MVC lets you partition Web applications into smaller units that are referred to as areas. Areas provide a way to separate a large MVC Web application into smaller functional groupings. An area is effectively an MVC structure inside an application. An application could contain several MVC structures (areas).
HTHs,
Charles

Go with the asp.net MVC convention for view location; if you want to have different url paths you need to look at creating your own routes, other than the default single route given to you. (See this primer.)
Here's an example of a route that you might add in your Global.asax to have the desired result but you'll have to map this route to a controller action appropriately. Really, your need to decide on the pattern to meet the need of your app...
routes.MapRoute(
"FolderRoute",
"{controller}/{folder}/{action}/{id}",
new { controller = "Home", folder = "yourFolderDefault", action = "Index", id = "" }
);

Related

asp.net MVC correct place for controllers for shared partial views

Where is the best place in the project directory for the controllers for Shared partial views?
I have found similar question to: ASP.NET MVC: Correct place for Partial Views?
I can't decide if it is better to do something like /Controller/Shared/CONTROLLER_FOR_PARTIAL_VIEW or just create its separate folder like /Controller/CONTROLLER_FOR_PARTIAL_VIEW
The partial view is specifically for dropdownlistfor, and the model wont be used for anything other than to populate the dropdown. So if a site has many dropdown lists or just partial views in general, a shared folder seems to be the best option. If the preferred way it the Shared folder, do you use one controller for each partial view, or one controller for all partials? I appreciate any thoughts or feedback, thanks!
EDIT: To be clear, I m specifically asking about the directory for the CONTROLLERS not the VIEWS. Thanks!
In one sense, it doesn't matter. There is no true standard or convention for this, so you have the freedom to do it however it makes the most sense to you and your application.
Having it under something like Controllers/Shared could make sense, if there's enough of these that that is worthwhile and it adds value to keep them separate from regular controllers. However, in terms of a project, everything is essentially shared, so there's no true distinction here. Personally, simply having it named something distinctive is probably the best route. For example, I have a number of child actions in one of my projects that are used in various parts of my layout. As a result, I created a LayoutController to house these.
The one thing to keep in mind is that, if you're using standard routing, any controller will be available to the routing infrastructure, regardless of where it's located in your project tree. You'd have to pretty much just know how to get to it, but if you named your shared controller something like SharedController, then with standard routing, its actions would be available via /shared/action. For things like child actions, this is easily solved by using [ChildActionOnly]. By adding that attribute to your child action, it will be divorced from the routing infrastructure for URL requests. Internally, MVC will still be able to get to it for the purposes of rendering it for a view, though.
Projects I've been on it was at /Area/Controllers/SharedPartialController.cs and with that naming the view was at /Area/Views/SharedPartial/_MenuDropdown.cshtml
Hopefully you're using "areas" in your MVC project, in which case I would suggest doing one shared controller per Area.
I.e. /Order/Controllers/TabsPartialController.cs for one that relates to Order area, and then /User/Controllers/NavTabsPartialController.cs etc.

What's the best way to change how Areas get created in Razor MVC?

I am transitioning to using Areas in a project, and each time I make a new one I have to change a few things to make it fit in with how I'd like things to work. The changes involve:
Removing one of the folders that gets created
Modifying the web.config file slightly
Adding a new file or two with some defaults
Modifying the AreaRegistration file slightly
I would rather not have to do these same things every time I create a new area because I'm afraid that the convention will be forgotten and something will get messed up. Is there a way to modify the defaults for New > Area? Or perhaps would it be possible to make a new file template that does what I'd like?
I am transitioning to using Areas in a project
I have been doing something similar for a few months now, but starting with an old WebForms project, adding MVC components via VS 2013's Add -> New Scaffolded Item... feature, in order to leverage MVC's structure and routing, on the server side. I have also been incorporating WebAPI and SignalR on the server side. I am definitely still a beginner, but being maybe a little further along in a similar process, here some of my thoughts and questions about what you want to achieve:
Removing one of the folders that gets created
Modifying the web.config file slightly
Adding a new file or two with some defaults
What environment are you developing in? For instance, if you're using VS 2013's scaffolding you can most likely modify the T4 templates to prevent or redirect the creation of folders, classes, and such. Here is a post addressing where you might find those templates, and here is just one of many intros out there for T4. The path to the templates on your machine will vary based on the VS version. By modifying or creating new templates you should be able to accomplish all 3 points above relatively easy. If you are working in such an environment I will try to expound on exactly how you might go about modifying the out of the box templates (there are probably already plenty of posts that you could refer to which would do a better job though).
Modifying the AreaRegistration file slightly
If you are working with MVC 5, or later, I would recommend using attribute routing. This seems more standard when working within the API paradigm (inheritting from ApiController instead of Controller), but I have found extending this to traditional MVC controllers to be very useful.
Assuming MVC 5, I would recommend modifying AppStart\RouteConfig.cs's RegisterRoutes() method, to enable attribute routing and then add a catch-all route such as:
routes.MapMvcAttributeRoutes();
routes.MapRoute(
"NotFound",
"{*url}",
new {
controller = "Error",
action = "Index"
});
At that point I would delete the xAreaRegistration.cs files, and remove the call to RegisterAllAreas() from Global.asax, but you don't have to go that far. Then I decorate my controllers' classes (wherever they live) and their methods, with attributes as needed. Using attribute routing I've been able to free myself from the traditional MVC conventions. I can still fall back to them, but I can then place my controllers anywhere in my project, and easily define their actions' routes.
That being said, you should probably follow some organizational standards for groups of similar routes, so that as the project grows you don't find yourself wasting a lot of time searching for all controllers/actions matching some set of routes.
Here's a simple example of how this actually translates from URI into method call:
If I had Controller ctl with action act, logically in Area ar, the URI being http://localhost/ar/ctl/a/1, would be routed to MyControllerNameDoesNotMatter.Index(1), below, by using attribute decoration such as:
[RouteArea("ar")]
[RoutePrefix("ctl")]
public class MyControllerNameDoesNotMatter : Controller {
...
[Route("a/{optionalParamDefaultsToNegativeOne=-1}")]
public ActionResult Index(int optionalParamDefaultsToNegativeOne) {
...
}
}
This way of looking at Area is more logical than physical, in that the MyControllerNameDoesNotMatter.cs file does not have to be in the Area\ar\Controllers folder. Since adopting this I have actually drifted away from using the Area scaffolding, other than to lay out application modules at a very high level - think sub-application that could be a stand alone SPA.
I have tried to make the "catch-all" route attribute based, and remove it from RouteConfig.cs, but I have not been able to do this successfully. The issue is route precedence. It works fine as a catch-all for invalid routes. But for a valid route, multiple (2) routes end up being matched because the two attribute routes have the same order of precedence. Whereas, with the catch-all defined in RouteConfig.cs, after registering all attribute routes, the attribute route takes precedence. I have found mixed answers that attempt to address this issue. There seems to have been a Number or Order parameter for the Route attribute at some point, but I have had no luck with that. This seems to be an unresolved issue. Just one of many SO questions, which have gone unanswered.
Edited to account for mvc4 tag
I had not seen the mvc4 tag prior to posting. There are nuget packages available that will achieve much of the same functionality, such as scaffolding and attribute routing for earlier versions of MVC.

Folders in Controllers directory in ASP.NET MVC 4

I'm kind of new to ASP.Net MVC 4. I'm working on an app that will have a lot of routes. With that in mind, I'm running into naming conflicts in my Controller. Because of this, I've decided that I want to split up my Controller into multiple controllers. In an attempt to keep things clean, I feel I have a need to put Controller classes in subdirectories within the Controllers directory. My questions are:
Is this even an option? I can't seem to find any examples with
this approach
How do I register the Controllers that are in the
subdirectories such that when I add routes in the RouteConfig.cs
file, they leverage the controller that is in a subdirectory?
Thank you!
Is this an option? Definitely. You can place the controllers wherever you want. MVC would automatically scan the assembly for controllers and it doesn't matter if they are placed only under Controllers.
If things get more complex, and you want better organization, you can leverage the concept of Areas in ASP.NET MVC - http://msdn.microsoft.com/en-us/library/ee671793(v=vs.100).aspx

Using MVC3 with folder structure like regular ASP.NET

So I am reading about building MVC3 projects and there is one thing that seriously bugs me. The folder structure of the project in no way corresponds to the path of the HTTP request. There is a bunch of things I like and would want to use, but having a flat folder structure is not one of them.
Why is this a problem? Well, I see it becoming a problem when building a site with a heavy mix of content pages and various forms/dynamic pages (most of our sites are like that), which would typically be done by different people. It seem it would be too complicated for client-side developers to follow routing rules of dynamic pages and/or creating new ones.
What I would like to understand is if there is way to configure MVC3 application in such a way that:
it follows directory structure for finding controllers without explicit route map for each one
views live in the same folder as corresponding controller
routing magic still works for actions and parameters
For instance I'd like to have a request /fus/ro/dah/ to try to find DahController in the \webroot\fus\ro\dah\ folder and execute its Index action. If not found it would look for RoController with Dah action in the \webroot\fus\ro\ folder, etc.
It is entirely possible that MVC was not meant to be working this way at all and I am just trying to force a square peg into a round hole.
UPDATE:
Looks like I can drop a view file into the desired folder structure, and it will be executed. However layout would not work apparently because it is expecting a controller. Does this mean I have to create a controller for pure content pages? That is a pretty crappy design...
UPDATE 2:
Main issue right now is that creating "fus" folder means that MVC will not even attempt to look for FusController... not under "fus" folder, nor anywhere else. Is it possible to get around that?
For instance I'd like to have a request /fus/ro/dah/ to try to find
DahController in the \webroot\fus\ro\dah\ folder and execute its Index
action. If not found it would look for RoController with Dah action in
the \webroot\fus\ro\ folder, etc.
MVC is not designed for a particular need like this, it is a general framework for building applications using model-view-controller pattern.
If you can't bend the application for the framework you can bend the framework for the application and honestly MVC is very customizable. [As a proof, in the current project (migration from ASP to MVC) that I'm working we have models as xml and no classes also we are using XSLTs for rendering. With a little work we have created custom components like custom view engine, custom validation provider, custom model binder... to make the framework best fit for the application and it does]
MVC is not designed and not forces to use it as it is and you can customize/extend as much you want. In your case you may have to create a
custom controller factory (because you want to customize the way in which the controller is seleced),
custom view engine (because you want to customize where the view is placed)
and may be others.
For custom controller factory you have to extend the DefaultControllerFactory class. There are lot of articles you can find through Google that explains about how to create custom controller factories.
Depending upon the view engine you are using you have to extend the respective one. For ex. if you are using web forms then you have to extend the WebFormsViewEngine and it razor then RazorViewEngine.
For more info. check this link
http://codeclimber.net.nz/archive/2009/04/08/13-asp.net-mvc-extensibility-points-you-have-to-know.aspx
you can mixup Asp.net and Asp.net MVC. as LukLed said, MVC is convention over configuration pattern. if you follow the convention. you dont need to configure. you can check this link for mixing up the asp.net content with MVC3
Mixing Asp.net and Razor
I believe ASP.NET MVC is not meant to be used that way. While you can configure MVC to do it, it is better to keep standard /controller/action/parameters URL format. If you have complex website with many different functionalities, areas may be helpful http://msdn.microsoft.com/en-us/library/ee671793.aspx. Every area get its own set of controllers, models and views, so teams working on different parts of website won't disturb each other.
While it may sound convenient, that framework first searches for DahController and executes Index action, then searches for another one, I find it bad idea. URLs should be clearly defined and Fus controller with Ro action shouldn't just stop working, because someone created RoController with Index action.
Look into using Areas as well. I think that helped me get over my folder structure issues with MVC honestly. So i could use the base folder as my Home details, then i could have a 'Admin' area which was a separate folder, things like that.
How "regular ASP.net" do you want it to be? If you want to do "legacy" ASP.Net Web Forms mixed in with MVC, you certainly can - re: mixing MVC with "file based aspx" - aka "hybrid". At the end of the day, it's all ASP.Net.
This is a standard MVC Application generated by Visual Studio. I've added a folder somedirectory where I want to use the legacy folder/file.ext paradigm and have a default.aspx Web Forms file:
Can I navigate to it via http://foo.com/somedirectory? Yes.
Can I use "pretty urls" too? Yes
Vanilla Global.asax generated by VS, just added MapPageRoute:
....
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//using "pretty urls" - ordering your routes matter.
routes.MapPageRoute("theWebForm", "legacy", "~/somedirectory/default.aspx");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
so now I can navigate to it via http://foo.com/legacy
Just check the order of your routes, and perhaps plan on your naming conventions so you don't have "collisions"...
Hth....

Grouping Views, Controllers, Models in MVC

maybe i am wrong but i seriously i don't like the current structure of MVC application, and i think on big projects it will cause trouble to maintain.
so is there a way to group related Controllers,Views, Models together, like if i have gallery Module i want all it's Controllers, Views, Models to be grouped under Gallery Folder.
Areas sound like what you are looking for. This will let you group controllers/views/etc. Unless I misunderstood the question?
Phil Haack discussed this here, it's the same issue I've faced and have yet to overcome correctly.
From the sound of it you're moving against the basic principals of MVC, that being the separation of Model, View and Controller rather than your desire to split at 90 degrees to that by using modules.
I'm not entirely sure what benefit you would get from splitting it in to modules any way since I would expect you to have one GalleryController. Where you are likely to have the most 'entities' needing grouping is with the views, possibly one or more for each GalleryController action, but they are in their own folder which gives the sort of functionality you are looking for anyway.
Finally there are the models. Obviously I don't know your project so I don't know how it is laid out, but the Models do not usually exist for the use of one Controller (or module in your case). For example - I have Models for Users, Companies, Vehicles, etc, etc. These models are a shared representation of my data structure and have nothing to do with modules as a user may see it looking at a web page. I can't split them in to modules because the whole point is that they are shared by the entire application.
So...in reality it is the Views which can get a bit messy, but they are already split in to folders based on their Controller. Having said that you can move them around a bit if that suits your needs better. For the rest of it there is no need, either because you shouldn't if you want to use 'proper' MVC (i.e. modular Models) or there's no need (i.e. only one Controller). And if your controller gets too big just create a separate module for any functionality in that you want to split out. I reckon that's as modular as you should ever need to get.
I found a relatively simple solution that uses IIS configuration to simulate areas. No extensions to the existing MVC framework are needed.
Create a new MVC project under your solution for each area you want in your site (ex. Root, Blog, Forum, App1, App2). If you need any common supporting code or a common model, put it in a seperate dll project that the MVC projects depend on.
In IIS, configure the site root to point at the root project directory. Create web applications under the site root that point to each of the sub-area project directories.
When configuring the route maps for each sub area, don't include the name of the application in the route. IIS seems to take care of this for you. (ex. "ShowPost/{postname}", not "/Blog/ShowPost/{postname}")
The benefit is that you can change the name of the web applications independent of the routing system, and each application believes it is running with the whole server to itself.

Categories