Asp.net core 2 Prefix Routing - c#

How to create prefixed routing for MVC CRUD operation. I am working on an application that requires admin and front-end. For the admin I want all route to point to localhost:5000/admin/....
I have different Controllers
public class RoomsController : Controller
{
// GET: Rooms
public async Task<IActionResult> Index()
{
return View(await _context.Rooms.ToListAsync());
}
//...
}
and
public class SlidersController : Controller
{
private readonly ApplicationDbContext _context;
public SlidersController(ApplicationDbContext context)
{
_context = context;
}
// GET: Sliders
public async Task<IActionResult> Index()
{
return View(await _context.Sliders.ToListAsync());
}
//...
}
Now I want the admin route to be
localhost:5000/admin/rooms
localhost:5000/admin/slider
while other routes remain
localhost:5000/
localhost:5000/about
localhost:5000/...

You can also use Attribute Routing for this. Till ASP.Net Web API we have the attribute named [RoutePrefix], but in ASP.Net Core 2 we can use [Route] attribute for the same purpose.
[Route("api/[controller]/[action]")]
public class DistrictController : ControllerBase
{
[Route("{id:int:min(1)}")] // i.e. GET /api/District/GetDetails/10
public IActionResult GetDetails(int id)
{
}
// i.e. GET /api/District/GetPage/?id=10
public IActionResult GetPage(int page)
{
}
[HttpDelete]
[Route("{id:int:min(1)}")] // i.e. Delete /api/District/Delete/10
public IActionResult Delete(int id)
{
}
[HttpGet]
[Route("~/api/States/GetAllState")] // i.e. GET /api/States/GetAllState
public IActionResult GetStates()
{
}
}

I solve the Problem by using MVC Area
docs

Related

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

cannot find C# netcore controller

I have added a netcore controller in my existing IdentityServer4 project. Here is my code
namespace IdentityServer4.Quickstart.UI
{
public class VersionController : Controller
{
IVersionService _repository;
public VersionController(IVersionService repository)
{
_repository = repository;
}
[HttpGet(nameof(GetBackgroundId))]
public IActionResult GetBackgroundId()
{
return new OkObjectResult(_repository.GetBackgroundId());
}
[HttpPut(nameof(SetBackgroundId))]
public IActionResult SetBackgroundId([FromQuery]int id)
{
_repository.SetBackgroundId(id);
return new NoContentResult();
}
}
}
I also have the following line of code in startup.cs
app.UseMvcWithDefaultRoute();
I can access the account controller by the following url
http://localhost:5001/account/login
However, I cannot access the version controller by the following url:
http://localhost:5001/version/GetBackgroundId
The error code is 404.
What is wrong?
You are missing a route prefix for controller. You are using attribute routing so you need to include the entire desired route.
The current GetBackgroundId controller action would map to
http://localhost:5001/GetBackgroundId
Add a route to the controller
[Route("[controller]")]
public class VersionController : Controller {
IVersionService _repository;
public VersionController(IVersionService repository) {
_repository = repository;
}
//Match GET version/GetBackgroundId
[HttpGet("[action]")]
public IActionResult GetBackgroundId() {
return Ok(_repository.GetBackgroundId());
}
//Match PUT version/SetBackgroundId?id=5
[HttpPut("[action]")]
public IActionResult SetBackgroundId([FromQuery]int id) {
_repository.SetBackgroundId(id);
return NoContent();
}
}
Also note the use of route tokens and that instead of newing up the responses, Controller already has helper methods that provide those results.
Reference Routing to controller actions in ASP.NET Core

ASP.NET Core Attribute routing

