.NET

15 mai, 2013

ASP .NET 4.5 Web Forms – Implementando o suporte ao roteamento via URL – Parte 08

Publicidade

Neste artigo, vamos modificar a nossa aplicação para suportar o roteamento de URL. O roteamento permite que sua aplicação web utilize URLs que são mais amigáveis, mais fáceis de lembrar e melhor suportadas pelos motores de busca.

O roteamento de URL foi introduzida com o objetivo de expor URLs limpas e mais amigáveis para os motores de busca no padrão “web 2.0”. O roteamento de URL permite que você configure uma aplicação para aceitar URLs de requisição que não mapeiam para arquivos físicos. Em vez disso, você pode usar o roteamento para definir URLs que são semanticamente significativas para os usuários e que podem ajudar no que diz respeito à otimização de motores de busca (SEO).

O que você vai aprender:

  • Como registrar rotas para uma aplicação ASP.NET Web Forms;
  • Como adicionar rotas estáticas para uma página web;
  • Como adicionar rotas dinâmicas para uma página web;
  • Como selecionar dados de um banco de dados para apoiar rotas dinâmicas.

Este artigo foi integralmente baseado no artigo original: http://www.asp.net/web-forms/tutorials/aspnet-45/getting-started-with-aspnet-45-web-forms/url-routing (com algumas alterações e portado para a linguagem VB .NET).

Conceitos sobre o roteamento ASP .NET

O roteamento de URL permite que você configure um aplicativo para aceitar URLs que não mapeiam para arquivos físicos. Um pedido de URL é simplesmente uma URL que um usuário digita em seu navegador para encontrar uma página em seu site. Você usa o roteamento para definir URLs que são semanticamente significativas para os usuários e que pode ajudar nos mecanismos de buscas como Search Engine Optimization (SEO).

Obs: O termo SEO ou otimização para mecanismos de pesquisa (português brasileiro) é o conjunto de estratégias com o objetivo de potencializar e melhorar o posicionamento de um site nas páginas de resultados naturais (orgânicos) nos sites de busca.

Em nossa aplicação atual, a URL usada para acessar um produto é escrita da seguinte forma: http://localhost:1234/ProdutoDetalhes.aspx?produtoID=2

Com a implementação do roteamento de URL, a nossa aplicação poderá ser acessada usando a seguinte URL: http://localhost:1234/Produto/Convertible%20Car

A seguir, veremos alguns conceitos importantes que usaremos em nossa implementação.

Rotas

Uma rota é um padrão de URL que está mapeada para um manipulador. O manipulador pode ser um arquivo físico, como um arquivo .aspx em um aplicativo Web Forms. O manipulador pode ser também uma classe que processa o pedido. Para definir uma rota, você cria uma instância da classe Route, especificando o padrão de URL, o manipulador e, opcionalmente, um nome para a rota.

Você pode adicionar a rota para a aplicação, adicionando o objeto Route para a propriedade estática Routes da classe RouteTable. A propriedade Routes é um objetoRouteCollection que armazena todas as rotas para a aplicação.

Padrões de URL

Um padrão de URL pode conter valores literais e marcadores de posição variáveis (conhecido como parâmetros de URL). Os literais e os marcadores estão localizados em segmentos da URL que são delimitados pelo caractere barra (/).

Quando uma solicitação para sua aplicação web é feita, a URL é analisada em segmentos e espaços reservados, e os valores das variáveis são fornecidos para o manipulador de solicitação. Este processo é semelhante à maneira como os dados em uma sequência de consulta é analisado e passado para o manipulador de solicitação. Em ambos os casos, a informação variável é incluída na URL e passada para o manipulador, sob a forma de um par chave-valor.

Para sequências de consulta, tanto as chaves como os valores estão na URL. Para as rotas, as chaves são os nomes de espaços reservados definidos no padrão da URL, e apenas os valores estão na URL.

Em um padrão de URL, você define espaços reservados, colocando-os entre chaves ({e}). Você pode definir mais do que um espaço reservado em um segmento, mas os espaços reservados devem ser separados por um valor literal. Por exemplo, {idioma}-{país}/{ação} é um padrão de rota válida. No entanto {idioma}{país}/{ação} não é um padrão válido, porque não existe um valor literal ou delimitador entre os espaços reservados.

Mapeando e registrando rotas

Antes de podermos incluir rotas para páginas da nossa aplicação web temos que registrar as rotas quando a aplicação web for iniciada.

Para registrar as rotas, vamos modificar o manipulador de eventos Application_Start do arquivo Global.asax.

Abra o arquivo Global.asax.vb e altere o seu código conforme o baixo. Onde você deve incluir o código destacado em negrito:

Imports System.Web.Optimization
Imports System.Data.Entity
Imports WingTipToys.WingtipToys.Models
<strong>Imports System.Web.Routing</strong>

