Vamos falar sobre o ASP.NET MVC. Este novo framework tornará popular o padrão MVC (Model View Controller) no mundo do desenvolvimento web na plataforma Microsoft. O Framework é realmente impressionante, ainda que esteja, no momento do fechamento desta edição, em versão de Preview 2, ou seja, não é sequer uma versão Beta (o que quer dizer que ainda não tem implementadas todas as funcionalidades previstas).

Você pode baixá-lo no site do ASP.NET MVC. Uma das funcionalidades mais interessantes do novo framework é o seu elegante roteamento, e ele é atribuído erroneamente como parte do componente MVC. Na verdade ele é um componente independente, do qual o MVC depende. Isso quer dizer que podemos utilizá-lo com os Web Forms padrões do ASP.NET, e é justamente o que faremos neste artigo e na sua seqüência.

O Routing é um dos componentes do qual o framework MVC depende, mais especificamente do componente System.Web.Routing. O outro componente do qual o MVC depende é o System.Web.Abstractions, do qual o Routing também depende. Na prática, o MVC depende do Routing, que depende do Web Abstractions. Portanto, para utilizarmos o Routing, teremos também que referenciar o componente Web Abstractions, mas não precisaremos do MVC.

Os outros componentes referenciados são parte do .NET Framework 3.5, ou seja, para utilizar o Routing em um projeto, precisamos apenas de 2 dlls no diretório Bin de uma aplicação Web, mais nada. Após a instalação do MVC, essas dlls ficam no diretório C:\Program Files\Microsoft ASP.NET MVC Preview 2\Assemblies. Para ajudar, as dlls são pequenas (menos de 100k) e assinadas. É possível baixar o código-fonte do MVC no Codeplex, o site de projetos open source da Microsoft. O código-fonte do Routing também vai ser aberto, e por enquanto pode-se gerar o código-fonte do Routing com auxílio do Reflector.

O que é o ASP.NET Routing

Atualmente, a única forma disponível out-of-the-box para entregar conteúdo ASP.NET é com a utilização de arquivos aspx (e ashx, asmx, axd etc.) dispostos fisicamente no disco. Sendo assim, quando chamamos no navegador o caminho http://servidorweb/app/Categorias.aspx, estamos, de forma simplificada, solicitando à máquina servidorweb, que, através da aplicação app, nos entregue a página dinâmica Categorias.aspx, que está no disco do servidor, provavelmente no caminho c:\inetpub\wwwroot\app\Categorias.aspx (assumindo o caminho padrão do IIS). Esta página de categoria poderia entregar todas as categorias do banco de dados Northwind, listadas de alguma forma. Para editar uma categoria específica, chamaríamos algo como http://servidorweb/app/CategoriaEditar.aspx?ID=3, assumindo que queremos a categoria de número 3.

O Routing é um mecanismo criado para facilitar o roteamento de uma aplicação Web. O exemplo citado anteriormente funciona perfeitamente, mas seria mais interessante se, em vez de utilizarmos aqueles endereços, com o identificador número 3, utilizássemos endereços que dissessem mais sobre o que estão exibindo. Neste caso, como a categoria número 3 do banco Northwind se refere à categoria Confections, a seguinte URL deixaria muito mais claro o que está sendo editado: http://servidorweb/app/Categoria/Confections/Editar. Para exibir a categoria, poderíamos utilizar simplesmente http://servidorweb/app/Categoria/Confections. Esse tipo de construção deixa a URL mais fácil de ser lida e também indexada por buscadores.

Como o Routing funciona?

Visto de fora, como uma caixa preta, o Routing tem um funcionamento muito claro. Vamos analisar sua interação com o MVC, e a partir dela derivar como faríamos para utilizá-lo com Web Forms.

O Routing utiliza um módulo HTTP .NET para receber as requisições. Dessa forma, a seguinte linha é acrescentada ao Web.config, como filha da tag:

Com isso, todos os requests passam pelo módulo UrlRoutingModule, que direciona as chamadas ao engine de roteamento.

A partir daí, a rota é configurada. Isso é feito no arquivo global.asax, na função Application_Start. O template padrão do MVC traz uma sugestão de registro de rotas no arquivo global.asax, conforme a Listagem 1.

Listagem 1. Arquivo global.asax do template do MVC configurando rotas.

