Web Api always accept POST verb on controller methods - asp.net

With an action name routing such as:
config.Routes.MapHttpRoute(
name: "ByActionName",
routeTemplate: "api/{controller}/{action}");
I want that all my controller methods accept the POST verb, is there a way to configure the route map so that I don't need to put a HttpPost attribute to all controller methods?
I was hoping to do something like:
config.Routes.MapHttpRoute(
name: "ByActionName",
verb: "POST"
routeTemplate: "api/{controller}/{action}");
Instead of:
public class MyController: ApiController
{
[HttpPost]
public List<int> GetItems() { ... }
[HttpPost]
public void DeleteItem(int id) { ... }
[HttpPost]
public void OtherMethod() { ... }
}

If the method name begins with a verb such as Get,Delete, etc the default verb will match that. If the beginning of the method name doesn't match any verb, webapi defaults to HttpPost. So you can avoid putting [HttpPost] attributes by renaming your controller methods.
See: Is there a default verb applied to a Web API ApiController method?

Related

Default route when using ASP.NET MVC attribute routing

I'm using attribute routing with Web API, and everything works as expected if I request the URL /myapi/list with the following controller:
[RoutePrefix("myapi")]
public class MyController : ApiController
{
[HttpGet]
[Route("list")]
public async Task<string> Get()
{
// Return result
}
}
However, I would like my Get() method to be the default, i.e. when requesting the URL /myapi (without the /list part).
But if I remove the "list" part of the Route attribute like so...
[RoutePrefix("myapi")]
public class MyController : ApiController
{
[HttpGet]
[Route] // Default route
public async Task<string> Get()
{
// Return result
}
}
...I get a 403.14 error saying
"The Web server is configured to not list the contents of this
directory."
Any ideas of what might be causing this?
Thanks!
Edit: If I request the API controller using the default route pattern like /api/myapi, it maps to the Get() method as expected.
Default route is registered after the attribute routes:
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Use
[Route("")]
for the default route
[RoutePrefix("myapi")]
public class MyController : ApiController
{
//GET myapi
[HttpGet]
[Route("")] // Default route
public async Task<string> Get() { ... }
}
Reference: Attribute Routing in ASP.NET Web API 2 : Route Prefixes
As pointed out by haim770 in the comments: the problem was that I had a physical folder with the same name as the route prefix.
Renaming either the folder or the route prefix solved the problem.
I guess an alternative would have been to tweak the route/handler order to ensure attribute routes take precedence over physical paths.

Route all Web API requests to one controller method

Is it possible to customize ASP.NET Web API's routing mechanism to route all requests to the API to one controller method?
If a request comes in to
www.mysite.com/api/products/
or
www.mysite.com/api/otherResource/7
All would be routed to my SuperDuperController's Get() method?
I ran into a case where I needed to do this. (Web API 2)
I first looked into creating custom IHttpControllerSelector and IHttpActionSelectors. However, that was a bit of a murky way around. So I finally settled on this dead simple implementation. All you have to do is setup a wildcard route. Example:
public class SuperDuperController : ApiController
{
[Route("api/{*url}")]
public HttpResponseMessage Get()
{
// url information
Request.RequestUri
// route values, including "url"
Request.GetRouteData().Values
}
}
Any GET request that starts with "api/" will get routed to the above method. That includes the above mentioned URLs in your question. You will have to dig out information from the Request or context objects yourself since this circumvents automatic route value and model parsing.
The good thing about this is you can still use other controllers as well (as long as their routes don't start with "api/").
I don't konw why you would want to do this and I certainly wouldn't recommend routing everything through one controller, however you could achieve this as follows. Assuming you are only ever going to have a resource with an optional id in your calls, add this to your WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{resource}/{id}",
defaults: new { controller = "SuperDuper", id = RouteParameter.Optional }
);
}
}
Then define your controller method as follows:
public class SuperDuperController : ApiController
{
public IHttpActionResult Get(string resource, int? id = null)
{
return Ok();
}
}
You would need to decide on an appropriate IHttpActionResult to return for each different type of resource.
Alternatively using Attribute Routing, ensure that config.MapHttpAttributeRoutes() is present in your WebApiConfig and add the following attributes to your controller method:
[RoutePrefix("api")]
public class SuperDuperController : ApiController
{
[Route("{resource}/{id?}")]
public IHttpActionResult Get(string resource, int? id = null)
{
return Ok();
}
}

