Pregunta

Tengo curiosidad por ver si puede sobrecargar los métodos de controlador en ASP.NET MVC. Cada vez que lo intento, aparece el siguiente error. Los dos métodos aceptan argumentos diferentes. ¿Es esto algo que no se puede hacer?

  

La solicitud actual de acción 'MyMethod' en el tipo de controlador 'MyController' es ambigua entre los siguientes métodos de acción:

¿Fue útil?

Solución

Puede usar el atributo si desea que su código se sobrecargue.

[ActionName("MyOverloadedName")]

Pero, tendrá que usar un nombre de acción diferente para el mismo método http (como han dicho otros). Entonces es solo semántica en ese punto. ¿Prefieres tener el nombre en tu código o tu atributo?

Phil tiene un artículo relacionado con esto: http://haacked.com/archive/2008/08/29/how-a-method-becomes-an-action.aspx

Otros consejos

Sí He podido hacer esto estableciendo el HttpGet / HttpPost (o el atributo equivalente AcceptVerbs ) para cada método de controlador en algo distinto, es decir , HttpGet o HttpPost , pero no ambos. De esa manera, puede determinar, según el tipo de solicitud, qué método utilizar.

[HttpGet]
public ActionResult Show()
{
   ...
}

[HttpPost]
public ActionResult Show( string userName )
{
   ...
}

Una sugerencia que tengo es que, para un caso como este, sería tener una implementación privada en la que confíen ambos métodos de Acción públicos para evitar la duplicación de código.

Aquí hay algo más que podría hacer ... desea un método que pueda tener un parámetro y no.

¿Por qué no pruebas esto?

public ActionResult Show( string username = null )
{
   ...
}

Esto me ha funcionado ... y en este método, puedes probar para ver si tienes el parámetro entrante.


Actualizado para eliminar la sintaxis anulable no válida en la cadena y usar un valor de parámetro predeterminado.

No, No y No. Vaya y pruebe el código del controlador a continuación donde tenemos el " LoadCustomer " sobrecargado.

public class CustomerController : Controller
    {
        //
        // GET: /Customer/

        public ActionResult LoadCustomer()
        {
            return Content("LoadCustomer");
        }
        public ActionResult LoadCustomer(string str)
        {
            return Content("LoadCustomer with a string");
        }
    }

Si intenta invocar el " LoadCustomer " acción obtendrá un error como se muestra en la siguiente figura.

ingrese la descripción de la imagen aquí

El polimorfismo es parte de la programación de C #, mientras que HTTP es un protocolo. HTTP no entiende el polimorfismo. HTTP funciona en el concepto o URL y la URL solo puede tener nombres únicos. Entonces HTTP no implementa el polimorfismo.

Para solucionar el problema, debemos usar " ActionName " atributo.

public class CustomerController : Controller
    {
        //
        // GET: /Customer/

        public ActionResult LoadCustomer()
        {
            return Content("LoadCustomer");
        }

        [ActionName("LoadCustomerbyName")]
        public ActionResult LoadCustomer(string str)
        {
            return Content("LoadCustomer with a string");
        }
    }

Entonces, si realiza una llamada a URL " Customer / LoadCustomer " el " LoadCustomer " se invocará la acción y con la estructura de URL " Customer / LoadCustomerByName " el " LoadCustomer (string str) " será invocado

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

La respuesta anterior que tomé de este artículo de codeproject - > MVC Action overloading

Para superar este problema, puede escribir un ActionMethodSelectorAttribute que examina el MethodInfo para cada acción y lo compara con los valores de formulario publicados y luego rechaza cualquier método para el que los valores del formulario no coincidan (excluyendo el nombre del botón, por supuesto).

Aquí hay un ejemplo: - http: // blog. abodit.com/2010/02/asp-net-mvc-ambiguous-match/

PERO, esta no es una buena idea.

Hasta donde yo sé, solo puede tener el mismo método cuando se utilizan diferentes métodos http.

es decir

[AcceptVerbs("GET")]
public ActionResult MyAction()
{

}

[AcceptVerbs("POST")]
public ActionResult MyAction(FormResult fm)
{

}

Lo he logrado con la ayuda de Enrutamiento de atributos en MVC5. Es cierto que soy nuevo en MVC luego de una década de desarrollo web usando WebForms, pero lo siguiente me ha funcionado. A diferencia de la respuesta aceptada, esto permite que todas las acciones sobrecargadas sean representadas por el mismo archivo de vista.