I am migrating a project to asp net core, but I could not configure these routes, i am using attributes to map actions.
Code for ASP.Net WebAPI2
[Route("api/[controller]")]
public class SalesController : Controller
{
// api/sales/1 -> ok
[HttpGet]
public HttpResponseMessage Get(int id)
{
// Logic
}
// api/sales -> ok
[HttpGet]
public HttpResponseMessage Get([FromUri] PaginationHelper pagination)
{
// Logic
}
// api/sales?me -> ok
[ActionName("Get")]
public HttpResponseMessage GetMe(bool? me)
{
// Logic
}
}
Code for ASP.Net Core
In the file Startup.cs is set app.UseMvc();
[Route("api/[controller]")]
public class SalesController : Controller
{
// api/sales/1 -> ok
[HttpGet("{id}")]
public IActionResult Get(int id)
{
// Logic
}
// api/sales -> don't work
[HttpGet] // -> ???
public IActionResult Get(PaginationHelper pagination)
{
// Logic
}
// api/sales?me -> don't work
[HttpGet] // -> ???
public IActionResult GetMe(bool? me)
{
// Logic
}
}
Maybe I'm too late to this discussion, but this could be valuable to other people who end up reading this page, like I did. The problem with your API endpoints is that you configured 2 of them to handle the same route: GET /api/sales.
If you try to access that route, the framework won't be able to distinguish between Get(PaginationHelper) and GetMe(bool?). The reason why is that they both have [HttpGet] attribute, which means that both are capable of handling the route you specified in the [Route("api/[controller]")] attribute, just above your class declaration. Since those are declared as capable of handling that same route, hence your Exception (Multiple actions matched).
The solution for your problem depends on which action you want to handle that ambiguous route. Assuming that you want the route GET /api/sales to be handled by Get(PaginationHelper), you can change the GetMe(bool?) action method and its [HttpGet] attribute to something like this:
[HttpGet("me")] // GET api/sales/me
public IActionResult GetMe() {
// Logic
}
The new framework expects a more explicit indication of the intent of the endpoint.
[Route("api/[controller]")]
public class SalesController : Controller {
[HttpGet("{id:int}")] // GET api/sales/1
public IActionResult Get(int id) {
// Logic
}
[HttpGet] // GET api/sales?page=1 assuming PaginationHelper has page property
public IActionResult Get([FromQuery]PaginationHelper pagination) {
// Logic
}
[HttpGet] // GET api/sales?me=true
public IActionResult GetMe(bool? me = false) {
// Logic
}
}
Reference Asp.Net Core: Model Binding

Map two different routes to the same controller action

I am working on extending the example at: https://docs.asp.net/en/latest/tutorials/first-web-api.html
They have a ToDo apis: /api/todo and /api/todo/{id}.
I want to extend it to ToDoGroups /api/ToDoGroup.
Under ToDoGroup, I want to reach a ToDo by the follwoing:
/api/ToDoGroup/{id}/ToDo/{id}.
How can I make it point to the same controller action? For example the following action below will also have another route like [HttpGet("ToDoGroup/{ToDoGroupid}/ToDo/{ToDoid}", Name = "GetTodo")]
[HttpGet("{id}", Name = "GetTodo")]
public IActionResult GetById(string id)
{
var item = TodoItems.Find(id);
if (item == null)
{
return NotFound();
}
return new ObjectResult(item);
}
first change the controller's route prefix:
[Route("api/todogroup/{groupId:int}")]
public class TodoController : Controller
then change your action's route:
[HttpGet("todo/{id}", Name = "GetTodo")]
public IActionResult GetById(int groupId, string id)
edit:
to get both routes, you can do this:
[Route("api")]
public class TodoController : Controller
[HttpGet("todo/{id}", Name = "GetTodo")]//api/todo/43
public IActionResult GetById(string id)
[HttpGet("todogroup/{groupdId:int}/todo/{id}", Name = "GetGroupTodo")]//api/todogroup/100/todo/43
public IActionResult GetById(int groupId, string id)
Asp.Net Web Api has a way of negating a route prefix (the route specified on the controller), but I cant find an equivalent in Asp.Net Core.

OData v4 Routing Prefix?

I have a side-by-side Web API 2.2 APIController and OData v4 ODataController. My APIController uses routing attributes internally like this (there are no predefined routing defaults):
[RoutePrefix("api")]
public class MyController : ApiController
{
[HttpGet]
[Route("My")]
public IHttpActionResult Get()
{
//Code Here
}
[HttpGet]
[Route("My")]
public IHttpActionResult Get([FromUri] String mykey)
{
//Code Here
}
}
and as such are routed to through ./api/My and ./api/My/?mykey=value
and I've tried setting up my ODataController to follow a similar suit with:
[ODataRoutePrefix("My")]
public class oMyController : ODataController {
[HttpGet]
public IHttpActionResult Get(ODataQueryOptions<FileModel> queryOptions) {
//Code Here
}
[HttpGet]
[ODataRoute("({mykey})")]
public IHttpActionResult Get([FromODataUri] String mykey) {
//Code Here
}
}
defining odata route ahead of time like this:
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<MyModel>("My");
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: "odata",
model: builder.GetEdmModel()
);
but attempts to access ./odata/My and ./odata/My(value) end up going into my APIController instead of the ODataController.
How can I route these using the different prefixes, but the same name, and have them go to the appropriate controllers. I don't want to have a different name for each route if I can prevent it, the prefixes should take care of everything, but for some reason they're not.
You need to specify the ODataRoute attribute, even if it's empty:
[ODataRoutePrefix("My")]
public class oMyController : ODataController {
[HttpGet]
[ODataRoute()] // <---<< This was the key to proper OData routing
public IHttpActionResult Get(ODataQueryOptions<FileModel> queryOptions) {
//Code Here
}
[HttpGet]
[ODataRoute("({mykey})")]
public IHttpActionResult Get([FromODataUri] String mykey) {
//Code Here
}
}

Categories

Resources