MVC3 Routing Basics - asp.net-mvc-3

I am learning MVC routing. Hope my question doesn't look silly, and please help :)
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Msdn reference says it takes a String, String, Object, so I try to make a small change (added a "my" in front of everything just to mod the names and see if it works):
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{myresource}.axd/{*mypathInfo}");
routes.MapRoute(
"myDefault", // Route name
"{mycontroller}/{myaction}/{myid}", // URL with parameters
new { mycontroller = "Home", myaction = "Index", myid = UrlParameter.Optional } // Parameter defaults
);
It doesn't work any more. What is the format of these strings in "{}" curly brackets, and the anonymous object value formats.
{controller}/{action}/{id}
/Products/show/beverages
{table}/Details.aspx
/Products/Details.aspx
blog/{action}/{entry}
/blog/show/123
{reporttype}/{year}/{month}/{day}
/sales/2008/1/5
{locale}/{action}
/US/show
{language}-{country}/{action}
/en-US/show
{controller}/{action}/{id}
http://server/application/Products/show/beverages
{resource}.axd/{*pathInfo}
http://server/application/WebResource.axd?d=...
I google'd around, but all the posts seem to assume I know the formats, and couldn't find any detail explanation.Do they have to be fixed names like {controller} {action} {id} etc, or they won't work? Does the default anonymous object value names need to match them, too? Further, what does the "*" mean in {*pathInfo} I couldn't find the explanation for that, neihter. Thank you.

First, we need some definitions here.
Let's break down the default route.
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
In this case, Default, on line 2, is merely a text name used to identify the route.
On line 3 is the url pattern. This defines how the route is matched. the things in braces are placeholders. They map to parameter names. so {controller} maps to the controller name. {action} maps to action name, and {id} maps to parameter called id.
On line 4 is the defaults object. This object supplies default values when they cannot be inferred from the url.
So, if we take all that together, here are some conclusions we can draw:
the default objects only supply values when they cannot be inferred from the url string. Thus, when the incoming request is just /, the dfault values from line 4 are used for controller and action. If the incoming request is /Blah, then the default controller supplied on line 4 is ignored, and instead MVC looks for BlahController. However, since no action was specified, the default action from line 4 is used Index.
The key thing to remember here is that the values on line 4 are only used if nothing matches the url in line 3.
So, when you changed everything, you threw everything for a loop. It's a meaningless route, because nothing defines which controller or action to use, and those two values are required in order to complete the route. As such, MVC can't figure out what controller you want. Or action method for that matter.
Another example:
routes.MapRoute(
"Example",
"Home/{action}/{myid}",
new { controller = "NotHome", action = "Index", myid = UrlParameter.Optional }
);
Because there is no {controller} placeholder in the url, then the default of "NotHome" is used, which makes MVC look for NotHomeController. So a url of /Home/About/3 would mean that controller = "NotHome", action = "About", and myid = 3.
All in all, in an incoming route, something must fill in the value for controller and action at a minimum. id is optional, and can be renamed to whatever you like. But, something must set controller and action parameters or MVC doesn't know how to route things.
Also, remember, the default route (or an effective default route) must come last in the list, otherwise no other routes will be matched.
The {*pathInfo} bit is called a slug. it's basically a wildcard saying "everything after this point is stuffed into a parameter called pathInfo". Thus if you have "{resource}.axd/{*pathInfo}" and a url like this: http://blah/foo.axd/foo/bar/baz/bing then two parameters get created, one called resource, which would contain foo and one called pathInfo which contains foo/bar/baz/bing.

Related

MVC3 Url Routing to create member area