Primero habilite el enrutamiento de atributos en App_Start / RouteConfig.cs.

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapMvcAttributeRoutes();

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );            
    }
}

Opcionalmente decora tu clase de controlador con un prefijo de ruta predeterminado.

[RoutePrefix("Returns")]
public class ReturnsController : BaseController
{
    //.......

Luego decora las acciones de tu controlador que se sobrecargan entre sí con una ruta y parámetros comunes que se adapten. Al usar parámetros de tipo restringido, puede usar el mismo formato de URI con ID de diferentes tipos.

[HttpGet]
// Returns
public ActionResult Index()
{
    //.....
}

[HttpGet]
[Route("View")]
// Returns/View
public ActionResult View()
{
    // I wouldn't really do this but it proves the concept.
    int id = 7026;
    return View(id);
}

[HttpGet]
[Route("View/{id:int}")]
// Returns/View/7003
public ActionResult View(int id)
{
    //.....
}

[HttpGet]
[Route("View/{id:Guid}")]
// Returns/View/99300046-0ba4-47db-81bf-ba6e3ac3cf01
public ActionResult View(Guid id)
{
    //.....
}

Espero que esto ayude y no esté guiando a alguien por el camino equivocado. :-)

Podría usar un solo ActionResult para tratar tanto con Post como Get :

public ActionResult Example() {
   if (Request.HttpMethod.ToUpperInvariant() == "GET") {
    // GET
   }
   else if (Request.HttpMethod.ToUpperInvariant() == "POST") {
     // Post  
   }
}

Útil si sus métodos Get y Post tienen firmas coincidentes.

Acabo de encontrar esta pregunta y, aunque ahora es bastante antigua, sigue siendo muy relevante. Irónicamente, el único comentario correcto en este hilo fue publicado por un principiante confeso en MVC cuando escribió la publicación. Incluso los documentos ASP.NET no son del todo correctos. Tengo un gran proyecto y sobrecargo con éxito los métodos de acción.

Si uno entiende el enrutamiento, más allá del simple patrón de ruta predeterminado {controller} / {action} / {id}, puede ser obvio que las acciones del controlador pueden asignarse utilizando cualquier patrón único. Alguien aquí habló sobre el polimorfismo y dijo: "HTTP no entiende el polimorfismo", pero el enrutamiento no tiene nada que ver con HTTP. Es, simplemente, un mecanismo para la coincidencia de patrones de cadena.

La mejor manera de hacer que esto funcione es usar los atributos de enrutamiento, por ejemplo:

[RoutePrefix("cars/{country:length(3)}")]
public class CarHireController
{
    [Route("{location}/{page:int=1}", Name = "CarHireLocation")]
    public ActionResult Index(string country, string location, int page)
    {
        return Index(country, location, null, page);
    }

    [Route("{location}/{subLocation}/{page:int=1}", Name = "CarHireSubLocation")]
    public ActionResult Index(string country, string location, string subLocation, int page)
    {
        //The main work goes here
    }
}

Estas acciones se encargarán de URL como / cars / usa / new-york y / cars / usa / texas / dallas , que se asignarán a la primera y segundas acciones del índice, respectivamente.

Al examinar este controlador de ejemplo, es evidente que va más allá del patrón de ruta predeterminado mencionado anteriormente. El valor predeterminado funciona bien si su estructura de URL coincide exactamente con las convenciones de denominación de código, pero este no es siempre el caso. El código debe ser descriptivo del dominio, pero las URL a menudo necesitan ir más allá porque su contenido debe basarse en otros criterios, como los requisitos de SEO.

El beneficio del patrón de enrutamiento predeterminado es que crea automáticamente rutas únicas. El compilador lo aplica, ya que las URL coincidirán con tipos y miembros de controlador únicos. La elaboración de sus propios patrones de ruta requerirá una cuidadosa reflexión para garantizar la unicidad y que funcionen.

Nota importante El único inconveniente es que el uso de enrutamiento para generar URL para acciones sobrecargadas no funciona cuando se basa en un nombre de acción, por ejemplo, cuando se usa UrlHelper.Action. Pero funciona si uno usa rutas con nombre, por ejemplo, UrlHelper.RouteUrl. Y el uso de rutas con nombre es, según fuentes muy respetadas, el camino a seguir de todos modos ( http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/ ).

