I have two action methods in my Products controller. This is my RouteConfig.
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
These are the two actions and their working urls.
[HttpGet]
//uri:http://localhost:49964/api/products/product?strKey=1
public IHttpActionResult Product(string strKey)
[HttpPost]
//uri:http://localhost:49964/api/products/product
public IHttpActionResult Product([FromBody] Product product)
But I also want to use the below url for GET.
http://localhost:49964/api/products/product/1
But web api responds with,
The requested resource does not support http method 'GET'.
Change strKey to id or do the reverse if you want to keep strKey.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{strKey}",
defaults: new { strKey = RouteParameter.Optional }
);
The route template needs to match up to the action for mapping to work as intended.
//GET api/products/product/1
//GET api/products/product?strKey=1
[HttpGet]
public IHttpActionResult Product(string strKey)
this would however mean that all actions in this route would optionally use strKey as a placeholder
Related
I have created a asp.net web.api. I have one controller named Books which has 2 methods that look like this..
public IHttpActionResult Read(string pass, string Id)
public IHttpActionResult Update(string pass, string Id)
How do I add routes for both methods in my webApiConfig file?
Right now I only have this that work on Read method.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{pass}/{Id}",
defaults: new { transationId = RouteParameter.Optional }
);
This one I can access like this..
Api/Books/xxxxpasscodexxx/1
How would the route for the update method look like?
Change your routing to
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{pass}/{Id}",
defaults: new { transationId = RouteParameter.Optional }
);
you can use the current default route for update also.web api will provide [FromUri] attribute for reading action parameters from URI of Httprequestmessage .
[HttpPut]
public IHttpActionResult Update([FromUri]string pass, [FromUri]string Id)
{
//do your stuff here and return
}
your request should be Api/Books?password=xxxx&string=abc
Add Attribute
[HttpGet]
public IHttpActionResult Read(string pass,int id)
[HttpGet]
public IHttpActionResult Update(string pass,int id)
Add the routing in webapiconfig
config.Routes.MapHttpRoute(
name: "DefaultActionApi",
routeTemplate: "api/{controller}/{action}/{pass}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Note: this must be above the existing route, otherwise it will take precedence.
Please take a look here. You can mark your Controller as APIController, specify the general route and then define the http verb and method path with the Route parameter. This will overwrite your Routes.MapHttpRoute definition.
I've got a simple web API that registers on one route. At the moment I've got two because only one of them does what I need.
My application only has one controller and one Post method in that Controller. I've registered a single Route which always returns a 405 (method not allowed)
The two routes are configured in the RouteConfig.cs:
routes.MapHttpRoute(
name: "app-events",
routeTemplate: "events",
defaults: new { controller = "Events" },
handler: new GZipToJsonHandler(GlobalConfiguration.Configuration),
constraints: null
);
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
The Controller method is essentially this...
public class EventsController : ApiController
{
public EventsController()
{
_sender = new EventHubSender();
}
public async Task<HttpResponseMessage> Post(HttpRequestMessage requestMessage)
{
// doing fun stuff here…
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
If I only configure the first route and post a request to http://devbox/events I will get a 405. However, if I add the second, default, route, and post to http://devbox/api/events I get back my expected 201.
With both routes configured at the same time, the same pattern, the route explicitly bound to the Controller receives a post request and fails with a 405, but the other URL will work.
I've spent a long time looking around before conceding to ask the question. Most things I read have a lot to do with Webdav and I think I've followed every one of them to fix the issue. I am not very experienced with this stack, so nothing is very obvious to me.
You mentioned RouteConfig File. This is used for configuring the MVC routes not Web API routes.
So it would appear you are configuring the wrong file which would explain why the api/... path works as it is probably mapping to the default configuration in WebApiConfig.Register, which would look like
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
You would need to update that file with the other desired route
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "app-events",
routeTemplate: "events",
defaults: new { controller = "Events" },
handler: new GZipToJsonHandler(GlobalConfiguration.Configuration),
constraints: null
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Web API routes are usually registered before MVC routes which explains why it was not working with your original configuration.
You should also adorn the action with the respective Http{Verb} attribute.
In this case HttpPost so that the route table knows how to handle POST requests that match the route template.
[HttpPost]
public async Task<IHttpActionResult> Post() {
var requestMessage = this.Request;
// async doing fun stuff here….
return OK();
}
Hi Guys i am new with web api routes and i have this issue where my call will pick up the more generic one over the specific one.
The ajax call i have is
$.getJSON("/api/solutions/GetSolutionByCategory/" + categoryId,
function (data) {//..some other functions}
Within the solutions controller there are 2 methods
[HttpGet]
public IHttpActionResult GetSolutionByCategory(int cateogryId)
{
List<Solution> solutions = _context.Solutions.Where(s => s.CategoryId == cateogryId).ToList();
return Ok(solutions.Select(Mapper.Map<Solution, SolutionDto>));
}
[HttpGet]
public IHttpActionResult GetSolutions()
{
return Ok(_context.Solutions.ToList().Select(Mapper.Map<Solution, SolutionDto>));
}
And then i have the following 3 routes
config.Routes.MapHttpRoute(
name: "WithAction",
routeTemplate: "api/{controller}/GetIssuesByFlag/{flag}",
defaults: new {flag = 3}
);
config.Routes.MapHttpRoute(
name: "SolutionByCategory",
routeTemplate: "api/{controller}/GetSolutionByCategory/{categoryId}",
defaults: new {categoryId = -1}
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new {id = RouteParameter.Optional}
);
What happens is that my ajax call will ignore the 2nd one that is the one i want it to hit and goes to the 3rd one there for instead of calling the GetSolutionsByCategory it hits the generic GetSolutions
What am i doing wrong here?
There is a typo in your action parameter name, its int cateogryId instead of int categoryId - public IHttpActionResult GetSolutionByCategory(int categoryId).
However, I would suggest you to go for attribute routing instead of adding lots of route configurations. Enable attribute routing in your web api config class - config.MapHttpAttributeRoutes(); and in your controller:
[RoutePrefix("api")]
public class SolutionsController:ApiController
{
[HttpGet]
[Route("GetSolutionByCategory/{categoryId})"]
public IHttpActionResult GetSolutionByCategory(int categoryId)
{
....
}
[HttpGet]
[Route("GetSolutions")]
public IHttpActionResult GetSolutions()
{
...
}
}
Using Attribute routing we can have same controller with multiple get and post methods. We need to add the routing on the action methods.
We can provide the constraints as well with attribute routing.
Situation :
I've created controller class that extends ApiController and includes following methods :
// GET api/Posts/5
[ResponseType(typeof(Post))]
public IHttpActionResult GetPost(int id)
{
...
}
// GET api/Posts/ByBoardID/2
[HttpGet]
[ActionName("ByBoardID")]
public IQueryable<Post> GetByBoardID(int boardID)
{
...
}
The idea is to match those method to a given routes (i.e 'api/Posts/ByBoardID/2' to a GetByBoardID(int boardID) method and 'api/Posts/2' to a GetPosts(int id) method).
Here's route config :
config.Routes.MapHttpRoute(
name: "ByParamApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
Problem :
Second route ('api/Posts/ByBoardID/2') cannot be matched - No HTTP resource was found that matches the request URI.
Question :
Whats the best practice to create such 'nested' routes inside controller? I will use many controllers with the same pattern (/{controller}/{id} and /{controller}/bySpecialParam/{id}) so I don't want to 'hardcode' such route that won't be reusable.
Only way I ever got working such combination is by changing this
[ActionName("ByBoardID")]
to
[Route("api/Posts/ByBoardID/{boardID}")]
Never able to figure out how the ActionName attribute works so always preferred to go with Route attribute
This worked:
1) Provide actionName for both the methods in the controller.
[ActionName("DefaultAction")]
[ActionName("ByBoardID")]
2) In the webapiconfig class, add the following routes
config.Routes.MapHttpRoute(
"defaultActionRoute",
"{controller}/{action}/{id}",
null,
new
{
action = "ByBoardId"
});
config.Routes.MapHttpRoute(
"defaultRoute",
"{controller}/{id}",
new
{
action = "DefaultAction"
});
Make sure you have the GlobalConfiguration.Configuration.EnsureInitialized(); at the end of Application_Start() method.
I have the following example where the request is http://{domain}/api/foo/{username} but I get a 404 status code back. No other Get actions exist on this controller. Shouldn't this work?
public class FooController : ApiController
{
public Foo Get(string username)
{
return _service.Get<Foo>(username);
}
}
By default your route will look something like this:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
When you visit the url http://{domain}/api/foo/{username} the controller is mapped as foo and the optional id parameter is mapped to {username}. As you don't have a Get action method with a parameter called id a 404 is returned.
To fix this you can either call the API method by changing the URL to be explicit about the parameter name:
http://{domain}/api/foo?username={username}
Or you could change your parameter name in your action method:
public Foo Get(string id)
{
var foo = _service.Get<Foo>(username);
return foo;
}
Or you could change your route to accept a username:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{username}",
defaults: new { username = RouteParameter.Optional }
);