Mapping controllers/action in route table - asp.net-mvc

Is it necessary to map all the controllers/actions to the route table in MapRoute function in an application ?
If not so, then how they added to the route tables ?

Using the default convention-based route will cover basic routing for many cases, especially those that aren't concerned so much with what the URL looks like. Since there is only 1 route in the route table, this is the best performing option, and it automatically "just works" for any controller or action that is added to the project.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Typically, other than that URLs are statically added either by using the MapRoute method or [Route] attributes, meaning they are compiled into the application and cannot change at runtime. This makes routes testable so the configuration can be verified before release.
However, if the goal is to make some sort of CMS where the application has control over the URLs and you want them to automatically be "made live" as you add records to your database you can extend RouteBase to handle that (along with virtually any other) routing scenario.

Related

Route Config Vs Attribute based routing mvc whose priority is more

I have been asked by someone that, suppose i have defined routing for a URL in route.config and i have defined the same routing in attribute based routing. Then whose priority will be more in each case. And what is the use of attribute based routing if we can achieve the same in route.config.
Then whose priority will be more in each case.
That would depend on whether you call the routes.MapMvcAttributeRoutes() extension method before or after the conventional routes. For example:
public static void RegisterRoutes(RouteCollection routes)
{
...
routes.MapMvcAttributeRoutes(); //Attribute routing
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
In this case the attribute based routes will be added first to the routing table and will take precedence.
And what is the use of attribute based routing if we can achieve the
same in route.config.
Attribute routes give you quite a bit more flexibility and places the routes next to the actions that will actually use them. But it's really a matter of preference. Microsoft has added attribute based routes in order to have an alternative way for defining the routes in the application compared to the conventional approach.

ASP.NET MVC4 Routing - Multiple routes to the same location

I am in the process of setting up a Single Page Application (SPA) and would like to setup, currently two routes. For instance:
Route 1: http://localhost - this is the default route which requires authentication (Admin area)
Route 2: http://localhost/<client>/<clients project name>/ - this does not require authentication (view only)
In the admin area, they setup the <client> and <clients project name>, therefore I know I need to setup this configuration in MVC4 Routes, but it is unclear to me how I would approach this.
Another caveat would be, if the <clients project name> was not entered into the URL, it would present a search page for that client.
One of the great things about routing in MVC is the ability to route anything to anywhere, regardless of whether the url matches the naming of controllers and action methods. The RouteConfig allows us to register specific routes to cater for this. Let me show you how you can achieve this.
Route 1:
This is handled by the default route in the route config.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home",
action = "Index",
id = UrlParameter.Optional });
Hitting http://localhost will take you to the Home controller and the Index action method.
Route 2:
We can set up one route that will cater for http://localhost/<client> and http://localhost/<client>/<clients project name>
routes.MapRoute(
"Client",
"{client}/{title}",
new { controller = "Home",
action = "Client",
title = UrlParameter.Optional });
Hitting either http://localhost/bacon or http://localhost/bacon/smokey will take you to the Home controller and the Client action method. Notice the title is an optional parameter this is how we can get both urls to work with the same route.
For this to work on the controller end our action method Client would need to look like this.
public ActionResult Client(string client, string title = null)
{
if(title != null)
{
// Do something here.
}
}

Setting up ASP.Net MVC 4 Routing with custom segment variables

