I have a reports controller (ReportsController), that i've decided to split up as it contains too many actions. I currently have three pages that the controller serves:
app/reports/settings/
app/reports/charts/
app/reports/tables/
I decided to use the ReportsController just for the settings page, and I have created two seperate controllers to handle the other pages - Reports__ChartsController & Reports__TablesController.
I added the following two routes to my routes config:
routes.Add(
new Route("reports/charts/{action}/{id}",
new RouteValueDictionary(
new { controller = "Reports__Charts", action = "Index", id = UrlParameter.Optional }),
new HyphenatedRouteHandler()
)
);
routes.Add(
new Route("reports/tables/{action}/{id}",
new RouteValueDictionary(
new { controller = "Reports__Tables", action = "Index", id = UrlParameter.Optional }),
new HyphenatedRouteHandler()
)
);
The approach works really well, but I was wondering if there is a better way? The downside to this approach is that if I wanted to split out other controllers I would need to keep adding entries to my route config specific to each controller, which could enlarge my route config to the point where it's hard to maintain.
I assume what I wanted to do (splitting up controllers) is a common requirement, but i've not come across a standard method of implementing it via google.
This problem is exactly why we pounced on attribute based routing as soon as it was released. One route per action, in a clear concise manner, and moving actions between controllers is seamless, especially if you make use of the controller level attributes [RouteArea] and [RoutePrefix]. The sooner you make the switch, the happier you'll be. We've never looked back.
Related
I am a bit new to the MVC so started off with MVC3 with ASPX engine.
my scenario is, that when I create a controller it automatically generates an Action named "Index" so suppose if I create a "Users" Controller + some actions, it would look something like this.
UserController
Index
Add
Delete
Edit
other actions
Then I create another controllers named "Products", "Company", etc with lets say the same set of Actions,
So normally when I would go to the link ../Users/Index I have the logic to show all users and it would do the same for ..Product/Index and ..Company/Index etc. It would show all products and all companies respectively.
This part of story is working good.
Now what I want to achieve is, I want to get rid of /Index everywhere in the url, not just for these three controllers, but for every controller that I create in future.
I want to consume "Index" Action but in a way that it doesn't need being typing everywhere.
It just makes me remember of old days where there used to be /index.html.
I have seen the links like these,
MVC Routing get rid of /Index in URL
they suggest i change the route for a specific situation, but I want this done not just in one or two controllers but every controller there is in my app.
Thanks.
In every route, specify Index as the default action, e.g.:
routes.MapRoute(null, "{controller}/{action}/{id}",
new { controller = "Home", action = "Index" });
I have very simple question. My site, based on ASP.NET MVC, can have many urls, but all of them should bring to the one controller. How to do that?
I suppose I need some magic in Global.asax but I don't know how to create route that will redirect any url to the specific controller.
For example I have url /about, /product/id etc. but all of them should be really bring to the content/show where the parts of url will be recognized and the decision what information to show will be make. It's some like CMS when you cannot define routes in advance. Is this information enough?
Thanks
This sounds like a horrible idea, but, well, if you must;
routes.MapRoute(
"ReallyBadIdea",
"{*url}",
new { controller = "MyFatController", action = "MySingleAction" }
);
This routes everything to a single action in a single controller. There's also {*path} and other URL patterns should you want slightly more flexibility.
Ideally you should try and specific with your routes, for example if you have a URL that is /products/42 and you want it to go to a generic controller you should specify it explicitly like
routes.MapRoute(
"Poducts",
"products/{id}",
new { controller = "Content", action = "Show", id = UrlParameter.Optional }
);
then you would specify another route for something else like /customers/42
routes.MapRoute(
"Customers",
"customers/{id}",
new { controller = "Content", action = "Show", id = UrlParameter.Optional }
);
this may seem a little verbose, and creating a single route might seem cleaner, but the issue a single route is you will never get a 404 and will have to handle such things in code.
Is there any best practice for how to best define and organize routes in MVC?
The company I work for runs a very extensive, complex ecommerce site with ~600K unique visitors/day.
Here's the problem: in our Global.asax.cs, we've got this HUGE list of approximately 75 route definitions in our RegisterRoutes():
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Is there a better way to define these routes other than having this gigantic list in the Global.asax.cs?
Because we've got a bunch of developers and half of them are incompetent and I can't go back refactoring these routes, it can take literally a couple minutes to figure out what controller is responsible for delivering a URL's View.
What can I do?
One developer toiled away building a prototype that allows us to do this in our Global.asax.cs:
public static void RegisterRoutes(RouteCollection routes)
{
routes.Include(new RootController());
routes.Include(new AccountController());
routes.Include(new HelpController());
routes.Include(new SearchController());
// etc., for each controller
}
In this prototype, Include() is an extension method and all Controllers inherit from IRoutedController, which provides Include() an IEnumerable<Route> list of Routes to add to the RouteCollection.
But with this prototype, we have a new problem: instead of looking through a list of route.MapRoute() calls to find which controller a specific URL invokes, we now have to guess which Controller is responsible for a specific URL and check its IRoutedController list of routes to see if the URL actually invokes that Controller we guessed. Not so hard, but sometimes takes just as long as examining our list of 75+ Routes in Global.asax.cs.
Is this a better solution?
Is there any good solution?
Should we just keep adding routes to Global.asax.cs; should we give the prototype the green light; or should we do something else? (Assume that you cannot refactor existing route URLs to make them more logical.)
I'm sorry, but what are you talking about? :P
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
This single route entry effectively allows you to call Any action method of Any controller with any parameters.
Is this a better solution?
Probably not.
Is there any good solution?
Yes. But you need to share more of your routes to be sure.
Should we just keep adding routes to Global.asax.cs; should we give the prototype the green light; or should we do something else?
No, No, and Yes. You need to share a decent amount of routes to have a better idea of the situation.
(Assume that you cannot refactor existing route URLs to make them more logical.)
But you can make sure new ones fit in the default route, so the problem doesn't keep growing i.e. {controller}/{action}
I would have stored the route information externally in xml file or database and loaded it in global.asax. I can add extra column/attribute that will have example url being routed so that I can search it quickly. Not to mention, I can update route information w/o rebuilding the project (of course, if there are new controllers, views etc then hey would need to be packaged in a new dll).
I use custom routes for my URLs and my action become accessible via two URLs (not counting trailing slash and lower\upper case letters): one via my custom route /my-custom-route-url/ and one via default /controller/action.
I see one possible solution -- put all controllers which use default routing (they are mostly backend) in one area, and place all others in separate area and use it without default route.
May be there is a better way?
The Default Route is an unnecessary evil in my opinion. It's helpful in that it means you write less code, but really I find it's far better to simply create each or at least most routes by hand.
Areas are a good way to separate different parts of your application, but using it just to avoid dealing with a blank default route isn't the correct reason. I use areas to isolate my admin area from my default area, but my reasoning for doing so is that they are two independent systems.
If you like you can make default routes for each controller as needed on a case by case basis. For example you could have a default products/{action} route and a default home/{action} route, but then individually define each route in the ContactController or what have you.
routes.MapRoute(
"Products_Default",
"products/{action}",
new {controller = "Products", action = "Index"},
new[] {"Web.Components.Controllers"}
);
routes.MapRoute(
"Contact_Send",
"contact/send",
new {controller = "Contact", action = "SendMessage"},
new[] {"Web.Components.Controllers"}
);
routes.MapRoute(
"Contact_Home",
"contact",
new {controller = "Contact", action = "Index"},
new[] {"Web.Components.Controllers"}
);
IMHO, this is duplication and should be avoided. You could use URL Rewriting of IIS to do this with its rewrite module.
The custom URL can be rewritten at the IIS level to use the normal controllers and actions and I think that should serve your purpose.
For more info look here: http://learn.iis.net/page.aspx/460/using-url-rewrite-module/
I've created a website with ASP.NET MVC. I have a number of static pages that I am currently serving through a single controller called Home. This creates some rather ugly URLs.
example.com/Home/About
example.com/Home/ContactUs
example.com/Home/Features
You get the idea. I'd rather not have to create a controller for each one of these as the actions simply call the View with no model being passed in.
Is there a way to write a routing rule that will remove the controller from the URL? I'd like it to look like:
example.com/About
example.com/ContactUs
example.com/Features
If not, how is this situation normally handled? I imagine I'm not the first person to run in to this.
Here's what I've done previously, using a constraint to make sure the shortcuts don't conflict with other routing rules:
routes.MapRoute(
"HomeShortcuts",
"{action}",
new { controller = "Home", action = "Index" },
new { action = "Index|About|ContactUs|Features" }
);
Add defaults for the controller names in the new statement. You don't have to have {controller} in the url.