Enrutamiento: la solicitud de acción actual […] es ambigua entre los siguientes métodos de acción

100

Tengo una vista llamada Browse.chtml, donde el usuario puede ingresar un término de búsqueda o dejar el término de búsqueda en blanco. Al ingresar el término de búsqueda, quiero dirigir la página a http://localhost:62019/Gallery/Browse/{Searchterm} y cuando no se ingresa nada, quiero dirigir el navegador a http://localhost:62019/Gallery/Browse/Start/Here.

Cuando intento esto, aparece el error:

La solicitud actual para la acción 'Examinar' en el tipo de controlador 'GalleryController' es ambigua entre los siguientes métodos de acción: System.Web.Mvc.ActionResult Browse (System.String) en el tipo AutoApp_MVC.Controllers.GalleryController System.Web.Mvc.ActionResult Browse (Int32, System.String) en el tipo AutoApp_MVC.Controllers.GalleryController

Todo lo que estoy haciendo con MVC es por primera vez. No estoy seguro de qué más probar en este 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);
}

También tengo esto en 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
fuente

Respuestas:

161

Solo puede tener un máximo de 2 métodos de acción con el mismo nombre en un controlador, y para hacer eso, 1 debe ser [HttpPost]y el otro debe ser [HttpGet].

Dado que ambos métodos son GET, debe cambiar el nombre de uno de los métodos de acción o moverlo a un controlador diferente.

Aunque sus 2 métodos de exploración son sobrecargas válidas de C #, el selector de métodos de acción de MVC no puede averiguar qué método invocar. Intentará hacer coincidir una ruta con el método (o viceversa), y este algoritmo no está fuertemente tipado.

Puede lograr lo que desee utilizando rutas personalizadas que apuntan a diferentes métodos de acción:

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

... y en el 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);
}

También puede mantener los métodos de acción con el mismo nombre en el controlador , aplicando un [ActionName]atributo a uno para distinguirlo. Usando el mismo Global.asax que el anterior, su controlador se vería así:

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
fuente
Entonces, ¿tendré que crear una nueva vista en su ejemplo anterior? Parece que no ayuda usar la etiqueta ActionName, ya que creo que solo funciona para cambiar el nombre de todos los métodos de acción (no se pueden mantener ambos al mismo tiempo). Es bueno saber cómo funciona MVC. Gracias.
Dave
6
No, no es necesario que cree nuevas vistas. Aún puede reutilizar la misma vista para ambas acciones. Simplemente pase el nombre de la vista como primer argumento areturn View("Browse", summaries);
danludwig
¿Se incluirá la sobrecarga en alguna versión futura? La modificación de rutas es un trabajo adicional y se requiere mantenimiento adicional cuando se realizan cambios.
Old Geezer
@OldGeezer probablemente no, ya que hay una solución (arriba) y porque los métodos de acción sobrecargados en un controlador generalmente no son una buena idea.
danludwig
4

No sé cuándo se hizo la pregunta, esta solución estaba disponible, pero puede usar:

Request.QueryString["key"]

Entonces esto debería funcionar bien para su 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
fuente
2

Agregue el siguiente código en RouteConfig.cs antes de la ruta predeterminada

routes.MapMvcAttributeRoutes();

Y agregue atributos de ruta en el 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
fuente
1

Creo que el punto es que no es necesario probar implícitamente los parámetros de la cadena de consulta utilizando la clase de solicitud.

MVC hace el mapeo por usted (a menos que haya realizado cambios severos en sus rutas MVC).

Por lo tanto, una ruta de enlace de acción de

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

estaría automáticamente disponible para su controlador (de superficie) con el parámetro definido:

public ActionResult Logout(string DestinationUrl)

MVC hace el trabajo.

Calle Darren
fuente