Public Class GlobalApplication

    Inherits System.Web.HttpApplication

    Shared Sub RegisterRoutes(ByVal routes As RouteCollection)

        routes.Add(New Route("{controller}/{action}/{id}", New MvcRouteHandler) With { _

            .Defaults = New RouteValueDictionary(New With {.action = "Index", .id = ""}) _

            })

        routes.Add(New Route("default.aspx", New MvcRouteHandler) With { _

            .Defaults = New RouteValueDictionary(New With {.controller = "Home", .action = "Index", .id = ""}) _

            })

    end sub

    sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)

        RegisterRoutes(RouteTable.Routes)

    end sub

End Class

O registro é feito adicionando novas rotas à coleção de rotas localizada na propriedade estática Routes da classe RouteTables. Cada rota recebe como parâmetro um padrão de URL, como uma string, e um endereçador de rotas, que é uma classe que implementa System.Web.Routing.IRouteHandler. O padrão de URL do MVC está dividido em três sub-parâmetros, identificados entre chaves, conforme visto no global.asax da Listagem 1: controller, action e id. É com estes parâmetros que informamos ao engine de roteamento do MVC que queremos que ele chame uma função (action) de uma classe controladora (controller), e passe um parâmetro (id). Dessa forma, uma chamada à http://servidorweb/app/categorias/editar/3 atribuirá a palavra categorias ao parâmetro controller, editar ao parâmetro action e 3 ao parâmetro id, chamando então na classe CategoriasController a função Editar, passando o valor 3 ao parâmetro id desta função.

O responsável por fazer a ligação entre a URL da rota à classe e o método a serem chamados, além de qual parâmetro passar, é o endereçador de rotas, ou seja, a classe MvcRouteHandler, e ele faz isso com Reflection.

Também é possível especificar valores padrão. Ou seja, valores para os três parâmetros especificados que, caso o parâmetro não seja passado via URL, será passado então em seu lugar. No código padrão, vemos na linha 5 da Listagem 1 que a ação padrão é Index, e id vazio (note o uso de tipos anônimos). Assim, para chamar a função Index, em uma classe controladora CategoriasController, sem o parâmetro id (ou com ele vazio), podemos chamar simplesmente http://servidorweb/app/categorias. Podemos mudar a ordem dos parâmetros na rota, simplesmente mudando o parâmetro de URL da rota. Se, em vez do valor passado na linha 4 da Listagem 1 para a URL, passássemos {action}/{controller}/{id}, a URL de edição de uma categoria poderia ser chamada assim: http://servidorweb/app/editar/categorias/3.

As rotas são buscadas na ordem em que são registradas, dessa forma, se você registrar as duas opções de rota, a original, e em seguida a com URL {action}/{controller}/{id}, você nunca verá a segunda rota executar, já que elas atendem ao mesmo formato de URL (três variáveis separadas por barra). Para isso, você deve criar uma rota singular, algo como acoes/{action}/{controller}/{id}, e poderia então chamar o caminho de edição assim: http://servidorweb/app/acoes/editar/categorias/3 e ainda chamar o caminho padrão.

Agora que entendemos como o Routing funciona com o MVC fica mais fácil traduzir esta implementação para a do Web Forms. Como vimos, quem traduz a URL para ações, controles e parâmetros é o endereçador de Rotas MvcRouteHandler. Esta classe, passada no construtor da Rota, implementa a interface IRouteHandler, do namespace System.Web.Routing, que tem, como única operação o método GetHttpHandler, que retorna um objeto que implemente System.Web.IHttpHandler: uma página (System.Web.Page), por exemplo.

