Why does this route not work? - c#

On the class I have:
[Route("api/candidate/free")]
On the method, I have:
[HttpDelete("{dateRangeId}")]
public IActionResult Delete(int dateRangeId)
This results in a 404:
/api/candidate/free/123
When the attribute is removed:
[HttpDelete]
public IActionResult Delete()
This doesn't result in a 404:
/api/candidate/free/
What is wrong with the parameter?

The route constraint is case sensitive. You have Int when it should be int
The action should also follow the expected route template with constraint for it to match the request otherwise you will get 404 (Not Found)
[Route("api/candidate/free")]
public class MyController : Controller {
//...
//DELETE api/candidate/free/123
[HttpDelete("{dateRangeId:int}")]
public IActionResult MyAction(int dateRangeId) {
//...
return Ok();
}
}
Reference Routing to Controller Actions
Reference Routing in ASP.NET Core

That'll do me...
[HttpPost("delete")]
public IActionResult Delete([FromQuery] int dateRangeId)

Related

Controller route attribute only relevant for root function?

I have a question about .NET Core controller routing. Recently I discovered that the controller route attribute (which you place just above the controller) only works for the root method, or at least it seems that way.
My code:
using KrabbelMicroservice.Models;
using KrabbelMicroservice.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace KrabbelMicroservice.Controllers;
[ApiController]
[Route("/profile")] // <-- This is the controller routing attribute I am talking about
public class ProfileKrabbelController : Controller
{
private readonly IProfileKrabbelService _krabbelService;
public ProfileKrabbelController(IProfileKrabbelService krabbelService)
{
_krabbelService = krabbelService;
}
[HttpGet]
public IActionResult Index()
{
// not relevant
}
[HttpGet]
[Route("/id/{krabbelId}")]
public IActionResult GetKrabbelById(long krabbelId)
{
// not relevant
}
[HttpGet]
[Route("/pid/to/{profileId}")]
public IActionResult GetKrabbelsToProfileId(long profileId)
{
// not relevant
}
[HttpGet]
[Route("/pid/from/{profileId}")]
public IActionResult GetKrabbelsFromProfileId(long profileId)
{
// not relevant
}
[HttpGet]
[Route("/pid/with/{profileId}")]
public IActionResult GetKrabbelsWithProfileId(long profileId)
{
// not relevant
}
[HttpPost]
[Route("/new")]
public IActionResult AddKrabbel(ProfileKrabbel krabbel)
{
// not relevant
}
[HttpPut]
[Route("/update")]
public IActionResult UpdateKrabbel(ProfileKrabbel krabbel)
{
// not relevant
}
[HttpDelete]
[Route("/delete")]
public IActionResult DeleteKrabbel(ProfileKrabbel krabbel)
{
// not relevant
}
}
In my swagger launch the requests look like this:
I expected that all paths would be prefixed by /profile/ but it seems like only the root function (which did not have its own route attribute) implemented the prefix.
I am not only trying to get a fix for this, but also looking for an explanation as to why my controller route attribute is ignored for the other requests. The only possibility I can think of is the specific route attributes for each endpoint overriding the controller route attribute but I would like to hear it from an expert.
Secondly I would of course also like to find a solution to this problem, preferrably not adding /profile before every seperate route but if that is the only solution so be it.
Thanks in advance!
you should be remove "/" if you have root route
ex:
[Route("test")]
[ApiController]
public class TestController3 : Controller
{
[HttpGet]
[Route("testobj")]
public TestObj Test()
{
return "test";
}
}
the even shorter in httpget
[HttpGet("testobj")]
the both output:
test/testobj

How to use HttpGet Method with two different parameter value

