Attribute Routing with Default Route - c#

Using attribute based routing I would like to match the following routes:
~/
~/Home
~/Home/Index
to HomeController.Index, and this route:
~/Home/Error
to HomeController.Error. Here is my configuration:
[Route("[controller]/[action]")]
public class HomeController : Controller {
[HttpGet, Route(""), Route("~/")]
public IActionResult Index() {
return View();
}
[HttpGet]
public IActionResult Error() {
return View();
}
}
I have tried adding Route("[action]"), Route("Index"), and other combinations but still don't get a match for:
/Home/Index

The empty route Route("") combines with the route on controller, use Route("/") to override it instead of combining with it:
[Route("[controller]/[action]")]
public class HomeController : Controller {
[HttpGet]
[Route("/")]
[Route("/[controller]")]
public IActionResult Index() {
return View();
}
[HttpGet]
public IActionResult Error() {
return View();
}
}
Alternatively, you can remove the /[action] on the controller, which makes it a bit easier (no need to override), but then you have to define a route on every action.
I'm assuming that you intentionally want to use attribute routing rather than conventional routing, so the above answer is what you need. However, just in case the assumption is wrong, this can be easily achieved with a simple conventional routing:
routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");

[Route("[controller]")]
public class HomeController : Controller
{
[Route("")] // Matches 'Home'
[Route("Index")] // Matches 'Home/Index'
public IActionResult Index(){}
[Route("Error")] // Matches 'Home/Error'
public IActionResult Error(){}
}

Related

Multiple controller types were found that match the URL in mvc app

I have a weird bug using attribute routing with the following two controllers:
[Route("{action=Index}")]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
[RoutePrefix("search")]
[Route("{action=Index}")]
public class SearchController : Controller
{
public ActionResult Index(string searchTerm)
{
return View();
}
}
And in the route config:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
As you can see, the second controller should have a prefix of search
However if I go to dev.local/search?searchterm=test
I get the error
The request has found the following matching controller types:
Marshalls.WebComponents.Web.Controllers.SearchController
Marshalls.WebComponents.Web.Controllers.HomeController
If I remove the [Route("{action=Index}")] from the homecontroller, it will work fine, but then I cannot get to the homepage using http://dev.local/
This hasn't happened before and usually works ok so I'm wondering if anyone can spot anything obvious I have messed up
Add RoutePrefix for HomeController and move Route from controller to methods/actions.
Empty string in Route and RoutePrefix attributes means that this controller or action is default.
http://dev.local/ => HomeController and Index action
http://dev.local/search?searchTerm=123 => SearchController and Index action
Please keep in mind that only one controller can have empty RoutePrefix and only one action in controller can have empty Route
[RoutePrefix("")]
public class HomeController : Controller
{
[Route("")]
public ActionResult Index()
{
return View();
}
}
[RoutePrefix("search")]
public class SearchController : Controller
{
[Route("")]
public ActionResult Index(string searchTerm)
{
return View();
}
}

ASP.NET Core route of a controller and the index action

I'm trying to set a route of my controller while also be able to navigate the index without typing Index, here's what I tried:
My route configuration
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Try #1
// My controller
[Route("panel/admin")]
public class MyController...
// My index action
public IActionResult Index()...
Problem: This doesn't work, all the actions become accessible at panel/admin so I get an error saying Multiple actions matched.
Even when setting the route of my index action to Route(""), doesn't change anything.
Try #2
// My controller
[Route("panel/admin/[action]")]
public class MyController...
// My index action
[Route("")]
public IActionResult Index()...
Here, the index route doesn't change, it stays panel/admin/Index.
What I want
I want to be able to access my index action when navigating to panel/admin and I also want my other actions to work with just their method names like panel/admin/UsersList.
Complete controller
[Route("panel/admin/[action]")]
public class MyController
{
[Route("")]
public IActionResult Index()
{
return View();
}
public IActionResult UsersList()
{
var users = _db.Users.ToList();
return View(users);
}
// Other actions like UsersList
}
Thank you.
Reference Routing to controller actions in ASP.NET Core
With attribute routes you have to be very specific about desired routes to avoid route conflicts. Which also means that you will have to specify all the routes. Unlike convention-based routing.
Option #1
[Route("panel/admin")]
public class MyController {
[HttpGet]
[Route("")] //GET panel/admin
[Route("[action]")] //GET panel/admin/index
public IActionResult Index() {
return View();
}
[HttpGet]
[Route("[action]")] //GET panel/admin/UsersList
public IActionResult UsersList() {
var users = _db.Users.ToList();
return View(users);
}
// Other actions like UsersList
}
Option #2
[Route("panel/admin/[action]")]
public class MyController {
[HttpGet] //GET panel/admin/index
[Route("~/panel/admin")] //GET panel/admin
public IActionResult Index() {
return View();
}
[HttpGet] //GET panel/admin/UsersList
public IActionResult UsersList() {
var users = _db.Users.ToList();
return View(users);
}
// Other actions like UsersList
}
The tilde (~) in [Route("~/panel/admin")] overrides the route prefix on the controller.
Tip
While using multiple routes on actions can seem powerful, it's better
to keep your application's URL space simple and well-defined. Use
multiple routes on actions only where needed, for example to support
existing clients.

