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

C# 您能在ASP.NET MVC中重载控制器方法吗?,c#,asp.net-mvc,overloading,C#,Asp.net Mvc,Overloading,我很想知道您是否可以在ASP.NET MVC中重载控制器方法。每当我尝试时,我都会得到下面的错误。这两个方法接受不同的参数。这是不能做的吗 当前对控制器类型“MyController”的操作“MyMethod”的请求在以下操作方法之间不明确: 据我所知,在使用不同的http方法时,只能使用相同的方法 i、 e 对。通过将每个控制器方法的HttpGet/HttpPost(或等效的AcceptVerbs属性)设置为不同的属性,即HttpGet或HttpPost,但不能两者都设置。这样,它就可以根据请

我很想知道您是否可以在ASP.NET MVC中重载控制器方法。每当我尝试时,我都会得到下面的错误。这两个方法接受不同的参数。这是不能做的吗

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


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

i、 e


对。通过将每个控制器方法的
HttpGet
/
HttpPost
(或等效的
AcceptVerbs
属性)设置为不同的属性,即
HttpGet
HttpPost
,但不能两者都设置。这样,它就可以根据请求的类型判断使用哪种方法

[HttpGet]
public ActionResult Show()
{
   ...
}

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

我的一个建议是,对于这样的情况,应该有一个私有实现,您的两个公共操作方法都依赖该实现来避免代码重复。

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

[ActionName("MyOverloadedName")]
但是,您必须为同一http方法使用不同的操作名称(正如其他人所说)。所以这只是语义上的问题。您希望在代码中使用名称还是在属性中使用名称


Phil有一篇与此相关的文章:

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

以下是一个例子:-


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

您还可以做一些其他事情。。。您需要一个能够有参数而不是参数的方法

为什么不试试这个

public ActionResult Show( string username = null )
{
   ...
}
这对我很有用。。。在这个方法中,您可以实际测试,看看是否有传入参数



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

将基本方法创建为虚拟方法

public virtual ActionResult Index()
将被重写的方法创建为override

public override ActionResult Index()

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

您可以使用单个
操作结果
来处理
Post
Get

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

如果您的
Get
Post
方法具有匹配的签名,则此方法非常有用。

我需要重载:

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

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

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

这主要用于从另一个控制器继承,并希望覆盖来自基本控制器的帐户


否、否和否。请尝试下面的控制器代码,其中“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文章中得到的上述答案-->

我是在MVC5的帮助下实现的。诚然,我是MVC的新手,使用WebForms进行了十年的web开发,但以下几点对我很有用。与接受的答案不同,这允许所有重载操作由同一视图文件呈现

首先在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)
{
    //.....
}

希望这会有所帮助,不会让别人走上错误的道路。:-)

我刚刚遇到这个问题,尽管它现在已经很老了,但它仍然非常相关。具有讽刺意味的是,这篇文章中的一条正确评论是由一位自称是MVC初学者的人在写这篇文章时发表的。甚至ASP.NET文档也不完全正确。我有一个大项目,我成功地重载了操作方法

如果理解路由,除了简单的{controller}/{action}/{id}默认路由模式之外,很明显,控制器操作可以使用任何唯一的模式进行映射。这里有人谈到多态性并说:“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
    }
}
这些操作将处理URL,如
/cars/usa/new york
/cars/usa/texas/dallas
,它们将分别映射到第一个和第二个索引操作

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

默认路由模式的好处是它会自动创建唯一的路由。这是由编译器强制执行的,因为URL将匹配唯一的控制器类型和成员。滚动你自己的路线模式
[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
    }
}
[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);

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