A Figura 1 mostra claramente como isso acontece. Criei um endereçador de Rotas para Web Forms (ele será visto em seguida), e coloquei um breakpoint na declaração da chamada de GetHttpHandler. Ao solicitar uma rota (no meu caso, http://localhost:51408/Categories) este ponto foi atingido. Note na pilha de chamadas (Call Stack) a progressão de chamadas. Coloquei 2 pontos importantes nesta pilha, além da própria parada do breakpoint. A pilha deve ser lida de baixo para cima, dessa forma, no ponto 1 temos a passagem da chamada do Web Server para o runtime do ASP.NET. No ponto 2 temos a passagem do runtime ao módulo UrlRoutingModule, que registramos no web.config. E finalmente temos o breakpoint atingido. Ele será responsável por resolver a rota e entregar uma página. No caso do MVC, isso é feito com controllers e ações. No nosso caso, precisamos simplesmente criar uma página Web comum e devolvê-la. Vamos ver como fazer isso em um caso bastante simples.

Call Stack de uma chamada de Routing parada no Gestor de Rotas
Figura 1. Call Stack de uma chamada de Routing parada no Gestor de Rotas.

Entregando páginas simples com o Routing

Existe uma maneira muito simples de entregar Web Forms via rotas alternativas com o Routing. Basta criar um gestor de rotas que saiba exatamente qual o caminho da página que deve entregar. O código deste gestor está disponível na Listagem 2. Note que ele solicita este caminho no construtor e o armazena em uma variável. Quando o método GetHttpHandler é solicitado, ele cria uma instância da página com auxílio da classe BuildManager e seu método estático CreateInstanceFromVirtualPath, que recebe como parâmetro o caminho virtual da página a ser criada. O objeto criado (a página) é então retornado. O caminho virtual passado poder ser o caminho de qualquer página aspx, como por exemplo ~/default.aspx.

Listagem 2. Classe de gestor de rotas muito simples.

Imports System.Web.Routing

Imports System.Web

Public Class GestorDeWebFormsRoteadosMuitoSimples

    Implements IRouteHandler



    Public Sub New(ByVal caminhoVirtual As String)

        'armazenamos o caminho real da rota

        _CaminhoVirtual = caminhoVirtual

    End Sub

    'variável modal para armazenar o caminho real da rota

    Private ReadOnly _CaminhoVirtual As String



    Public Function GetHttpHandler(ByVal requestContext As RequestContext) _

    As IHttpHandler Implements IRouteHandler.GetHttpHandler

        'criamos uma página a partir do caminho e retornamos

        Dim pagina = DirectCast( _

            System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath( _

                _CaminhoVirtual, _

                GetType(Page)),  _

            Page)

        Return pagina

    End Function

End Class

Crie um diretório chamado “Roteado”. Vamos colocar todas as páginas aspx roteadas lá. Então crie neste diretório a página Pedidos.aspx, e escreva algo para identificá-la. No global.asax, inclua a rota, conforme mostra a Listagem 3, nomeando-a de RotaDePedido. Ao rodar, chame a rota, ou seja, o nome do servidor, mais /pedidos. O resultado deve ser semelhante à Figura 2.

Listagem 3. Global.asax que configura uma rota com o gestor muito simples.

Imports System.Web.SessionState

Public Class Global_asax

    Inherits System.Web.HttpApplication

    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)

        RegistraRotas(Routing.RouteTable.Routes)

    End Sub

    Private Sub RegistraRotas(ByVal rotas As Routing.RouteCollection)

        rotas.Add("RotaDePedido", _

            New Routing.Route("pedidos", _

                New GestorDeWebFormsRoteadosMuitoSimples("~/roteado/pedidos.aspx")))

    End Sub

End Class
Resultado de um roteamento muito simples
Figura 2. Resultado de um roteamento muito simples

Entregando rotas parametrizadas

Da forma com que a rota foi configurada apenas a chamada à URL ~/pedidos será atendida. Note que não usamos parâmetros, como é feito no MVC: não há em nossa rota nada entre chaves, sendo ela apenas pedidos (no MVC o padrão é {controller}/{action}/{id}). Por esse motivo, se quisermos que alguma rota atenda ~/clientes, temos que criar uma rota para ela. Vamos fazer isso, passando um id como parâmetro. No entanto, o endereçador de rotas criado, como dizia seu nome, era muito simples. Para passarmos um parâmetro utilizando a estrutura do framework de Routing, seria interessante se pudéssemos fazer algo como chamar http://localhost:51408/Cliente/3. Para isso, basta adicionar uma rota que atenda esse requisito, que seria cliente/{id}.

Este id não seria recuperado da forma usual da URL, que é via query string. A maneira mais fácil é colocá-lo no contexto da requisição. É isso que está sendo feito no próximo endereçador de rotas, que tem seu método GetHttpHandler disponível na Listagem 4, o GestorDeWebFormsRoteadosSimples (todo o resto é igual à classe GestorDeWebFormsRoteadosMuitoSimples). Note que a única diferença com o endereçador anterior é que estamos agora adicionando os dados de rotas ao contexto (linhas 16 a 19), além de armazenar o contexto do Routing também no contexto HTTP.

