ASP .NET 4.5 Web Forms - Implementando o suporte ao roteamento via URL - VIII


Neste tutorial, 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.

Obs: Acompanhe todas as partes do curso neste link: http://www.macoratti.net/Cursos/aspn_450.htm

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:

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 nossa aplicação vai passar a poder ser acessada usando a seguinte URL o mesmo produto: 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 as propriedade estática Routes da classe RouteTable. A propriedade Routes é um objeto RouteCollection 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 de 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 seqüê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 seqüê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 azul:

Imports System.Web.Optimization
Imports System.Data.Entity
Imports WingTipToys.WingtipToys.Models
Imports System.Web.Routing

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

        'adicionando rotas
        RegisterRoutes(RouteTable.Routes)

    End Sub

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

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

    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étodo RegisterRoutes 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:

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 arquivo Gobal.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:

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. Neste tutorial, 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 exibidos 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:

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

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 seqüência de consulta para o caso em que o usuário tem 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:

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

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

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%

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 seqüência de consulta, para o caso em que um usuário tem um link marcado em seu bookmark.

Neste tutorial, 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 tutorial, vamos implementar o tratamento de erro global em nossa aplicação.

Aguarde: Tratamento de erros e registro de log - IX

Referências:


José Carlos Macoratti