How do I implement following method?
I have two HttpGet Methods with following parameter value:-
[HttpGet("{id}")] int value for route
[HttpGet("{slug}")] string value for route
Route looks like this on controller:-
[Route("api/[controller]")
Route configuration:-
app.UseMvc(routes =>
{
routes.MapRoute(
name: "defaultRoute",
template: "{controller=Posts}/{action=GetAsync}/{id?}");
});
How to make sure that specific HttpGet Method gets triggered based on route value. In the above case only HttpGet with {id} route is working. Latter only works if former does not exist/remove. How can I direct my route to a method with specific header value.
Thanks!
Use route constraints
[Route("api/[controller]")
public class ValuesController : Controller {
//GET api/values/1
[HttpGet("{id:int}")] //int value for route
public IActionResult GetById(int id) {
//...
}
//GET api/values/something-else
[HttpGet("{slug}")] //string value for route
public IActionResult Get(string slug) {
//...
}
}
Reference Routing in ASP.NET Core
Reference Routing to controller actions in ASP.NET Core
You can configure routes using attributes in your controller and actions.
[Route("api/[controller]")]
public class HomeController : BaseController
{
[HttpGet("[action]")]
public IActionResult Index() => View();
[HttpGet("[action]")]
public IActionResult Error() => View();
[HttpGet("[action]/{name}")]
public IActionResult Detail(string name)
{
return RedirectToAction(nameof(Index));
}
}
You can see the two tokens [controller] and [action] indicate that we have to refer to the controller and action name that has been declared. In this case, “Home” is the name of the controller, and “Detail” the name of the action, therefore it the name of the route.

Can't map route to action, ASP.NET Core Web API

I am working on Web API project and have the following problem:
I have tried to call the action method called 'GetUserBy' with the following Url (https://localhost:44328/api/Users/GetUserBy?username=myusername&password=mypassword), but the result I received in the browser looks like this:
{"id":["The value 'GetUserBy' is not valid."]}
Below is my UsersController:
[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
// GET: api/Users
[HttpGet]
public IEnumerable<User> GetUsers()
{
//this works
//code removed for simplicity
}
//GET: api/Users/5
[HttpGet("{id}")]
public async Task<IActionResult> GetUser([FromRoute] int id)
{
//this works too
}
[HttpGet("Users/GetUserBy")]
public async Task<IActionResult> GetUserBy([FromQuery]string username, [FromQuery]string password)
{
//this doesn't work
}
}
when I insert the breakpoint on this method, code execution never seems to come there regardless I call it or not.
I added the following code in startup.cs file, but nothing has changed.
app.UseMvc(
routes =>
{
routes.MapRoute("GetUserBy", "{controller=Users}/{action=GetUserBy}");
}
);
I have also visited the following web page, but I can't find the answer.
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-2.1
try changing your Tag from this:
[HttpGet("Users/GetUserBy")]
to this:
[HttpGet("GetUserBy")]
you already have it routing to the Controller Users
You are experiencing route conflicts.
api/Users/GetUserBy
matches this route
//GET: api/Users/5
[HttpGet("{id}")]
public async Task<IActionResult> GetUser([FromRoute] int id)
{
//this works too
}
but it is treating the GetUserBy string in the URL as the {id} in the route template.
Since "GetUserBy" is not an int you get that invalid value error message.
add a route constraint so that it will only match for an integer.
//GET: api/Users/5
[HttpGet("{id:int}")]
public async Task<IActionResult> GetUser([FromRoute] int id) {
//...
}
The current GetUserBy action has Users/GetUserBy as its route template, which would resolve to api/Users/Users/GetUserBy given the current api/[controller] route template on the controller.
Consider using the action token to get the desired behavior.
Here is the completed code with the changes suggested above.
[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase {
// GET: api/Users
[HttpGet]
public IEnumerable<User> GetUsers() {
//...
}
//GET: api/Users/5
[HttpGet("{id:int}")]
public async Task<IActionResult> GetUser([FromRoute] int id) {
//...
}
//GET: api/Users/GetUserBy
[HttpGet("[action]")]
public async Task<IActionResult> GetUserBy([FromQuery]string username, [FromQuery]string password) {
//...
}
}
Reference Routing to controller actions in ASP.NET Core

Why my api doesn't match the correct routes

I have a weird situation... I have this api methods:
[Route("api/something")]
public class MyController : Controller
{
[HttpGet("test-{id}")]
public Task<T> method1() { ... }
[HttpGet("test-something-{id}")]
public Task<T> method2() { ... }
}
I want to call api/something/test-something-1 but my api calls api/something/test-1
why?
The route "test-{id}" matches api/something/test-something-1 where template parameter would end up as id = something-1.
That is the reason why when you call api/something/test-something-1 that it calls method1 with route template test-{id}
When there are route conflicts like this then you should use route constraints to better differentiate routes.
[Route("api/something")]
public class MyController : Controller {
[HttpGet("test-{id:int}")]//Matches GET api/something/test-1
public Task<IActionResult> method1(int id) {
//...
}
[HttpGet("test-something-{id}")]//Matches GET api/something/test-something-any_id_here
public Task<IActionResult> method2(string id) {
//...
}
}
You can apply route constraints to the second one as well if the id is suppose to be an int as well.
[HttpGet("test-something-{id:int}")]//Matches GET api/something/test-something-1
public Task<IActionResult> method2(int id) {
//...
}
Reference: Routing in ASP.NET Core : Route Constraint Reference
Class declaration is incorrect
[RoutePrifix("api/something")]
public Class blabla : Controller
{
[HttpGet("test-{id}")]
public Task<T> method1{}
[HttpGet("test-something-{id}")]
public Task<T> method1{}
}
In route config file you have to enable attribute routing.
routes.MapMvcAttributeRoutes();

Unusual [RoutePrefix] behavior in ASP.NET WebAPI

I have two Controllers as follows:
[RoutePrefix("v1/user/something")]
public class SomethingsController : ApiController
{
[Route("{id}")]
[HttpGet]
[ResponseType(typeof(SomethingsViewModel))]
public async Task<IHttpActionResult> GetAsync([FromUri]int id)
{
}
}
[RoutePrefix("v1/user")]
public class UserController : ApiController
{
[Route("{id}")]
[HttpGet]
[Authorize(Roles = "Super Admin")]
public async Task<IHttpActionResult> GetByIdAsync([FromUri]int id)
{
}
}
Now by looking at the code above, I'd think that the following two routes are being created:
v1/user/something/{id}
v1/user/{id}
But unfortunately, for some reason, that is not the case. I keep getting the following exception message when trying to access one of the above routes:
Multiple controller types were found that match the URL. This can happen if attribute routes on multiple controllers match the requested URL.
The request has found the following matching controller types: MyProject.Api.Controllers.UserController, MyProject.Api.Controllers.SomethingsController
Please help me out in figuring what I might be doing wrong or which small detail am I missing out here.
Though their route prefix are different their resolved routes match. for example v1/user/{id} will match v1/user/something/{id} where id parameter arg in the first route will take something/{id}.
Route prefix and Route attributes combine to create a full route that is added to the route table.
In a case like this you will need to use constraints in order to better differentiate the routes.
[RoutePrefix("v1/user/something")]
public class SomethingsController : ApiController {
[Route("{id:int}")]
[HttpGet]
[ResponseType(typeof(SomethingsViewModel))]
public async Task<IHttpActionResult> GetAsync([FromUri]int id) { ... }
}
[RoutePrefix("v1/user")]
public class UserController : ApiController {
[Route("{id:int}")]
[HttpGet]
[Authorize(Roles = "Super Admin")]
public async Task<IHttpActionResult> GetByIdAsync([FromUri]int id) { ... }
}
So now with the int constraint something wont be mistaken for valid parameter for the UserController.GetByIdAsync action
Reference Attribute Routing in ASP.NET Web API 2: Route Constraints
Route Constraints
Route constraints let you restrict how the parameters in the route
template are matched. The general syntax is "{parameter:constraint}".
For example:
[Route("users/{id:int}"]
public User GetUserById(int id) { ... }
[Route("users/{name}"]
public User GetUserByName(string name) { ... }
Here, the first route will only be selected if the "id" segment of the
URI is an integer. Otherwise, the second route will be chosen.

Categories

Resources