I am working on an existing Web API in which I need to make all actions HttpPost based. For achieving this I am using configuration like this.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{action}",
defaults: new { id = RouteParameter.Optional },
constraints: new { httpMethod= new HttpMethodConstraint(HttpMethod.Post) }
);
But this is not working on actions having name strating with "Get". But It is working fine when I am decorating action with [HttpPost] atrribute like this
[HttpPost]
public IHttpActionResult GetUserByName()
There are many actions like this and I want to avoid decorating each Action with [HttpPost] atrribute. Is there any way to set [HttpPost] atrribute globally?
Related
Should I follow WebApi route convention?
I want to change my default route config (api/{controller}/{id}) to api/{controller}/{action}/{id}
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Is it ok to add {action} placeholder to my route?
What is the pros/cons of default WebApi route?
Yes, you can have action names in your routes and use them.
First, you have to add the following to your WebApiConfig.cs
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Be sure to add this before the default route or else it will not work.
Then add ActionName attribute in your controller methods
public class ProductsController : ApiController
{
[HttpGet]
[ActionName("Thumbnail")]
public HttpResponseMessage GetThumbnailImage(int id);
}
Then your route will be /api/Products/Thumbnail
For more info check the Routing by Action Name from here
Be sure to marks as answer if this helped you :)
By using Custom Action Names, you can move beyond the HTTP verbs in your controllers and have customized methods available in the API
I work on my web api project.
I have two get action methods in controller.
Here the controller:
namespace Playground.Web.Controllers.API
{
[RoutePrefix("api/DamageEvent/{actionType}")]
public class DamageEventController : ApiController
{
#region API methods
[HttpGet]
public async Task<IHttpActionResult> GetDamageEvent(int damageEventId = 0)
{
//some logic
}
[HttpGet]
[Route("{ddd:int}")]
public async Task<IHttpActionResult> GetDamageEvent2(int ddd = 0)
{
//some logic
}
#endregion
}
}
Here WebApiConfig defenition:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.JsonFormatter.SerializerSettings.DateFormatString = "dd/MM/yyyy";
}
}
Here the example of URL in fiddler compose to trigger web api action:
http://localhost/playground/api/DamageEvent/GetDamageEvent2/?ddd=22
I expect that for the URL above the GetDamageEvent2 web api action will be fired. But instead GetDamageEvent action method is fired.
Why GetDamageEvent2 not fired? Any idea what do I am missing?
==============================Update================================
After I red answer from Nkosi
I made some changes to my code, I added to class WebApiConfig new route:
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
And here the changes in action type:
namespace Playground.Web.Controllers.API
{
[RoutePrefix("api/DamageEvent")]
public class DamageEventController : ApiController
{
#region API methods
[HttpGet]
[Route("GetDamageEvent/{damageEventId}")]
public async Task<IHttpActionResult> GetDamageEvent(int damageEventId = 0)
{
//some logic
}
[HttpGet]
[Route("GetDamageEvent2/{ddd}")]
public async Task<IHttpActionResult> GetDamageEvent2(int ddd = 0)
{
//some logic
}
#endregion
}
}
After I make the changes above the I tryed to fire the both actions and it worked.
But the problem now is when I try to call another actions in another controllers, For example:
http://localhost/playground/api/Contracts/1
I get 404 error.
So I guess the error occures because of the new route template.
So my question how can I fix the error above and to take the new route template into consideration only when the URI try to access to DamageEventController?
You are mixing attribute routing and convention based routing.
Nothing matches your RoutePrefix because there are no actions in the controller that has both a {actionType} and {ddd} templates.
But your stated URL...
api/DamageEvent/GetDamageEvent2/?ddd=22
...matches the DefaultApi convention based route for GetDamageEvent in the route table because it does not have a [RouteAttribute] and it defaults back the convention where...
api/{controller=DamageEvent}/{id=GetDamageEvent2/?ddd=22}
Take a look at Routing in ASP.NET Web API to understand the convention based routing.
and also Attribute Routing in ASP.NET Web API 2
Each entry in the routing table contains a route template. The default
route template for Web API is "api/{controller}/{id}". In this
template, "api" is a literal path segment, and {controller} and {id}
are placeholder variables.
When the Web API framework receives an HTTP request, it tries to match
the URI against one of the route templates in the routing table. If no
route matches, the client receives a 404 error. For example, the
following URIs match the default route:
/api/DamageEvent
/api/DamageEvent/1
/api/DamageEvent/GetDamageEvent2/?ddd=22
Once a matching route is found, Web API selects the controller and the
action:
To find the controller, Web API adds "Controller" to the value of the {controller} variable.
To find the action, Web API looks at the HTTP method, and then looks for an action whose name begins with that HTTP method name. For
example, with a GET request, Web API looks for an action that starts
with "Get...", such as "GetDamageEvent". This
convention applies only to GET, POST, PUT, and DELETE methods. You can
enable other HTTP methods by using attributes on your controller.
We’ll see an example of that later.
Other placeholder variables in the route template, such as {id}, are mapped to action parameters.
To get your stated route to work you need to update your route templates. Either the attribute route or add a new convention route to the route table
I am working on Web Api. By default, it uses the api/{controller}/{id} as a url. I am able to have it to route api/device/{controller}/{id} but this will affect to all Web API route to that path.
But I only want certain controller to be in api/device/{controller}/{id} and the rest will go to another path.
I saw something like RoutePrefix but it doesn't seem to work...
[RoutePrefix (api/data/abc)] where abc is the controller name.
Add the custom route mapping in WebApiConfig.cs file before default route map:
By adding this before, any requests which matches the custom route will be executed, else the other one.
config.Routes.MapHttpRoute(
name: "CustomRoute",
routeTemplate: "api/device/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
If you want to customize the routing with a per controller approach, then you have to use Attribute Routing instead of the standard convention-based routing.
Decorate your controllers with RoutePrefix attribute, and your actions with Route attribute in this way:
[RoutePrefix("api/device/mydevice")]
public class MyDeviceController : ApiController {
[Route("{id}")]
[HttpGet]
public IHttpActionResult Get(int id) {
//DoWork
//...
}
}
And remember to enable attribute routing on the HttpConfiguration object:
config.MapHttpAttributeRoutes();
You may also remove MapHttpRoute method calls if you do not want to allow access to your actions in the standard convention-based way.
More on attribute routing on the official documentation.
I am trying to create a WebAPI controller with multiple Get commands using the ActionName method. I successfully did this on another project, but have been having problems with this latest project and cannot see to understand why my knockout view model ajax call cannot find the specific URI.
WebApiConfig.cs:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Controller:
// GET api/lot
[ActionName("Default")]
public IEnumerable<DataObject> Get()
{
//...
}
// GET api/lot/Specific/5
[ActionName("Specific")]
public IEnumerable<DataObject> Get(int? data)
{
//...
}
// GET api/lot/5
public string Get(int id)
{
return "value";
}
My default action for GET works perfect but the Specific action continues to have this error when I attempt to call it from the view-model:
"Failed to load resource: the server responded with a status of 404 (Not Found)"
I added [HttpGet] next to the [ActionName("Specific")] and had the following error:
"GET http://localhost:57492/api/lot/Specific/1 404 (Not Found)"
I've tried several different things such as removing the int? data argument, but then when I attempt to build the project it tells me an existing function with same arguments already exists, even with different action names.
Ultimately I would like to have multiple Get(parameter) actions to call for interacting with my view-model.
I was able to solve this by adding the Route property with HttpGet and renaming all of my functions to unique names like GetAll(), GetSpecific(ind id), etc..
// GET api/lot
[HttpGet]
[Route("api/lot/GetAll")]
public IEnumerable<DataObject> GetAll()
{...}
// GET api/lot/GetSpecific/{id}
[HttpGet]
[Route("api/lot/GetSpecific/{id}")]
public IEnumerable<DataObject> GetSpecific(string id)
{
Adding a new route in config.Routes as below. Will this help? I didn't test this.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/specific/{data}",
defaults: new {
action = "Specific",
data = RouteParameter.Optional }
);
I'm trying to call a webapi hosted within the same project as an umbraco website.
I'm using the default webapi routing and calling it in on application start:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
...and set up a controller in an api folder under the controllers folder:
public class ServiceContactFormController : UmbracoApiController
{
[HttpGet]
public HttpResponseMessage Get()
{
return Request.CreateResponse(HttpStatusCode.Accepted);
}
}
When I call the webapi using http://localhost:[port]/api/ServiceContactForm I receive a 404.
Are there any additional steps required specifically for Umbraco?
Regards
Never mind - for anyone else out there, Umbraco kindly take over the routing and add 'umbraco' to the route, plus you need the action due to the default get, post, etc methods not being recognised...more info here https://our.umbraco.org/forum/developers/api-questions/39075-Web-API-routing-not-working.
Working example was:
http://localhost:[port]/umbraco/api/ServiceContactForm/get