Question

Je suis curieux de voir si vous pouvez surcharger les méthodes du contrôleur dans 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 "MyMethod" actuelle sur le type de contrôleur "MyController" est ambiguë entre les méthodes d'action suivantes:

Était-ce utile?

La solution

Vous pouvez utiliser l'attribut si vous souhaitez que votre code soit surchargé.

[ActionName("MyOverloadedName")]

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

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

Autres conseils

Oui. J'ai pu le faire en définissant le HttpGet / HttpPost (ou un attribut AcceptVerbs équivalent) pour chaque méthode de contrôleur en quelque chose de distinct, c'est-à-dire , HttpGet ou HttpPost , mais pas les deux. De cette manière, il est possible d'indiquer, en fonction du type de demande, la méthode à utiliser.

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

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

Une de mes suggestions est que, pour un cas comme celui-ci, serait d'avoir une implémentation privée sur laquelle vos deux méthodes d'action publiques s'appuient pour éviter la duplication de code.

Voici une autre chose que vous pouvez faire: vous voulez une méthode capable d’avoir un paramètre et non.

Pourquoi ne pas essayer ceci ...

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

Cela a fonctionné pour moi ... et avec cette seule méthode, vous pouvez réellement tester pour voir si vous avez le paramètre entrant.


Mise à jour pour supprimer la syntaxe nullable non valide sur chaîne et utiliser une valeur de paramètre par défaut.

Non, non et non. Essayez le code du contrôleur ci-dessous où nous avons le code "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’appeler le " LoadCustomer " action, vous obtiendrez une erreur comme indiqué dans la figure ci-dessous.

entrer la description de l'image ici

Le 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 qu'un nom unique. Donc, HTTP n’implémente pas le polymorphisme.

Pour résoudre le même problème, nous devons utiliser " NomAction " attribut.

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

Alors maintenant, si vous appelez l'URL " Client / LoadCustomer " le " LoadCustomer " l'action sera appelée et avec la structure d'URL "quot / Customer / LoadCustomerByName " le " LoadCustomer (string str) " sera invoqué.

entrer la description de l'image ici

entrer la description de l'image ici

La réponse ci-dessus que j'ai tirée de cet article de codeprojet - > Surcharge des actions MVC

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

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

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

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

c'est-à-dire

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

}

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

}

J'ai réalisé cela avec l'aide de Routage d'attributs dans MVC5. Certes, je suis nouveau chez MVC après une décennie de développement Web utilisant WebForms, mais les éléments suivants ont fonctionné pour moi. Contrairement à la réponse acceptée, cela permet à toutes les actions surchargées d'être rendues par le même fichier de vue.

Activez d'abord le routage d'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 éventuellement votre classe de contrôleur avec un préfixe de route par défaut.

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

Décorez ensuite les actions de votre contrôleur qui se surchargent d’un itinéraire commun et de paramètres adaptés. En utilisant des paramètres de type contrainte, vous pouvez utiliser le même format URI avec des identifiants de types différents.

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

J'espère que cela aide et ne conduit pas quelqu'un dans la mauvaise voie. : -)

Vous pouvez utiliser un seul ActionResult pour traiter à la fois les codes Post et Obtenir :

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 identiques.

Je viens juste de tomber sur cette question et, même si elle est assez ancienne maintenant, elle reste très pertinente. Ironiquement, le seul commentaire correct dans ce fil a été posté par un débutant confiant dans MVC quand il a écrit le post. Même les documents ASP.NET ne sont pas tout à fait corrects. J'ai un gros projet et je surcharge avec succès les méthodes d'action.

Si l’on comprend le routage, au-delà du simple modèle de route par défaut {contrôleur} / {action} / {id}, il peut être évident que les actions du contrôleur peuvent être mappées à l’aide de tout modèle unique. Quelqu'un ici a parlé de polymorphisme et a déclaré: "HTTP ne comprend pas le polymorphisme", mais le routage n'a rien à voir avec HTTP. En bref, il s’agit d’un mécanisme de correspondance de modèles de chaînes.

