我很好奇您是否可以在ASP.NET MVC中重载控制器方法。每当我尝试时,都会出现以下错误。这两种方法接受不同的参数。这是无法完成的事情吗?
在以下操作方法之间,当前对控制器类型“ MyController”的操作“ MyMethod”的请求不明确:
我很好奇您是否可以在ASP.NET MVC中重载控制器方法。每当我尝试时,都会出现以下错误。这两种方法接受不同的参数。这是无法完成的事情吗?
在以下操作方法之间,当前对控制器类型“ MyController”的操作“ MyMethod”的请求不明确:
Answers:
如果希望代码进行重载,则可以使用该属性。
[ActionName("MyOverloadedName")]
但是,对于相同的http方法,您必须使用不同的操作名称(就像其他人所说的那样)。所以这只是语义。您希望在代码或属性中使用名称吗?
菲尔(Phil)有与此相关的文章:http : //haacked.com/archive/2008/08/29/how-a-method-becomes-an-action.aspx
return View();
。例如:return View("MyOverloadedName");
。
是。通过将每个控制器方法的HttpGet
/ HttpPost
(或等效AcceptVerbs
属性)设置为不同的值(即HttpGet
or HttpPost
,但不能同时设置两者),我已经能够做到这一点。这样,它可以根据请求的类型确定使用哪种方法。
[HttpGet]
public ActionResult Show()
{
...
}
[HttpPost]
public ActionResult Show( string userName )
{
...
}
我的一个建议是,对于这样的情况,将有一个私有实现,您的两个公共Action方法都依赖此私有实现来避免重复代码。
Show()
方法具有不同的签名。如果并且当您需要将信息发送到Get版本中时,那么您的Get和Post版本将以相同的签名结尾,并且您将需要该ActionName
属性或本文中提到的其他修补程序之一。
ActionNameAttribute
。实际上,我很少发现这种情况。
这是您可以做的其他事情...您想要一个能够有参数而没有参数的方法。
为什么不试试这个...
public ActionResult Show( string username = null )
{
...
}
这对我有用...在这种方法中,您实际上可以测试一下是否具有传入参数。
string
不能为空。)
string
不能做到nullable
; 但是可以null
!无论哪种方式,我都没有诚意发表最初的评论。
不,不,不。去尝试下面的“ 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)”。
我从此代码项目文章-> MVC Action重载中获取了以上答案
为了克服这个问题,你可以写一个ActionMethodSelectorAttribute
是检查MethodInfo
每个操作的,并将其与发布的Form值进行比较,然后拒绝任何表单值不匹配的方法(当然,不包括按钮名称)。
这是一个示例:-http : //blog.abodit.com/2010/02/asp-net-mvc-ambiguous-match/
但是,这不是一个好主意。
据我所知,当使用不同的http方法时,只能使用相同的方法。
即
[AcceptVerbs("GET")]
public ActionResult MyAction()
{
}
[AcceptVerbs("POST")]
public ActionResult MyAction(FormResult fm)
{
}
[HttpPost]
属性代替[AcceptVerbs("POST")]
。
我已经借助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
{
//.......
然后用适合的通用路径和参数来装饰使彼此过载的控制器动作。使用类型受限的参数,您可以使用具有不同类型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)
{
//.....
}
希望这会有所帮助,并且不会导致别人走错路。:-)
您可以使用一个ActionResult
来处理Post
和Get
:
public ActionResult Example() {
if (Request.HttpMethod.ToUpperInvariant() == "GET") {
// GET
}
else if (Request.HttpMethod.ToUpperInvariant() == "POST") {
// Post
}
}
如果您的Get
和Post
方法具有匹配的签名,则很有用。
我刚刚遇到了这个问题,尽管它已经很老了,但仍然非常重要。具有讽刺意味的是,该主题中的一个正确评论是由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
,它们将分别映射到第一个和第二个Index操作。
检查此示例控制器,很明显它超出了上面提到的默认路由模式。如果您的url结构与您的代码命名约定完全匹配,则默认设置很好用,但是并非总是如此。代码应该描述域,但是url通常需要走得更远,因为它们的内容应该基于其他标准,例如SEO要求。
默认路由模式的好处是它会自动创建唯一的路由。这是由编译器强制执行的,因为url将匹配唯一的控制器类型和成员。滚动自己的路线模式将需要仔细考虑,以确保唯一性并使其起作用。
重要说明:一个缺点是,基于路由名称(例如,使用UrlHelper.Action时),无法使用路由为重载的操作生成url。但是,如果使用命名路由,例如UrlHelper.RouteUrl,它确实可以工作。根据备受尊敬的消息来源,使用命名路由无论如何都是可行的方法(http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/)。
祝好运!
您可以使用[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");
}
}
我需要重载:
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
}
}
这不是一个完美的解决方案,尤其是在您有很多争论的情况下,但对我来说效果很好。
我的应用程序中也遇到了同样的问题。没有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);
}
将基本方法创建为虚拟方法
public virtual ActionResult Index()
创建覆盖方法作为覆盖
public override ActionResult Index()
编辑:显然,仅当override方法在派生类中,这似乎不是OP的意图时,才适用。
每种控制器方法仅允许一个公共签名。如果尝试重载它,它将编译,但您遇到的是运行时错误。
如果您不愿意使用其他动词(例如[HttpGet]
和[HttpPost]
属性)来区分重载的方法(将起作用)或更改路由,那么剩下的就是您可以提供另一个具有不同名称的方法,或者您可以在现有方法内分派。这是我的做法:
我曾经遇到必须保持向后兼容性的情况。原始方法需要两个参数,但新方法只有一个。由于MVC找不到入口点,因此无法按预期方式进行重载。
为了解决这个问题,我做了以下工作:
创建了一个新的公共方法,其中包含“仅” 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);
}
当然,这是一个hack,应该在以后进行重构。但是暂时,它对我有用。
您还可以创建一个调度程序,例如:
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仅需要1个参数。
抱歉耽搁了。我遇到了同样的问题,我发现了一个链接,上面有很好的答案,这对新手有帮助吗
BinaryIntellect网站和作者的所有学分
基本上,有四种情况:使用型动物动词,使用路由选择,以[无动作]属性过载标志和更改与[ActionName] action属性名称
因此,这取决于您的要求和您的情况。
但是,请点击以下链接:
链接:http: //www.binaryintellect.net/articles/8f9d9a8f-7abf-4df6-be8a-9895882ab562.aspx
如果这是尝试对多个视图使用一个GET操作,然后将其发布到具有不同模型的多个操作,则尝试为每个POST操作添加一个GET操作,该操作重定向到第一个GET,以防止刷新404。
远射但常见的情况。