Asp.net web api routing to be like mvc site

How can I add a route so that my controllers will work similar to a mvc web appliation.
Because the default way that they have configured the routes will end up with you having so many controllers.
I just want to have a controller called Auth,
and then in my web API be able to call api/auth/login or api/auth/logout etc.
Because with the default routing I will have to create a controller for login and one for logout.
So then I would have my Controller like so:
public class AuthController : ApiController
{
[HttpPost]
public IEnumerable<string> Login()
{
return new string[] { "value1", "value2" };
}
[HttpGet]
public HttpMessageHandler Logout()
{
return new HttpMessageHandler.
}
}
The default Web API route uses the http method to determine the action to select. For example POST api/auth would look for an action named Post on AuthController.
If you want to use RPC style routing (like MVC) you need to change the default route to:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Now POST api/auth/login will look for an action named Login on AuthController.

Routing in ASP .NET Web API

I created a web service using WEB API.
I'm using this routing configuration
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
And my solution include two controller (ProductController and DetailController)
So when I want to call a WS that refers to the GetDetails method(is located inside DetailController) I have to use a URL like this:
http://localhost/api/Details/GetDetails/?id=4
Is there a way for use, for the same request, this URL instead:
http://localhost/api/Product/GetDetails/?id=4
letting the GetDetails method inside the DetailController?
Actually your urls should be:
http://localhost/api/Details/4
http://localhost/api/Products/4
and your controllers:
public class DetailsController: ApiController
{
public HttpResponseMessage Get(int id)
{
...
}
}
and:
public class ProductsController: ApiController
{
public HttpResponseMessage Get(int id)
{
...
}
}
Now that's RESTful.

The web API controller action name can not be determined by the type of the request

Doing a REST styled API I would like to know how I deal with duplicate action names:
public SchoolyearBrowseResponse Get(int userId)
{
return _service.GetSchoolyears(userId);
}
public SchoolyearOpenResponse Get(int id)
{
return _service.OpenSchoolyear(id);
}
It is said that the action`s name should be the request type. Now I have TWO Get methods with an int parameter which is not possible in C#.
Should I name the 2nd Get: Open(int id) ?
Doing a REST styled API I would like to know how I deal with duplicate action names
In a RESTful styled API you should never have to deal with such duplicates. In a RESTful styled API you are dealing with resources.
So in your particular case you have 2 resources:
a user
a school year
So you would have the following routes:
/users/{userId}/schoolyears -> which corresponds to your first action
/shoolyears/{id} -> which corresponds to your second action
So:
public class UsersController : ApiController
{
public SchoolyearBrowseResponse GetSchoolYears(int userId)
{
return _service.GetSchoolyears(userId);
}
}
and:
public class SchoolYearsController : ApiController
{
public SchoolyearOpenResponse Get(int id)
{
return _service.OpenSchoolyear(id);
}
}
and the final step is your routes:
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "UserSchoolYears",
routeTemplate: "api/{controller}/{userId}/schoolyears",
defaults: new { controller = "Users", action = "GetSchoolYears" }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
As a side note I would like to mention that a school year for a user (your SchoolyearBrowseResponse) class hardly makes sense. Normally for a given user you have a list of school years. And if you wanted to get a specific school year for a user you would use /users/{userId}/schoolyears/{schoolyearid}.
a typical solution would be naming then in the following order :)
_service.OpenSchoolyearByYear(id);
_service.OpenSchoolyearByUserId(id);

Resources