Usando querystring em ASP.NET MVC

Em toda a aplicação web há dois mecanismos básicos que se são usados para passar informação de cliente ao servidor: usando a URL (o que se conhece como querystring) ou usando um formulário (o que se conhece como POST).

Por Eduard Tomás - Tradução CRV


Publicado em: 28/3/12
Valorize este artigo:
ASP.NET MVC tem um suporte direto para usar a querystring: os parâmetros que se coloquem na URL serão enviados como parâmetros da ação correspondente.

Ou seja, se eu tenho a seguinte url: http://host/home/Index?p1=10&p2=no (e supondo a tabela de rotas por padrão), se invocará a ação Index de HomeController com dois parâmetros p1 (com valor 10) e p2 com valor "não". Assim no controlador poderíamos ter definida a ação da seguinte forma:

public ActionResult Index(int p1, string p2)
{
// Codigo...
}

Os nomes dos parâmetros devem coincidir com os nomes dos parâmetros da querystring. Bem, observem que dado que declaramos o parâmetro p1 como int só podemos passar valores inteiros, enquanto que no parâmetro p2, podemos passar qualquer cadeia. Se passamos uma cadeia no parâmetro p1, p.ex. a url http://host/home/index?p1=texto&p2=outrotexto o erro que recebemos é o seguinte:

O que ocorreu é que ASP.NET MVC tentou converter o valor de p1 ("texto") a um inteiro. Como não pode fazê-lo, internamente atribui null ao valor do parâmetro p1, porém depois quando deve invocar o método Index e passar-lhe um int percebe que int não aceita valores null. Daí o erro que recebemos.

Como poderíamos evitar isto? Bom, uma maneira fácil e simples é usar int? (ou seja Nullable) em lugar de int para declarar o tipo de p1:

public ActionResult Index(int? p1, string p2)
{
// Codigo
}

Agora se invocamos a url e o valor de p1 não é numérico, nos chegará null, enquanto que se o valor de p1 é numérico receberemos seu valor.

A regra é realmente muito simples: Se você quiser que um parâmetro de querystring seja opcional deve usar um tipo por referência (ou seja uma classe como string ou Nullable). Se você usar um tipo por valor (como int ou duplo) o parâmetro não pode ser opcional e ademais o valor que se entre na URL deve ser convertível de cadeia ao tipo específico que você ponha no controlador.

Gerar URLs com querystrings a partir das visões

Um dos erros mais frequentes em ASP.NET MVC é ter código nas visões que seja parecido a este:

Pressiona <a href="/Home/View?pid=10">aquí</a> para ver os detalhes

Este código tem dois erros fundamentais.

  1. Está ignorando a tabela de rotas. Está gerando as URLs usando a convenção de Controlador/ Ação pero esta convenção só é válida se se usa a tabela de rotas standard. Em projetos de tamanho médio é normal ter uma tabela de rotas que seja totalmente personalizada (essa é uma das graças de ASP.NET MVC!)
  2. Está passando os parâmetros sempre em querystring, ignorando os valores de rota
Para solucionar o primeiro ponto, o que devemos fazer é usar o Helper Url. Os Helpers são classes que nos proporcionam mecanismos de ajuda (de série vêm alguns que iremos vendo e podem ser criados deles próprios), para nos ajudar com tarefas repetitivas. Para gerar uma URL que respeite a tabela de rotas devemos usar o método Url.Action. Sua assinatura básica é Url.Action ("ação", "controlador"). Assim podemos reescrever o código anterior da forma:

Pressione <a href="@Url.Action("View","Home")?pid=10">aquí</a> para ver os detalhes

Se executamos isso e olhamos o código HTML veremos que é exatamente o que havíamos teclado antes (porque usamos a tabela de rotas standard). Porém, se acrescento uma entrada à tabela de rotas, deixando-a assim:

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Ver",
"VerProduto",
new {controller = "Home", action = "View"});
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

Agora a URL que é gerada usando Url.Action é a seguinte:

Pressione <a href="/VerProducto?pid=10">aquí</a> para ver os detalhes

