REST url - user by id and name - c#

I have two actions:
[HttpGet]
[Route("Users/{id}")]
public async Task<IActionResult>GetUser(int id)
[HttpGet]
[Route("Users")]
public async Task<IActionResult>GetUser(string name)
When I am trying to call /Users?name=aaa I am getting the following error:
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The
request matched multiple endpoints. Matches:
What am I doing wrong?
-----------
I have noticed I have one more action:
[HttpGet]
public async TaskGetOffers()
This was the reason, sorrry

If you want to retrieve data from query string, you need to use FromQueryAttribute
// e.g. Users/10
[HttpGet]
[Route("Users/{id:int}")]
public async Task<IActionResult>GetUser([FromRoute] int id)
// e.g. Users?name=John
[HttpGet]
[Route("Users")]
public async Task<IActionResult>GetUser([FromQuery] string name)

try with the below code
[HttpGet]
[Route("Users/{id}")]
public async Task<IActionResult>GetUser([FromQuery] int id)
[HttpGet]
[Route("Users")]
public async Task<IActionResult>GetUser([FromQuery]string name)

Can you change from
[Route("Users")]
public async Task<IActionResult>GetUser(string name)
To
[Route("Users/{name}")]
public async Task<IActionResult>GetUser(string name)
And also provide type in your route
[Route("Users/{id:int}")]

Related

Handle WebApi Core methods with Id as string and int

I have two methods:
[HttpGet("{id}")]
public IActionResult GetTask([FromRoute] int id)
{
}
[HttpGet("{userId}")]
public IActionResult GetUserTask([FromRoute] string userId)
{
}
As you can see, i want to pass to my API routes like:
https://localhost:44365/Task/1
and
https://localhost:44365/Task/string
But my WebApi project cant handle it. When i pass route like this:
https://localhost:44365/Task/7dd2514618c4-4575b3b6f2e9731edd61
i get an 400 http and this response:
{
"id": [
"The value '7dd2514618c4-4575b3b6f2e9731edd61' is not valid."
]
}
While debugging, im not hitting any methods (when i pass string instead of int)
My question is, how to verload methods with one parameters with string or int? These methods do diffrent things
EDIT
When i pass something like:
https://localhost:44365/Task/dddd
I still get response with invalid id
You can define parameter type like [HttpGet("{id:int}")]. For more information refer below link.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2#route-constraints
Your actions should be like below.
[HttpGet("{id:int}")]
public IActionResult GetTask([FromRoute] int id)
{
}
[HttpGet("{userId}")]
public IActionResult GetUserTask([FromRoute] string userId)
{
}
Use like this
[HttpGet("{id}")]
public IActionResult GetTask([FromRoute] int id)
{
}
[HttpGet("User/{userId}")]
public IActionResult GetUserTask([FromRoute] string userId)
{
}
and while calling api with guid/string use
https://localhost:44365/Task/User/7dd2514618c4-4575b3b6f2e9731edd61

Handling multiple IDs in Route

As far as I can understand, the conventional routing in .NET Core MVC is [controller]/[action]/{id?}
However, I have the following POST request I'm trying to catch which looks like this:
myDomain/MyController/MyAction/userID/anotherID/myInfo
I have tried the following, but it doesn't seem to be working:
public class MyController : Controller
{
[HTTPPost]
[Route("MyAction/{userID:minlength(2)}/{anotherID:int}/myInfo")]
public IActionResult MyAction([FromRoute] string userID, [FromRoute] int anotherID, [FromBody] string stuffIWant)
{
return Ok();
}
}
Obviously I'm not handling the routing correctly, but I'm not sure how I would get userID and anotherID from that route. I've published this action to my site, and tried to do a test post with the same URL, but didn't get a response.
Change to:
public class MyController : Controller
{
[HTTPPost]
[Route("MyAction/{userID:minlength(2)}/{anotherID:int}/myInfo")]
public IActionResult MyAction(string userID, int anotherID, [FromBody] string stuffIWant)
{
return Ok();
}
}

How to make valid route for {id}/visit?

I am new at asp.core , so I try to make valid route to {id}/visits
My code:
[Produces("application/json")]
[Route("/Users")]
public class UserController
{
[HttpGet]
[Route("{id}/visits")]
public async Task<IActionResult> GetUser([FromRoute] long id)
{
throw new NotImplementedException()
}
}
But, at route {id} generated method the same:
// GET: /Users/5
[HttpGet("{id}")]
public async Task<IActionResult> GetUser([FromRoute] long id)
{
return Ok(user);
}
How to make route /Users/5/visits nethod?
What parameters at GetUser should I add?
Name the methods differently and use constraints to avoid route conflicts:
[Produces("application/json")]
[RoutePrefix("Users")] // different attribute here and not starting /slash
public class UserController
{
// Gets a specific user
[HttpGet]
[Route("{id:long}")] // Matches GET Users/5
public async Task<IActionResult> GetUser([FromRoute] long id)
{
// do what needs to be done
}
// Gets all visits from a specific user
[HttpGet]
[Route("{id:long}/visits")] // Matches GET Users/5/visits
public async Task<IActionResult> GetUserVisits([FromRoute] long id) // method name different
{
// do what needs to be done
}
}

