ASP.NET MVC 6 attribute routing – the [controller] and [action] tokens

When working with attribute routing in Web API 2 or MVC 5 it was relatively easy to get the route to the controller and the controller name out of sync. That was because the route always had to be specified as a string, so whenever you changed the name of the controller you would always have to change the string in the route attribute too.

That could be easily forgotten – especially if you use refactoring tools of Visual Studio or an external refactoring plugin.

This issue has been addressed in MVC6 with a tiny addition – the introduction of [controller] ad [action] tokens into attribute routing.

The problem

In a typical Web API project (actually, MVC as well), you might have a controller like this:

If, for whatever reason, you were working with Remote Procedure Calling instead of RESTful controllers, you might have something like this:

In either case, the relationship between the controller and its route, and the action and its route, were non-existant – purely relying on the fact that you maintain them by hand. (note, if you read my Web API book you might be aware of a workaround).

The solution in MVC6

By using the new [controller] token in your attribute routes you can ensure that the controller name in the route, is kept in sync with the name of the controller class. In the example below, [controller] will always be expanded to the name of the controller regardless of any future refactorings – in this case it will be Hello.

The same principle applies to an [action] token – which is going to be expanded to the name of the action. This is obviously relevant for RPC-types APIs only.

For example the setup below will match the URL such as /api/hello/GetHello/1 and so on.

How does it work under the hood?

ASP.NET MVC will use a class called AttributeRouteModel and its public static method ReplaceTokens to replace the tokens with the values from route defaults.

Since the controller and action names are guaranteed to be in the route dictionary defaults, the tokens are certain to be expanded correctly. This process happens only once – at application startup, for all routes, from within the ControllerActionDescriptorBuilder class and its Build method.

If you go a step earlier in the MVC setup process, the builder itself is called from within ControllerActionDescriptorProvider which is an IActionDescriptorProvider. The purpose of the provider is to provide a set of action descriptors which represent all callable HTTP endpoints of your application. The provider technically can be customized/replaced – however, this shouldn’t be done. As Yishai from the MVC team pointed out, they actually recommend using the ApplicationModel to customize the ActionDescriptors instead.

Be Sociable, Share!

  • Pingback: Dew Drop – January 7, 2015 (#1928) | Morning Dew()

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1773()

  • http://www.Marisic.Net/ dotnetchris

    That attribute inside of the string is pretty awesome. Also the RpcRouteAttribute is a great solution. There’s nothing wrong with RPC, in fact modeling RPC as REST is one of the biggest antipatterns as possible. Most obvious RPC example is executing a workflow step, there is inherently no resource.

  • Matt Honeycutt

    I really like this change. Having to keep magic strings and action names in sync seemed really pointless in a statically typed language like C#…

  • TomasJansson

    Good thing they added this option. At the same time this could break a lot of clients when renaming an action but forgot that the route is also changed which the clients rely on.

  • Pingback: Interessante Links – week 06 2015 - Ansem's Blog()

  • Matthew Abbott

    Does this pick out any route value, or just specifically controller and action?

  • Tien Tran

    In MVC 5, attribute routing used {controller}, {action} placeholder. So, why MVC 6 has tokens, I still don’t know that. Can you help me explain?

  • Gintoki Gin-chan Sakata

    how is this different from the Controller/Action/Id routes in mvc5?