Public Class Global_asax
    Inherits HttpApplication

    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        ' Fires when the application is started
        BundleConfig.RegisterBundles(BundleTable.Bundles)
        AuthConfig.RegisterOpenAuth()
        Database.SetInitializer(New ProdutoDatabaseInitializer())

        ' Inclui um Administrator.
        If Not Roles.RoleExists("Administrator") Then
            Roles.CreateRole("Administrator")
        End If

        If Membership.GetUser("Admin") Is Nothing Then
            Membership.CreateUser("Admin", "123456", "macoratti@yahoo.com")
            Roles.AddUserToRole("Admin", "Administrator")
        End If

        <strong>'adicionando rotas</strong>
<strong>        RegisterRoutes(RouteTable.Routes)</strong>

    End Sub

    <strong>Private Sub RegisterRoutes(ByVal routes As RouteCollection)</strong>
<strong>        routes.MapPageRoute("HomeRoute", "Home", "~/Default.aspx")</strong>
<strong>        routes.MapPageRoute("AboutRoute", "About", "~/About.aspx")</strong>
<strong>        routes.MapPageRoute("ContatoRoute", "Contato", "~/Contact.aspx")</strong>
<strong>        routes.MapPageRoute("ProdutoListaRoute", "ProdutoLista", "~/ProdutoLista.aspx")</strong>

<strong>        routes.MapPageRoute("ProdutosPorCategoriaRoute", "ProdutoLista/{categoriaNome}", "~/ProdutoLista.aspx")</strong>
<strong>        routes.MapPageRoute("ProdutoPorNomeRoute", "Produto/{produtoNome}", "~/ProdutoDetalhes.aspx")</strong>
<strong>    End Sub</strong>

    Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
        ' Fires at the beginning of each request
    End Sub

    Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As EventArgs)
        ' Fires upon attempting to authenticate the use
    End Sub

    Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
        ' Fires when an error occurs
    End Sub

    Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
        ' Fires when the application ends
    End Sub
End Class

Quando nossa aplicação for iniciada, ela chama o manipulador de eventos Application_Start. No final deste processador de eventos, o método RegisterRoutes é chamado. O métodoRegisterRoutes adiciona cada rota, chamando o método MapPageRoute do objeto RouteCollection.

O método MapPageRoute é usado para registrar tanto as rotas estáticas como as rotas dinâmicas. As rotas estáticas e dinâmicas são definidas usando um nome de rota, uma URL de rota e uma URL física. A seguir, temos um exemplo de rota estática: routes.MapPageRoute(“HomeRoute”, “Home”, “~/Default.aspx”)

Em uma rota estática temos a seguinte composição:

  • O primeiro parâmetro (“HomeRoute”) é o nome da rota. Ele é usado para chamar a rota quando for necessário;
  • O segundo parâmetro (“Home”) é a URL da rota. É a URL de substituição amigável que é mostrada como parte da URL;
  • O terceiro parâmetro (“~/Default.aspx”) é o caminho real para o conteúdo que será exibido.

Usando o HomeRoute, o link Home irá navegar para a seguinte URL: http://localhost:1234/Home

Uma rota dinâmica é semelhante a uma rota estática. No entanto, o segundo parâmetro que define a URL de substituição amigável pode ser dinâmico e baseado em código. Você usa rotas dinâmicas quando você está preenchendo um controle de dados com links que são gerados com base nos seus dados.

Um exemplo de rota dinâmica é mostrado a seguir: routes.MapPageRoute(“ProdutosPorCategoriaRoute”, “ProdutoLista/{categoriaNome}”, “~/ProdutoLista.aspx”).

O segundo parâmetro da rota dinâmica inclui um valor dinâmico especificado por chaves ({}). Neste caso, categoriaNome é uma variável que será utilizada para determinar o percurso de encaminhamento adequado.

Recuperando e usando dados de rota

Como mencionado acima, tanto as rotas estáticas como as dinâmicas podem ser definidas. O código que incluímos no manipulador de eventos Application_Start no arquivoGobal.asax.vb carrega as rotas estáticas e as dinâmicas.

Configurando rotas estáticas

Podemos usar o método GetRouteUrl para renderizar uma rota. Para rotas estáticas, passamos para o método GetRouteUrl o nome da rota como o primeiro parâmetro e um espaço reservado nulo (nothing) como o segundo parâmetro. Não há valores dinâmicos passados.

Uma rota estática não implementa todos os dados gerados dinamicamente. Não usamos as rotas estáticas com um controle de dados. Em vez disso, usamos o método GetRouteUrl para recuperar a rota estática que foi registrada no arquivo Global.asax.cs.

Na janela Solution Explorer abra o arquivo Site.master e atualize o elemento nav da página conforme mostrado a seguir:

aspn_4581

As linhas de código incluídas para definir o roteamento substituíram as seguintes linhas de código:

<li><a href="/">Home</a></li>
<li><a href="/About.aspx">Sobre</a></li>
<li><a href="/Contato.aspx">Contato</a></li>
<li><a href="/ProdutoLista.aspx">Produtos</a></li>