¡Buena suerte!

Puede usar [ActionName (" NewActionName ")] para usar el mismo método con un nombre diferente:

public class HomeController : Controller
{
    public ActionResult GetEmpName()
    {
        return Content("This is the test Message");
    }

    [ActionName("GetEmpWithCode")]
    public ActionResult GetEmpName(string EmpCode)
    {
        return Content("This is the test Messagewith Overloaded");
    }
}

Necesitaba una sobrecarga para:

public ActionResult Index(string i);
public ActionResult Index(int groupId, int itemId);

Hubo pocos argumentos suficientes donde terminé haciendo esto:

public ActionResult Index(string i, int? groupId, int? itemId)
{
    if (!string.IsNullOrWhitespace(i))
    {
        // parse i for the id
    }
    else if (groupId.HasValue && itemId.HasValue)
    {
        // use groupId and itemId for the id
    }
}

No es una solución perfecta, especialmente si tienes muchos argumentos, pero funciona bien para mí.

También he enfrentado el mismo problema en mi aplicación. Sin modificar ninguna información del Método, he proporcionado [ActionName (" SomeMeaningfulName ")] en el encabezado de Action. problema resuelto

[ActionName("_EmployeeDetailsByModel")]
        public PartialViewResult _EmployeeDetails(Employee model)
        {
            // Some Operation                
                return PartialView(model);
            }
        }

[ActionName("_EmployeeDetailsByModelWithPagination")]
        public PartialViewResult _EmployeeDetails(Employee model,int Page,int PageSize)
        {

                // Some Operation
                return PartialView(model);

        }

Crear el método base como virtual

public virtual ActionResult Index()

Crear el método anulado como anulación

public override ActionResult Index()

Editar: Esto obviamente se aplica solo si el método de anulación se encuentra en una clase derivada que parece no haber sido la intención del OP.

Me gusta esta respuesta publicada en otro hilo

Esto se usa principalmente si hereda de otro controlador y desea anular una acción del controlador base

ASP.NET MVC: anulación de una acción con diferentes parámetros

Solo se permite una firma pública para cada método de controlador. Si intenta sobrecargarlo, se compilará, pero obtendrá el error de tiempo de ejecución que ha experimentado.

Si no está dispuesto a usar diferentes verbos (como los atributos [HttpGet] y [HttpPost] ) para diferenciar los métodos sobrecargados (que funcionarán), o cambie el enrutamiento, lo que queda es que puede proporcionar otro método con un nombre diferente o puede enviarlo dentro del método existente. Así es como lo hice:

Una vez llegué a una situación en la que tenía que mantener la compatibilidad con versiones anteriores. El método original esperaba dos parámetros, pero el nuevo tenía solo uno. Sobrecargar la forma que esperaba no funcionó porque MVC ya no encontró el punto de entrada.

Para resolver eso, hice lo siguiente:

  1. Cambió los 2 métodos de acción sobrecargados de público a privado
  2. Creó un nuevo método público que contenía " solo " 2 parámetros de cadena. Ese actuó como despachador, es decir:

    public ActionResult DoSomething(string param1, string param2)
    {
        if (string.IsNullOrEmpty(param2))
        {
            return DoSomething(ProductName: param1);
        }
        else
        {
            int oldId = int.Parse(param1);
            return DoSomething(OldParam: param1, OldId: oldId);
        }
    }
    
    
    private ActionResult DoSomething(string OldParam, int OldId)
    {
        // some code here
        return Json(result);
    }
    
    
    private ActionResult DoSomething(string ProductName)
    {
        // some code here
        return Json(result);
    }
    

Por supuesto, este es un truco y debería ser refactorizado más tarde. Pero por el momento, funcionó para mí.

También puede crear un despachador como:

public ActionResult DoSomething(string action, string param1, string param2)
{
    switch (action)
    {
        case "update":
            return UpdateAction(param1, param2);
        case "remove":
            return DeleteAction(param1);
    }
}

Puede ver que UpdateAction necesita 2 parámetros, mientras que DeleteAction solo necesita uno.

Si este es un intento de usar una acción GET para varias vistas que PUBLICAN en varias acciones con diferentes modelos, intente agregar una acción GET para cada acción POST que redirija al primer GET para evitar 404 al actualizar.

Posibilidad muy remota pero escenario común.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top