É bom notar que esse contexto é do tipo System.Web.Routing.RequestContext, não sendo o mesmo tipo que System.Web.HttpContext (acessado em WebForms pela propriedade Context), ou mesmo o do tipo System.Web.HttpContextBase, que é um novo tipo abstrato, implementado concretamente no tipo System.Web.HttpContextWrapper2, e que envolve (é um wrapper) um objeto do tipo System.Web.HttpContext. Esses dois tipos System.Web.HttpContextBase e System.Web.HttpContextWrapper2 fazem parte do novo componente System.Web.Abstractions. É por esse motivo que armazenamos esse contexto de Routing ao contexto HTTP: ele não estaria disponível nos Web Forms se não o fizéssemos. No artigo seguinte veremos onde utilizá-lo.

Listagem 4. Método GetHttpHandler na classe GestorDeWebFormsRoteadosSimples.

Public Function GetHttpHandler(ByVal requestContext As RequestContext) _

As IHttpHandler Implements IRouteHandler.GetHttpHandler

    'adicionamos as variáveis de rotas nas chaves de contexto:

    For Each key In requestContext.RouteData.Values.Keys

        requestContext.HttpContext.Items.Add(key, _

            requestContext.RouteData.Values(key))

    Next

    'adicionamos ao contexto também o requestContext do Routing:

    requestContext.HttpContext.Items.Add("contexto", requestContext)

    'criamos a página a partir do caminho:

    Dim pagina = DirectCast( _

        System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath( _

            _CaminhoVirtual, _

            GetType(Page)),  _

        Page)

    Return pagina

End Function

Esse novo endereçador de rotas precisa agora ser configurado no global.asax. Inclua o conteúdo da Listagem 5 ao método RegistraRotas. Note que agora temos um parâmetro variável na rota, que é o {id}. Para utilizá-lo, crie a página cliente.aspx no diretório roteado. O código deve ficar como o da Listagem 6, onde um label exibirá o número passado ao id. Como vimos no endereçador de rotas, o id será armazenado no contexto. Para recuperá-lo, basta buscar a coleção de itens, e exibí-lo no label. O código da Listagem 7, que exibe o code-behind da página cliente.aspx, faz exatamente isso. A Figura 3 mostra o resultado. Troque o valor da URL para ver como ele será refletido na página.

Listagem 5. Complemento ao método RegistraRotas do global.asax.

 rotas.Add("RotaDeCliente", _

   New Routing.Route("cliente/{id}", _

       New GestorDeWebFormsRoteadosSimples("~/roteado/clientes.aspx")))
Listagem 6. Página cliente.aspx com um label exibindo o id.

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="clientes.aspx.vb" Inherits="RoutingWebForms2.clientes" %>

Essa é a página de pedidos

Ela está localizada no diretório: Roteado/Clientes.aspx

Você solicitou o cliente número:

Listagem 7. Code-behind da página cliente.aspx

Partial Public Class clientes

    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        If Not Page.IsPostBack Then

            lblIDCliente.Text = DirectCast(Context.Items("id"), String)

        End If

    End Sub

End Class
Resultado do roteamento com parâmetros
Figura 3. Resultado do roteamento com parâmetros

Uma página de soma roteada

Para fazer uma página de soma, fica bastante fácil. Utilizando o mesmo endereçador de rotas simples, adicione a nova rota de soma ao global.asax, crie a página de soma e está pronto. A Listagem 8 mostra esses códigos, e a Figura 4 mostra o resultado.

Listagem 8. Mudanças para incluir uma página de soma. Global.asax, método RegistraRotas:

rotas.Add("RotaDeSoma", _

    New Routing.Route("soma/{num1}/{num2}", _

        New GestorDeWebFormsRoteadosSimples("~/roteado/soma.aspx")))
Página soma.aspx:

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="soma.aspx.vb" Inherits="RoutingWebForms2.Soma" %>

Resultado da soma:

Code behind de soma.aspx (soma.aspx.vb):

Public Partial Class Soma

    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _

    Handles Me.Load

        If Not Page.IsPostBack Then

            lblResultado.Text = CStr(CInt(Context.Items("num1")) + _

            CInt(Context.Items("num2")))

        End If

    End Sub

End Class
Página de soma roteada
Figura 4. Página de soma roteada

Existe ainda a possibilidade de fazer a página de soma pegar todos os parâmetros que se seguirem à rota básica. Pode-se criar um parâmetro pega-tudo (catch all, em inglês). Para isso, o nome do parâmetro deve começar com um asterísco, como soma/{*números}. Nesse caso, todos os parâmetros são passados a uma variável do tipo string, com o caminho completo. Uma chamada à http://localhost:56119/soma/5/4/7/3 traria no parâmetro numeros o valor 5/4/7/3. A partir daí, basta separar os valores e somá-los. Veja essas alterações na Listagem 9.

