Advanced routing (MVC Framework)

As we know the routing configuration of a MVC Framework application can be found within the RouteConfig.cs file. The default configuration is something like this:

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

Which tells MVC Framework that we want to map an url like “/myController/myAction” to an action named “MyAction” of a controller named “MyControllerController”. The {id} parameter allows us to to send a parameter (optional in this case), called “id”, to our action. So an action like the following one is automatically handled by the default configuration and can be reached with this url: “/myController/GetTestObjectWithId/123”.

public ActionResult GetTestObjectWithId(int id)
{
    return Json(new
    {
        Name = "Test",
        Value = "TestValue",
        Id = id
    }, JsonRequestBehavior.AllowGet);
}

Defining a custom routing

If we need a custom routing we have to setup a specific rule to tell MVC Framework how to map the action with the desired url. For example let’s say that we want to reach the following action with this url “/myController/GetTestObjectWithParameter/123”:

public ActionResult GetTestObjectWithParameter(int parameter)
{
    return Json(new
    {
        Name = "Test",
        Value = "TestValue",
        Parameter = parameter
    }, JsonRequestBehavior.AllowGet);
}

This action looks very similar to the previous one, apart the parameter’s name. Well, this difference is enough to require us to define a custom routing rule. Indeed the default configuration uses a parameter called “id”, so if we try to refer this action with the url “/myController/GetTestObjectWithParameter/123” MVC Framework will not be able to map the token “123” of the url to the action’s parameter because it has a different name.

Without defining a custom routing the only way to reach this action is using this url “/myController/GetTestObjectWithParameter?parameter=123”. That is not as beautiful as the previous one.

So how can we define a custom routing rule? The classic way is to add another rule within the RouteConfig.cs file. Is important to insert any custom rule before the default one, because if many rules match the same url just the first one will be considered.

routes.MapRoute(
    name: "TestGetObjectWithParameters",
    url: "test/getTestObjectWithParameter/{parameter}",
    defaults: new { controller = "Test", action = "GetTestObjectWithParameter", parameter = @"\d+" });
 
routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

With the @”\d+” configuration over the “parameter” parameter we are telling that it should fit the provided regular expression, so we want an integer parameter. Other options are available, see the documentation for a complete list.


Using the routing attibutes

From the version 5.0 of MVC Framework is possible to use another way to define custom route rules. We can use the routing attributes to associate an action with its route directly on the action’s definition, without writing anything on the RouteConfig.cs. In order to be able to take advantage of this feature we need to enable it from he RouteConfig.cs (before any other rule). This can be done using the MapMvcAttributeRoutes() method in this way:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.MapMvcAttributeRoutes();
 
    routes.MapRoute(
        name: "TestGetObjectWithParameters",
        url: "test/getTestObjectWithParameter/{parameter}",
        defaults: new { controller = "Test", action = "GetTestObjectWithParameter", parameter = @"\d+" }
    );
 
    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

After enabled this feature we can easily assign a custom route to an action:

[Route("test/getTestObjectWithParameters/{parameter1}/{parameter2}")]
public ActionResult GetTestObjectWithParameters(int parameter1, int parameter2)
{
    return Json(new
    {
        Name = "Test",
        Value = "TestValue",
        Parameter1 = parameter1,
        Parameter2 = parameter2
    }, JsonRequestBehavior.AllowGet);
}

With attributes is possible to specify many behaviors, not just at action-level, but a controller-level as well. For example we can specify the route prefix for any action of the controller or the default action name. At action-level we can define if a parameter is optional (using “?”) or other constraints like the value type. See the documentation for a complete list of options.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s