简体   繁体   English

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

[英]Can you overload controller methods in ASP.NET MVC?

I'm curious to see if you can overload controller methods in ASP.NET MVC.我很好奇您是否可以在 ASP.NET MVC 中重载控制器方法。 Whenever I try, I get the error below.每当我尝试时,都会收到以下错误。 The two methods accept different arguments.这两种方法接受不同的参数。 Is this something that cannot be done?这是不能做的事吗?

The current request for action 'MyMethod' on controller type 'MyController' is ambiguous between the following action methods:当前对控制器类型“MyController”的操作“MyMethod”的请求在以下操作方法之间不明确:

You can use the attribute if you want your code to do overloading.如果您希望代码进行重载,则可以使用该属性。

[ActionName("MyOverloadedName")]

But, you'll have to use a different action name for the same http method (as others have said).但是,您必须为相同的 http 方法使用不同的操作名称(正如其他人所说)。 So it's just semantics at that point.所以在这一点上它只是语义。 Would you rather have the name in your code or your attribute?您更愿意在代码或属性中使用名称吗?

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

Yes.是的。 I've been able to do this by setting the HttpGet / HttpPost (or equivalent AcceptVerbs attribute) for each controller method to something distinct, ie, HttpGet or HttpPost , but not both.我已经能够通过将每个控制器方法的HttpGet / HttpPost (或等效的AcceptVerbs属性)设置为不同的东西来做到这一点,即HttpGetHttpPost ,但不能同时设置两者。 That way it can tell based on the type of request which method to use.这样它就可以根据请求的类型判断使用哪种方法。

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

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

One suggestion I have is that, for a case like this, would be to have a private implementation that both of your public Action methods rely on to avoid duplicating code.我的一个建议是,对于这样的情况,应该有一个私有实现,您的两个公共 Action 方法都依赖该实现来避免重复代码。

Here's something else you could do... you want a method that is able to have a parameter and not.这是你可以做的其他事情......你想要一个能够有参数而不是的方法。

Why not try this...为什么不试试这个...

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

This has worked for me... and in this one method, you can actually test to see if you have the incoming parameter.这对我有用......在这种方法中,您实际上可以测试以查看是否有传入参数。


Updated to remove the invalid nullable syntax on string and use a default parameter value. 更新以删除字符串上无效的可为空的语法并使用默认参数值。

No,No and No. Go and try the controller code below where we have the "LoadCustomer" overloaded.不,不,不。去试试下面的控制器代码,我们重载了“LoadCustomer”。

public class CustomerController : Controller
    {
        //
        // GET: /Customer/

        public ActionResult LoadCustomer()
        {
            return Content("LoadCustomer");
        }
        public ActionResult LoadCustomer(string str)
        {
            return Content("LoadCustomer with a string");
        }
    }

If you try to invoke the "LoadCustomer" action you will get error as shown in the below figure.如果您尝试调用“LoadCustomer”操作,您将收到如下图所示的错误。

在此处输入图片说明

Polymorphism is a part of C# programming while HTTP is a protocol.多态是 C# 编程的一部分,而 HTTP 是一种协议。 HTTP does not understand polymorphism. HTTP 不理解多态性。 HTTP works on the concept's or URL and URL can only have unique name's. HTTP 适用于概念或 URL,而 URL 只能具有唯一名称。 So HTTP does not implement polymorphism.所以 HTTP 没有实现多态。

In order to fix the same we need to use "ActionName" attribute.为了解决这个问题,我们需要使用“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");
        }
    }

So now if you make a call to URL "Customer/LoadCustomer" the "LoadCustomer" action will be invoked and with URL structure "Customer/LoadCustomerByName" the "LoadCustomer(string str)" will be invoked.因此,现在如果您调用 URL“Customer/LoadCustomer”,将调用“LoadCustomer”操作,并使用 URL 结构“Customer/LoadCustomerByName”调用“LoadCustomer(string str)”。

在此处输入图片说明

在此处输入图片说明

The above answer i have taken from this codeproject article --> MVC Action overloading我从这篇 codeproject 文章中获得的上述答案 --> MVC Action 重载

To overcome this problem you can write an ActionMethodSelectorAttribute that examines the MethodInfo for each action and compares it to the posted Form values and then rejects any method for which the form values don't match (excluding the button name, of course).为了克服这个问题,您可以编写一个ActionMethodSelectorAttribute来检查每个操作的MethodInfo并将其与发布的表单值进行比较,然后拒绝任何表单值不匹配的方法(当然不包括按钮名称)。

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

BUT, this isn't a good idea.但是,这不是一个好主意。

As far as I know you can only have the same method when using different http methods.据我所知,在使用不同的 http 方法时,您只能使用相同的方法。

ie IE

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

}

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

}

I have achieved this with the help of Attribute Routing in MVC5.我在 MVC5 中的属性路由的帮助下实现了这一点。 Admittedly I am new to MVC coming from a decade of web development using WebForms, but the following has worked for me.诚然,我是 MVC 的新手,使用 WebForms 进行了十年的 Web 开发,但以下内容对我有用。 Unlike the accepted answer this allows all the overloaded actions to be rendered by the same view file.与接受的答案不同,这允许所有重载的动作由同一个视图文件呈现。

