Routing: bieżące żądanie akcji […] jest niejednoznaczne między następującymi metodami akcji

100

Mam wywoływany widok Browse.chtml, w którym użytkownik może wprowadzić wyszukiwany termin lub pozostawić wyszukiwany termin pusty. Wprowadzając wyszukiwane hasło, chcę skierować stronę do, http://localhost:62019/Gallery/Browse/{Searchterm} a gdy nic nie zostanie wprowadzone, chcę skierować przeglądarkę do http://localhost:62019/Gallery/Browse/Start/Here.

Kiedy próbuję tego, pojawia się błąd:

Bieżące żądanie akcji „Przeglądaj” na kontrolerze typu „GalleryController” jest niejednoznaczne między następującymi metodami akcji: System.Web.Mvc.ActionResult Browse (System.String) na typie AutoApp_MVC.Controllers.GalleryController System.Web.Mvc.ActionResult Browse (Int32, System.String) w typie AutoApp_MVC.Controllers.GalleryController

Wszystko, co robię z MVC, robię po raz pierwszy. Nie wiem, czego jeszcze spróbować w tym momencie.

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

Mam to również w 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
źródło

Odpowiedzi:

161

Możesz mieć maksymalnie 2 metody akcji o tej samej nazwie na kontrolerze i aby to zrobić, 1 musi być [HttpPost], a druga musi być [HttpGet].

Ponieważ obie metody to GET, należy zmienić nazwę jednej z metod akcji lub przenieść ją do innego kontrolera.

Chociaż metody 2 Browse są prawidłowymi przeciążeniami języka C #, selektor metody akcji MVC nie może określić, którą metodę wywołać. Spróbuje dopasować trasę do metody (lub odwrotnie), a ten algorytm nie jest silnie wpisany.

Możesz osiągnąć to, co chcesz, używając niestandardowych tras wskazujących różne metody akcji:

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

... iw kontrolerze ...

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

Możesz również zachować metody akcji o takich samych nazwach w kontrolerze , stosując [ActionName]atrybut do jednej z nich, aby ją odróżnić. Używając tego samego Global.asax co powyżej, twój kontroler wyglądałby tak:

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
źródło
Więc będę musiał utworzyć nowy widok w powyższym przykładzie? Wygląda na to, że użycie tagu ActionName nie pomaga, ponieważ myślę, że działa to tylko w celu zmiany nazwy wszystkich metod akcji (nie można zachować obu jednocześnie). Dobrze jest wiedzieć, jak działa MVC. Dzięki.
Dave
6
Nie, nie musisz tworzyć żadnych nowych widoków. Nadal możesz użyć tego samego widoku do obu działań. Po prostu return View("Browse", summaries);
podaj
Czy przeciążenie zostanie uwzględnione w jakiejś przyszłej wersji? Modyfikowanie tras to dodatkowa praca, a po wprowadzeniu zmian wymagana jest dodatkowa konserwacja.
Old Geezer
@OldGeezer prawdopodobnie nie, ponieważ istnieje obejście (powyżej) i ponieważ przeciążone metody akcji w kontrolerze generalnie nie są dobrym pomysłem.
danludwig
4

Nie wiem, kiedy zadano pytanie, to rozwiązanie było dostępne, ale możesz użyć:

Request.QueryString["key"]

Więc to powinno działać dobrze dla twojego problemu:

[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
źródło
2

Dodaj następujący kod w RouteConfig.cs przed domyślną trasą

routes.MapMvcAttributeRoutes();

I dodaj atrybuty trasy w kontrolerze, takie jak:

    [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
źródło
1

Myślę, że chodzi o to, że nie trzeba niejawnie testować parametrów zapytań przy użyciu klasy żądania.

MVC wykonuje mapowanie za Ciebie (chyba że wprowadziłeś poważne zmiany w trasach MVC).

Tak więc ścieżka actionlink do

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

byłby automatycznie dostępny dla twojego (powierzchniowego) kontrolera ze zdefiniowanym parametrem:

public ActionResult Logout(string DestinationUrl)

MVC wykonuje całą pracę.

Darren Street
źródło