Pergunta

Estou curioso para ver se você pode sobrecarregar métodos do controlador em ASP.NET MVC. Sempre que eu tento, eu recebo o erro abaixo. Os dois métodos aceitam argumentos diferentes. Isto é algo que não pode ser feito?

A solicitação atual para a ação 'MyMethod' no tipo de controlador 'MyController' é ambíguo entre os métodos seguintes medidas:

Foi útil?

Solução

Você pode usar o atributo se você quiser que o seu código para fazer a sobrecarga.

[ActionName("MyOverloadedName")]

Mas, você terá que usar um nome de ação diferente para o mesmo método http (como já foi dito). Portanto, é apenas semântica nesse ponto. Você prefere ter o nome em seu código ou o seu atributo?

Phil tem um artigo relacionado com isto: http://haacked.com/archive/2008/08/29/how-a-method-becomes-an-action.aspx

Outras dicas

Sim. Eu tenho sido capaz de fazer isso, definindo o HttpGet / HttpPost (ou atributo AcceptVerbs equivalente) para cada método de controlador de algo distinto, ou seja, HttpGet ou HttpPost, mas não ambos. Dessa forma, ele pode dizer com base no tipo de pedido qual método usar.

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

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

Uma sugestão que tenho é que, para um caso como este, seria ter uma implementação privada que ambos os métodos de ação pública dependem para código de duplicação evitar.

O Aqui outra coisa que você poderia fazer ... você quer um método que é capaz de ter um parâmetro e não.

Por que não tentar isso ...

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

Isso tem funcionado para mim ... e neste método, você pode realmente teste para ver se você tem o parâmetro de entrada.


Atualizado para remover a sintaxe anulável inválido na corda e usar um valor de parâmetro padrão.

Não, Não e Não. Vá e experimente o código do controlador abaixo de onde temos o "LoadCustomer" sobrecarregado.

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

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

Se você tentar chamar a ação "LoadCustomer" você vai ter erro, como mostrado na figura abaixo.

enter descrição da imagem aqui

O polimorfismo é uma parte de programação C #, enquanto HTTP é um protocolo. O HTTP não entendo polimorfismo. HTTP trabalha no conceito de ou URL e URL só pode ter único nome de. Então HTTP não implementar polimorfismo.

A fim de corrigir a mesma necessidade que usar 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");
        }
    }

Portanto, agora se você fizer uma chamada para URL "Cliente / LoadCustomer" a ação "LoadCustomer" será invocado e com estrutura de URL "Cliente / LoadCustomerByName" a "LoadCustomer (string str)" será invocado.

enter descrição da imagem aqui

enter descrição da imagem aqui

A resposta acima i ter tomado a partir deste artigo codeproject -> MVC Ação sobrecarga

Para ultrapassar este problema você pode escrever um ActionMethodSelectorAttribute que examina o MethodInfo para cada ação e compara-a com os valores do formulário publicado e, em seguida, rejeita qualquer método para o qual os valores do formulário não corresponder (excluindo o nome do botão, é claro).

Aqui está um exemplo: - http: // blog. abodit.com/2010/02/asp-net-mvc-ambiguous-match/

Mas, isso não é uma boa idéia.

Tanto quanto eu sei que você só pode ter o mesmo método ao utilizar diferentes métodos HTTP.

i.

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

}

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

}

eu tenho conseguido isso com a ajuda de Atributo Encaminhamento em MVC5. É certo que eu sou novo para MVC vindo de uma década de desenvolvimento web usando WebForms, mas a seguir tem trabalhado para mim. Ao contrário da resposta aceita isso permite que todas as ações sobrecarregados a ser proferida pelo mesmo arquivo de visão.

Primeiro permitir Atributo Roteamento na 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 decorar a sua classe de controlador com um prefixo de rota padrão.

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

Em seguida, decorar suas ações do controlador que sobrecarregam o outro com uma rota comum e parâmetros para o exemplo. Usando parâmetros de tipo restrito você pode usar o mesmo formato URI com IDs 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 isso ajude e não está levando alguém para o caminho errado. : -)

Você pode usar um único ActionResult para lidar com ambos Post e Get:

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

Útil se seus métodos Get e Post ter assinaturas correspondente.

Acabei de se deparar com esta questão e, mesmo que seja muito velho agora, ainda é muito relevante. Ironicamente, o comentário correto neste segmento foi escrito por um iniciante auto-confessou em MVC quando escreveu o post. Mesmo os docs ASP.NET não são totalmente corretas. Eu tenho um grande projeto e eu sobrecarregar com sucesso métodos de ação.

