How to use HttpGet Method with two different parameter value - c#

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.

Related

Routing in dot net core with more than one parameter

Please let me know the exact method to ensure that correct parameters are sent in URL in order to navigate correctly in dot net core.
[HttpGet("{id},{id2}",Name ="Edit")]
[AllowAnonymous]
public ActionResult Edit(int id, int id2)
{
return Ok(3);
}
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}
When i try navigating to following url:
/api/test/Edit?id=1&id2=4
it gets navigated to the other method Get and returns value as string.
Startup.cs file has the following contents
app.UseMvcWithDefaultRoute();
Ensure that the correct route templates are applied to the actions
[Route("api/[controller]")]
public class TestController: Controller {
//GET api/test/edit?id=1&id2=4
[HttpGet("Edit")]
[AllowAnonymous]
public ActionResult Edit(int id, int id2) {
//...
return Ok(3);
}
//GET api/test/5
[HttpGet("{id}")]
public string Get(int id) {
return "value";
}
}
Reference Routing to controller actions in ASP.NET Core
.Net Core 3.1.3
In the Startup.Configure Method:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Controller Annotation: [Route("[controller]/[action]")]
Action Method Annotation: [HttpGet("{param1:int}/{param2:int}")]
From the postman: https://localhost:5001/controller/action/param1/param2
Hope this helps!

default route with id does not working in asp.net core

This is my controller:
public class HomeController : Controller
{
public IActionResult Index()
{
var route = Request.Path.Value;
return View("index" as object);
}
[HttpGet("{id}")]
public IActionResult Index(int id)
{
return View("index id" as object);
}
}
This is my route:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
url : /1 -> return index with id
url : /Home/Index/1 -> return index without id
I don't understand why?
You're using mixed routing - you've got conventional routing for the first action and attribute routing for the second.
When you navigate to /1, you hit the second action with the id parameter, because it's been set to use attribute routing for a path of /{id} (by using [HttpGet("{id}")]): Attribute routing overrides conventional routing.
When you navigate to /Home/Index/1, you hit your first action without the id parameter, simply because the other action you have is no longer a match given that it's been set to use attribute routing (/{id}), so it no longer matches /Home/Index/1 at all. With your conventional routing template from UseMvc, you've said that id is optional and so the match is still valid.
In order to achieve what you're looking for, you can use attribute routing exclusively for this controller. Here's what that would look like:
[Route("/")]
[Route("[controller]/[action]")]
public class HomeController : Controller
{
public IActionResult Index()
{
...
}
[HttpGet("{id}")]
public IActionResult Index(int id)
{
...
}
}
The addition of the two [Route(...)] attributes here adds support for the following two routes:
/ and /{id}.
/Home/Index and /Home/Index/{id}.
[controller] and [action] are placeholders that represent the name of the controller and action respectively - You could also just use the literal values Home and Index if you'd prefer something more fixed.
You don't necessarily need both [Route(...)] attributes, but the / version ensures the root of the site also matches the same controller/action pair.

Why does this route not work?

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)

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.

Creating a different route to a specific action

I am working on an asp.net 5 mvc api, and I am currently working on the Accounts Controller.
since I saw in many different places that there is a convention of using /api/Tokenrouting to a login in a web api. I would like to route to that specific method without the accounts prefix, I would prefer not using a different controller, and I would prefer using Attributes over routing in Startup.cs to avoid confusion in the future.
this is what I have currently
[Route("api/[controller]")]
public class AccountsController : Controller
{
[HttpPost("login")]
public async Task<JwtToken> Token([FromBody]Credentials credentials)
{
...
}
[HttpPost]
public async Task CreateUser([FromBody] userDto)
{
...
}
}
With attribute routing you can use a tilde (~) on the Action's route attribute to override the default route of the Controller if needed:
[Route("api/[controller]")]
public class AccountsController : Controller {
[HttpPost]
[Route("~/api/token")] //routes to `/api/token`
public async Task<JwtToken> Token([FromBody]Credentials credentials) {
...
}
[HttpPost]
[Route("users")] // routes to `/api/accounts/users`
public async Task CreateUser([FromBody] userDto) {
...
}
}
For ASP.NET Core it seems that the tilde ~ symbol (see accepted answer) is not needed anymore to override the controller's route prefix – instead, the following rule applies:
Route templates applied to an action that begin with a / don't get combined with route templates applied to the controller. This example matches a set of URL paths similar to the default route.
Here is an example:
[Route("foo")]
public class FooController : Controller
{
[Route("bar")] // combined with "foo" to map to route "/foo/bar"
public IActionResult Bar()
{
// ...
}
[Route("/hello/world")] // not combined; maps to route "/hello/world"
public IActionResult HelloWorld()
{
}
}
from https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing
[Route("[controller]/[action]")]
public class HomeController : Controller
{
[Route("~/")]
[Route("/Home")]
[Route("~/Home/Index")]
public IActionResult Index()
{
return ControllerContext.MyDisplayRouteInfo();
}
public IActionResult About()
{
return ControllerContext.MyDisplayRouteInfo();
}
}
In the preceding code, the Index method templates must prepend / or ~/ to the route templates. Route templates applied to an action that begin with / or ~/ don't get combined with route templates applied to the controller.

Categories

Resources