你可以重载ASP.NET MVC中的控制器方法?

我很好奇,看看你是否可以在ASP.NET MVC中重载控制器方法。 每当我尝试,我得到下面的错误。 这两种方法接受不同的论点。 这是不能做的吗?

当前在控制器types“MyController”上的操作“MyMethod”的请求在以下操作方法之间是不明确的:

如果您希望代码重载,则可以使用该属性。

[ActionName("MyOverloadedName")] 

但是,您必须为同一个http方法使用不同的操作名称(如其他人所说的)。 所以这只是语义。 你想在你的代码或属性中有名字吗?

菲尔有一篇文章与此有关: http : //haacked.com/archive/2008/08/29/how-a-method-becomes-an-action.aspx

是。 我已经能够通过设置每个控制器方法的HttpGet / HttpPost (或等价的AcceptVerbs属性)为不同的东西,即HttpGetHttpPost ,但不是两者。 这样可以根据请求的types来判断使用哪种方法。

 [HttpGet] public ActionResult Show() { ... } [HttpPost] public ActionResult Show( string userName ) { ... } 

我有一个build议是,对于这样的情况,将有一个私人的实现,你的公共行动方法依靠避免重复的代码。

这是你可以做的其他事情…你想要一个能够有一个参数而不是一个方法。

为什么不试试这个…

 public ActionResult Show( string username = null ) { ... } 

这对我来说很有效…在这个方法中,你可以testing你是否有传入的参数。


已更新,以删除string上无效的可空语法并使用默认参数值。

为了克服这个问题,你可以编写一个ActionMethodSelectorAttribute来检查每个操作的MethodInfo ,并将其与发布的Form值进行比较,然后拒绝表单值不匹配的任何方法(当然不包括button名称)。

这是一个例子: – http://blog.abodit.com/2010/02/asp-net-mvc-ambiguous-match/

但是,这不是一个好主意。

