首页 文章

你能在ASP.NET MVC中重载控制器方法吗?

提问于
浏览
306

我很想知道你是否可以重载ASP.NET MVC中的控制器方法 . 每当我尝试时,我都会收到以下错误 . 这两种方法接受不同的论点 . 这是不能做的事吗?

控制器类型'MyController'上的当前操作请求'MyMethod'在以下操作方法之间不明确:

16 回答

  • 0

    如果希望代码执行重载,可以使用该属性 .

    [ActionName("MyOverloadedName")]
    

    但是,你必须为同一个http方法使用不同的动作名称(正如其他人所说) . 所以这就是语义 . 您希望在代码或属性中使用该名称吗?

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

  • 0

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

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

    我的一个建议是,对于这样的情况,将有一个私有实现,你的两个公共Action方法都依赖于它来避免重复代码 .

  • 0

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

    为什么不尝试这个......

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

    这对我有用......在这一种方法中,您可以实际测试以查看是否有传入参数 .


    已更新以删除字符串上的无效可空语法并使用默认参数值 .

  • 13

    不,否和否 . 请尝试下面的控制器代码,我们将“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”操作,则会出现错误,如下图所示 .

    enter image description here

    多态性是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)” .

    enter image description here

    enter image description here

    上面的答案我从这个代码项目文章 - > MVC Action overloading

  • 69

    要解决此问题,您可以编写一个 ActionMethodSelectorAttribute ,检查每个操作的 MethodInfo 并将其与发布的Form值进行比较,然后拒绝任何表单值不匹配的方法(当然不包括按钮名称) .

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

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

  • 3

    据我所知,在使用不同的http方法时,你只能使用相同的方法 .

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

    我已经在MVC5的Attribute Routing的帮助下实现了这一点 . 不可否认,我是使用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
    {
        //.......
    

    然后用适当的路径和参数来装饰你的控制器动作,这些动作相互重载 . 使用类型约束参数,您可以使用具有不同类型ID的相同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)
    {
        //.....
    }
    

    希望这有助于并且不会导致某人走上错误的道路 . :-)

  • 2

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

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

    如果您的 GetPost 方法具有匹配的签名,则非常有用 .

  • 15

    我刚刚遇到过这个问题,即使现在已经很老了,但它仍然非常重要 . 具有讽刺意味的是,这篇帖子中的一个正确评论是由一位自称为MVC的初学者在撰写帖子时发布的 . 即使是ASP.NET文档也不完全正确 . 我有一个大项目,我成功地超载了动作方法 .

    如果理解路由,除了简单的 / / 默认路由模式之外,很明显可以使用任何唯一模式映射控制器操作 . 这里有人谈到多态,并说:“HTTP不理解多态”,但路由与HTTP无关 . 简而言之,它是一种用于字符串模式匹配的机制 .

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

    [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,它们将分别映射到第一个和第二个Index操作 .

    检查这个示例控制器显然它超出了上面提到的默认路由模式 . 如果您的url结构与您的代码命名约定完全匹配,则默认情况很有效,但情况并非总是如此 . 代码应该描述域名,但网址往往需要更进一步,因为它们的内容应该是基于其他标准,如SEO要求 .

    默认路由模式的好处是它会自动创建唯一的路由 . 这是由编译器强制执行的,因为url将匹配唯一的控制器类型和成员 . 滚动自己的路线模式需要仔细考虑,以确保其独特性和工作 .

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

    祝好运!

  • -1

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

    public class HomeController : Controller
    {
        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");
        }
    }
    
  • 1

    我需要一个重载:

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

    这不是一个完美的解决方案,特别是如果你有很多论点,但它适合我 .

  • 3

    我的申请也面临同样的问题 . 如果没有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);
    
            }
    
  • 192

    将基本方法创建为虚拟

    public virtual ActionResult Index()
    

    将覆盖的方法创建为覆盖

    public override ActionResult Index()
    

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

  • 41

    我喜欢在另一个帖子中发布的这个答案

    这主要用于从其他控制器继承并希望覆盖基本控制器的操作

    ASP.NET MVC - Overriding an action with differing parameters

  • 4

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

    如果您不愿意使用不同的动词(例如 [HttpGet][HttpPost] 属性)来区分重载方法(这将起作用)或更改路由,那么剩下的就是您可以提供另一个具有不同名称的方法,或者你可以在现有方法内部发送 . 我是这样做的:

    我曾经遇到过必须保持向后兼容性的情况 . 原始方法预期有两个参数,但新的只有一个参数 . 重载我期望的方式不起作用,因为MVC不再找到入口点 .

    为了解决这个问题,我做了以下事情:

    • 将2个重载的操作方法从公共更改为私有

    • 创建了一个新的公共方法,其中包含“只”2个字符串参数 . 那个人担任调度员,即:

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

    当然,这是一个黑客,应该稍后重构 . 但就目前而言,它对我有用 .

    您还可以创建一个调度程序,如:

    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只需要一个 .

  • 19

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

    远射但常见的情况 .

相关问题