Can I override the default action for a single controller in ASP.Net Core MVC - asp.net-core

Is it possible to override the default action for a single controller without affecting the rest of the routing?
I currently have a default route of
routes.MapRoute(
name: "Default",
template: "{controller}/{action}",
defaults: new { controller = "Book", action = "Index" }
);
This works in the general case but I now want to add an AdminController, but I want the default action on AdminController to be Users, instead of Index.
I don't really want to use attribute routing on this controller as we may later update the default routing and I want to keep as much as possible centralised and DRY. I just want the urls /Admin and /Admin/Users to route to the Users action in this one controller.
I'm currently using ASP.Net Core 2.0 with the intention to move to 2.1 as soon as it is released. It's currently running on .Net Framework but we want to upgrade to .Net Core as soon as we can get rid of some dependencies we currently have on the framework (unlikely to be for the first release).
Any suggestions?

While more intensive than using attribute routing you can do
routes.MapRoute(
name: "AdminDefault",
template: "Admin/{action}",
defaults: new { controller = "Admin", action = "Users" }
);
routes.MapRoute(
name: "Default",
template: "{controller=Book}/{action=Index}",
);
using Attribute routing on the controller it would have been
[Route("[controller]")]
public class AdminController : Controller {
[HttpGet]
[Route("")] //Match GET admin
[Route("[action]")] //Match Get admin/users
public IActionResult Users() {
return View();
}
}
Or even
[Route("[controller]/{action=Users}")]
public class AdminController : Controller {
[HttpGet]
public IActionResult Users() {
return View();
}
}
Reference Routing to Controller Actions in ASP.NET Core

Please check below code:
routes.MapRoute(
name: "Admin",
template: "{controller}/{action}",
defaults: new { controller = "Admin", action = "Users" }
);

Related

ASP.NET Core WebAPI default route not working

I've followed several examples suggesting that to set my default route in an ASP.NET Core WebAPI project, I need to replace
app.UseMvc();
with
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action}",
defaults: new { controller = "Traders", action = "Get" });
});
But when I run it defaults to localhost:54321/api/values and it should default to localhost:54321/Traders
What's wrong?
As #tmg mentioned, do the following:
Right click your web project -> Select Properties -> Select the Debug tab on the left -> Then edit the 'Launch Url' field to set your own default launch url.
You can change the default route by modifying LaunchSettings.json file as shown
Follow the steps below.
Create a base controller for your API that extends base controller of dotnet core:
using Microsoft.AspNetCore.Mvc;
namespace WebApi.Controllers
{
[Route("api/[controller]")]
public abstract class ControllerApiBase : Controller
{
}
}
And inherit the base class in your API controllers:
using Microsoft.AspNetCore.Mvc;
using WebApi.Dtos;
namespace WebApi.Controllers
{
public class PingController : ControllerApiBase
{
public PingDto Get()
{
return new PingDto
{
Version = "0.0.0"
};
}
}
}

Defalut routing not working after adding route attribute in asp.net mvc

I created an mvc project with no attribute route. It was working fine. When I added an attribute route [Route("employeehome")] on one of my action methods, the conventional routing {controller}/{action}/{id} ie employee/index for that method ceased working. Is there anything wrong with my approach?
Adding my code snippet.
Route Config Code.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Controller code.
public class EmployeeController : Controller
{
// GET: Employee
[Route("employeehome")]
public ActionResult Index()
{
return View();
}
}

Create a route with an additional url parameter without creating an area

I'm building a site for a client using .Net MVC 4. The entire site uses the default MVC 4 route and all the pages work fine
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
)
There is a page on the site called 'Teachers'. For this page, there are several links that take you to new pages that are subsets of the 'Teachers' page. The client wants the url structure to appear like this
www.{mysite}.com/School/Teachers/Apply
www.{mysite}.com/School/Teachers/Benefits
I thought I could simple add the Apply and Benefits pages as an ActionResult in my SchoolController then use the routing feature in MVC to map the url to the correct ActionResult method in the SchoolController.
This is my controller:
public class SchoolController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Administration()
{
return View();
}
public ActionResult Teachers()
{
return View();
}
public ActionResult Apply()
{
return View();
}
public ActionResult Benefits()
{
return View();
}
}
This is the custom route that I tried.
routes.MapRoute(
"Teachers",
"{controller}/{page}/{action}",
new { controller = "School", page = "Teachers", action = "Index" }
)
I placed this route before the default route but this adds 'teachers' to every url on the site like this:
www.{mysite}.com/{controller}/teachers/{action}
SUMMARY
All the pages on my site use this url structure:
www.{mysite}.com/{controller}/{action}
This one page, however, has the following structure:
www.{mysite}.com/{controller}/teachers/{action}
How can I do this with routes?
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "TeachersActions",
url: "School/Teachers/{action}",
defaults: new { controller = "School" },
constraints: new { action = "Apply|Benefits" } // actions under Teachers
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
);
}
Any actions you want to be under Teachers should be added to the route. It is actually not necessary to specify defaults for action or page for this route to work (unless you do have some need for a page route value to be captured). The catch here is that a user can still target the actions under Teachers by entering the URL School/{action} because it is caught by the default route. Now this may or may not be a concern for you. Personally I would not consider it such a big issue since the users should just be using the site's navigation instead of entering the URLs manually.