否,否和否。转到下面的“LoadCustomer”超载的地方,尝试下面的控制器代码。

 public class CustomerController : Controller { // // GET: /Customer/ public ActionResult LoadCustomer() { return Content("LoadCustomer"); } public ActionResult LoadCustomer(string str) { return Content("LoadCustomer with a string"); } } 

如果您尝试调用“LoadCustomer”操作,则会出现如下图所示的错误。

在这里输入图像说明

多态是C#编程的一部分,而HTTP是协议。 HTTP不了解多态。 HTTP工作在概念或URL上,URL只能有唯一的名字。 所以HTTP不实现多态。

为了解决这个问题,我们需要使用“ActionName”属性。

 public class CustomerController : Controller { // // GET: /Customer/ public ActionResult LoadCustomer() { return Content("LoadCustomer"); } [ActionName("LoadCustomerbyName")] public ActionResult LoadCustomer(string str) { return Content("LoadCustomer with a string"); } } 

因此,现在如果您调用URL“Customer / LoadCustomer”,则将调用“LoadCustomer”操作,并使用URL结构“Customer / LoadCustomerByName”调用“LoadCustomer(string str)”。

在这里输入图像说明

在这里输入图像说明

上面的答案我已经从这个codeproject文章 – > MVC操作重载

据我所知,只有在使用不同的http方法时才能使用相同的方法。

 [AcceptVerbs("GET")] public ActionResult MyAction() { } [AcceptVerbs("POST")] public ActionResult MyAction(FormResult fm) { } 

我已经在MVC5的属性路由的帮助下实现了这一点。 无可否认,我是使用WebForms进行Web开发十年的MVC的新手,但以下方面对我很有帮助。 与接受的答案不同,这允许所有重载操作由同一个视图文件呈现。

首先在App_Start / RouteConfig.cs中启用属性路由。

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

可以用一个默认路由前缀来装饰你的控制器类。

 [RoutePrefix("Returns")] public class ReturnsController : BaseController { //....... 

然后装饰你的控制器动作,使用适合的通用路由和参数重载对方。 使用types约束参数,您可以使用具有不同typesID的相同URI格式。

 [HttpGet] // Returns public ActionResult Index() { //..... } [HttpGet] [Route("View")] // Returns/View public ActionResult View() { // I wouldn't really do this but it proves the concept. int id = 7026; return View(id); } [HttpGet] [Route("View/{id:int}")] // Returns/View/7003 public ActionResult View(int id) { //..... } [HttpGet] [Route("View/{id:Guid}")] // Returns/View/99300046-0ba4-47db-81bf-ba6e3ac3cf01 public ActionResult View(Guid id) { //..... } 

希望这有帮助,而不是把人引向错误的道路。 🙂

您可以使用一个ActionResult来处理PostGet

 public ActionResult Example() { if (Request.HttpMethod.ToUpperInvariant() == "GET") { // GET } else if (Request.HttpMethod.ToUpperInvariant() == "POST") { // Post } } 

如果您的GetPost方法具有匹配的签名,则很有用。

我刚刚遇到这个问题,尽pipe现在已经很老了,但仍然非常相关。 具有讽刺意味的是,这个post中的一个正确的评论是由一个自认交给MVC的初学者发表的。 即使是ASP.NET文档也不完全正确。 我有一个大项目,我成功地重载操作方法。

如果你理解路由,除了简单的{controller} / {action} / {id}默认路由模式外,很明显控制器动作可以使用任何独特的模式进行映射。 这里有人谈到多态性,并说:“HTTP不理解多态性”,但路由与HTTP无关。 简而言之,就是一种string模式匹配的机制。

使这个工作的最好方法是使用路由属性,例如:

 [RoutePrefix("cars/{country:length(3)}")] public class CarHireController { [Route("{location}/{page:int=1}", Name = "CarHireLocation")] public ActionResult Index(string country, string location, int page) { return Index(country, location, null, page); } [Route("{location}/{subLocation}/{page:int=1}", Name = "CarHireSubLocation")] public ActionResult Index(string country, string location, string subLocation, int page) { //The main work goes here } } 

这些行动将照顾像/cars/usa/new-york/cars/usa/texas/dallas ,这将分别映射到第一和第二索引行动。

检查这个示例控制器显然它超出了上面提到的默认路由模式。 如果你的url结构完全符合你的代码命名约定,默认情况下效果很好,但事实并非总是如此。 代码应该描述的领域,但网站往往需要进一步,因为他们的内容应该基于其他标准,如search引擎优化要求。

默认路由模式的好处是它会自动创build唯一的路由。 这由编译器执行,因为urls将匹配唯一的控制器types和成员。 滚动你自己的路线模式将需要仔细的思考,以确保独特性,他们的工作。

重要说明一个缺点是使用路由来生成重载操作的URL时,基于操作名称,例如,当使用UrlHelper.Action时不起作用。 但是,如果使用命名路由,例如UrlHelper.RouteUrl,它也可以工作。 而根据备受推崇的消息来源,使用命名路线是无论如何要走的路( http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/ )。

祝你好运!

我需要一个重载:

 public ActionResult Index(string i); public ActionResult Index(int groupId, int itemId); 

没有足够的论据,我最终这样做了:

 public ActionResult Index(string i, int? groupId, int? itemId) { if (!string.IsNullOrWhitespace(i)) { // parse i for the id } else if (groupId.HasValue && itemId.HasValue) { // use groupId and itemId for the id } } 

这不是一个完美的解决scheme,特别是如果你有很多争论,但是对我来说效果很好。

创build基本方法为虚拟

 public virtual ActionResult Index() 

创build覆盖的方法作为重写

 public override ActionResult Index() 

编辑:这显然只适用于覆盖方法是派生类似乎不是OP的意图。

我喜欢这个答案张贴在另一个线程

这主要用于从另一个控制器inheritance并且想要覆盖来自基础控制器的访问

ASP.NET MVC – 用不同的参数覆盖一个动作

我的应用程序也面临同样的问题。 如果没有Modifiyig任何方法信息,我已经在Action头上提供了[ActionName(“SomeMeaningfulName”)]。 问题解决了

 [ActionName("_EmployeeDetailsByModel")] public PartialViewResult _EmployeeDetails(Employee model) { // Some Operation return PartialView(model); } } [ActionName("_EmployeeDetailsByModelWithPagination")] public PartialViewResult _EmployeeDetails(Employee model,int Page,int PageSize) { // Some Operation return PartialView(model); } 

您可以使用[ActionName(“NewActionName”)]以不同的名称使用相同的方法。

公共类HomeController:控制器
{

  public ActionResult GetEmpName() { return Content("This is the test Message"); } [ActionName("GetEmpWithCode")] public ActionResult GetEmpName(string EmpCode) { return Content("This is the test Messagewith Overloaded"); } } 

每个控制器方法只允许一个公共签名。 如果你试图重载它,它会编译,但是你得到了你遇到的运行时错误。

如果你不愿意使用不同的动词(如[HttpGet][HttpPost]属性)来区分重载的方法(这将工作),或改变路由,剩下的是,你可以提供另一种方法不同的名字,或者你可以在现有的方法内派发。 以下是我如何做到的:

我曾经遇到过要维护向后兼容性的情况。 原来的方法预计两个参数,但新的只有一个。 重载我所期望的方式不起作用,因为MVC没有find入口点了。

为了解决这个问题,我做了以下工作:

  1. 将2个重载的操作方法从公共更改为私有
  2. 创build了一个包含“只”2个string参数的新的公共方法。 那一个充当调度员,即:

     public ActionResult DoSomething(string param1, string param2) { if (string.IsNullOrEmpty(param2)) { return DoSomething(ProductName: param1); } else { int oldId = int.Parse(param1); return DoSomething(OldParam: param1, OldId: oldId); } } private ActionResult DoSomething(string OldParam, int OldId) { // some code here return Json(result); } private ActionResult DoSomething(string ProductName) { // some code here return Json(result); } 

当然,这是一个黑客,应该在以后重构。 但就目前而言,这对我很有帮助。

您也可以创build一个调度程序,如:

 public ActionResult DoSomething(string action, string param1, string param2) { switch (action) { case "update": return UpdateAction(param1, param2); case "remove": return DeleteAction(param1); } } 

你可以看到,UpdateAction需要2个参数,而DeleteAction只需要一个参数。

如果这是尝试对多个使用不同模型的多个操作进行POST的视图使用一个GET操作,则尝试为每个POST操作添加一个GET操作,以redirect到第一个GET,以防止404刷新。

远射,但常见的情况。