Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NETCORE MVC - How to work with nested, multi-parameterized routes

Tags:

Looking for best practices when working with nested routes in .NET Core MVC.

Let's say CampusController.cs works with a base model:

[Route("api/campus/")] public class CampusController : Controller {     ...     [HttpGet]     [Route("{campusId}")]     public IActionResult GetCampusInfo ([FromQuery]int campusId) { ... } } 

And BuildingController.cs works with a child model:

[Route("api/campus/{campusId}/building")] public class BuildingController : Controller {     ...     [HttpGet]     [Route("{buildingId}")]     public IActionResult GetBuilding ([FromQuery]int buildingId) { ... }      [Route("{buildingId}/")]     public IActionResult GetBuilding ([FromQuery]int buildingId) { ... }     ....     (more Action Methods) } 

If buildingId maps directly to the database it could retrieved even if the provided campusId isn't the parent. To keep the URL clean when calling /api/campus/{campusId}/building/{buildingId} I'd like to validate {campusId} and return a 4xx coded IActionResult if it's invalid. There has to be a better way than including validation logic in every Action Method inside BuildingController.

  • Is there a way to cascade multiple Action methods on different controllers? So that a validation method on CampusController would be called first and in turn call a method onBuildingController?
  • Is there a way to have a controller-level verification of campusId that could short circuit and return a ActionResult if validation fails?

EDIT: When I refer to validation logic I mean API signals; not the business-logic that actually determines if campusId is/isn't valid.

Thanks in advance!

like image 708
James Dudley Avatar asked Aug 01 '17 22:08

James Dudley


People also ask

How do you pass multiple parameters in route attribute?

you could add a route like: routes. MapRoute( "ArtistImages", // Route name "{controller}/{action}/{artistName}/{apikey}", // URL with parameters new { controller = "Home", action = "Index", artistName = "", apikey = "" } // Parameter defaults );

How can add multiple route in ASP.NET MVC?

Multiple Routes You can also configure a custom route using the MapRoute extension method. You need to provide at least two parameters in MapRoute, route name, and URL pattern. The Defaults parameter is optional. You can register multiple custom routes with different names.

What is use of UseRouting and UseEndpoints in startup configure method?

UseRouting adds route matching to the middleware pipeline. This middleware looks at the set of endpoints defined in the app, and selects the best match based on the request. UseEndpoints adds endpoint execution to the middleware pipeline. It runs the delegate associated with the selected endpoint.


2 Answers

If using placeholder in the route prefix you would also need to include it in the action itself

[Route("api/campus/{campusId:int}/building")] public class BuildingController : Controller {     //...      [HttpGet]     [Route("{buildingId:int}")] // Matches GET api/campus/123/building/456     public IActionResult GetBuilding ([FromRoute]int campusId, [FromRoute]int buildingId) {          //... validate campus id along with building id      }     } 

If concerned about repeated code for validation then create a base controller for campus related request and have a shared validation method.

Another option is to have a service/repository that can be used to verify campus id and its relation to the provided building id if needed.

like image 130
Nkosi Avatar answered Oct 30 '22 19:10

Nkosi


It sounds like you want your users to provide a campusId when talking to the BuildingController, and your BuildingController to validate campusId in a DRY kind of way.

If that's the case, you can create an input model for your BuildingController methods:

public class BuildingIdInput {    [Required]    public int? CampusId { get; set; }    [Required]    public int? BuildingId { get; set; } } 

Then you can let MVC bind user input to this model.

[Route("api/campus")] public class BuildingController : Controller {    [HttpGet]    [Route("{campusId}/building/{buildingId}")]    public IActionResult GetBuilding (BuildingIdInput input)     {        if (ModelState.IsValid)        {...}    } } 
like image 22
Frank Fajardo Avatar answered Oct 30 '22 19:10

Frank Fajardo