How to add multiple routes to MVC4

To define your own URL routes in ASP.NET MVC4, I believe you modify Global.asax.cs so it looks something like...
using System.Web.Mvc;
using System.Web.Routing;
namespace MvcApplication1 {
public class MvcApplication : System.Web.HttpApplication {
public static void RegisterRoutes(RouteCollection routes) {
routes.MapRoute( .....
But what I cant find anywhere, is how you add multiple routes - e.g. do you just call routes.MapRoute(....) again?
Also, does this overwrite the hidden default routing definitions? If I want to keep it do I need to define it also?
I just want add to Embram's answer that the best practice is to add routes from most detailed to general:
routes.MapRoute(
name: "Route1",
url: "Mail/{id}",
defaults: new { controller = "Home", action = "Mail", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Route2",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
To add multiple routes, kindly check this adding_routes_to_an_mvc_application. As you said just make call routes.MapRoute(....) again.
The one thing to put into consideration MVC Routing respect ordering route. Your last route must be generic as possible, and your previous route must be specific as possible.(check this out ASP.NET MVC Default route)
does this overwrite the hidden default routing definitions?
I don't think so, but your reoutes sure 'll be checked first before the default MVC routes.(check this SO post)
It seems you're confused on where the routes are defined in an MVC 4 application.
You're global.asax should look like (by default):
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
}
}
Where RouteConfig is defined in /App_Start/RouteConfig.cs as looks like (by default):
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Knowing this, you should be able to edit the routes as needed.

Have Microsoft changed how ASP.NET MVC deals with duplicate action method names?

I might be missing something here, but in ASP.NET MVC 4, I can't get the following to work.
Given the following controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(string order1, string order2)
{
return null;
}
}
and it's view:
#{
ViewBag.Title = "Home";
}
#using (Html.BeginForm())
{
#Html.TextBox("order1")<br />
#Html.TextBox("order2")
<input type="submit" value="Save"/>
}
When start the app, all I get is this:
The current request for action 'Index' on controller type
'HomeController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult Index() on type
ViewData.Controllers.HomeController System.Web.Mvc.ActionResult
Index(System.String, System.String) on type
ViewData.Controllers.HomeController
Now, in ASP.NET MVC 3 the above works fine, I just tried it, so what's changed in ASP.NET MVC 4 to break this?
OK there could be a chance that I'm doing something silly here, and not noticing it.
EDIT:
I notice that in the MVC 4 app, the Global.asax.cs file did not contain this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
which the MVC 3 app does, by default. So I added the above to the MVC 4 app but it fails with the same error. Note that the MVC 3 app does work fine with the above route. I'm passing the "order" data via the Request.Form.
EDIT:
In the file RouteConfig.cs I can see RegisterRoutes is executed, with the following default route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
I still get the original error, regards ambiguity between which Index() method to call.
Because MVC4 ships with ASP.Net Web.API you can potentially reference two HttpPostAttribute (the same applies to the other attributes like HttpGet, etc.):
System.Web.Mvc.HttpPostAttribute is used by ASP.Net MVC so you need to use it on actions inside Controller derived controllers
System.Web.Http.HttpPostAttribute is used by ASP.Net Web.API so you need to use it on actions inside
ApiController derived controllers
You have acidentally referenced System.Web.Http.HttpPostAttribute in your code. Change it to use the right attribute and it should work correctly:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[System.Web.Mvc.HttpPost]
public ActionResult Index(string order1, string order2)
{
return null;
}
}