c# - route - ¿Se pueden sobrecargar los métodos del controlador en ASP.NET MVC?




asp.net mvc route attribute (11)

Tengo curiosidad por ver si puede sobrecargar los métodos del controlador en ASP.NET MVC. Cada vez que lo intento, me sale el error de abajo. 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:


Acabo de encontrar esta pregunta y, aunque ya es bastante antigua, sigue siendo muy relevante. Irónicamente, el comentario correcto en este hilo fue publicado por un principiante confesado en MVC cuando escribió la publicación. Incluso los documentos de 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 patrón de ruta predeterminado simple {controller} / {action} / {id}, podría ser obvio que las acciones del controlador se pueden asignar mediante un 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 ocuparán de direcciones URL como /cars/usa/new-york y /cars/usa/texas/dallas , que se asignarán a 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 sus convenciones de nomenclatura de códigos, pero no siempre es así. El código debe ser descriptivo del dominio, pero las direcciones URL a menudo deben ir más lejos porque su contenido debe basarse en otros criterios, como los requisitos de SEO.

La ventaja del patrón de enrutamiento predeterminado es que crea automáticamente rutas únicas. El compilador impone esto, ya que las direcciones URL coincidirán con los tipos de controladores y miembros únicos. Hacer rodar sus propios patrones de ruta requerirá una reflexión cuidadosa para asegurar la singularidad 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 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 fuentes bien respetadas, el camino a seguir ( http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/ ).

¡Buena suerte!


Aquí hay algo más que podría hacer ... quiere un método que sea capaz de tener un parámetro y no.

¿Por qué no intentar esto ...

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

Esto me ha funcionado ... y con este método, puedes probar 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.


He enfrentado el mismo problema en mi aplicación también. Sin modificar ningún tipo de información sobre el método, proporcioné [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);

        }

Lo he logrado con la ayuda del enrutamiento de atributos en MVC5. Es cierto que soy nuevo en MVC proveniente de una década de desarrollo web con WebForms, pero lo siguiente me ha funcionado. A diferencia de la respuesta aceptada, esto permite que todas las acciones sobrecargadas se representen en 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, decore su 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 ajusten. Usando parámetros de tipo restringido, puede usar el mismo formato 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 guíe a alguien por el camino equivocado. :-)


Necesitaba una sobrecarga para:

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

Hubo pocos argumentos 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 tiene muchos argumentos, pero funciona bien para mí.


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 la acción "Cargar cliente", obtendrá un error, como se muestra en la siguiente figura.

El polimorfismo es una 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. Así que HTTP no implementa polimorfismo.

Para arreglar el mismo necesitamos usar el atributo "ActionName".

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

Así que ahora, si realiza una llamada a la URL "Customer / LoadCustomer", se invocará la acción "LoadCustomer" y con la estructura de URL "Customer / LoadCustomerByName" se invocará a "LoadCustomer (string str)".

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


Podría usar un único 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.


Por lo que sé, solo se 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)
{

}

Puede usar el atributo si desea que su código realice una sobrecarga.

[ActionName("MyOverloadedName")]

Pero tendrá que usar un nombre de acción diferente para el mismo método http (como han dicho otros). Así que 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


Sí. He podido hacer esto configurando el HttpGet / HttpPost (o el atributo AcceptVerbs equivalente) para cada método del controlador en algo distinto, es decir, HttpGet o HttpPost , pero no ambos. De esa manera, puede determinar en función del 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 ambos métodos públicos de Acción se basen para evitar la duplicación de código.


Si se trata de un intento 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 la actualización de 404.

Plano general pero muy largo.







overloading