Attribute Routing vs Convention - asp.net-web-api

Playing around with the Web.API 2.0 stuff- in particular Attribute Routing. The docs state that you can have attribute routing AND the 1.0 routing by convention... but these two don't seem to play that well together. For example, given these two methods:
public override HttpResponseMessage PutModel(SampleForm form)
[HttpPut("approvesampleform/{form}")]
public string ApproveSampleForm([FromBody]SampleForm form)
While I can call http://localhost/api/sampleform/approvesampleform just fine, a PUT to http://localhost/api/sampleform/ generates a Multiple actions were found that match the request error.
Is there any way that if a method is marked with the attribute routing it is ignored by the convention? This would be ideal... but I don't see any way to accomplish this in the docs.
Note: I don't see a asp.net-web-api-2 tag. Perhaps someone with more than 1500 rep can create it?

Right, RC (Release Candidate) did not have the logic where conventional routes cannot access attributed controller/actions. This change came post-RC. The scenario you are trying would work fine in post-RC bits.
Probably the docs you mentioned aren't very clear, but I think they mean that you could have attributed and convention based controllers work side-by-side and not particularly about mixing both attributed and conventional semantics in the same controller.
For time being you could probably use only attribute routing for your controller mentioned above.

Related

Attribute vs Conventional Routing

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.
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:
It puts the routes in the context with the rest of the controller code, which might make it easier to maintain.
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.
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.

Implementing Front Controller pattern

I've been trying to implement a Front Controller on a VBScript (ASP Classic) based system for a couple of days. I come from a ASP.NET MVC and Java background, where MVC implementations are kind common and mostly done by existing frameworks. On VBScript, however, there's almost nothing done in this area, so it is the reason why I'm trying to do it by myself. I used this and this article as a guide on how to implement it.
I believed at first that I'd need to define some constant parameters for each request, so I created 3:
class_command 'which command responsible to execute the correct class handler
action 'which method of the class handler to execute
action_params 'which parameters the action will need
Next, I defined a generic controller handler for treating the request:
Public Function Controller_Handler(action_params)
Its task is to extract the constant parameters (class_command, action, action_params) and treat any errors (I'll add later a filter to process it) that might come like absence of the constant parameters or authentication problems.
But soon I realized a problem: how will the handler know which command to call, since the request is a string? I can't simply converting it to class using reflection, because VBScript (I think) doesn't have a reflection library or built-in feature.
So I thought I could create a Switch Case like this:
Select action_Params.Item("action_params")
Case "command_A"
' Call Command A
Case "command_B"
' Call Command_B
.
.
.
Case "Command_X"
' And so on
End Select
But that would kinda procedural way to do it. Next I thought of creating a XML file which would map all the commands and other stuff.
So my question is: is this a good way of implementing a Front Controlller pattern, considering VBScript limitations? If not, could you provide a guidance (hopefully with some example, even a simple one) on how can I do it?
Moving from classic to .net/mvc I can share what I did in classic asp to try to emulate this behavior as closely as possible without making it too much of a maintenance issue.
Using URL Rewrite in IIS are my routes. I usually just make one route and direct/rewrite all inbound requests to one controller.asp page to simplify things and not have a bunch of rules and controller redirects directly in my URL Rewrite settings for maintaining it easier (for me).
Using Request.ServerVariables("HTTP_X-ORIGINAL-URL") in controllers.asp you can grab the actual URL that was entered, which return something like.. /real/url
In controllers.asp programatically call the view based on the entered url using Server.Execute("view1.asp")
I have one class file called routes.asp that is included in each model/class file, and helps me gather the URL properties oRoute.GetPath_FirstDirectory() and so on. The model/class file then uses this data to create its property values that can be consumed by the view. Using CLASS_INITIALIZE in each model/class to populate itself from the route/url, or it could also be done directly in the view.
In the respective view I include my class/model file (if even needed) using <!--#include file="class.asp"--> then simply open Set Model = new cModelClass to initialize and start using it in the view. I don't include the class in the controllers.asp because the view will not inherit any of the variables from controllers.asp when using Server.Execute() to the view. So I include it directly in the view.
Error handling can be at multiple levels here, but ideally its in the controllers.asp. Specific error handling is usually at the actual model/class CLASS_INITIALIZE to avoid redundant use of the class in the controller, since it's already going to be initialized in the view.
Now this is not exactly what goes in in .Net mvc, but it's the best way I've come up with, and easiest to maintain for me. Maybe others have other implementations, but this is mine and solely based on my experience. And so far, it's been working out pretty well.

acceptable MVC parameter usage

would it be considered a valid implementation if I do not use the model for certain parameters? For example a webform posting values directly to the controller which then passes them to another class. Is it necessary to make sure that all the fields in the webform are also referenced/stored in the model?
I consider it a valid implementation, but suggest that you do this only if the parameters you want to exclude from the Model are absolutely NOT going to be used by the View (other than for confirmation of data entry in your webform), AND there is no need for the parameters to be referenced again once handled by the Controller.
Yes, it would work, strictly speaking.
However, you probably want to use the model. You don't want to create a new variable every time you run the view, which would happen if you use the controller.
I would consider it valid implementation if you decided not to use the model for certain parameters. I believe there are instances where certain fields may not relate directly to the model in question therefore giving valid reason to break those fields/parameters off from the model.

ActionMethodSelectorAttribute equivalent in ASP.NET Web API?

Is there a Web API equivalent to the MVC ActionMethodSelectorAttribute?
My specific purpose is this: I have, for example, a ResourceController and when I POST to the controller, I'd like to be able to receive a single resource (Resource) or a list (IEnumerable<Resource>).
I was hoping creating two methods with different parameters would cause the deserialization process to do some evaluation but this doesn't seem to be the case (and frankly, I don't think it's efficiently realistic with the combination of content negotiation and the fact that many data formats, like JSON, make it difficult to infer the data type). So I originally had:
public HttpResponseMessage Post(Resource resource) {...}
public HttpResponseMessage Post(IEnumerable<Resource> resources) {...}
...but this gets the "multiple actions" error. So I investigated how to annotate my methods and came across ActionMethodSelectorAttribute but also discovered this is only for MVC routing and not Web API.
So... without requiring a different path for POSTing multiple resources vs. one (which isn't the end of the world), what would I do to differentiate?
My thoughts along the ActionMethodSelectorAttribute were to require a query parameter specifying multiple, which I suppose is no different than a different path. So, I think I just eliminated my current need to do this, but I would still like to know if there is an equivalent ActionMethodSelectorAttribute for Web API :)
I haven't seen a replacement for that method (there is an IActionMethodSelector interface but it is internal to the DLL). One option (although it seems like it might be overdoing it) is to overload the IHttpActionSelector implementation that is used.
But changing gears slightly, why not always expect an IEnumerable<Resource>? My first guess is that the collection method (that takes IEnumerable<Resource>) would simply loop and call the single value (just Resource) function?

Transforming action name in route declaration

I'm wondering if there is a way to declare routes in MVC3 so that the route "zone1/{controller}/{action}" would direct to {controller}.zone1{action} method and "zone2/{controller}/{action}" would direct to {controller}.zone2{action} method, for example. So that's basically transforming the target action name based on the route.
Thanks
Check out The Attribute Routing project. You can specify on your methods the routes which I feel is a bit easier to read. Here's a decent blurb on it:
http://gregorsuttie.com/2012/01/12/attributerouting-for-mvc/
You could also write your own custom route handler but I don't believe you can do what you want without some custom code. I could be wrong here though. The attribute routing project should work just fine for what you want however.

Resources