Friday, December 21, 2012

MVC and Routing Basics

Routing is located in the System.Web.Routing namespace

Can be used in MVC and also ASP.NET web forms apps.

Routing is used to map incoming URLS to action methods in a controller and optionally pass arguments to the action methods.

Generates outgoing urls (links in pages; generally used for navigation).

check out www.useit.com for guidelines on url best practices.

Routing is similar to URL Rewriting (been around for a long time in ASP.NET web forms). URL rewriting is geared towards pages and doesn’t really apply to MVC. Now you should almost always use Routing, but in MVC it is hard not to use routing.

 

Defining a route

  • URL Pattern
  • Default values
  • Constraints
  • Arbitrary properties

Look in the Global.asax.cs file under the RegisterRoute() method. In the RegisterRoute method you will use the MapRoute() method to specify any of the 4 items listed above. There are many overloads for this method.

routes.MapRoute(
“Default”, // route name
”{controller}/{action}/{id}”, // url pattern
new { controller = "Home”, action = “Index”, id = “”} // parameter defaults
);

The order or the MapRoute method is very important. They are processed from top to bottom. so put routes from more specific to more general.

URL Pattern

Default URL pattern: {controller}/{action}/{id}

Consists of segments. Each segment has URL parameters or placeholders and are shown as {…} and some static text.

The RouteValueDictionary holds the values that the parameters take based on the current url. For example if the url is http://localhost/Dog/Edit/3 then when the route is matched the RouteValueDictionary will contain keys and values as shown below.

controller = Dog
action = Edit
id = 3

You don’t have to use / to separate the placeholders. You can use just about anything, but it should be something that is not the data

Some other examples of url patterns:

“Brent/{controller}-{action}-{id}” –> Brent/Dog-Edit-3

“Brent/{controller}-{action}/{id}” –> Brent/Dog-Edit/3

 

Default Values

Works much like optional parameters in methods. If the parameter is not specified routing looks to see if there is a default value for that parameter (placeholder). They are passed to the routes.MapRoute() method.

http://localhost - default values for controller and action

http://localhost/Dog/List - default values for id

 

Constraint

What will happen if your url is http://localhost/Dog/Edit/3? In this example, let’s assume that the id is an int and 3 will be assigned to it. This matches the routing pattern fine, but what would http://localhost/Dog/Edit/Jewel do? It would try to assign Jewel to an int and that would not work and would result in the YSOD. To make it so the pattern is not matched we can introduce a constraint to only match numbers. Constraints can use regular expressions to control accepted values.

We could change the route to something like this using an overloaded Map method.

routes.MapRoute(
“Default”, // route name
”{controller}/{action}/{id}”, // url pattern
new { controller = "Home”, action = “Index”} // parameter defaults – notice no id default
new { id = @”\d{1,6} }

);

routes.MapRoute(
“Default”, // route name
”{controller}/{action}”, // url pattern
new { controller = "Home”, action = “Index”} // parameter defaults,
);

The first route is to accomplish what we were looking for. Unfortunately, it doesn’t allow for things like http://localhost and http://localhost/Dog/List. So, we had to add the second route to allow those routes.

Handling an Arbitrary Number of Parameters

Can use a catch-all parameter that:

  • match URLS with arbitrary number of parameters
  • Ignores slashes
  • Captures everything after what matches the url pattern to the end of the url
  • Excludes the query string parameters (doesn’t capture)
  • MUST be the last parameter in the url
  • Can only have one in url pattern

To do this, just a * to the beginning of the parameter name.

routes.MapRoute(
“CatchAll”, // route name
”Catch/All/Params/{*randomParams}”, // url pattern
new { controller = "Dog”, action = “CatchAll” } // parameter defaults
);

There needs to be a method in the Dog controller called CatchAll. It would look something like this

public ActionResult CatchAll(string randomParams) {… }

A matching url might look like this: http://localhost/Catch/All/Params/and/more/stuff/goes/here.

In this example, “and/more/stuff/goes/here” would be passed to the CatchAll method.

It is up to you to do something with the string. In most cases you will parse it and do something interesting with the values in the url.

 

Blocking Routes

You may want to block users from particular urls. To do that you would typically put a new route as shown below as one of the first routes in your routes collection so that it matches first.

routes.IgnoreRoute(“{resource.axd/{*pathInfo}”)

or

routes.Add(new Route(“{resource}.axd/{*pathInfo}”, new StopRouteHandler()));

Both of these do the same thing.

 

Generating URLS

You could hardcode urls in your MVC application, but is difficult to maintain and messy. Luckily MVC makes it easy when you use the routes to automatically generate urls. To access this automatic generation you would typically use HtmlHelper.ActionLink and HtmlHelper.RouteLink helper methods.

ActionLink – the url is based on the combination of the controller and action name, and any other parameters

RouteLink – relies on the route definitions and parameters

Works just like incoming routes regard order, so Routing will match the first one it finds which is based on the order you add it to the collection of routes.

 

Named Routes

If you want to force a particular route to be used. This works because the route name is basically a key into the list of routes in the route collection. This affects both the automatically generated urls (see ActionLink and RouteLink) and incoming urls. This would be useful if you want to use a route that is farther down the list of routes and thus would not usually be matched. Some people say that you should not use named routes, but the choice is yours.

No comments: