Pouvez-vous surcharger les méthodes de controller ASP.NET MVC?

je suis curieux de voir si vous pouvez surcharger les méthodes de contrôle en ASP.NET MVC. Chaque fois que j'essaie, j'obtiens l'erreur ci-dessous. Les deux méthodes acceptent des arguments différents. Est-ce quelque chose qui ne peut pas être fait?

la demande d'action actuelle "MyMethod" sur le type de contrôleur "MyController" est ambiguë entre les méthodes d'action suivantes:

303
demandé sur Wayne Koorts 2009-01-12 23:20:20

16 réponses

Vous pouvez utiliser l'attribut si vous voulez que votre code ne surcharge.

[ActionName("MyOverloadedName")]

mais, vous devrez utiliser un nom d'action différent pour la même méthode http (comme d'autres l'ont dit). Donc c'est juste de la sémantique à ce moment-là. Préférez-vous le nom de votre code ou votre attribut?

Phil a un article à ce sujet: http://haacked.com/archive/2008/08/29/how-a-method-becomes-an-action.aspx

190
répondu JD Conley 2009-01-12 20:37:43

Oui. J'ai pu le faire en paramétrant l'attribut HttpGet / HttpPost (ou l'équivalent AcceptVerbs ) pour chaque méthode de controller à quelque chose de distinct, i.e., HttpGet ou HttpPost , mais pas les deux. De cette façon, il peut dire en fonction du type de requête quelle méthode utiliser.

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

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

une suggestion que j'ai est que, pour un cas comme celui-ci, serait d'avoir une mise en œuvre privée que vos deux méthodes d'Action publique comptent sur pour éviter la duplication de code.

67
répondu tvanfosson 2012-12-13 20:12:01

voici quelque chose d'autre que vous pourriez faire... vous voulez une méthode qui est capable d'avoir un paramètre et non.

pourquoi ne pas essayer ceci...

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

ça a marché pour moi... et dans cette méthode, vous pouvez réellement tester pour voir si vous avez le paramètre entrant.


Mise à jour pour supprimer la syntaxe nulle non valide sur string et utiliser une valeur de paramètre par défaut.
41
répondu Farrel 2012-12-18 22:15:05

non,non et Non. Allez essayer le code du contrôleur ci-dessous où nous avons le "LoadCustomer" surchargé.

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

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

si vous essayez d'invoquer L'action" LoadCustomer " vous obtiendrez l'erreur comme indiqué dans la figure ci-dessous.

enter image description here

polymorphisme fait partie de la programmation C# tandis que HTTP est un protocole. HTTP ne comprend pas le polymorphisme. HTTP fonctionne sur le concept ou L'URL et L'URL ne peut avoir un nom unique. Donc, HTTP N'implémente pas de polymorphisme.

pour corriger la même chose, nous devons utiliser l'attribut" 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");
        }
    }

donc maintenant si vous faites un appel à URL" client/LoadCustomer "l'action" LoadCustomer "sera invoquée et avec la structure D'URL" client/LoadCustomerByName "le" LoadCustomer(string) " sera invoqué.

enter image description here

enter image description here

La réponse ci-dessus j'ai pris cette codeproject article --> MVC Action surcharge

18
répondu Shivprasad Koirala 2014-11-27 23:48:25

pour surmonter ce problème vous pouvez écrire un ActionMethodSelectorAttribute qui examine le MethodInfo pour chaque action et le compare aux valeurs de formulaire postées et rejette ensuite toute méthode pour laquelle les valeurs de formulaire ne correspondent pas (à l'exclusion du nom du bouton, Bien sûr).

voici un exemple: - http://blog.abodit.com/2010/02/asp-net-mvc-ambiguous-match /

mais, ce n'est pas une bonne idée.

15
répondu Ian Mercer 2011-08-22 17:10:37

autant que je sache, vous ne pouvez avoir la même méthode que si vous utilisez des méthodes http différentes.

c'est à dire

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

}

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

}
13
répondu keeney 2009-01-12 20:35:08

j'ai atteint cet objectif avec l'aide de attribut Routing dans MVC5. Certes, je suis nouveau à MVC venant d'une décennie de développement web en utilisant des formulaires Web, mais ce qui suit a fonctionné pour moi. Contrairement à la réponse acceptée, ceci permet à toutes les actions surchargées d'être rendues par le même fichier de vue.

pour la première fois, activez le routage des attributs dans 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 }
        );            
    }
}

décorez votre contrôleur en option classe avec un préfixe de route par défaut.

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

puis décorez vos actions de contrôleur qui se surchargent avec une route commune et des paramètres à convenir. En utilisant les paramètres de type contraint, vous pouvez utiliser le même format URI avec des IDs de différents types.

[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)
{
    //.....
}

espérons que cela aide et ne mène pas quelqu'un sur la mauvaise voie. :- )

9
répondu cookdn 2015-06-03 10:11:05

vous pouvez utiliser un seul ActionResult pour traiter à la fois Post et Get :

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

utile si vos méthodes Get et Post ont des signatures correspondantes.

4
répondu DevDave 2012-12-03 14:49:39

je viens de rencontrer cette question et, même si elle est assez ancienne maintenant, elle est encore très pertinente. Ironiquement, le seul commentaire correct dans ce fil a été posté par un débutant auto-avoué dans MVC quand il a écrit le post. Même Le ASP.NET les docs ne sont pas tout à fait corrects. J'ai un grand projet et j'ai réussi à surcharger les méthodes d'action.

