Neste artigo será dada uma visão geral do conceito de rotas no ASP.NET MVC 4 fazendo a comparação com funcionamento nos WebForms.

Antes do surgimento do MVC Framework , o ASP.NET assumiu que havia uma ligação direta entre URLs solicitadas e os arquivos no disco rígido do servidor, cabendo a ele receber o pedido do navegador e entregar a saída do arquivo correspondente, como mostrado na Figura 1.

Correspondência
entre as URL’s e arquivos
Figura 1. Correspondência entre as URL’s e arquivos.

Essa abordagem funciona muito bem para Web Forms, mas não para uma aplicação MVC, onde os pedidos são processados por Actions em classes de Controller. Não existe uma correlação um-para-um para os arquivos no disco. Esse sistema de rotas tem duas funções:

  • Examinar uma URL de entrada para o Controller e a Action a que se destinam.
  • Gerar URLs de saída, que é o HTML renderizado a partir das nossas Views.

Criando o Projeto

Para demonstrar o funcionamento das rotas criaremos uma aplicação ASP.NET MVC 4 Web Aplicattion usando o basic template com o nome de MvcRoutesApplication no visual studio 2010, como mostrado na Figura 2.

Criação
do projeto no visual studio 2010
Figura 2. Criação do projeto no visual studio 2010.

Neste primeiro momento nos preocuparemos em adicionar apenas alguns controles simples, pois iremos focar apenas de como as URLs são interpretadas pelas Actions. Para isso, adicionaremos dois Controllers que são Home e Cliente com o conteúdo mostrado na Listagem 1.

Listagem 4 1. Código fonte dos Controllers Home e Cliente.

  namespace MvcRoutesApplication.Controllers
  {
      public class HomeController : Controller
      {
          //
          // GET: /Home/
   
          public ActionResult Index()
          {
              ViewBag.Controller = "Home";
              ViewBag.Action = "Index";
              return View("ActionName");
              
          }
   
      }
  }
  …
  namespace MvcRoutesApplication.Controllers
  {
      public class ClienteController : Controller
      {
          // GET: /Cliente/
   
          public ActionResult Index()
          {
              ViewBag.Controller = "Customer";
              ViewBag.Action = "Index";
              return View("ActionName");
          }
          public ActionResult List()
          {
              ViewBag.Controller = "Customer";
              ViewBag.Action = "List";
              return View("ActionName");
          }
   
      }
  }

Veja que especificamos a ActionName como View para esses Controllers. Criaremos agora a mesma clicando com o botão direito na pasta Views e em seguida add. Depois de criada, colocaremos nela o conteúdo da Listagem 2.

Listagem 4 2. Criação da View Action Name.

  @{
      Layout = null;
  }
  <!DOCTYPE html>
  <html>
    <head>
      <meta name="viewport" content="width=device-width" />
      <title>ActionName</title>
    </head>
    <body>
      <div>
          The controller is: @ViewBag.Controller</div>
      <div>
          The action is: @ViewBag.Action</div>
    </body>
  </html>

Executaremos a aplicação apertando F5 e veremos que será lançado um erro, como mostrado na Figura 3.

Tela de erro
Figura 3. Tela de erro.

O erro acima ocorreu, pois não estamos respeitando o esquema de montagem das rotas do MVC da nossa aplicação, para que assim a mesma possa reconhecer e responder as URLs. Para que nossa aplicação funcione, o primeiro passo é dividir as URLs em segmentos, excluindo o hostname, como mostrado na Figura 4.

Estrutura de rotas no MVC 4
Figura 4. Estrutura de rotas no MVC 4.

Note que o primeiro segmento contém a palavra Admin e o segundo segmento contém a palavra Index. Sendo assim, em uma URL padrão do MVC, o primeiro segmento refere-se ao Controller e o segundo refere-se a Action para que o sistema de rotas possa funcionar.Depois de termos em mente nossas rotas iremos defini-las no arquivo RouteConfig.cs, localizado na pasta App_Start. Veja a Listagem 3.

Listagem 4 3. Arquivo RouteConfig.cs.

  namespace MvcRoutesApplication
  {
      public class RouteConfig
      {
          public static void RegisterRoutes(RouteCollection routes)
          {
              routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
   
              routes.MapRoute(
                  name: "Default",
                  url: "{controller}/{action}/{id}",
                  defaults: new { controller = "Home", action = "Index", 
                  id = UrlParameter.Optional }
              );
          }
      }
  }

O método estático RegisterRoute, que é definido no arquivo RouteConfig.cs, é chamado a partir do Arquivo Global.asax.cs, cujo o conteúdo é mostrado na Listagem 4.

Listagem 4. Arquivo Global.asax.cs.

  public class MvcApplication : System.Web.HttpApplication
      {
          protected void Application_Start()
          {
              AreaRegistration.RegisterAllAreas();
   
              WebApiConfig.Register(GlobalConfiguration.Configuration);
              FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
              RouteConfig.RegisterRoutes(RouteTable.Routes);
          }
      }

O método Application_Start é chamado pela plataforma ASP.NET sempre quando a aplicação for iniciada. Sendo assim, podemos usar o Global.asax.cs para definir configurações necesárias para a execução da aplicação, como o método RouteConfig. RegisterRoutes que é uma instância da classe RouteCollection.