First enable Attribute Routing in App_Start/RouteConfig.cs.首先在 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 }
        );            
    }
}

Optionally decorate your controller class with a default route prefix. (可选)使用默认路由前缀装饰您的控制器类。

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

Then decorate your controller actions that overload each other with a common route and parameters to suit.然后用通用的路由和参数来装饰你的控制器动作,这些动作会相互重载以适应。 Using type constrained parameters you can use the same URI format with IDs of different types.使用类型约束参数,您可以对不同类型的 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)
{
    //.....
}

Hope this helps and is not leading somebody down the wrong path.希望这会有所帮助,并且不会导致某人走上错误的道路。 :-) :-)

You could use a single ActionResult to deal with both Post and Get :您可以使用单个ActionResult来处理PostGet

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

Useful if your Get and Post methods have matching signatures.如果您的GetPost方法具有匹配的签名,则很有用。

I've just come across this question and, even though it's quite old now, it's still very relevant.我刚刚遇到这个问题,尽管它现在已经很老了,但它仍然非常相关。 Ironically, the one correct comment in this thread was posted by a self-confessed beginner in MVC when he wrote the post.具有讽刺意味的是,这个帖子中一个正确的评论是由一位自称是 MVC 初学者的人在写这篇文章时发表的。 Even the ASP.NET docs are not entirely correct.甚至 ASP.NET 文档也不完全正确。 I have a large project and I successfully overload action methods.我有一个大项目,我成功地重载了动作方法。

If one understands routing, beyond the simple {controller}/{action}/{id} default route pattern, it might be obvious that controller actions can be mapped using any unique pattern.如果理解路由,除了简单的 {controller}/{action}/{id} 默认路由模式之外,很明显可以使用任何独特的模式来映射控制器操作。 Someone here talked about polymorphism and said: "HTTP does not understand polymorphism", but routing has nothing to do with HTTP.这里有人讲多态说:“HTTP不懂多态”,但是路由和HTTP没有关系。 It is, simply put, a mechanism for string pattern matching.简单地说,它是一种字符串模式匹配机制。

The best way to make this work is to use the routing attributes, for example:使这项工作的最佳方法是使用路由属性,例如:

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

These actions will take care of urls like /cars/usa/new-york and /cars/usa/texas/dallas , which will map to the first and second Index actions respectively.这些操作将处理/cars/usa/new-york/cars/usa/texas/dallas等网址,它们将分别映射到第一个和第二个索引操作。

Examining this example controller it's evident that it goes beyond the default route pattern mentioned above.检查这个示例控制器,很明显它超出了上面提到的默认路由模式。 The default works well if your url structure exactly matches your code naming conventions, but this is not always the case.如果您的 url 结构与您的代码命名约定完全匹配,则默认设置效果很好,但情况并非总是如此。 Code should be descriptive of the domain, but urls often need to go further because their content should be based on other criteria, such as SEO requirements.代码应该描述域,但 url 通常需要更进一步,因为它们的内容应该基于其他标准,例如 SEO 要求。

The benefit of the default routing pattern is that it automatically creates unique routes.默认路由模式的好处是它会自动创建唯一的路由。 This is enforced by the compiler since urls will match unique controller types and members.这是由编译器强制执行的,因为 url 将匹配唯一的控制器类型和成员。 Rolling your own route patterns will require careful thought to ensure uniqueness and that they work.滚动您自己的路线模式需要仔细考虑以确保唯一性并且它们有效。

Important note The one drawback is that using routing to generate urls for overloaded actions does not work when based on an action name, eg, when using UrlHelper.Action.重要说明一个缺点是,当基于动作名称时,例如使用 UrlHelper.Action 时,使用路由为重载动作生成 url 不起作用。 But it does work if one uses named routes, eg, UrlHelper.RouteUrl.但如果使用命名路由,例如 UrlHelper.RouteUrl,它确实有效。 And using named routes is, according to well respected sources, the way to go anyhow ( http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/ ).根据备受推崇的消息来源,使用命名路由是无论如何都要走的路( http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/ )。

Good luck!祝你好运!

You can use [ActionName("NewActionName")] to use the same method with a different name:您可以使用 [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");
    }
}

I needed an overload for:我需要一个重载:

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

There were few enough arguments where I ended up doing this:我最终这样做的论据很少:

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

It's not a perfect solution, especially if you have a lot of arguments, but it works well for me.这不是一个完美的解决方案,特别是如果你有很多争论,但它对我来说效果很好。

I have faced same issue in my application too.我的申请中也遇到了同样的问题。 Without Modifiyig any Method information, I have provided [ActionName("SomeMeaningfulName")] on Action head.在没有修改任何方法信息的情况下,我在 Action 头上提供了 [ActionName("SomeMeaningfulName")]。 issue resolved问题解决了

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

        }

I like this answer posted in another thread我喜欢在另一个帖子中发布的这个答案