si l'on comprend le routage, au-delà du simple {controller} / {action} / {id} schéma de route par défaut, il peut être évident que les actions du contrôleur peuvent être mappées à l'aide de n'importe quel motif unique. Quelqu'un ici a parlé de polymorphisme et a dit: "HTTP ne comprend pas le polymorphisme", mais routing n'a rien à voir avec HTTP. Il s'agit, en termes simples, d'un mécanisme de correspondance des motifs de chaîne.

la meilleure façon de faire ce travail est d'utiliser les attributs de routage, par exemple:

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

ces actions s'occuperont des urls comme /cars/usa/new-york et /cars/usa/texas/dallas , qui seront première et deuxième actions de L'indice respectivement.

en examinant cet exemple de contrôleur, il est évident qu'il va au-delà du modèle de route par défaut mentionné ci-dessus. La valeur par défaut fonctionne bien si votre structure d'url correspond exactement à vos conventions de nommage de code, mais ce n'est pas toujours le cas. Le Code doit être descriptif du domaine, mais les urls doivent souvent aller plus loin parce que leur contenu doit être basé sur d'autres critères, tels que les exigences de référencement.

le l'avantage du modèle de routage par défaut est qu'il crée automatiquement des routes uniques. Ceci est appliqué par le compilateur puisque les urls vont correspondre aux types de controller uniques et aux membres. Rouler votre propre itinéraire modèles devra être soigneusement pensé pour garantir l'unicité et qu'ils travaillent.

Note importante le seul inconvénient est que l'utilisation du routage pour générer des urls pour des actions surchargées ne fonctionne pas lorsque basé sur un nom d'action, par exemple, lorsque l'utilisation UrlHelper.Action. Mais cela fonctionne si on utilise des routes nommées, par exemple, UrlHelper.RouteUrl. Et l'utilisation de routes nommées est, selon des sources bien respectées, la voie à suivre de toute façon ( http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx / ).

bonne chance!

3
répondu DvS 2016-10-06 13:28:05

j'ai eu besoin d'une surcharge pour:

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

il y avait assez peu d'arguments où j'ai fini par faire ceci:

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

Ce n'est pas la solution idéale, surtout si vous avez beaucoup d'arguments, mais il fonctionne bien pour moi.

2
répondu Kasey Speakman 2013-06-10 21:57:00

vous pouvez utiliser [ActionName ("NewActionName")] pour utiliser la même méthode avec un nom différent:

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");
    }
}
2
répondu Stephen Mooney 2018-01-30 06:45:14

j'ai fait face à la même question dans ma demande aussi. Sans modifier aucune information de méthode, j'ai fourni [ActionName ("SomeMeaningfulName")] sur action head. question résolue

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

        }
1
répondu ಅನಿಲ್ 2016-05-27 11:43:29

créer la méthode de base comme virtuelle

public virtual ActionResult Index()

créer la méthode overridden comme override

public override ActionResult Index()

Edit: ceci ne s'applique évidemment que si la méthode override est dans une classe dérivée qui ne semble pas avoir été l'intention de L'OP.

0
répondu Andiih 2012-06-01 07:49:22

j'aime cette réponse posté dans un autre fil

ceci est principalement utilisé si vous héritez d'un autre contrôleur et que vous voulez annuler une acction du contrôleur de base

ASP.NET MVC-outrepasser une action avec des paramètres différents

0
répondu Keyjote 2017-05-23 12:34:48

une seule signature publique est autorisée pour chaque méthode de contrôle. Si vous essayez de surcharge, de compiler, mais vous obtenez l'erreur d'exécution que vous avez vécu.

si vous n'êtes pas prêt à utiliser des verbes différents (comme les attributs [HttpGet] et [HttpPost] ) pour différencier les méthodes surchargées( qui fonctionneront), ou changer le routage, alors ce qui reste est que vous pouvez soit fournir une autre méthode avec un nom différent, ou vous pouvez envoyer à l'intérieur de la méthode existante. Voici comment je l'ai fait:

une fois, je me suis retrouvé dans une situation où je devais maintenir la compatibilité ascendante. La méthode originale prévoyait deux paramètres, mais la nouvelle n'en avait qu'un. Surcharger comme je m'y attendais n'a pas fonctionné parce que MVC n'a plus trouvé le point d'entrée.

pour résoudre cela, j'ai fait ce qui suit:

  1. a changé les 2 méthodes d'action surchargées du public au privé
  2. a créé une nouvelle méthode publique qui contenait "juste" 2 paramètres de chaîne.

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

bien sûr, il s'agit d'un hack et devrait être remanié plus tard. Mais pour le moment, ça a marché pour moi.

, Vous pouvez aussi créer un répartiteur comme:

public ActionResult DoSomething(string action, string param1, string param2)
{
    switch (action)
    {
        case "update":
            return UpdateAction(param1, param2);
        case "remove":
            return DeleteAction(param1);
    }
}

vous pouvez voir, que UpdateAction a besoin de 2 Paramètres, alors que DeleteAction en a juste besoin.

0
répondu Matt 2017-10-06 07:47:29

Si ceci est une tentative d'utiliser une action GET pour plusieurs vues qui postent à plusieurs actions avec différents modèles, puis essayez d'ajouter une action GET pour chaque action POST qui redirige vers la première action GET pour prevent 404 sur refresh.

Long shot, mais scénario commun.

-1
répondu Panos Roditakis 2016-09-12 16:19:58