Agora que já entendemos o funcionamento da arquitetura das rotas, vamos usar esses conhecimentos para colocar a aplicação para funcionar.

No arquivo HomeController clicaremos com o botão direito no nome View e em seguida AddView. Na janela de criação da view verificaremos se o campo view name está preenchido como index e, em seguida, clicaremos no botão Add, como mostra a Figura 5.

Janela de criação de View
Figura 5. Janela de criação de View.

Depois que a view for criada, a aplicação ganhará um pasta com o nome do nosso Controller e dentro dela o nome de nossa view recém-criada. Ao visualizarmos isso, arrastaremos a view ActionName criada no início desse artigo para esta pasta e clicaremos em F5 para que a aplicação seja executada. Veja o resultado nas Figuras 6 e 7.

Estrutura da aplicação MVC
Figura 6. Estrutura da aplicação MVC.
Aplicação executada com sucesso
Figura 7. Aplicação executada com sucesso.

Note na URL da Figura 7 a estrutura de segmentos Controller e Action explicadas anteriomente. Agora que já entendemos o funcionamento das rotas, vamos dar um passo além e aprender a restringir URLs através das rotas. Acompanhe a Listagem 5.

Listagem 4 5. Restrição em URLs.

  public static void RegisterRoutes(RouteCollection routes)
          {
              routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
   
              routes.MapRoute(
                  name: "Default",
                  url: "{controller}/{action}/{id}",
                  defaults: new { controller = "Home", action = "Index", 
                  id = UrlParameter.Optional },
                  constraints: new { controller = "^H.*"});
              
          }

No código acima definimos uma constraint de tipo anônimo com uma expressão regular filtrando URLs, onde o valor da variável Controller se inicie com a letra H. Podemos ainda aprimorar mais nosso refinamento impondo além da restrição para o Controller uma restrição aplicada a Action. Veja a Listagem 6.

Listagem 4 6. Restrição aplicada.

  public static void RegisterRoutes(RouteCollection routes)
          {
              routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
              new { controller = "Home", action = "Index", 
                 id = UrlParameter.Optional },
              new
              {
                  controller = "^H.*",
                  action = "Index|About",
                  httpMethod = new HttpMethodConstraint("GET")
              },
              new[] { "URLsAndRoutes.Controllers" });
          }

Essa restrição irá filtrar as URLs pelas Actions de valor Index e About. As restrições das variáveis do tipo Action são aplicadas em conjunto com a valor das variáveis do tipo Controller, ou seja, as filtragens ocorreram quando o Controller começa com a letra H e nas Actions Index e About.

Esses são apenas pequenos exemplos de como se pode tirar proveito do recurso de rotas. Para finalizarmos esse artigo criaremos uma restrição personalizada implementando a interface IrouteConstraint. Para isso, adicionaremos uma pasta Infraestrutura para o projeto e criaremos um novo arquivo de classe chamado UserAgentConstraint.cs. Observe a Listagem 7.

Listagem 4 7. Arquivo UserAgentConstraint.cs.

  public class UserAgentConstraint : IRouteConstraint
      {
          private string requiredUserAgent;
          public UserAgentConstraint(string agentParam)
          {
              requiredUserAgent = agentParam;
          }
          public bool Match(HttpContextBase httpContext, Route route, 
           string parameterName,
          RouteValueDictionary values, RouteDirection routeDirection)
          {
              return httpContext.Request.UserAgent != null &&
              httpContext.Request.UserAgent.Contains(requiredUserAgent);
          }
      }

A interface IRouteConstraint define o método Match que usaremos para verificar o valor da propriedade UserAgent do cliente, assim, verificará qual browser está sendo executado a aplicação. Veja na Listagem 8 o uso da classe no método RegisterRoutes do arquivo RouteConfig.

Listagem 4 8. Arquivo RouteConfig.

  public static void RegisterRoutes(RouteCollection routes)
          {
              routes.MapRoute("ChromeRoute", "{*catchall}",
              new { controller = "Home", action = "Index" },
              new
              {
                  customConstraint = new UserAgentConstraint("Chrome")
              },
              new[] { "UrlsAndRoutes.AdditionalControllers" });
              routes.MapRoute("MyRoute", "{controller}/{action}/{id}/{*catchall}",
              new
              {
                  controller = "Home",
                  action = "Index",
                  id = UrlParameter.Optional
              },
              new[] { "URLsAndRoutes.Controllers" });
          }

Na listagem acima o código fará com que a aplicação apresente comportamentos diferentes quando executada no navegador Chrome e no Internet Explorer. Para comprovarmos isso executaremos a aplicação em cada um dos navegadores e a aplicação deverá apresentar os dois comportamentos mostrados nas Figuras 8 e 9.

Aplicação executada no Google Chrome
Figura 8. Aplicação executada no Google Chrome.
Aplicação executada no Internet Explorer
Figura 9. Aplicação executada no Internet Explorer.

Neste artigo entendemos a estrutura de funcionamento das rotas e aprendemos um pouco sobre os vários recursos que elas podem nos proporcionar através de códigos de exemplos e uma aplicação, onde interagimos com os tipos de navegadores. Espero que tenham gostado e não deixem de deixar sua opinião e sugestões para os próximos artigos. Um forte abraço.

Confira também