Servidores web como o IIS tratam nativamente arquivos como imagens, scripts JavaScript, HTML e CSS como recursos estáticos. Por padrão, esses recursos não são processados pelas regras de roteamento de URL para otimizar o desempenho do servider.
Este artigo detalha como implementar rotas personalizadas para controlar o acesso a recursos estáticos em um projeto web, abordando desafios comuns encontrados por desenvolvedores iniciantes.
Configurando Rotas Personalizadas em um Projeto Web Novo
Para adicionar rotas personalizadas em um projeto web recém-criado, é necessário um ponto de entrada para o gerenciamento global da aplicação. Um arquivo Global.asax.cs na raiz do projeto pode ser utilizado para interceptar o evento de inicialização da aplicação e registrar as rotas.
O método Application_Start no Global.asax.cs é executado quando a aplicação inicia, sendo o local ideal para chamar o registro de rotas.
protected void Application_Start(object sender, EventArgs e)
{
CustomUrlManager.RegisterApplicationRoutes();
}
A classe CustomUrlManager seria responsável por orquestrar o registro de todas as rotas:
using System;
using System.Collections.Generic;
using System.Web.Routing;
using UrlRouting.Config; // Assumindo que esta namespace contém as configurações de rota
public static class CustomUrlManager
{
public static void RegisterApplicationRoutes()
{
// Ignora requisições para tipos comuns de arquivos estáticos
RegisterIgnoredRoutes();
string allowedCultures = "en|pt"; // Exemplo de culturas permitidas
RouteValueDictionary routeConstraints;
foreach (var routeConfig in UrlRoutingSettingConfig.UrlRoutingSettingCollection)
{
routeConstraints = new RouteValueDictionary();
foreach (var constraint in routeConfig.Constraints)
{
if (constraint.Key.Equals("culture", StringComparison.OrdinalIgnoreCase))
{
routeConstraints.Add("culture", string.IsNullOrEmpty(allowedCultures) ? constraint.Value : allowedCultures);
}
else
{
routeConstraints.Add(constraint.Key, constraint.Value);
}
}
if (!string.IsNullOrEmpty(routeConfig.DomainName))
{
RouteTable.Routes.Add(new DomainRoute(routeConfig.DomainName, routeConfig.RouteUrl, routeConfig.PhysicalFile, routeConfig.CheckPhysicalUrlAccess, routeConfig.Defaults, routeConstraints));
}
else if (!string.IsNullOrEmpty(routeConfig.RouteName))
{
if (routeConfig.RouteName.Equals("ajax", StringComparison.OrdinalIgnoreCase))
{
// Rota para manipuladores HTTP genéricos (ex: ASHX)
RouteTable.Routes.Add(new Route(routeConfig.RouteUrl, routeConfig.Defaults, routeConstraints, new HttpHandlerRoute(routeConfig.PhysicalFile)));
}
else
{
// Rota nomeada padrão
RouteTable.MapPageRoute(routeConfig.RouteName, routeConfig.RouteUrl, routeConfig.PhysicalFile, routeConfig.CheckPhysicalUrlAccess, routeConfig.Defaults, routeConstraints);
}
}
}
}
private static void RegisterIgnoredRoutes()
{
// Ignora requisições para formatos comuns de imagem
RouteTable.Routes.Ignore("{resource}.png/{*pathInfo}");
RouteTable.Routes.Ignore("{resource}.jpg/{*pathInfo}");
RouteTable.Routes.Ignore("{resource}.jpeg/{*pathInfo}");
// Ignora requisições para arquivos CSS e JavaScript
RouteTable.Routes.Ignore("{resource}.css/{*pathInfo}");
RouteTable.Routes.Ignore("{resource}.js/{*pathInfo}");
// Ignora requisições para manipuladores genéricos (ASHX)
RouteTable.Routes.Ignore("{resource}.ashx/{*pathInfo}");
}
}
Configuração de Rotas no Web.config
As definições específicas das rotas são configuradas no arquivo Web.config. Este exemplo demonstra como configurar rotas para requisições AJAX (arquivos .js que apontam para manipuladores .ashx) e requisições de páginas HTML (arquivos .html que apontam para páginas .aspx).
<configuration>
<configSections>
<section name="urlRoutingSettings" type="UrlRouting.Config.UrlRoutingSettingConfigSection, TLZ.UrlRouting" />
</configSections>
<urlRoutingSettings>
<settings>
<clear />
<!-- Rota para processar arquivos .js via manipuladores ASHX -->
<add routeName="ajax" routeUrl="scripts/{*fileName}.js" physicalFile="~/handlers/{fileName}.ashx" checkPhysicalUrlAccess="true" />
<!-- Rota para exibir páginas .aspx com URLs terminando em .html -->
<add routeName="htmlPages" routeUrl="pages/{*pageName}.html" physicalFile="~/Views/{pageName}.aspx" />
</settings>
</urlRoutingSettings>
<system.webServer>
<!-- Configurações adicionais aqui -->
</system.webServer>
</configuration>
Forçando o Processamento de Todas as Requisições HTTP pelas Rotas
Um desafio comum é que, por padrão, o .NET não aplica as regras de roteamento a recursos estáticos. Para contornar isso e garantir que todas as requisições HTTP sejam consideradas pelas regras de roteamento, configure o módulo UrlRoutingModule no Web.config.
A diretiva runAllManagedModulesForAllRequests="true" garante que todos os módulos gerenciados, incluindo o roteador, sejam executados para cada requisição.
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
<!-- outras configurações -->
</system.webServer>
Após essa configuração, as rotas personalizadas, incluindo as que mapeiam para recursos estáticos ou manipuladores, começarão a funcionar conforme o esperado. Por exemplo, uma requisição para /pages/home.html agora pode ser corretamente direcionada para ~/Views/home.aspx.
Configurando a Página Inicial Padrão
Para definir qual página será exibida quando o usuário acessar a raiz do site, a configuração defaultDocument no Web.config pode ser utilizada. Isso é especialmente útil quando se utiliza roteamento para "mascarar" páginas como arquivos .html.
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
<defaultDocument>
<files>
<!-- Define index.aspx como a página padrão -->
<add value="index.aspx" />
</files>
</defaultDocument>
</system.webServer>
Entendendo os Benefícios da "Pseudo-Estática"
A prática de usar rotas personalizadas para criar URLs amigáveis (como URLs com extensão .html para páginas .aspx) é conhecida como "pseudo-estática". As motivações para isso incluem:
- SEO (Otimização para Mecanismos de Busca): URLs mais simples e descritivsa tendem a ser melhor indexadas por motores de busca.
- Segurança: Oculta a estrutura real do projeto, dificultando a identificação de tecnologias ou vulnerabilidades.
- Legibilidade e Manutenibilidade: Facilita a compreensão das URLs pelos usuários e desenvolvedores.
- Consistência de URL: Permite padronizar a forma como os parâmetros são passados na URL.
É importante notar que, ao forçar requisições de recursos estáticos a passarem pelo sistema de roteamento, você pode estar adicionando uma camada de processamento que o .NET tenta evitar por padrão para otimizar o desempenho. Contudo, os benefícios de SEO e de uma estrutura de URL mais limpa muitas vezes superam essa consideração em aplicações web modernas.
Recursos estáticos referenciados de domínios externos (por exemplo, via <script src="http://external.com/script.js">) não são afetados pelas rotas configuradas no projeto local, pois a requisição é feita diretamente ao servidor externo.