No código passamos o nome da rota quando chamamos o método GetRouteUrl – este método usa o nome da rota para procurar os detalhes da rota que foram registradas no arquivo Global.asax.vb. Os valores retornados são então adicionados a cada link.

Definindo rotas dinâmicas

As rotas dinâmicas exigem que seja definido um código adicional. Usaremos o modelo de ligação (Model Binding) para recuperar um objeto RouteValueDictionary que é usado ao gerar as rotas, utilizando dados de um controle de dados. Esse objeto conterá uma lista de nomes de produtos que pertencem a uma categoria específica de produtos. A ligação é criada para cada produto, com base nos dados e na rota.

Ativando as rotas para Categorias e Produtos

A seguir, vamos atualizar nossa aplicação para usar a rota ProdutosPorCategoriaRoute para determinar a rota correta para incluir para cada link a categoria do produto.

Vamos atualizar também a página ProdutoLista.aspx para incluir um link direcionado para cada produto. As ligações serão exibidas como eram antes da mudança, no entanto os links agora vão usar o roteamento da URL.

Abra a página Site.master e atualize o controle ListView com id igual a categoriaLista, incluindo o código destacado mostrado a seguir:

aspn_4582

Agora abra o arquivo ProdutoLista.aspx e atualize o elemento ItemTemplate com o código destacado exibido a seguir:

aspn_4583

Substitua o método GetProdutos do arquivo code-behind ProdutoLista.aspx.vb com o seguinte código:

Public Function GetProdutos(<QueryString("id")> categoriaId As System.Nullable(Of Integer), <RouteData> categoriaNome As String) As IQueryable(Of Produto)

        Dim _db = New WingtipToys.Models.ProdutoContexto()
        Dim query As IQueryable(Of Produto) = _db.Produtos

        If categoriaId.HasValue AndAlso categoriaId > 0 Then
            query = query.Where(Function(p) p.CategoriaID = categoriaId)
        End If

        If Not [String].IsNullOrEmpty(categoriaNome) Then
            query = query.Where(Function(p) [String].Compare(p.Categoria.CategoriaNome, categoriaNome) = 0)
        End If

        Return query

    End Function

Adicionando código para os detalhes do produto

Agora, atualize o arquivo code-behind ProdutoDetalhes.aspx.vb para que a página ProdutoDetalhes.aspx use os dados de rota.

Observe que o novo método getProduto também aceita um valor de sequência de consulta para o caso em que o usuário tenha um link marcado que usa as antigas URLs não amigáveis.

Substitua o método getProduto com o seguinte código:

 Public Function GetProduto(<QueryString("ProdutoID")> produtoId As System.Nullable(Of Integer), <RouteData> produtoNome As String) As IQueryable(Of Produto)
        Dim _db = New WingtipToys.Models.ProdutoContexto()
        Dim query As IQueryable(Of Produto) = _db.Produtos
        If produtoId.HasValue AndAlso produtoId > 0 Then
            query = query.Where(Function(p) p.ProdutoID = produtoId)
        ElseIf Not [String].IsNullOrEmpty(produtoNome) Then
            query = query.Where(Function(p) [String].Compare(p.ProdutoNome, produtoNome) = 0)
        Else
            query = Nothing
        End If
        Return query
    End Function

Rodando a aplicação

Execute a aplicação pressionando CTRL+F5 (ou clicando no botão do menu que executa a aplicação);

O navegador irá abrir e apresentar a página Default.aspx:

aspn_4584

Clique no link Produtos no topo da página. Todos os produtos são apresentados na página ProdutoLista.aspx. A seguinte URL (usando o seu número de porta) é exibida para o navegador: http://localhost:64786/ProdutoLista

aspn_4585

A seguir, clique no link de categoria Carros perto do topo da página.

Apenas carros são exibidos na página ProdutoLista.aspx. A seguinte URL é exibida para o navegador: http://localhost:1234/ProdutoLista/Carros

aspn_4586

Clique no link com o nome do primeiro carro listado na página – Convertible Car (“carro conversível”) para exibir os detalhes do produto.

Os detalhes do carro será exibido e a seguinte URL (usando o seu número de porta) é exibida para o navegador: http://localhost:1234/Produto/Convertible 20Car%

aspn_4587

Agora vamos fazer um teste: digite a seguinte URL não roteada (usando o seu número de porta) no seu navegador: http://localhost:xxxx/ProdutoDetalhes.aspx?produtoID=2

O código ainda reconhece uma URL que inclui uma sequência de consulta, para o caso em que um usuário tenha um link marcado em seu bookmark.

aspn_4588

Neste artigo, adicionamos rotas estáticas e rotas dinâmicas para categorias e produtos.

Você aprendeu como definir rotas estáticas e dinâmicas e também como as rotas dinâmicas podem ser integradas com controles de dados que usam o modelo de ligação. No próximo artigo, vamos implementar o tratamento de erro global em nossa aplicação.