¿Puede sobrecargar los métodos de controlador en ASP.NET MVC?

Tengo curiosidad por ver si puedes sobrecargar los métodos de control en ASP.NET MVC. Cada vez que lo bash, obtengo el siguiente error. Los dos métodos aceptan diferentes argumentos. ¿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:

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

[ActionName("MyOverloadedName")] 

Sin embargo, deberá usar un nombre de acción diferente para el mismo método http (como otros han dicho). Entonces es solo semántica en ese punto. ¿Prefiere tener el nombre en su código o su atributo?

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

Sí. He podido hacer esto al configurar el HttpGet / HttpPost (o el atributo equivalente de AcceptVerbs ) para cada método de controlador en algo distinto, es decir, HttpGet o HttpPost , pero no ambos. De esta forma, puede determinar, en función del tipo de solicitud, qué método usar.

 [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 de la que dependan sus dos métodos de acción pública para evitar la duplicación del código.

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

Por qué no probar esto …

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

Esto funcionó para mí … y en este único método, puedes probar para ver si tienes el parámetro entrante.


Se actualizó para eliminar la syntax 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 intentas invocar la acción “LoadCustomer” obtendrás un error como se muestra en la figura a continuación.

enter image description here

El polymorphism es parte de la progtwigción de C # mientras que HTTP es un protocolo. HTTP no entiende el polymorphism. HTTP funciona en el concepto o URL y la URL solo puede tener un nombre único. Entonces HTTP no implementa polymorphism.

Para arreglarlo, necesitamos usar el atributo “Nombre de la acción”.

 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 la URL “Cliente / Cliente de carga”, se invocará la acción “Cargar cliente” y se invocará “Cargar cliente (cadena str)” con la estructura de URL “Cliente / CarcustomerByName”.

enter image description here

enter image description here

La respuesta anterior que he tomado de este artículo del proyecto de código -> Sobrecarga de acción MVC

Para solucionar este problema, puede escribir un ActionMethodSelectorAttribute que examine el MethodInfo para cada acción y lo compare con los valores del formulario publicados y luego rechace 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.

Por lo que yo sé, solo puedes tener el mismo método cuando usas diferentes métodos http.

es decir

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

Lo logré con la ayuda de Attribute Routing en MVC5. Es cierto que soy nuevo en MVC y vengo de una década de desarrollo web usando WebForms, pero el siguiente me ha funcionado. A diferencia de la respuesta aceptada, esto permite que todas las acciones sobrecargadas sean renderizadas 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, decore las acciones de su controlador que se sobrecarguen entre sí con una ruta y parámetros comunes que se adapten. Con los 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é llevando a alguien por el camino equivocado. 🙂

Puede usar un solo ActionResult para tratar tanto con Post como con Get :

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

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

Acabo de encontrarme con esta pregunta y, aunque ya 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 de ASP.NET no son del todo correctos. Tengo un proyecto grande y sobrecargo con éxito los métodos de acción.

Si uno entiende el enrutamiento, más allá del patrón de ruta predeterminado {controlador} / {acción} / {id}, puede ser obvio que las acciones del controlador se pueden mapear usando cualquier patrón único. Alguien aquí habló sobre el polymorphism y dijo: “HTTP no entiende el polymorphism”, pero el enrutamiento no tiene nada que ver con HTTP. Es, simplemente, un mecanismo para emparejar patrones de cuerdas.

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 ocuparán de las URL como /cars/usa/new-york y /cars/usa/texas/dallas , que se correlacionarán con la primera y la segunda acción 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 nomenclatura de código, pero este no es siempre el caso. El código debe ser descriptivo del dominio, pero las URL a menudo deben 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. Esto es impuesto por el comstackdor ya que las URL coincidirán con los únicos tipos y miembros de controlador. Hacer rodar tus propios patrones de ruta requerirá una cuidadosa reflexión para garantizar la singularidad y que funcionen.

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

¡Buena suerte!

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 me funciona bien.

Me he enfrentado el mismo problema en mi aplicación también. Sin modificar ninguna información del Método, proporcioné [Nombre de la acción (“SomeMeaningfulName”)] en el encabezado de acción. 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); } 

Puede usar [Nombre de la acción (“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"); } } 

Crea el método base como virtual

 public virtual ActionResult Index() 

Cree el método reemplazado como anulación

 public override ActionResult Index() 

Editar: Esto obviamente se aplica solo si el método de reemplazo está 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 heredas de otro controlador y deseas anular una acción desde el controlador base

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

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

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

Una vez llegué a una situación en la que tuve que mantener la compatibilidad con versiones anteriores. El método original esperaba dos parámetros, pero el nuevo tenía solo uno. La sobrecarga de la manera 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 esto es un bash de usar una acción GET para varias vistas que POST a varias acciones con diferentes modelos, intente agregar una acción GET para cada acción POST que redirija al primer GET para evitar 404 en la actualización.

Posibilidad remota, pero escenario común.