Routage: la demande d'action actuelle […] est ambiguë entre les méthodes d'action suivantes

100

J'ai une vue appelée Browse.chtml, dans laquelle l'utilisateur peut entrer un terme de recherche ou laisser le terme de recherche vide. Lors de la saisie du terme de recherche, je souhaite diriger la page vers http://localhost:62019/Gallery/Browse/{Searchterm} et lorsque rien n'est saisi, je souhaite diriger le navigateur vers http://localhost:62019/Gallery/Browse/Start/Here.

Quand j'essaye ceci, j'obtiens l'erreur:

La demande d'action actuelle 'Parcourir' sur le type de contrôleur 'GalleryController' est ambiguë entre les méthodes d'action suivantes: System.Web.Mvc.ActionResult Browse (System.String) sur le type AutoApp_MVC.Controllers.GalleryController System.Web.Mvc.ActionResult Browse (Int32, System.String) sur le type AutoApp_MVC.Controllers.GalleryController

Tout ce que je fais avec MVC est pour la première fois. Je ne sais pas quoi essayer d'autre à ce stade.

public ActionResult Browse(string id)
{
    var summaries = /* search using id as search term */
    return View(summaries);
}

public ActionResult Browse(string name1, string name2)
{
    var summaries = /* default list when nothing entered */
    return View(summaries);
}

J'ai aussi ceci dans Global.asax.cs:

    routes.MapRoute(
         "StartBrowse",
         "Gallery/Browse/{s1}/{s2}",
         new
         {
             controller = "Gallery",
             action = "Browse",
             s1 = UrlParameter.Optional,
             s2 = UrlParameter.Optional
         });



    routes.MapRoute(
         "ActualBrowse",
         "Gallery/Browse/{searchterm}",
         new
         {
             controller = "Gallery",
             action = "Browse",
             searchterm=UrlParameter.Optional
         });
Dave
la source

Réponses:

161

Vous ne pouvez avoir qu'un maximum de 2 méthodes d'action avec le même nom sur un contrôleur, et pour ce faire, 1 doit être [HttpPost]et l'autre doit l'être [HttpGet].

Étant donné que vos deux méthodes sont GET, vous devez soit renommer l'une des méthodes d'action, soit la déplacer vers un contrôleur différent.

Bien que vos 2 méthodes Browse soient des surcharges C # valides, le sélecteur de méthode d'action MVC ne peut pas déterminer la méthode à appeler. Il essaiera de faire correspondre une route à la méthode (ou vice versa), et cet algorithme n'est pas fortement typé.

Vous pouvez accomplir ce que vous voulez en utilisant des itinéraires personnalisés pointant vers différentes méthodes d'action:

... dans Global.asax

routes.MapRoute( // this route must be declared first, before the one below it
     "StartBrowse",
     "Gallery/Browse/Start/Here",
     new
     {
         controller = "Gallery",
         action = "StartBrowse",
     });

routes.MapRoute(
     "ActualBrowse",
     "Gallery/Browse/{searchterm}",
     new
     {
         controller = "Gallery",
         action = "Browse",
         searchterm = UrlParameter.Optional
     });

... et dans le contrôleur ...

public ActionResult Browse(string id)
{
    var summaries = /* search using id as search term */
    return View(summaries);
}

public ActionResult StartBrowse()
{
    var summaries = /* default list when nothing entered */
    return View(summaries);
}

Vous pouvez également conserver le même nom dans le contrôleur en appliquant un [ActionName]attribut à l'un pour le distinguer. En utilisant le même Global.asax que ci-dessus, votre contrôleur ressemblerait alors à ceci:

public ActionResult Browse(string id)
{
    var summaries = /* search using id as search term */
    return View(summaries);
}

[ActionName("StartBrowse")]
public ActionResult Browse()
{
    var summaries = /* default list when nothing entered */
    return View(summaries);
}
Danludwig
la source
Alors, je devrai créer une nouvelle vue dans votre exemple ci-dessus? Il semble que cela n'aide pas d'utiliser la balise ActionName, car je pense que cela ne fonctionne que pour renommer toutes les méthodes d'action (impossible de conserver les deux en même temps). Il est bon de savoir comment fonctionne MVC. Merci.
Dave
6
Non, vous n'avez pas besoin de créer de nouvelles vues. Vous pouvez toujours réutiliser la même vue pour les deux actions. return View("Browse", summaries);
Passez
La surcharge sera-t-elle incluse dans une prochaine version? La modification des itinéraires est un travail supplémentaire et une maintenance supplémentaire est nécessaire lorsque des modifications sont apportées.
Old Geezer
@OldGeezer probablement pas, car il existe une solution de contournement (ci-dessus), et parce que les méthodes d'action surchargées dans un contrôleur ne sont généralement pas une bonne idée.
danludwig
4

Je ne sais pas quand la question a été posée cette solution était disponible mais vous pouvez utiliser:

Request.QueryString["key"]

Cela devrait donc fonctionner correctement pour votre problème:

[HttpGet]
public ActionResult Browse()
{
    if( Request.QueryString["id"] != null )        
        var summaries = /* search using id as search term */
    else /*assuming you don't have any more option*/
        var summaries = /* default list when nothing entered */

    return View(summaries);
} 
Saygın Doğu
la source
2

Ajouter le code suivant dans RouteConfig.cs avant la route par défaut

routes.MapMvcAttributeRoutes();

Et ajoutez des attributs de route dans le contrôleur comme:

    [Route("Cars/deteals/{id:int}")]
    public ContentResult deteals(int id)
    {
        return Content("<b>Cars ID Is " + id + "</b>");
    }

    [Route("Cars/deteals/{name}")]
    public  ContentResult deteals(string name)
    {
        return Content("<b>Car name Is " + name + "</b>");

    }
omar mohameed
la source
1

Je pense que le point qui est fait est que vous n'avez pas besoin de tester implicitement les paramètres de chaîne de requête en utilisant la classe de requête.

MVC effectue le mappage pour vous (sauf si vous avez apporté des modifications importantes à vos routes MVC).

Ainsi un chemin actionlink de

/umbraco/Surface/LoginSurface/Logout?DestinationUrl=/home/

serait automatiquement disponible pour votre contrôleur (de surface) avec le paramètre défini:

public ActionResult Logout(string DestinationUrl)

MVC fait le travail.

Rue Darren
la source