I just began working on an application with a couple areas (basic grid master / details type system..) I'm looking into taking advantage of the nice routing features in MVC (4 specifically) and I'm "just not getting it" I presume.
Currently the only route defined is the basic one:
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Account", action = "Index", id = UrlParameter.Optional }
);
which is fine, it works with the areas we have defined, so I'm assuming it must know where the user is and route to the appropriate controller based contextually on the location / area that the user is in.. so far nice..
Now, i'm trying to set up a new route that can handle
/someController/someAction/{statusName}
and specifically something like:
/OrderManager/List/New
AND
/OrderManager/List/Viewed
where "New" is the "New" status and have the Action Signature look like:
public ActionResult List(string statusName)
i was assuming I could just add the new route below the default one identifying "statusName" instead of Id, but of course, how the H would the routing mechanism know the difference between :
/controller1/action1/15
/controller2/action2/new
I did try adding a "static" route in the form of
routes.MapRoute("Default",
"ControllerName/ControllerAction/{statusName}",
new { statusName = UrlParameter.Optional }
);
I thought I could "hiJack" just that one route and do something special with it, but to know avail, the router stops at first match?? I'm assuming that was the wrong way to address this issue anyhow..
so now I'm going through the idea of getting to something like:
/somecustomroutename/somesortValue
ex.
/OrderManagerList/viewNew
where these routes would basically be "aliases". I had thought that adding the following route would do the trick:
routes.MapRoute("Default_List",
"OrderManagerList/{statusName}",
new {controller="OrderManager", action="List", statusName= UrlParameter.Optional }
);
with the associated action on the OrderManager controller:
public ActionResult List(string statusName)
no matter what I try, the argument is null, or the "resource cannot be found"
I know the controllers need to have a corresponding View file.. but that's not the issue here, the issue is my attempt at understanding the routing..
SO my questions.. fundamentally, what am I missing about the routing in MVC (4)? even some good articles for a simpleton like myself to understand?
my understanding; define a route, and map it's "endpoint".. however, i think i'm not understanding the assumptions that the machine is making..
anyhow, let me know if further explain / edit is required..
thanks in advance.
The basic principle of routes is that they are evaluated from the top down, and the routing systems uses the first match, not the best match.
The implication of this is that you must order your routes in order of specificity, with the most specific route first and the most general route last.
With this principle in mind, let’s look at your situation. Initially, you have only the default route defined:
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Account", action = "Index", id = UrlParameter.Optional }
);
The URL pattern is "{controller}/{action}/{id}". By itself, this would match any three-segment URL, and would not match any URL that had less than three segments. However, the third input parameter is the default parameter, which defines defaults for the first and second segment and indicates that the third segment is optional. The next effect of this is to make the route match URL having 0,1, 2 or 3 segments.
Now you want to add a route where the third URL segment is mapped to a “statusName” parameter, and can handle URLs like:
OrderManager/List/New
OrderManager/List/Viewed
There are two basic approaches you can take here. You can 1) create a very specific route that will handle these two URLs only, or 2) you can try and create a more general route to handle the general case. Let’s look at the first case first. You can create a route as follows:
routes.MapRoute("", "OrderManager/List/{statusName}",
new { Controller = "OrderManager", Action = "List" });
Note that because this route is more specific than the default route, you must put this route before the default route.
If you want to have a more general route, you need to decide how this route will differ from the default route, since they both will match URLs having three segments. Let’s say you decide that the new route will accept anything that only contains letters in the third segment, leaving the default route to handle anything containing numbers. You can do this using route constraints. For example you could write a route as follows:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { id = #"^\d+$" });
routes.MapRoute(
name: "NewRoute",
url: "{controller}/{action}/{statusName}",
defaults: new { Controller = "OrderManager", Action = "List" },
constraints: new { statusName = "^[A-Za-z]+$" });
With these two routes, any three-segment URL having only letters in the third segment will put the third segment into a variable called “statusName”, whereas any URL with an integer in the third segment will put the third segment into a variable called “id”.
In any applications of real complexity, routes can get complicated, and it is very advantageous to write unit tests for your routes, to insure that you don’t screw things up when you add or modify a route.
For good references on routing, see Scott Sanderson's book or see the MSDN documentation

MapRoute without affecting ActionLinks

Typically I want the default route used when generating URLs ("backwards" mapping), even if I've added alternate or legacy routes to reach an action ("forwards"):
routes.MapRoute("Legacy", "legacy/home/index", // want forward-only mapping!
new { controller = "Home", action = "Index" };
routes.MapRoute("Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
In this case, I'd still want the default route used when I call:
#ActionLink("Index", "Home") // generates legacy URLs ;(
In the thread: Routing legacy requests with and without querystring (issue #1), the solution is to add two MapRoute statements for each legacy route, or specify the route name in each ActionLink call.
Is there a way to define a route used only for URL -> Action mapping, not the inverse?
I can't find a way to have the route statements apply only one way, so I installed the IIS URL Rewrite module. This works to rewrite the URL transparently, or 301-redirect it in the case of legacy URLs.
It's a more maintainable solution than editing the global.asax anyway.

Duplicate content in ASP.NET MVC because of custom routes MapRoute(), are areas the rescue?

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/

Resources