Le meilleur moyen de résoudre ce problème consiste à 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 prendront en charge des URL telles que / cars / usa / new-york et / cars / usa / texas / dallas , qui mapperont au premier et au suivant. deuxième actions d'index, 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 aux conventions de nommage de votre code, mais ce n'est pas toujours le cas. Le code doit être descriptif du domaine, mais les URL doivent souvent aller plus loin, car leur contenu doit être basé sur d'autres critères, tels que les exigences de référencement.

L’avantage du modèle de routage par défaut est qu’il crée automatiquement des itinéraires uniques. Ceci est imposé par le compilateur puisque les URL correspondront à des types de contrôleurs et à des membres uniques. Rouler sur vos propres modèles de parcours nécessitera une réflexion approfondie pour garantir l'unicité et leur efficacité.

Remarque importante L'inconvénient est que l'utilisation du routage pour générer des URL pour les actions surchargées ne fonctionne pas si vous utilisez un nom d'action, par exemple lorsque vous utilisez UrlHelper.Action. Mais cela fonctionne si on utilise des itinéraires nommés, par exemple, UrlHelper.RouteUrl. Et selon des sources respectées, utiliser des itinéraires nommés est néanmoins une solution ( http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/ ).

Bonne chance!

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

J'avais besoin d'une surcharge pour:

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

Il y avait peu d'arguments suffisants 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 une solution parfaite, surtout si vous avez beaucoup d'arguments, mais cela fonctionne bien pour moi.

J'ai également rencontré le même problème dans ma candidature. Sans modifier aucune information de méthode, j'ai fourni [ActionName ("SomeMeaningfulName")] sur Action head. problème résolu

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

        }

Créez la méthode de base en tant que virtuelle

public virtual ActionResult Index()

Créez la méthode remplacée en tant que substitution

public override ActionResult Index()

Éditer: Ceci ne s'applique évidemment que si la méthode de substitution est dans une classe dérivée qui semble ne pas avoir été l'intention du PO.

J'aime cette réponse publiée dans un autre fil

Ceci est principalement utilisé si vous héritez d'un autre contrôleur et souhaitez remplacer une action du contrôleur de base

ASP.NET MVC - Remplacement d'une action avec des paramètres différents

Une seule signature publique est autorisée pour chaque méthode de contrôleur. Si vous essayez de le surcharger, il se compilera, mais vous obtenez l'erreur d'exécution que vous avez rencontrée.

Si vous ne souhaitez pas utiliser différents verbes (comme les attributs [HttpGet] et [HttpPost] ) pour différencier les méthodes surchargées (ce qui fonctionnera), ou Si vous modifiez le routage, il vous reste alors la possibilité de fournir une autre méthode portant un nom différent ou d’envoyer à l’intérieur de la méthode existante. Voici comment je l'ai fait:

Je me suis déjà trouvé dans une situation où je devais maintenir une compatibilité ascendante. La méthode originale prévoyait deux paramètres, mais le nouveau n'en avait qu'un. La surcharge telle que prévue ne fonctionnait pas car MVC ne trouvait plus le point d’entrée.

Pour résoudre ce problème, j’ai fait ce qui suit:

  1. Changement des 2 méthodes d'action surchargées du public au privé
  2. Création d'une nouvelle méthode publique contenant "" just " 2 paramètres de chaîne. Celui-ci a agi en tant que répartiteur, à savoir:

    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 qui devrait être modifié ultérieurement. Mais pour le moment, cela a fonctionné pour moi.

Vous pouvez également créer un répartiteur tel que:

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

Vous pouvez constater que UpdateAction a besoin de 2 paramètres, alors que DeleteAction en a juste besoin.

S'il s'agit d'une tentative d'utilisation d'une action GET pour plusieurs vues que POST en plusieurs actions avec des modèles différents, essayez d'ajouter une action GET pour chaque action POST redirigée vers le premier GET afin d'empêcher l'actualisation du code 404.

Longue mais scénario commun.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top