I would like to create a member area on my site with the following URL patterns:
Pattern for logged out user:
domain.com
domain.com/About
domain.com/Blog
domain.com/Blog/1 (where 1 is the post ID)
But I also have a member area where I prefix the Url with Member like this:
domain.com/Member/MyProfile
domain.com/Member/MySettings
This seems simple, but I can't see an obvious way to make routing rules for this. I have:
routes.MapRoute(
"Member", // Route name
"Member/{controller}/{action}/{id}", // URL with parameters
new { controller = "Task", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
This works great for the member when you are logged in, but unfortunately the first rule also matches the logged out view and Url.Action("Blog", "Home") produces a Url that looks like this:
domain.com/Member/Home/Blog
How do I tell Url.Action that it must form Urls with the default rule outside the member area?
You could use a real MVC area instead of trying to simulate one. There's also a video you might checkout. The idea is that you leave your default route definition in Global.asax and then add a Member area to your site which will have a separate route configuration.

Can we use just the controller name and id parameter in URL for Asp.net MVC application

Suppose, I have a controller named category with an action method, Index which takes id as parameter.
Therefore, the URL appears like this : category/Index/foo. As you can see, the Index segment just doesn't seem right. A URL such as this : category/foo will be more readable and understandable.
Just like in SO, these guys use : question/857344
How can I achieve such a URL. In my routes, I have set defaults for all three : controller, action and id. But, when i try to visit category/foo, I get the "404 - resource not find"
routes.MapRoute(
"Category/{id}",
new { controller = "Category", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
You map it how you want it to look then specify the Action.
Also make sure you put it before the default route

MVC 3 Custom Url Routing

I want to create a custom route, as a default mvc creates route like this:
domain.com/deals/detail/5
but in my case i want to create a custom route for it:
domain.com/delicious-food-in-paris
so it has to look for deals controller's detail action with passing an id value 5 to it.
how can i do it?
Thanks
This route maps all one segment urls to the detail method of the deals controller and passes one string argument called dealName to it:
routes.MapRoute(
null,
"{dealName}",
new { controller = "deals", action = "detail" }
);
But as AdamD have said, you should register that route as the last route in your setup because it will catch all urls which have only one segment.
With this approach you have to lookup your deal by name which might be not acceptable. So many apps use a hybrid approach and include the name and the id in the url like this:
domain.com/deals/5-HereComesTheLongName
Then you can use a route like this to get the id and optionally the name:
routes.MapRoute(
null,
"{id}-{dealName}",
new {
controller = "deals",
action = "detail",
dealName = UrlParameter.Optional
}
);
You can do this by defining a custom route in the Global.asax RegisterRoutes function. You would need to add this route after the default route so if the default controller action id pattern fails it will try to execute the final route.
An example would be to use the following:
routes.MapRoute(
"RouteName",
"/{uri}", //this is www.domain.com/{uri}
new { controller = "Controller", action = "ByUri" },
new { uri = #"[a-z\-0-9]+" } //parameter regex can be tailored here
);
After you register this route you can add a new custom controller to handle these routes, add the action that will handle this and accept a string as the parameter.
In this new action you can have a database lookup or some hardcoded valide routes that return Views.

ASP.NET MVC Routing help

I am trying to create a route that can allow for different formats (html/json/xml etc)
This is what I am trying, but it doesn't work.
routes.MapRoute(
"Default",
"{controller}/{action}/{id}/{format}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional, format = "html" },
new { format = #"html|json" , id=#"\d+"}
);
The routes that do work are these:
/Person/details/1
/Person/details/1/json
But this don't work:
/Person which imo should default to /Person/Index/html
/Person/json and imo should lead to /Person/Index/json
But it doesn't match.
For the second of the ones that don't work I assume it thinks json is an action and that's the problem there, but for the first one I don't fully get it as I have defaults for each part of the url, and id is optional and it can't think html/json is the id as I say id have to be a number anyway, so it should imo get that one.
So who aren't the first one working?
For the second one I have been meaning to write a regex like this (I know it's not a real regex btw, any help on that is also appreciated..): action = #"!(html|json|\d+)" so that it will see that I'm not trying to say that json/html is an action, but that it then should use the default action of index.
But since the first one isn't even working I think I have to resolve that one first.
The problem
Routes can have multiple optional parameters (although I suggest you don't use this unless you know Asp.net MVC routing very well), but you can't have non-optional parameters after optional ones as you've done it...
Imagine what would happen if you set a non-default "json" value for your format but don't provide id? What would come in place of the id? You'd run against a very similar problem with multiple optionals, hence I advise you not to use them.
Two solutions
Change parameter order:
"{controller}/{action}/{format}/{id}"
Use two routes
routes.MapRoute(
"Ordering",
"{controller}/{action}/{format}",
new { controller = "Home", action = "Index", format = "html" },
new { format = #"html|json|xml"}
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}/{format}",
new { controller = "Home", action = "Index", format = "html" },
new { format = #"html|json|xml", id = #"\d+"}
);
The first one will cover requests where ID is optional and you do provide format, and the second one will cover situations when ID is present.
The id parameter cannot be optional. Only the last parameter of a route definition can be optional.

Did Microsoft change the way to pass string as parameter in ASP.NET MVC 3?

I have this simple question. Previously, when I wanted to call a controller method with only one parameter, I could do it simply calling /ControllerName/Method/Parameter, whatever type this parameter was. Now, I did the same thing with an integer value without problems, but with a string it didn't work. Am I going nuts or Microsoft actually changed this?
The default route that you'll find in Global.aspx.cs is still the following:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
So your "parameter" is the {id} in the example above, presumably a number as IDs tend to be. Get to know your routes, they're fun! Linkage: http://www.asp.net/mvc/tutorials/asp-net-mvc-routing-overview-cs
I'm imagining your actions that work for ints look something like this:
public ActionResult Index(int id)
If you want to accept a string parameter instead of an integer and have it be part of the (default) route, it also would need to be named id in the method signature, like so:
public ActionResult Index(string id)
If you had an action with a signature like this:
public ActionResult Post(string slug)
Then with the default route slug would only have a value if you had a querystring (get) or form (post) value with the key slug. A route that would match the above action and have the slug parameter be populated (assuming it was a method of the BlogController controller) would be:
routes.MapRoute(
"BlogPost",
"post/{slug}",
new { controller = "Blog", action = "Post", slug = "" }
);

Resources