ASP.NET MVC - passando parâmetros para o controlador

105

Eu tenho um controlador com um método de ação da seguinte maneira:

public class InventoryController : Controller
{
    public ActionResult ViewStockNext(int firstItem)
    {
        // Do some stuff
    }
}

E quando eu o executo, recebo um erro informando:

O dicionário de parâmetros não contém um valor válido do tipo 'System.Int32' para o parâmetro 'firstItem'. Para tornar um parâmetro opcional, seu tipo deve ser um tipo de referência ou um tipo que pode ser anulado.

Eu tinha funcionado em um ponto e decidi tentar a função sem parâmetros. Descobrindo que o controlador não era persistente, coloquei o parâmetro de volta, agora ele se recusa a reconhecer o parâmetro quando chamo o método.

Estou usando esta sintaxe de url para chamar a ação:

http://localhost:2316/Inventory/ViewStockNext/11

Alguma ideia de por que eu receberia esse erro e o que preciso fazer para corrigi-lo?

Tentei adicionar outro método que leva um inteiro para a classe, mas também falha pelo mesmo motivo. Eu tentei adicionar um que leva uma string, e a string está definida como nula. Tentei adicionar um sem parâmetros e funciona bem, mas é claro que não atenderá às minhas necessidades.

Ímpar
fonte

Respostas:

106

Seu roteamento precisa ser configurado ao longo das linhas de {controller}/{action}/{firstItem}. Se você deixou o roteamento como padrão {controller}/{action}/{id}em seu global.asax.csarquivo, será necessário transmiti-lo id.

routes.MapRoute(
    "Inventory",
    "Inventory/{action}/{firstItem}",
    new { controller = "Inventory", action = "ListAll", firstItem = "" }
);

... Ou alguma coisa parecida.

Jarrett Meyer
fonte
44
Ou apenas renomeie "firstItem" para "id"
Kyle Trauberman
8
Além disso, ele mundo ser sábio para adicionar um objeto de restrições à MapRoute, assim: new { firstItem = @"\d" }. Desta forma, aceitará se o parâmetro for qualquer tipo de número. Você pode modificar a regex como quiser e até mesmo limitar o número de decimais, como este: new { firstItem = @"\d{4}" }- agora ela pode ter apenas 4 números. Editar: exemplo de MapRoute totalmente modificado: jsfiddle.net/HJRgT
KristianB
86

você pode alterar firstItem para id e funcionará

você pode alterar o roteamento em global.asax (eu não recomendo isso)

e, não acredito que ninguém mencionou isso, você pode ligar para:

http://localhost:2316/Inventory/ViewStockNext?firstItem=11

Em um @ Url.Action seria:

@Url.Action("ViewStockNext", "Inventory", new {firstItem=11});

dependendo do tipo de coisa que você está fazendo, a última será mais adequada. Além disso, você deve considerar não fazer a ação ViewStockNext e, em vez disso, uma ação ViewStock com índice. (meus 2 centavos)

Bart Calixto
fonte
15

Para reformular a resposta de Jarret Meyer , você precisa alterar o nome do parâmetro para 'id' ou adicionar uma rota como esta:

routes.MapRoute(
        "ViewStockNext", // Route name
        "Inventory/ViewStockNext/{firstItem}",  // URL with parameters
        new { controller = "Inventory", action = "ViewStockNext" }  // Parameter defaults
    );

O motivo é que a rota padrão procura apenas ações sem nenhum parâmetro ou um parâmetro chamado 'id'.

Edit: Heh, não importa Jarret adicionou um exemplo de rota após a postagem.

Matt Mitchell
fonte
8

ou faça isso com Atributo de rota:

public class InventoryController : Controller
{
    [Route("whatever/{firstItem}")]
    public ActionResult ViewStockNext(int firstItem)
    {
        int yourNewVariable = firstItem;
        // ...
    }
}
Yar
fonte
Esta propriedade pode não funcionar com versões MVC mais antigas.
Suat Atan PhD
Além disso, para que isso funcione, você precisa garantir que chamou routes.MapMvcAttributeRoutes();dentro do RegisterRoutes(RouteCollection)método do aplicativo (geralmente com scaffold em App_Start \ RouteConfig.cs). Pode não estar lá por padrão.
Daniel Scott
7

Headspring criou uma boa biblioteca que permite adicionar apelidos aos seus parâmetros em atributos na ação. É assim:

[ParameterAlias("firstItem", "id", Order = 3)]
public ActionResult ViewStockNext(int firstItem)
{
    // Do some stuff
}

Com isso, você não precisa alterar seu roteamento apenas para lidar com um nome de parâmetro diferente. A biblioteca também suporta a aplicação várias vezes para que você possa mapear várias grafias de parâmetros (útil ao refatorar sem quebrar sua interface pública).

Você pode obtê-lo com Nuget e ler o artigo de Jeffrey Palermo sobre ele aqui

Matthew Nichols
fonte
7

public ActionResult ViewNextItem(int? id)torna o idinteiro um tipo anulável, sem necessidade de conversões de string <-> int.

Oskar Duveborn
fonte
3

Usando o recurso ASP.NET Core Tag Helper:

<a asp-controller="Home" asp-action="SetLanguage" asp-route-yourparam1="@item.Value">@item.Text</a>
Sasha Yakobchuk
fonte
Ironicamente, a resposta mais curta é a melhor (esta).
1

Há outra maneira de fazer isso (descrito em mais detalhes no exemplo do Pager de Stephen Walther

Basicamente, você cria um link na visualização:

Html.ActionLink("Next page", "Index", routeData)

Em routeData, você pode especificar pares de nome / valor (por exemplo, routeData ["página"] = 5) e, na função de índice do controlador, os parâmetros correspondentes recebem o valor. Isso é,

public ViewResult Index(int? page)

terá a página passada como 5. Tenho que admitir, é bastante incomum que string ("página") se torne automagicamente uma variável - mas é assim que MVC funciona em outras linguagens também ...

Felix
fonte
0

A razão para o tratamento especial de "id" é que ele é adicionado ao mapeamento de rota padrão. Para alterar isso, vá para Global.asax.cs e você encontrará a seguinte linha:

routes.MapRoute ("Default", "{controller}/{action}/{id}", 
                 new { controller = "Home", action = "Index", id = "" });

Altere para:

routes.MapRoute ("Default", "{controller}/{action}", 
                 new { controller = "Home", action = "Index" });
Aristoteles
fonte
0

Ou, você pode tentar alterar o tipo de parâmetro para string e, em seguida, converter a string em um inteiro no método. Eu sou novo no MVC, mas acredito que você precisa de objetos anuláveis ​​em sua lista de parâmetros. De que outra forma o controlador indicará que esse parâmetro não foi fornecido? Assim...

public ActionResult ViewNextItem(string id)...
RAL
fonte