Roteamento: A solicitação atual de ação [...] é ambígua entre os seguintes métodos de ação

100

Tenho uma View chamada Browse.chtml, onde o usuário pode inserir um termo de pesquisa ou deixar o termo de pesquisa em branco. Ao inserir o termo de pesquisa, desejo direcionar a página para http://localhost:62019/Gallery/Browse/{Searchterm} e quando nada for inserido, desejo direcionar o navegador para http://localhost:62019/Gallery/Browse/Start/Here.

Quando tento fazer isso, obtenho o erro:

A solicitação atual de ação 'Browse' no tipo de controlador 'GalleryController' é ambígua entre os seguintes métodos de ação: System.Web.Mvc.ActionResult Browse (System.String) no tipo AutoApp_MVC.Controllers.GalleryController System.Web.Mvc.ActionResult Browse (Int32, System.String) no tipo AutoApp_MVC.Controllers.GalleryController

Tudo que estou fazendo com MVC é pela primeira vez. Não tenho certeza do que mais tentar neste momento.

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

Eu também tenho isso em 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
fonte

Respostas:

161

Você só pode ter no máximo 2 métodos de ação com o mesmo nome em um controlador e, para fazer isso, 1 deve ser [HttpPost]e o outro deve ser [HttpGet].

Como os dois métodos são GET, você deve renomear um dos métodos de ação ou movê-lo para um controlador diferente.

Embora seus 2 métodos de navegação sejam sobrecargas C # válidas, o seletor de método de ação MVC não consegue descobrir qual método invocar. Ele tentará combinar uma rota com o método (ou vice-versa), e este algoritmo não é fortemente tipado.

Você pode realizar o que deseja usando rotas personalizadas apontando para diferentes métodos de ação:

... em 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 no controlador ...

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

Você também pode ser capaz de manter os métodos de ação com o mesmo nome no controlador , aplicando um [ActionName]atributo a um para distingui-lo. Usando o mesmo Global.asax acima, seu controlador ficaria assim:

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
fonte
Então, vou precisar criar uma nova visualização em seu exemplo acima? Parece que não adianta usar a tag ActionName, pois acho que só funciona para renomear todos os métodos de ação (não é possível manter os dois ao mesmo tempo). É bom saber como funciona o MVC. Obrigado.
Dave de
6
Não, você não precisa criar novas visualizações. Você ainda pode reutilizar a mesma visualização para ambas as ações. Basta passar o nome da visualização como o primeiro argumento parareturn View("Browse", summaries);
danludwig
A sobrecarga será incluída em alguma versão futura? A modificação de rotas é um trabalho adicional e manutenção adicional é necessária quando as alterações são feitas.
Old Geezer
@OldGeezer provavelmente não, já que há uma solução alternativa (acima) e porque métodos de ação sobrecarregados em um controlador geralmente não são uma boa ideia.
danludwig 01 de
4

Não sei quando a pergunta foi feita, esta solução estava disponível, mas você pode usar:

Request.QueryString["key"]

Portanto, isso deve funcionar bem para o seu 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);
} 
Saygın Doğu
fonte
2

Adicione o seguinte código em RouteConfig.cs antes da rota padrão

routes.MapMvcAttributeRoutes();

E adicione atributos de rota no controlador como:

    [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
fonte
1

Acho que o que está sendo dito é que você não precisa testar implicitamente os parâmetros da string de consulta usando a classe de solicitação.

MVC faz o mapeamento para você (a menos que você tenha feito mudanças severas em suas rotas MVC).

Assim, um caminho de link de ação de

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

estaria automaticamente disponível para seu controlador (de superfície) com o parâmetro definido:

public ActionResult Logout(string DestinationUrl)

MVC faz o trabalho.

Darren Street
fonte