Instradamento: l'attuale richiesta di azione […] è ambigua tra i seguenti metodi di azione


100

Ho una vista chiamata Browse.chtml, in cui l'utente può inserire un termine di ricerca o lasciare vuoto il termine di ricerca. Quando inserisco il termine di ricerca, voglio indirizzare la pagina a http://localhost:62019/Gallery/Browse/{Searchterm} e quando non viene inserito nulla, voglio indirizzare il browser a http://localhost:62019/Gallery/Browse/Start/Here.

Quando provo questo, ottengo l'errore:

La richiesta corrente di azione "Sfoglia" sul tipo di controller "GalleryController" è ambigua tra i seguenti metodi di azione: System.Web.Mvc.ActionResult Sfoglia (System.String) sul tipo AutoApp_MVC.Controllers.GalleryController System.Web.Mvc.ActionResult Sfoglia (Int32, System.String) sul tipo AutoApp_MVC.Controllers.GalleryController

Tutto quello che sto facendo con MVC è per la prima volta. Non sono sicuro di cos'altro provare a questo punto.

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

Ho anche questo in 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
         });

Risposte:


161

È possibile avere solo un massimo di 2 metodi di azione con lo stesso nome su un controller e, per farlo, 1 deve essere [HttpPost]e l'altro deve essere [HttpGet].

Poiché entrambi i metodi sono GET, è necessario rinominare uno dei metodi di azione o spostarlo su un controller diverso.

Sebbene i due metodi Browse siano overload C # validi, il selettore del metodo di azione MVC non è in grado di capire quale metodo richiamare. Proverà ad abbinare una rotta al metodo (o viceversa) e questo algoritmo non è fortemente tipizzato.

Puoi ottenere ciò che desideri utilizzando percorsi personalizzati che puntano a diversi metodi di azione:

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

... e nel controller ...

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

Potresti anche essere in grado di mantenere i metodi di azione con lo stesso nome nel controller , applicando un [ActionName]attributo a uno per distinguerlo. Usando lo stesso Global.asax come sopra, il tuo controller sarebbe quindi simile a questo:

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

Quindi, dovrò creare una nuova vista nel tuo esempio sopra? Sembra che non aiuti usare il tag ActionName, dal momento che penso che funzioni solo per rinominare tutti i metodi di azione (impossibile mantenerli entrambi allo stesso tempo). È bello sapere come funziona MVC. Grazie.
Dave

6
No, non è necessario creare nuove visualizzazioni. Puoi comunque riutilizzare la stessa visualizzazione per entrambe le azioni. Basta passare il nome della vista come primo argomento areturn View("Browse", summaries);
danludwig

Il sovraccarico sarà incluso in qualche versione futura? La modifica dei percorsi è un lavoro aggiuntivo ed è necessaria una manutenzione aggiuntiva quando vengono apportate modifiche.
Old Geezer

@OldGeezer probabilmente no, poiché esiste una soluzione alternativa (sopra) e perché i metodi di azione sovraccaricati in un controller generalmente non sono una buona idea.
danludwig

4

Non so quando è stata posta la domanda questa soluzione era disponibile ma puoi usare:

Request.QueryString["key"]

Quindi questo dovrebbe funzionare bene per il tuo problema:

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

2

Aggiungere il codice seguente in RouteConfig.cs prima della route predefinita

routes.MapMvcAttributeRoutes();

E aggiungi attributi di percorso nel controller come:

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

    }

1

Penso che il punto sia che non è necessario testare implicitamente i parametri della stringa di query utilizzando la classe di richiesta.

MVC esegue la mappatura per te (a meno che tu non abbia apportato modifiche sostanziali ai percorsi MVC).

Quindi un percorso actionlink di

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

sarebbe automaticamente disponibile per il tuo controller (di superficie) con il parametro definito:

public ActionResult Logout(string DestinationUrl)

MVC fa il lavoro.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.