-->

Attribute vs Conventional Routing

2019-02-27 22:15发布

问题:

Q1: So this article says attribute routing is more favourable than conventional routing for api versioning. It's not clear to me the reasons behind such claim because to me in order to support these:

/api/v1/products
/api/v2/products

all you need to do is to define two routes:

routes.MapHttpRoute("V1", "api/v1/products",    new {controller = "V1Controller", action = "ListProducts"});
routes.MapHttpRoute("V2", "api/v2/products",    new {controller = "V2Controller", action = "ListProducts"});

Can something share some insight?

Q2: this article says one issue with conventional routing is the order of the entries in the table and that you can accidentally have requests being mapped to the wrong controller. Why is this not an issue with attribute routing? I mean the template is just a string so how can it prevent me from defining two routes where one is more generic than the other?

Q3: Can any give a concret example where you can accomplish with attribute routing but can't with the conventional routing? - I am not talking about code readability and maintainability.

回答1:

Q1

The document specifically states "makes it easy" for API versioning, not "makes it easier" or "is preferred".

I don't agree that convention-based routes are necessarily "hard to support" (provided you understand how routing works). But if you are not using a convention that is shared across multiple controllers in your project, it is far less code to maintain if you use attribute routing. Namely, you don't have to specify the controller and action to use on every route in the code since the RouteAttribute knows the action/controller it is paired with natively.

But as the document points out, putting all of your routes in one place does also have its merits. If your API is such that you can use conventions that apply to multiple/all controllers, then setting a single convention is easier to maintain than multiple route attributes.

For those conventions that might be "hard to support" with the built-in MapRoute method, you can extend convention-based routing as necessary using your own extension methods and even inherit the RouteBase class to define them however you like.

Q2

Ordering is an issue with attribute routing. In fact, attribute routing makes it more difficult to see what order your routes are registered in. Not all routes are order-sensitive, so it is not an issue much of the time.

However, when you do have an ordering problem with attribute routing, it is much more subtle than when using convention-based routing. Attributes do not guarantee any order when Reflection retrieves them. Therefore, the default ordering is unknown regardless of what order you have specified them on your controller actions.

Fixing ordering on attribute routing can be easy. Simply specify the Order property of the attribute (lower values are evaluated before higher values).

That said, there is no way to specify order between different controllers, so it could end up biting you. If that happens, the only built-in alternative is convention-based routing.

Q3

I can't give a concrete example of where you can use attribute routing where you can't use convention-based routing (and AFAIK, there isn't one). An example of using convention-based routing in a way that is not supported by attribute routing is to make data-driven CMS routes.

Attribute routing supports a subset of the functionality that convention-based routing supports. It is not more advanced technologically than convention-based routing. Convention-based routing gives you the ability to directly specify your own RouteBase (or Route) subclass, which allows you to do many things that you cannot do with the built-in attribute routing, such as make routes that are based on subdomains, query string values, form post values, or cookies. You can even make extension methods that generate routes based on conventions in advanced scenarios.

Attribute routing cannot be extended this way without resorting to Reflection because many of the types it uses are marked internal.

But there are 3 compelling reasons you might consider using attribute routing instead of convention-based routing, depending on your project:

  1. It puts the routes in the context with the rest of the controller code, which might make it easier to maintain.
  2. It means you don't need to type (or copy and paste) controller and action names into each of your route definitions. Maintaining this relationship (and working out when it is wrong) between routes and your controllers might cost more than what it is worth to have all of your routes defined in one place in terms of maintainability.
  3. Attribute routing is easier to learn than convention-based routing. If your deadline is tight and/or your team is inexperienced with routing it could be a better choice to use attribute routing because the learning curve is shorter.

The thing to take away from this is: Use the type of routing that will be easiest to maintain in your project. If you have lots of similar patterns, use convention-based routing. If your URLs are inconsistent or irregular across the project or you simply like to see your URLs in the same context as your action methods when you work, consider attribute routing, but keep in mind that convention-based routing is another option.

NOTE: Most of the examples I have linked to are for MVC, not Web API. Routing is very similar (in fact, most of the code classes are shared) between the two frameworks. The same concepts can be used in both MVC and Web API as far as attribute/convention-based routing goes, but do be aware that you need to target the System.Web.Http namespace rather than the System.Web.Mvc namespace if you are using Web API and you want to take advantage of those examples.