你能重载控制器方法在ASP。净MVC吗?

我很好奇你是否可以重载控制器方法在ASP。净MVC。每当我尝试时,都会得到下面的错误。这两个方法接受不同的参数。这是做不到的事情吗?

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

176591 次浏览

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

即。

[AcceptVerbs("GET")]
public ActionResult MyAction()
{


}


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


}

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

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


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

我的一个建议是,对于这种情况,应该有一个私有实现,你的两个公共Action方法都依赖于它,以避免重复代码。

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

[ActionName("MyOverloadedName")]

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

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

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

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

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

你还可以这么做……您需要一个能够有参数而没有参数的方法。

为什么不试试这个……

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

这对我很有效……在这个方法中,你可以测试是否有传入参数。

人力资源> < p > < 更新删除了字符串上无效的nullable语法,并使用默认参数值

将基方法创建为virtual

public virtual ActionResult Index()

将被覆盖的方法创建为override

public override ActionResult Index()

编辑:这显然只适用于当override方法在一个派生类中,而这似乎不是OP的意图。

你可以使用一个ActionResult来处理PostGet:

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

如果你的GetPost方法有匹配的签名,这很有用。

我需要一个过载:

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

这不是一个完美的解决方案,尤其是当你有很多争论的时候,但它对我来说很有效。

我喜欢这个贴在另一个帖子里的答案

这主要用于从另一个控制器继承,并希望重写来自基本控制器的操作

ASP.NET MVC -覆盖一个动作与不同的参数

不,不,不。去试试下面的控制器代码,在这里我们重载了“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“客户/LoadCustomer”,“LoadCustomer”动作将被调用,URL结构“客户/LoadCustomerByName”,“LoadCustomer(字符串str)”将被调用。

enter image description here

enter image description here

上面的答案我已经从这篇codeproject文章——> MVC动作重载

我已经在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
}
}

这些操作将负责像/cars/usa/new-york/cars/usa/texas/dallas这样的url,它们将分别映射到第一个和第二个索引操作。

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

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

重要提示一个缺点是使用路由为重载操作生成url,当基于操作名称时不起作用,例如,当使用UrlHelper.Action时。但是,如果使用命名路由,例如UrlHelper.RouteUrl,它就可以工作。并且使用命名的路线,根据非常受尊敬的来源,无论如何都是这样(http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/)。

好运!

我在申请的时候也遇到过同样的问题。没有Modifiyig任何方法信息,我已经提供了[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);


}

如果这是尝试对几个视图使用一个GET操作,这些视图POST到不同模型的几个操作,那么尝试为每个POST操作添加一个GET操作,重定向到第一个GET,以防止刷新时出现404。

可能性不大,但很常见。

您可以使用[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");
}
}

每个控制器方法只允许有一个公共签名。如果您试图重载它,它将被编译,但您将得到您所经历的运行时错误。

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

我曾经遇到过必须保持向后兼容性的情况。原来的方法需要两个参数,但新的方法只有一个参数。重载我所期望的方式没有工作,因为MVC不再找到入口点。

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

  1. 将2个重载操作方法从public更改为private
  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);
    }
    

Of course, this is a hack and should be refactored later. But for the time being, it worked for me.

You can also create a dispatcher like:

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只需要一个参数。

抱歉耽搁了。我也遇到过同样的问题,我找到了一个有很好的答案的链接,可以帮助新人

所有的功劳为BinaryIntellect网站和作者

基本上,有四种情况:使用不同的动词使用路由带有[NoAction]属性的过载标记使用[ActionName]更改动作属性名称

这取决于你的需求和你的情况。

无论如何,请点击以下链接:

< p >链接: http://www.binaryintellect.net/articles/8f9d9a8f-7abf-4df6-be8a-9895882ab562.aspx < / p >
  1. 这是对那些正在与同样问题斗争的人的回答。你可以 实现您自己的自定义过滤器 ActionMethodSelectorAttribute。我找到了最好的解决方案 解决了你的问题。

    .net 5项目
  2. 如果你试图实现与web api控制器相同的逻辑,那么使用Microsoft.AspNetCore.Mvc.WebApiCompatShim。这个nuget包提供了ASP中的兼容性。asp.net核心MVC与ASP。NET Web API 2简化现有Web API实现的迁移。请检查这个答案,但考虑一下 从ASP开始。

    . NET Core 3.0, Microsoft.AspNetCore.Mvc.WebApiCompatShim包不再可用