URLs em páginas mestras (C#)
por Scott Mitchell
Aborda como as URLs na página master podem ser interrompidas devido ao arquivo de página master estar em um diretório relativo diferente da página de conteúdo. Analisa a rebasing de URLs por meio de ~ na sintaxe declarativa e usando ResolveUrl e ResolveClientUrl programaticamente. (Veja também
Introdução
Em todos os exemplos que vimos até agora, as páginas de master e conteúdo foram localizadas na mesma pasta (a pasta raiz do site). Mas não há razão para que o master e as páginas de conteúdo estejam na mesma pasta. Você certamente pode criar páginas de conteúdo em subpastas. Da mesma forma, você pode criar uma ~/MasterPages/
pasta na qual colocará as páginas master do site.
Um problema potencial com a colocação de master e páginas de conteúdo em pastas diferentes envolve URLs quebradas. Se a página master contiver URLs relativas em hiperlinks, imagens ou outros elementos, o link será inválido para páginas de conteúdo que residem em uma pasta diferente. Neste tutorial, examinamos a origem desse problema, bem como soluções alternativas.
O problema com URLs relativas
Uma URL em uma página da Web será considerada uma URL relativa se o local do recurso para o qual ele aponta for relativo à localização da página da Web na estrutura de pastas do site. Qualquer URL que não comece com uma barra à esquerda (/
) ou um protocolo (como http://
) é relativa porque é resolvida pelo navegador com base no local da página da Web que contém a URL.
Por exemplo, nosso site tem uma ~/Images/
pasta com um único arquivo de imagem, PoweredByASPNET.gif
. O arquivo Site.master
de página master tem um <img>
elemento na footerContent
região com a seguinte marcação:
<div id="footerContent">
<img src="Images/PoweredByASPNET.gif" alt="Powered by ASP.NET!" />
</div>
O src
valor do atributo no <img>
elemento é uma URL relativa porque não começa com /
ou http://
. Em resumo, o valor do src
atributo informa ao navegador para procurar na Images
subpasta um arquivo chamado PoweredByASPNET.gif
.
Ao visitar uma página de conteúdo, a marcação acima é enviada diretamente para o navegador. Reserve um momento para visitar About.aspx
e exibir a origem HTML enviada para o navegador. Você descobrirá que exatamente a mesma marcação na página master foi enviada para o navegador.
<div id="footerContent">
<img src="Images/PoweredByASPNET.gif" alt="Powered by ASP.NET!" />
</div>
Se a página de conteúdo estiver na pasta raiz (como é About.aspx
) tudo funcionará conforme o esperado porque há uma Images
subpasta em relação à pasta raiz. No entanto, as coisas serão interrompidas se a página de conteúdo estiver em uma pasta diferente da página master. Para ilustrar isso, crie uma subpasta chamada Admin
. Em seguida, adicione uma página de conteúdo chamada Default.aspx
à Admin
pasta , certificando-se de associar a nova página à Site.master
página master.
Observação
No tutorial Especificando o título, meta tags e outros cabeçalhos HTML na Página Mestra , criamos uma classe de página base personalizada chamada BasePage
que define automaticamente o título da página de conteúdo (se ela não foi atribuída explicitamente). Não se esqueça de ter a classe code-behind da página recém-criada derivada de BasePage
para que ela possa utilizar essa funcionalidade.
Depois de criar essa página de conteúdo, seu Gerenciador de Soluções deverá ser semelhante à Figura 1.
Figura 01: Uma nova pasta e uma página de ASP.NET foram adicionadas ao projeto
Em seguida, atualize o Web.sitemap
arquivo para incluir uma nova <siteMapNode>
entrada para esta lição. O XML a seguir mostra a marcação completa Web.sitemap
, que agora inclui a adição de um terceiro <siteMapNode>
elemento.
<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="~/Default.aspx" title="Home">
<siteMapNode url="~/About.aspx" title="About the Author" />
<siteMapNode url="~/MultipleContentPlaceHolders.aspx" title="Using Multiple ContentPlaceHolder Controls" />
<siteMapNode url="~/Admin/Default.aspx" title="Rebasing URLs" />
</siteMapNode>
</siteMap>
A página recém-criada Default.aspx
deve ter quatro controles de conteúdo correspondentes aos quatro ContentPlaceHolders em Site.master
. Adicione algum texto ao controle Conteúdo referenciando o MainContent
ContentPlaceHolder e visite a página por meio de um navegador. Como mostra a Figura 2, o navegador não pode encontrar o arquivo de PoweredByASPNET.gif
imagem. O que está acontecendo?
A ~/Admin/Default.aspx
página de conteúdo é enviada o mesmo HTML para a footerContent
região como foi a About.aspx
página:
<div id="footerContent">
<img src="Images/PoweredByASPNET.gif" alt="Powered by ASP.NET!" />
</div>
Como o <img>
atributo do src
elemento é uma URL relativa, o navegador tenta procurar uma Images
pasta em relação ao local da pasta da página da Web. Em outras palavras, o navegador está procurando o arquivo Admin/Images/PoweredByASPNET.gif
de imagem .
Figura 02: O PoweredByASPNET.gif
arquivo de imagem não pode ser encontrado (clique para exibir a imagem em tamanho real)
Substituindo URLs relativas por URLs absolutas
O oposto de uma URL relativa é uma URL absoluta, que é aquela que começa com uma barra (/
) ou um protocolo como http://
. Como uma URL absoluta especifica o local de um recurso de um ponto fixo conhecido, a mesma URL absoluta é válida em qualquer página da Web, independentemente da localização da página da Web na estrutura de pastas do site.
Para corrigir a imagem quebrada mostrada na Figura 2, precisamos atualizar o <img>
atributo do src
elemento para que ele use uma URL absoluta em vez de uma relativa. Para determinar a URL absoluta correta, visite uma das páginas da Web em seu site e examine a barra de endereços. Como mostra a barra endereço na Figura 2, o caminho totalmente qualificado para o aplicativo Web é http://localhost:3908/ASPNET_MasterPages_Tutorial_04_CS/
. Portanto, poderíamos atualizar o <img>
atributo do src
elemento para uma das duas URLs absolutas a seguir:
/ASPNET_MasterPages_Tutorial_04_CS/Images/PoweredByASPNET.gif
http://localhost:3908/ASPNET_MasterPages_Tutorial_04_CS/Images/PoweredByASPNET.gif
Reserve um momento para atualizar o <img>
atributo do src
elemento para uma URL absoluta usando um dos formulários mostrados acima e, em seguida, visite a ~/Admin/Default.aspx
página por meio de um navegador. Desta vez, o navegador localizará e exibirá corretamente o PoweredByASPNET.gif
arquivo de imagem (consulte a Figura 3).
Figura 03: A PoweredByASPNET.gif
imagem agora é exibida (clique para exibir a imagem em tamanho real)
Embora a codificação rígida na URL absoluta funcione, ela associa firmemente seu HTML ao servidor do site e ao local da pasta, o que pode mudar. O uso de uma URL absoluta do formulário http://localhost:3908/...
é frágil porque o número da porta anterior localhost
é selecionado automaticamente sempre que o servidor Web de desenvolvimento de ASP.NET interno do Visual Studio é iniciado. Da mesma forma, a http://localhost
parte só é válida ao testar localmente. Depois que o código for implantado em um servidor de produção, a base de URL será alterada para outra coisa, como http://www.yourserver.com
. A URL absoluta no formulário /ASPNET_MasterPages_Tutorial_04_CS/...
também sofre da mesma fragilidade porque, muitas vezes, esse caminho de aplicativo difere entre servidores de desenvolvimento e produção.
A boa notícia é que ASP.NET oferece um método para gerar uma URL relativa válida em runtime.
Usando~
eResolveClientUrl
Em vez de codificar uma URL absoluta, ASP.NET permite que os desenvolvedores de página usem o bloco (~
) para indicar a raiz do aplicativo Web. Por exemplo, anteriormente neste tutorial, usei a notação ~/Admin/Default.aspx
no texto para fazer referência à Default.aspx
página na Admin
pasta. O ~
indica que a Admin
pasta é uma subpasta da raiz do aplicativo Web.
O Control
método da classe usa uma URL e a modifica em uma URL relativa apropriada para a página da ResolveClientUrl
Web na qual o controle reside. Por exemplo, chamar ResolveClientUrl("~/Images/PoweredByASPNET.gif")
de About.aspx
retorna Images/PoweredByASPNET.gif
. Chamá-lo de ~/Admin/Default.aspx
, no entanto, retorna ../Images/PoweredByASPNET.gif
.
Observação
Como todos os controles de servidor ASP.NET derivam da Control
classe , todos os controles de servidor têm acesso ao ResolveClientUrl
método . Até mesmo a Page
classe deriva da classe , o Control
que significa que você pode usar esse método diretamente das classes code-behind de suas ASP.NET páginas.
Usando~
na Marcação Declarativa
Vários controles da Web ASP.NET incluem propriedades relacionadas à URL: o controle HyperLink tem uma NavigateUrl
propriedade; o controle Image tem uma ImageUrl
propriedade e assim por diante. Quando renderizados, esses controles passam seus valores de propriedade relacionados à URL para ResolveClientUrl
. Consequentemente, se essas propriedades contiverem um ~
para indicar a raiz do aplicativo Web, a URL será modificada para uma URL relativa válida.
Tenha em mente que apenas ASP.NET controles de servidor transformam o ~
em suas propriedades relacionadas à URL. Se um ~
aparecer na marcação HTML estática, como <img src="~/Images/PoweredByASPNET.gif" />
, o mecanismo de ASP.NET enviará o ~
para o navegador junto com o restante do conteúdo HTML. O navegador pressupõe que o ~
faz parte da URL. Por exemplo, se o navegador receber a marcação <img src="~/Images/PoweredByASPNET.gif" />
, ele pressupõe que há uma subpasta chamada ~
com uma subpasta Images
que contém o arquivo PoweredByASPNET.gif
de imagem .
Para corrigir a marcação de imagem no Site.master
, substitua o elemento existente <img>
por um ASP.NET controle Web image. Defina o controle web de ID
imagem como PoweredByImage
, sua ImageUrl
propriedade como ~/Images/PoweredByASPNET.gif
e sua AlternateText
propriedade como "Alimentado por ASP.NET!"
<div id="footerContent">
<asp:Image ID="PoweredByImage" runat="server" ImageUrl="~/Images/PoweredByASPNET.gif"
AlternateText="Powered by ASP.NET!" />
</div>
Depois de fazer essa alteração na página master, reveja a ~/Admin/Default.aspx
página novamente. Desta vez, o PoweredByASPNET.gif
arquivo de imagem aparece na página (consulte Figura 3). Quando o controle Web de Imagem é renderizado, ele usa o ResolveClientUrl
método para resolve seu ImageUrl
valor de propriedade. ImageUrl
No ~/Admin/Default.aspx
é convertido em uma URL relativa apropriada, como mostra o seguinte snippet de código-fonte HTML:
<div id="footerContent">
<img id="ctl00_PoweredByImage" src="../Images/PoweredByASPNET.gif" alt="Powered by ASP.NET!" />
</div>
Observação
Além de ser usado em propriedades de controle Web baseadas em URL, o ~
também pode ser usado ao chamar os Response.Redirect
métodos e Server.MapPath
, entre outros. Além disso, o ResolveClientUrl
método pode ser invocado diretamente de um ASP.NET ou master marcação declarativa da página.
Corrigindo as URLs relativas restantes da página mestra
Além do <img>
elemento no footerContent
que acabamos de corrigir, a página master contém mais uma URL relativa que requer nossa atenção. A topContent
região inclui o link "Tutoriais de Páginas Mestras", que aponta para Default.aspx
.
<div id="topContent">
<a href="Default.aspx">Master Pages Tutorials</a>
</div>
Como essa URL é relativa, ela enviará o usuário para a Default.aspx
página na pasta da página de conteúdo que ele está visitando. Para que esse link sempre aponte para na pasta raiz, precisamos substituir o <a>
elemento por um controle Web HyperLink para Default.aspx
que possamos usar a ~
notação.
Remova a marcação do <a>
elemento e adicione um controle HyperLink em seu lugar. Defina o HyperLink como ID
lnkHome
, sua NavigateUrl
propriedade como ~/Default.aspx
e sua Text
propriedade como "Tutoriais de Páginas Mestras".
<div id="topContent">
<asp:HyperLink ID="lnkHome" runat="server" NavigateUrl="~/Default.aspx"
Text="Master Pages Tutorials" />
</div>
É isso! Neste ponto, todas as URLs em nossa página master são adequadamente baseadas quando renderizadas por uma página de conteúdo, independentemente de quais pastas a página master e a página de conteúdo estão localizadas.
Resolução automática de URL na<head>
seção
No tutorial Criando um layout de Site-Wide usando páginas mestras , adicionamos um <link>
ao Styles.css
arquivo na <head>
região:
<head runat="server">
<title>Untitled Page</title>
<asp:ContentPlaceHolder id="head" runat="server">
</asp:ContentPlaceHolder>
<link href="Styles.css" rel="stylesheet" type="text/css" />
</head>
Embora o <link>
atributo do href
elemento seja relativo, ele é convertido automaticamente em um caminho apropriado em runtime. Como discutimos no tutorial Especificando o título, metamarques e outros cabeçalhos HTML na Página Mestra , a <head>
região é, na verdade, um controle do lado do servidor, que permite modificar o conteúdo de seus controles internos quando ele é renderizado.
Para verificar isso, reveja a ~/Admin/Default.aspx
página e exiba a origem HTML enviada ao navegador. Como ilustra o snippet abaixo, o <link>
atributo do href
elemento foi modificado automaticamente para uma URL relativa apropriada, ../Styles.css
.
<head>
<title>
Default
</title>
<link href="../Styles.css" rel="stylesheet" type="text/css" />
</head>
Resumo
As páginas mestras geralmente incluem links, imagens e outros recursos externos que devem ser especificados por meio de uma URL. Como as páginas de master e conteúdo podem não existir na mesma pasta, é importante abster-se de usar URLs relativas. Embora seja possível usar URLs absolutas codificadas, fazer isso associa firmemente a URL absoluta ao aplicativo Web. Se a URL absoluta mudar - como geralmente faz ao mover ou implantar um aplicativo Web - você precisará lembrar de voltar e atualizar as URLs absolutas.
A abordagem ideal é usar o bloco (~
) para indicar a raiz do aplicativo. ASP.NET controles Web que contêm propriedades relacionadas à URL mapeiam o ~
para a raiz do aplicativo em runtime. Internamente, os controles da Web usam o Control
método da ResolveClientUrl
classe para gerar uma URL relativa válida. Esse método é público e está disponível em todos os controles de servidor (incluindo a Page
classe), para que você possa usá-lo programaticamente em suas classes code-behind, se necessário.
Programação feliz!
Leitura Adicional
Para obter mais informações sobre os tópicos discutidos neste tutorial, consulte os seguintes recursos:
Sobre o autor
Scott Mitchell, autor de vários livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 3.5 em 24 Horas. Scott pode ser contatado em mitchell@4GuysFromRolla.com ou através de seu blog em http://ScottOnWriting.NET.
Agradecimentos Especiais
Interessado em revisar meus próximos artigos do MSDN? Nesse caso, solte-me uma linha em mitchell@4GuysFromRolla.com.