Controller without the controller suffix - asp.net-web-api

based on my design requirements, I will like to exclude the suffix 'Controller' from my controllers and replace it with 'Resource'. So that 'FundsController' will become 'FundsResource'.
The problem is that I am not able to route to my specified actions by either convention based or attribute routing when I change replace the term 'Controller' and get an error saying that the controller with this name could not be found.
How can I satisfy the above mentioned design requirement and also be able to route without a problem? Either in Convention based or Attribute routing? Or whether if we can merge the benefits of convention based and attribute routing to achieve this?
Thanks in advance.

"Controller" is hard-coded into the framework but you can you can create a new controller type resolver. Here is an excellent article from Filip - http://www.strathweb.com/2013/02/but-i-dont-want-to-call-web-api-controllers-controller/.

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.

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.

Attribute Routing vs Convention

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.

Named restful routes in Laravel 4

So, I've been able to get restful controllers working with
Route::controller('users','UserController');
class UserController extends BaseController {
public function getAccount(){}
}
and so /users/account works. However if I try to do something like
Route::any('account',array('as' => 'account','uses' => 'UserController#account'));
and go to /account, it doesn't work (NotFoundHTTPException). Is there a way to use named routes and restful controllers in conjunction? I like how the restful system breaks up requests, and how named routes encapsulate the URI's and decouple them from the function names. This worked in Laravel 3. Am I missing something in the syntax, or did Laravel 4 purposefully disallow this kind of mix-and-match behavior? Thanks...
This would depend entirely on the order you have defined the routes. If it's not working try reversing the order of the definitions.
But because Laravel is all about making your life easier you can pass an array of method names and their corresponding route name as the third parameter to Route::controller.
Route::controller('users', 'UsersController', ['getProfile' => 'user.profile']);
This might not directly apply to your situation but it is super handy.
Try this:
Route::get('/',array('as'=>'named_route','uses'=>'yourRestfulController#getMethod'));
This works nice for me. The trick was adding the action type after # part. You should use the full name of the method unlike in L3.
This works nice for me. The trick was adding the action type after # part. You should use the full name of the method unlike in L3.
Because REST prefix get, post, and so on are patterns to distinguish what type of REST it implements. When you named restful controllers route they didn't act like RESTful controllers anymore but a normal Controller you wish to named. Example of this:
Route::get('user/profile/', array('as'=>'dashboard', 'uses'=>'ProfileController#showDashboard'));
Consider this one:
Assuming we want SystemController to be a RESTful controller so you'll define:
Route::controller('/', 'SystemController');
Then you want to named the postDashboard on the SystemController as dashboard, so you'll modified your routes as:
Route::get('user/profile/', array('as'=>'dashboard','uses'=>'SystemController#postDashboard'));
Route::controller('/', 'SystemController');
On that scenario,postDashboard should not be access via GET protocol since we declared it to bePOST, that is if Laravel treated it as RESTful Controller, since we named it that way it will be treated as normal not RESTful, so we can access it tru GET protocol. Naming it that way will be so dramatically not appropriate, coz we are breaking what we want first which is telling Laravel to treat SystemController as a RESTful.
I think you have to consider the post of Jason Lewis as the appropriate answer. No hard feelings #arda, since you are also correct.

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