Portanto, sempre que vocês necessitem obter uma URL a partir de uma visão , usem Url.Action lembrem que o formato real das URLs depende da tabela de rotas. Assumir que sempre estarão na forma /controlador/ação é uma má prática (e como disse antes, um erro comum no começo).

Parâmetros querystring e route values

Vamos ver agora o que significa o segundo dos erros que cometíamos (passar os valores sempre em querystring ignorando os valores de rota). Para evitar entrar demasiado em tecnicismos direi que ASP.NET MVC mistura todos os parâmetros que chegam a ele antes de passá-los aos controladores. A um controlador podem chegar parâmetros por três formas básicas (tudo bem, isso não é totalmente certo, há mais formas mas vamos ignorá-las de momento): como parâmetros de rota, como querystring e como POST (desses falaremos em um artigo posterior).

Os parâmetros de rota são os que colocamos na URL separados pela barra, ou seja: http://host/ controlador/ação/10. Neste caso 10 é o valor de um parâmetro de rota. De qual? Pois o nome deve estar explicitado na tabela de rotas. Vamos supor que usamos a tabela de rotas standard. Neste caso o nome de tal parâmetro é id. Agora eu pergunto a vocês o que aconteceria se usássemos a URL http://host/controlador/ação/10?id=20 ?

Observem que a questão não é sem importância: estamos passando a nosso controlador:

  • Um parâmetro de rota com valor 10 e que (graças à tabela de rotas) se chama id
  • Um parâmetro de querystring chamado id com valor 20.
Ambos parâmetros (de rota e querystring) se mapeiam a parâmetros da ação do controlador. Sendo assim, que valor receberemos no parâmetro id de nossa ação? Ou então ASP.NET MVC gerará um erro?

Pois o que receberemos em nossa ação será o valor do parâmetro de rota (ou seja, 10 em lugar de 20):

Observem a URL entrada (/Home/Index/10?id=20) e como o valor do parâmetro id é ?10? e não ?20?.

Isso se deve ao que comentávamos antes: ASP.NET MVC mistura todos os parâmetros que lhe chegam antes de juntá-los com os controladores e o faz de acordo com uma certa prioridade. E os parâmetros de rota (cujo nome se define na tabela de rotas) têm mais prioridade. Isso deveria tê-lo em conta quando gero URLs, ou seja, neste caso deveria gerar URLs usando a convenção / controlador/ação/valor_id antes que /controlador/ação?id=valor_id

No final isso implica que não deveríamos nunca gerar as URLs com parâmetros querystring acrescentados manualmente. Para nossa sorte o helper Url.Action que vimos antes vem de novo em nossa ajuda. Em uma de suas sobrecargas Url.Action aceita um objeto anônimo cujas propriedades são os valores a serem mandados ao controlador. Url.Action é o suficientemente inteligente para usar valores de rota se estão definidos e querystring no caso de que não!

Desse modo se temos a tabela de rotas standard e temos as seguintes chamadas a Url.Action:

Url 1: @Url.Action("Index", "Home", new { id = 20 })

Url 2: @Url.Action("Index", "Home", new { id = 20, outro_id=30})

Url 3: @Url.Action("Index", "Home", new {outro_id=30})

A resposta gerada por essa visão é a seguinte:

Url 1: /Home/Index/20
Url 2: /Home/Index/20?outro_id=30
Url 3: /?outro_id=30

Não é uma maravilha? Url.Action sabe que id é um parâmetro de rota e o coloca como tal. E sabe que outro_id não é e o coloca usando query_string. Neste caso temos a ação definida no controlador :

public ActionResult Index(string id, string outro_id)
{
return View();
}

Observem como a partir do controlador recebemos de igual maneira parâmetros de rota e parâmetros que venham por querystring :)

No artigo seguinte do tutorial vamos ver como mandar dados de formulários para as visões, ou seja como usar POST.






Usuários :    login / registro

Manuais relacionados
Categorias relacionadas
O autor

Home | Sobre nós | Copyright | Anuncie | Entrar em contato