Have Microsoft changed how ASP.NET MVC deals with duplicate action method names? - asp.net-mvc-4

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;
}
}

Related

asp.net core maproute template with string concatenate to action

I have a HelloController
When i input URL with http://localhost/Hello/1234
How Could i link to the W1234
I try to modify maproute template like
template: {controller}/W{action}
But it didn't work
app.UseMvc(routes =>
{
routes.MapRoute(
name: "Hello",
template: "{controller}/{action}/{id?}");
});
public partial class HelloController : Controller
{
public IActionResult W1234()
{
return View();
}
}
You could try to use Attribute routing uses a set of attributes to map actions directly to route templates.
[[Route("Hello/1234")]
public IActionResult W1234()
{
return View();
}
Attribute routing can also make use of the Http[Verb] attributes such as HttpPostAttribute. All of these attributes can accept a route template.
[HttpGet("/Hello/1234")]
public IActionResult W1234()
{
return View();
}
Reference : Routing to controller actions in ASP.NET Core

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

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" }
);

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.

ASP.NET MVC 4 and Web API And Overloads

I'm new to ASP.NET MVC 4. I've created an endpoint. That endpoint is available at:
/myController/actionName
In my controller, I have the following defined:
[HttpPost]
public void ActionName(string parameter1)
{
}
I am trying to figure out if its possible to have overloads. In ASP.NET MVC 4 Web API, is there a way for me to say something like the following:
[HttpPost]
public void ActionName(string parameter1)
{
}
[HttpPost]
public void ActionName(string parameter1, string parameter2)
{
}
If not, is there a way to make parameters optional?
Thank you!
You cannot overload controller actions, however, you can specify a parameter to be optional when defining your routing as follows:
routes.MapRoute(
name: "OptionalParameter",
url: "myController/actionName/{parameter1}/{parameter2}",
defaults: new { controller = "myController", action = "actionName", parameter1 = "Default Value", parameter2 = UrlParameter.Optional }
);