Listagem 9. Alterações na rota e na página de soma. Global.asax, método RegistraRotas:

rotas.Add("RotaDeSoma", _

    New Routing.Route("soma/{*numeros}", _

        New GestorDeWebFormsRoteadosSimples("~/roteado/soma.aspx")))
Code-behind de soma.aspx (soma.aspx.vb):

Public Partial Class Soma

    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _

    Handles Me.Load

        If Not Page.IsPostBack Then

            Dim res As Integer

            Dim numeros = TryCast(Context.Items("numeros"), String)

            If numeros IsNot Nothing Then

                For Each num In numeros.Split("/"c)

                    res += CInt(num)

                Next

            End If

            lblResultado.Text = res.ToString()

        End If

    End Sub

End Class

Uma aplicação com dados

Vamos criar uma aplicação com dados e Roteamento e que vai utilizar o banco padrão Northwind e sua tabela Categories. Utilizaremos rotas parametrizadas, e por padrão o nome das páginas derivará do nome da rota e da ação. Ao chamar http://servidorweb/app/categories, a chamada deve ser roteada para a página CategoriesListar.aspx, ou seja, como não foi especificada uma categoria específica, será exibibida uma lista com todas as categorias. Ao chamar http://servidorweb/app/categories/Beverages, a categoria Beverages deverá ser exibida, com utilização da página CategoriesEditar.aspx, e ao chamar http://servidorweb/app/categories/Beverages/editar, deve-se ser capaz de editar o registro na mesma página CategoriesEditar.aspx. A Tabela 1 resume esse padrão.

Caminho Página Ação
http://servidorweb/app/tabela TabelaListar.aspx Listar os registros
http://servidorweb/app/tabela/registro TabelaEditar.aspx Consultar um registro
http://servidorweb/app/tabela/registro/editar TabelaEditar.aspx Editar um registro
Tabela 1. Aplicações da solução

Duas rotas podem ser abstraídas desta tabela. A URL da primeira seria somente de consulta: {tabela}, e a URL da segunda permitiria a edição e a consulta: {tabela}/{nome}/{operacao}, sendo que, se a operação não for informada, deve ser consultar.

O endereçador de rotas precisa agora ser mais inteligente. Ele precisa entender esse padrão, da mesma forma que o endereçador do MVC entende os parâmetros {controller} e {action}. Este gestor de Web Forms está na Listagem 10. Note que ele é muito parecido com o gestor que utilizamos nos exemplos anteriores, tendo apenas o código adicional para trabalhar os parâmetros de tabela e nome (o parâmetro operação deverá ser tratado pela própria página).

Listagem 10. Novo gestor trabalhando as rotas.

Imports System.Web.Routing

Imports System.Web

Public Class GestorDeWebFormsRoteados

    Implements IRouteHandler



    Public Function GetHttpHandler(ByVal requestContext As RequestContext) _

    As IHttpHandler Implements IRouteHandler.GetHttpHandler

        'adicionamos as chaves de roteamento às chaves de contexto web:

        For Each key In requestContext.RouteData.Values.Keys

            requestContext.HttpContext.Items.Add(key, _

                requestContext.RouteData.Values(key))

        Next

        'adicionamos o contexto de roteamento ao contexto web:

        requestContext.HttpContext.Items.Add("contexto", requestContext)



        'cria o caminho virtual, no nosso caso, as chaves "tabela" e "sufixo"

        'vão permitir criar um endereço web:

        Dim strTabela = TryCast(requestContext.RouteData.Values("tabela"), String)

        Dim strSufixoPagina = TryCast(requestContext.RouteData.Values("sufixo"), String)

        If String.IsNullOrEmpty(strTabela) Then

            Throw New ArgumentException("Tabela não foi passada.")

        End If

        'As webs roteadas vão ficar no sub diretório "Roteado", e o nome da página aspx

        'será o nome da tabela mais o sufixo. Assim, uma chamada de listagem

        'de categorias ficaria assim:

        '        "~/Roteado/CategoriesListar.aspx"

        Dim strCaminhoVirtual = "~/Roteado/" & strTabela & strSufixoPagina & ".aspx"

        'guardamos o nome da página chamada em outra variável de contexto:

        requestContext.HttpContext.Items.Add("caminhovirtual", strCaminhoVirtual)

        'criamos a página com auxílio do BuildManager do ASP.NET e retornamos:

        Dim pagina = DirectCast( _

            System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath( _

                strCaminhoVirtual, _

                GetType(Page)),  _

            Page)

        Return pagina

    End Function