This is mainly used if you inherit from another controller and want to override an acction from the base controller这主要用于如果您从另一个控制器继承并希望覆盖来自基本控制器的操作

ASP.NET MVC - Overriding an action with differing parameters ASP.NET MVC - 覆盖具有不同参数的操作

There is only one public signature allowed for each controller method.每个控制器方法只允许一个公共签名。 If you try to overload it, it will compile, but you're getting the run-time error you've experienced.如果您尝试重载它,它将编译,但您会遇到您遇到的运行时错误。

If you're not willing to use different verbs (like the [HttpGet] and [HttpPost] attributes) to differentiate overloaded methods (which will work), or change the routing, then what remains is that you can either provide another method with a different name, or you can dispatch inside of the existing method.如果您不愿意使用不同的动词(如[HttpGet][HttpPost]属性)来区分重载方法(这将起作用)或更改路由,那么剩下的就是您可以提供另一种方法不同的名称,或者您可以在现有方法内部调度。 Here's how I did it:这是我如何做到的:

I once came into a situation where I had to maintain backwards compatibility.我曾经遇到过必须保持向后兼容性的情况。 The original method expected two parameters, but the new one had only one.原始方法需要两个参数,但新方法只有一个。 Overloading the way I expected did not work because MVC didn't find the entry point any more.以我预期的方式重载不起作用,因为 MVC 不再找到入口点。

To solve that, I did the following:为了解决这个问题,我做了以下事情:

  1. Changed the 2 overloaded action methods from public to private将 2 个重载的 action 方法从 public 更改为 private
  2. Created one new public method which contained "just" 2 string parameters.创建了一个包含“仅”2 个字符串参数的新公共方法。 That one acted as a dispatcher, ie:那个充当调度员的角色,即:

     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.当然,这是一个 hack,以后应该重构。 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);
    }
}

You can see, that UpdateAction needs 2 parameters, while DeleteAction just needs one.你可以看到,UpdateAction 需要 2 个参数,而 DeleteAction 只需要一个。

Sorry for the delay.抱歉耽搁了。 I was with the same problem and I found a link with good answers, could that will help new guys我遇到了同样的问题,我找到了一个很好答案的链接,这对新人有帮助吗

All credits for BinaryIntellect web site and the authors BinaryIntellect 网站和作者的所有学分

Basically, there are four situations: using differents verbs , using routing , overload marking with [NoAction] attribute and change the action attribute name with [ActionName]基本上有四种情况:使用不同动词使用路由使用 [NoAction] 属性进行重载标记以及使用 [ActionName] 更改动作属性名称

So, depends that's your requiriments and your situation.所以,这取决于你的要求和你的情况。

Howsoever, follow the link:但是,请按照以下链接操作:

Link: http://www.binaryintellect.net/articles/8f9d9a8f-7abf-4df6-be8a-9895882ab562.aspx链接: http : //www.binaryintellect.net/articles/8f9d9a8f-7abf-4df6-be8a-9895882ab562.aspx

  1. This answer for those who struggling with the same issue.这是为那些在同一问题上苦苦挣扎的人提供的答案。 You can implement your own custom filter based on ActionMethodSelectorAttribute.您可以基于 ActionMethodSelectorAttribute 实现自己的自定义过滤器。 Here I found the best solution for solving your question.在这里,我找到了解决您问题的最佳解决方案。 Works fine on .net 5 project.在 .net 5 项目上工作正常。

  2. If you try to implement the same logic as was in web api controllers then use Microsoft.AspNetCore.Mvc.WebApiCompatShim.如果您尝试实现与 Web api 控制器中相同的逻辑,请使用 Microsoft.AspNetCore.Mvc.WebApiCompatShim。 This nuget package provides compatibility in ASP.NET Core MVC with ASP.NET Web API 2 to simplify migration of existing Web API implementations.此 nuget 包提供 ASP.NET Core MVC 与 ASP.NET Web API 2 的兼容性,以简化现有 Web API 实现的迁移。 Please check this answer but consider that starting with ASP.NET Core 3.0, the Microsoft.AspNetCore.Mvc.WebApiCompatShim package is no longer available.请检查此答案,但请考虑从 ASP.NET Core 3.0 开始,Microsoft.AspNetCore.Mvc.WebApiCompatShim 包不再可用。

Create the base method as virtual将基本方法创建为虚拟

public virtual ActionResult Index()

Create the overridden method as override创建覆盖的方法作为覆盖

public override ActionResult Index()

Edit: This obviously applies only if the override method is in a derived class which appears not to have been the OP's intention.编辑:这显然仅适用于覆盖方法位于派生类中的情况,而派生类似乎不是 OP 的意图。

If this is an attempt to use one GET action for several views that POST to several actions with different models, then try add a GET action for each POST action that redirects to the first GET to prevent 404 on refresh.如果这是尝试对多个视图使用一个 GET 操作,这些视图将 POST 到具有不同模型的多个操作,然后尝试为每个重定向到第一个 GET 的 POST 操作添加一个 GET 操作,以防止刷新时出现 404。

Long shot but common scenario.远射但常见的场景。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM