C
C#2y ago
Anton

ASP.NET Core routing options

Say, I have a single server for some views and some apis, so I'd route views by default, while the api would go under /api. The question is what's the correct way to achieve the routing? - Am I supposed to use this https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-6.0#areas , stick an [Area("api")] on all api controllers? - Is there a way to have all api controllers be imported from a separate assembly, making them end up in the right grouping on the bases of assembly? Or by namespace prefix? - Should I explicitly stick a Route to all controllers? So to be a bit more clear, I want my api controllers resolving to /api/whatever, while all the rest should go to /. I've read the entire page linked above, but it doesn't really mention such a use case, and suggests no best practices in that regard. Ideally it would be the second option, but the first one also seems fine, if the constant were to be factored out.
Routing to controller actions in ASP.NET Core
Learn how ASP.NET Core MVC uses Routing Middleware to match URLs of incoming requests and map them to actions.
22 Replies
Angius
Angius2y ago
I just use an area for my API No, sorry, not even that I just have an /Api directory and API controllers there lol
Anton
Anton2y ago
How do you map them to /api?
Angius
Angius2y ago
namespace Ogma3.Api.V1;

[Route("api/[controller]", Name = nameof(ErrorController))]
[ApiController]
public class ErrorController : ControllerBase
{
[HttpGet]
public ActionResult<Result> OnGet([FromQuery] int? code)
{
var text = code.HasValue
? ReasonPhrases.GetReasonPhrase((int)code)
: "Unknown Error";
return new JsonResult(new Result(code, text))
{
StatusCode = code ?? 0
};
}

public sealed record Result(int? Code, string Reason);
}
namespace Ogma3.Api.V1;

[Route("api/[controller]", Name = nameof(ErrorController))]
[ApiController]
public class ErrorController : ControllerBase
{
[HttpGet]
public ActionResult<Result> OnGet([FromQuery] int? code)
{
var text = code.HasValue
? ReasonPhrases.GetReasonPhrase((int)code)
: "Unknown Error";
return new JsonResult(new Result(code, text))
{
StatusCode = code ?? 0
};
}

public sealed record Result(int? Code, string Reason);
}
an example My namespaces follow the directories
Anton
Anton2y ago
Yeah imo that's shit the route thing
Angius
Angius2y ago
Yeah, most probably lol Just use areas, then You still need [Route("[controller]")] tho
Anton
Anton2y ago
no i don't? Look at the examples in the docs ApiController already makes the class attribute-routed only, no?
Angius
Angius2y ago
Ah, huh, maybe
Anton
Anton2y ago
Do you use the explicit route name for something in your app?
Angius
Angius2y ago
For the entirety of my API But now you told me I might not need to lol I'll probably refactor it to being an area
Anton
Anton2y ago
No I mean do you consume it?
Angius
Angius2y ago
I do, yeah /api/whatever/...
Anton
Anton2y ago
I mean the Name why do you need to specify it explicitly at all [Route("blah", Name = nameof(...))] What do you use the name for
Angius
Angius2y ago
Ah To generate the URL that I sometimes need
Anton
Anton2y ago
So you're doing that because by default the name is the name of the class, without the controller part, so you're adding that explicitly, so that you could get the link by doing nameof(WhateverController) So I assume there's no built-in function to get the controller name by type? Like nameof(WhateverController)[.. ^("Controller".Length)] I guess Do you create the link in a way similar to GetLink(controller = nameof(WhateverController), action = nameof(WhateverController.Action))?
Angius
Angius2y ago
Yeah, I use the nameof() approach I think in one place I do some substringing because... I don't even remember why, but apparently I had to
Anton
Anton2y ago
I'm kinda disappointed about this one, seems like a rough edge I mean, having to either remove the controller part manually, or rename the routes
Angius
Angius2y ago
You could prolly write your own helper
Anton
Anton2y ago
Yeah, but it's bad ux kinda bad anyway
Angius
Angius2y ago
Oh sure
Anton
Anton2y ago
Unhandled exception. System.InvalidOperationException: Action 'fourtynine.StuffApiController.GetStuff (fourtynine)' does not have an attribute route. Action methods on controllers annot ated with ApiControllerAttribute must be attribute routed. huh I guess it doesn't imply being attribute-routed, you were right
Angius
Angius2y ago
Looks like I wasn't writing those attributes pointlessly then, yay mweh
Anton
Anton2y ago
There's no way it's the right way to do it though, right? I mean, there are tons of repetition The only other way of grouping attributes that I can think of is inheritance, but firstly, inheritance is bad because you can't inherit from some other class, and secondly, it will only work if the attributes have attribute usage inherit set to true