End Class

Para registrar as rotas no global.asax o procedimento é exatamente o mesmo. Utilizaremos agora um recurso adicional ao registro de rotas: valores padrão. Vimos que o novo endereçador de rotas está esperando uma variável sufixo, que utilizará para compor o nome da página (é ele quem fará a diferença entre a página CategoriesListar, e CategoriesExibir). Esse valor não vem da URL, de forma que precisamos ser capazes de passá-lo de alguma forma ao gestor de roteamento. Isso é feito criando valores padrão para esse tipo de variável, que são passados na criação da rota, com o auxílio de tipos anônimos. Veja as 2 rotas adicionais na Listagem 11. Para a segunda rota estamos ainda adicionando um padrão para a operação, o valor consultar, para que o usuário não precise digitar http://servidorweb/app/categories/Beverages/consultar, podendo digitar somente http://servidorweb/app/categories/Beverages, sendo o valor consultar assumido como padrão.

Listagem 11. Novas rotas no global.asax.

rotas.Add("Listagem", _

    New Routing.Route("{tabela}", _

        New GestorDeWebFormsRoteados()) _

        With {.Defaults = New Routing.RouteValueDictionary( _

            New With {.sufixo = "listar"})})

rotas.Add("Consulta", _

    New Routing.Route("{tabela}/{nome}/{operacao}", _

        New GestorDeWebFormsRoteados()) _

        With {.Defaults = New Routing.RouteValueDictionary( _

            New With {.sufixo = "editar", .operacao = "consultar"})})

Para fazer a ligação com os dados utilizaremos LINQ to SQL. Precisamos, antes de mais nada, criar uma fonte de dados. Adicione um novo arquivo DBML do LINQ to SQL e nomeie-o Northwind.dbml (Figura 5). Arraste do Server Explorer a tabela de Categories, e salve. O resultado deve ser conforme a Figura 6.

Adicionando a fonte de dados LINQ to SQL
Figura 5. Adicionando a fonte de dados LINQ to SQL.
LINQ to SQL configura com a tabela Categories
Figura 6. LINQ to SQL configura com a tabela Categories

Vamos então criar a página de listagem de categorias. Seguindo o padrão, crie a página CategoriesListar.aspx no diretório roteado. Adicione a ela um LinqDataSource e aponte para o DataContext criado pelo arquivo dbml (não esqueça de compilar o projeto antes, ou o LinqDataSource não vai ser capaz de encontrá-lo), seu nome deve ser NorthwindDataContext. Selecione a tabela Categories e clique em Finish.

Adicione então um GridView e aponte para o LinqDataSource1 recém criado. Isso já deve ser suficiente para rodar o teste de listagem de categorias. Adicione na default.aspx um link para categories. Veja na Listagem 12 o código das 2 páginas. Rode a solução e selecione o link Exibir Categorias. A página http://localhost:56119/Categories (com outro número de porta) deve ser solicitada, e a página CategoriesListar.aspx deve ser exibida.

Listagem 12. Páginas CategoriesListar.aspx e Default.aspx. Categories.aspx:

 <%@ Page Language="vb" AutoEventWireup="false" CodeBehind="CategoriesListar.aspx.vb" 
 Inherits="RoutingWebForms2.CategoriesListar" %>

 
  ContextTypeName="RoutingWebForms2.NorthwindDataContext" TableName="Categories">

        DataKeyNames="CategoryID" DataSourceID="LinqDataSource1">

            InsertVisible="False" ReadOnly="True" SortExpression="CategoryID" />
                
                SortExpression="CategoryName" />
                      
                      SortExpression="Description" />
Default.aspx:

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="RoutingWebForms2._Default" %>

Exibir Categorias

Conclusão

Vimos como criar uma aplicação com roteamento customizado baseado no novo componente de Routing do ASP.Net. Vimos como ele pode nos auxiliar a criar rotas dinâmicas e demos os primeiros passos na criação de uma aplicação baseada em dados. No próximo artigo concluiremos a aplicação, veremos como solucionar os problemas que o roteamento traz ao lidarmos com links gerados dinamicamente, como implementar segurança com o Routing e Web Forms, como criar links automaticamente, e como alterar as rotas sem quebrar os links da aplicação.

ASP.NET Routing - Parte 2

Confira também