MVC Route match based on parameter type

I have a situation where I want the ThisAction controller to look like this :
public ActionResult Index()...
public ActionResult Index(int programId)...
public ActionResult Index(string programKey)...
With the goal of a route being set up like so
www.website.com/ThisAction/ <- matches first function
www.website.com/ThisAction/123 <- matches second function
www.website.com/ThisAction/ABC <- matches third function
Is this possible to set up in the global.asx route?
You would need to use attribute routing with route constraints to easily get that flexibility.
[RoutePrefix("ThisAction")]
public class ThisActionController : Controller {
[HttpGet]
[Route("")] //Matches GET ThisAction
public ActionResult Index() {
//...
}
[HttpGet]
[Route("{programId:int}")] //Matches GET ThisAction/123
public ActionResult Index(int programId) {
//...
}
[HttpGet]
[Route("{programKey}")] //Matches GET ThisAction/ABC
public ActionResult Index(string programKey) {
//...
}
}
Make sure that attribute routeing is enabled in RouteConfig
public class RouteConfig {
public static void RegisterRoutes(RouteCollection routes) {
//...other code removed for brevity
//Attribute routes
routes.MapMvcAttributeRoutes();
//convention-based routes
//...other code removed for brevity
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
}
}
The route will work along side convention-based routing.
Just note that once you use it on a controller you have to use it on the entire controller. So the controller is either all convention-based or all attribute routing.

Asp.net MVC - Area Attribute Routing is not working

I have code like below
[RouteArea("Client")]
public Class LoginController : Controller {
[Route("register")]
public ActionResult SignUp() {
return View();
}
}
Attribute routing unfortunately is not working in the areas :/, if I will remove "register" route for signup, it will work just for for client/signup, but with route "register" it is not working.
I have added [RouteArea()], tried with [RoutePrefix] but nothing is working correctly "Route Area" just enabled to use it with views (before that Razor couldn't find the view).
What am I doing wrong ?
Ok I HAVE FOUND THE SOLUTION.
1 Remove Area registration class from your area
2 Use this convention :
[RouteArea("Client")]
[RoutePrefix("login")]
[Route("{action}")]
public class LoginController : Controller
{
[Route("")]
// GET: Client/Login
public ActionResult Index()
{
return View();
}
[Route("register")]
// GET: client/login/register
public ActionResult SignUp()
{
return View();
}
}
Now you can use any route you want, with any prefix :)

Default route interferes with defined path in attribute routing in ASP.MVC

I have a controller with an action method and I have configured attribute routing:
[RoutePrefix("foos")]
public class FooController : BaseController
{
[HttpGet]
[Route("")]
public ActionResult List()
{
return View();
}
}
Here's routing configuration:
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapMvcAttributeRoutes();
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
}
Everything works fine. When I navigate to http://webPageAddress/foo/ my action is called and list is returned.
Now I want to make this route default. I've added new attribute so:
[HttpGet]
[Route("~/")]
[Route("")]
public ActionResult List()
{
return View();
}
The result is default route (http://webPageAddress/) works, but the old one (http://webPageAddress/foo/) doesn't work anymore (http 404 code).
How can I mix it and have both configured properly?
You need to make sure the route for http://webPageAddress/foo/ is registered before the route for http://webPageAddress/. With attribute routing, the only way to do this is to use the Order property to set the order.
[HttpGet]
[Route("~/", Order = 2)]
[Route("", Order = 1)]
public ActionResult List()
{
return View();
}
Reference: Understanding Routing Precedence in ASP.NET MVC and Web API

Categories