Web Api how to define 2 methods with same parameters

I'm new to Web API. Reading up on restful made me think it was based upon verbs and as such I was hoping that the logic would be as well.
If I want to create an API for Delete and Get, which have the same signature I'm told off .
[HttpGet]
public HttpResponseMessage Index(int id)
{
return Request.CreateResponse(HttpStatusCode.OK, GetValue());
}
[HttpDelete]
public HttpResponseMessage Index(int id)
{
//logic
return Request.CreateResponse(HttpStatusCode.OK, true);
}
I was hoping by specifying the different verb Web Api 2 would tell. But even if I update the delete to (note the void return type)
[HttpDelete]
public void Index(int id)
{
//logic
}
I am still told off as the member called index with the same parameter types already exist.
According to https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client it shows
Action HTTP method Relative URI
Get a product by ID GET /api/products/id
Create a new product POST /api/products
Update a product PUT /api/products/id
Delete a product DELETE /api/products/id
The Get, Put and Delete have the same URL. Sadly, they don't display the server side code, only the client.
Are my only options to:
1. Overload the method (in this example, seems like it would be hacking as it's not needed to perform the required task)
2. Give the method a different name (eg `Delete` instead of `Index`)
Or is there another way?
You have a syntax issue. You can use attribute routes to maintain same paths but the methods must have different names and structures or you will get compilation error like you already experienced.
Using the example from your question
Action HTTP method Relative URI
Get a product by ID GET /api/products/id
Create a new product POST /api/products
Update a product PUT /api/products/id
Delete a product DELETE /api/products/id
The following would be a controller that matches the above
[RoutePrefix("api/products")]
public class ProductsController : ApiController {
[HttpGet]
[Route("{id:int}")] //Matches GET api/products/1
public IHttpActionResult Get(int id) {
return Ok(GetValueById(id));
}
[HttpPost]
[Route("")] //Matches POST api/products
public IHttpActionResult Post([FromBody]Product model) {
//...code removed for brevity
}
[HttpPut]
[Route("{id:int}")] //Matches PUT api/products/1
public IHttpActionResult Put(int id, [FromBody]Product model) {
//...code removed for brevity
}
[HttpDelete]
[Route("{id:int}")] //Matches DELETE api/products/1
public IHttpActionResult Post(int id) {
//...code removed for brevity
}
}
You can use Route attribute on api methods, check below:
[HttpGet]
[Route("same")]
public IHttpActionResult get(int id)
{
return Ok();
}
[HttpDelete]
[Route("same")]
public IHttpActionResult delete(int id)
{
return Ok();
}
And set http method to get for get request and delete for delete request, similar for post/put.

Same url for overloaded controller methods

In my web api application, I want to enable clients to make requests, using the same path, but pass different type of parameters.
For example:
public class MyController : ApiController
{
[HttpDelete]
public IHttpActionResult Delete(int id) {..}
[HttpDelete]
public IHttpActionResult Delete2(Guid id) {..}
[HttpDelete]
public IHttpActionResult Delete3(string id) {..}
}
I want the url for each method to be similar, for example:
api/MyController/1
api/MyController/abc etc..
Is this possible? Iv'e tried alot of combinations with ActionName attribute and Routing configuration, but nothing seemed to work.
Thanks
You can use attribute routing for this. For example:
[RoutePrefix("MyController")]
public class MyController : ApiController
{
[HttpDelete]
[Route("delete/{id:int}")]
public IHttpActionResult Delete(int id) {..}
[HttpDelete]
[Route("delete/{id:guid}")]
public IHttpActionResult Delete2(Guid id) {..}
[HttpDelete]
[Route("delete/{id:alpha}")]
public IHttpActionResult Delete3(string id) {..}
}
If you do this then the request url will be:
http://yoursever/mycontroller/delete/123
http://yoursever/mycontroller/delete/abc
http://yoursever/mycontroller/delete/91c74f8f-d981-4ee1-ba36-3e9416bba202
You need to provide a Route with different parameter types for each of your methods:
[RoutePrefix("api/MyController")]
public class MyController : ApiController
{
[HttpDelete]
[Route("{id:int}", Order = 1)]
public IHttpActionResult Delete(int id) {..}
[HttpDelete]
[Route("{id:guid}", Order = 2)]
public IHttpActionResult Delete2(Guid id) {..}
[HttpDelete]
[Route("{id}", Order = 3)]
public IHttpActionResult Delete3(string id) {..}
}
Of course you have to enable attribute routing if you haven't already.
The Order property for the Route attribute ensures that the route templates are checked in the correct order so that an int value will not match the string route.
Yes, this is possible. Try setting the route as a decoration.
example:
[Route("DeleteThis/{id}")]
[HttpDelete]
public IHttpActionResult DeleteThis(int id)
{
return Ok();
}
[Route("NowDeleteThis/{name}")]
[HttpDelete]
public IHttpActionResult DeleteThis(string name)
{
return Ok();
}

Categories