Se alguém entende de roteamento, além da simples {controlador} / {ação} / padrão {id} rota padrão, pode ser óbvio que ações do controlador podem ser mapeados usando qualquer padrão único. Alguém aqui falou sobre polimorfismo e disse: "HTTP não entende polimorfismo", mas roteamento não tem nada a ver com HTTP. É, simplesmente, um mecanismo para a correspondência de cadeia padrão.

A melhor maneira de fazer este trabalho é usar os atributos de roteamento, por exemplo:

[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 acções irão cuidar de urls como /cars/usa/new-york e /cars/usa/texas/dallas, que irá mapear para a primeira ea segunda ação Índice respectivamente.

Examinando este controlador exemplo, é evidente que ele vai além do padrão de rota padrão mencionado acima. O padrão funciona bem se a sua estrutura de URL corresponde exatamente seu código convenções de nomenclatura, mas isso nem sempre é o caso. Código deve ser descritivo do domínio, mas urls muitas vezes precisam ir mais longe porque o seu conteúdo deve ser com base em outros critérios, tais como requisitos de SEO.

O benefício do padrão padrão de roteamento é que ele cria automaticamente rotas únicas. Isso é reforçado pelo compilador desde urls irá corresponder a tipos de controladores únicos e membros. Rolar seus próprios padrões de rota vai exigir uma reflexão cuidadosa para garantir a exclusividade e que eles trabalham.

Nota importante O único inconveniente é que o uso de roteamento para gerar urls para ações sobrecarregados não funciona quando baseado em um nome de ação, por exemplo, quando se utiliza UrlHelper.Action. Mas ela não funciona Se alguém usa o nome rotas, por exemplo, UrlHelper.RouteUrl. E usando rotas nomeadas é, de acordo com fontes bem respeitado, o caminho a percorrer de qualquer forma ( http://haacked.com/archive/2010/11/21/named-routes-to-the-rescue.aspx/ ).

Boa sorte!

Você pode usar [ActionName ( "NewActionName")] para usar o mesmo método com um nome 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");
    }
}

Eu precisava de uma sobrecarga para:

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

Houve poucos argumentos suficientes onde eu acabei fazendo o seguinte:

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

Não é uma solução perfeita, especialmente se você tem um monte de argumentos, mas funciona bem para mim.

Já enfrentei mesmo problema no meu aplicativo também. Sem Modifiyig qualquer informação Método, eu tenho desde [ActionName ( "SomeMeaningfulName")] na cabeça Ação. problema resolvido

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

        }

Criar o método de base como virtual

public virtual ActionResult Index()

Criar o método substituído como override

public override ActionResult Index()

Edit:. Isto, obviamente, se aplica somente se o método de substituição é em uma classe derivada que parece não ter sido a intenção do OP

Eu gosto desta resposta postada em outro segmento

Isto é usado principalmente se você herdar de outro controlador e quer substituir uma Acction da base controlador

ASP.NET MVC - Substituindo uma ação com parâmetros diferentes

Há apenas uma assinatura pública permitido para cada método de controlador. Se você tentar sobrecarregá-lo, ele irá compilar, mas você está recebendo o erro de tempo de execução que você experimentou.

Se você não está disposto a usar verbos diferentes (como os atributos [HttpGet] e [HttpPost]) para diferenciar métodos sobrecarregados (que vai funcionar), ou alterar o roteamento, então o que resta é que você pode fornecer um outro método com um diferente nome, ou você pode despachar dentro do método existente. Aqui está como eu fiz isso:

Uma vez eu entrou em uma situação onde eu tinha de manter compatibilidade com versões anteriores. O método original espera dois parâmetros, mas o novo tinha apenas um. Sobrecarga do jeito que eu esperava não funcionou porque MVC não encontrou o ponto de entrada mais.

Para resolver isso, eu fiz o seguinte:

  1. Mudou os 2 métodos de ação sobrecarregados de público para privado
  2. Criado um novo método público que continha "apenas" 2 parâmetros de cadeia. Aquele agiu como um despachante, ou seja:.

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

É claro que este é um hack e deve ser reformulado depois. Mas, por enquanto, ele trabalhou para mim.

Você também pode criar um despachante como:

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

Você pode ver que UpdateAction precisa de 2 parâmetros, enquanto DeleteAction só precisa de um.

Se esta é uma tentativa de usar uma ação GET por vários pontos de vista que o POST para diversas acções com diferentes modelos, em seguida, tentar adicionar uma ação de GET para cada ação POST que redireciona para o primeiro GET para evitar 404 na atualização.

Long tiro, mas cenário comum.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top