Article Details                  
 
Programação em Asp.Net - parte I

Apresenta os novos controlos de navegação que acompanham a nova framework. Demonstra a implementação de um provider personalizado.

Programação em Asp.Net - parte I

Nível: Iniciado
Conteúdo: Introdução à programação em Asp.Net
Ferramentas: Visual Web Dev Express
Linguagem: C#

Ao que parece, 2005 vai ser um ano de evolução a nível da plataforma .Net. Como sempre acontece nestas alturas, é costume aparecerem novos componentes. Dando continuidade ao meu artigo anterior, em que apresentei algumas das novidades esperadas a nível do ADO.Net, hoje vou também iniciar uma série sobre algumas das novidades que poderemos encontrar no Asp.Net.

Para além de estarmos a falar de uma plataforma excelente, temos também uma outra novidade que (quase de certeza) irá motivar muito mais os programadores a migrarem as suas aplicações. Pois é, parece que a Microsoft ultrapassou o seu último tabu: fornece-nos (praticamente) o Visual Studio de borla através das designadas Express Tools. Bem, é verdade que estas ferramentas não possuem todo o potencial do Visual Studio (por exemplo, a construção de um assembly com strong name exige a utilização da linha de comandos), mas para quem quer programar em .Net, parece-me que estas ferramentas são ideais (e, ainda por cima, são gratuitas - algo que é anormal quando falamos da Microsoft)

As novidades são muitas: novas pastas com funções especiais, Master pages e Themes, utilização de Web Parts, alterações a nível do caching, novos controlos (incluindo novos controlos de acesso a dados), etc. Como ainda não tive tempo para explorar todas estas novidades, optei por hoje centrar a minha atenção em torno dos controlos de navegação que, como o próprio nome indica, permitem navegar (ou, pelo menos, auxiliar a navegação) num site.


Navegação dentro de um site

A nova versão da framework permite a construção de um sistema de navegação sem ter que escrever praticamente uma linha de código. E como é que fazemos isso? Bem, o primeiro passo consiste em definir a estrutura do site, utilizando para tal um ficheiro de XML. Depois, é só utilizar os controlos que pretendemos para permitir a navegação ao utilizador. Bem, passemos então à parte mais interessante: demonstração prática de como construir um site que utilize estes componentes.


Construção de um ficheiro de navegação

Segundo a documentação actual (é preciso termos em atenção que estamos a falar de uma versão beta), cada site pode definir a sua navegação através de um ficheiro de xml que deve ser definido com o nome web.sitemap. Já agora, o ficheiro que contém o schema tem o nome de siteMapSchema.xsd. O conteúdo é o seguinte:


<?xml version="1.0" encoding="utf-8" ?>
<xs:schema targetNamespace="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" elementFormDefault="qualified"
xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:annotation>
<xs:documentation>XmlSiteMapProvider SiteMap File Schema</xs:documentation>
</xs:annotation>
<xs:element name="siteMap">
<xs:complexType>
<xs:choice>
<xs:element ref="siteMapNode" />
</xs:choice>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="urlNodeAttributes">
<xs:attribute name="url" type="xs:anyURI" />
<xs:attribute name="title" type="xs:string" />
<xs:attribute name="description" type="xs:string" />
<xs:attribute name="keywords" type="xs:string" />
<xs:attribute name="roles" type="xs:string" />
</xs:attributeGroup>
<xs:attributeGroup name="fileNodeAttributes">
<xs:attribute name="siteMapFile" type="xs:string" />
<xs:attribute name="securityTrimmingEnabled" type="xs:boolean" default="false" />
</xs:attributeGroup>
<xs:attributeGroup name="providerNodeAttributes">
<xs:attribute name="provider" type="xs:string" />
</xs:attributeGroup>
<xs:element name="siteMapNode">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element ref="siteMapNode" />
</xs:sequence>
<!--Only one of the following attribute groups is allowed -->
<xs:attributeGroup ref="urlNodeAttributes" />
<xs:attributeGroup ref="fileNodeAttributes" />
<xs:attributeGroup ref="providerNodeAttributes" />
<!--end attribute groups -->
</xs:complexType>
</xs:element>
</xs:schema>


Contudo, cada siteMapNode pode conter (opcionalmente) vários outros elementos siteMapNode no seu interior. Normalmente, cada elemento siteMapNode pode definir as seguintes características:


  • Url: url que representa o destino deste nó. Atenção: não pode haver vários elementos siteMapNode com o mesmo url;

  • Title: propriedade que indica o nome utilizado para representar este nó num controlo de navegação;

  • Description: descrição associada a este nó. Esta informação é apresentada como tooltip;

  • Roles: lista de roles que têm permissões para ver este elemento (só utilizado quando são utilizadas opções de segurança);

  • Key: string utilizada como chave aquando da execução de uma pesquisa.

Para além de podermos definir esta informação através de um ficheiro de xml, podemos também aceder a estes elementos programaticamente através do elemento SiteMapNode (que está definido no namespace System.Web).

Após definirmos o ficheiro de xml, é só arrastar os controlos desejados para as páginas e relacioná-los com o nosso ficheiro de navegação.


Controlo SiteMapPath

O código que acompanha este artigo contém duas samples. A primeira, designada de site1, demonstra como podemos definir o nosso ficheiro de navegação e relacioná-lo com os vários controlos. Nessa aplicação, é possível verificar alguns aspectos interessantes:


  • Por defeito, só podemos definir um ficheiro web.sitemap por aplicação web. Para demonstrar essa funcionalidade, defini um novo ficheiro de navegação no interior de uma subpasta (Subpasta) e utilizei os mesmos controlos que tinha utilizado para as páginas definidas na raiz do site. Como é possível observar, os controlos continuam a obter a sua informação a partir do ficheiro definido na raiz (em vez de se adaptarem à pasta em que a página está - como acontece, por exemplo, com os ficheiros de configuração). Bem, se por algum acaso houver necessidade de utilizar outro nome para o ficheiro, então torna-se necessário alterar a estrutura do ficheiro de configuração através dos elementos <siteMap> et al.

  • Se quisermos relacionar o web.sitemap com os controlos web temos de recorrer a um provider.

Antes de aprofundarmos estes tópicos, queria apenas deixar o esquema definido no ficheiro web.sitemap:


<?xml version="1.0" encoding="utf-8" ?>
<siteMap>
<siteMapNode url="Default.aspx" title="Homepage" description="Navegar para homepage">
<siteMapNode url="Pagina1.aspx" title="Página1" description="Navegar para a página1" roles="role1;role2" />
<siteMapNode url="Pagina2.aspx" title="Página2" description="Navegar para a página2" roles="" />
<siteMapNode url="Pagina3.aspx" title="Página3" description="Navegar para a página 3">
<siteMapNode url="Pagina4.aspx" title="Página4" description="Navegar para a página4" roles="" />
</siteMapNode>
<siteMapNode url="subpasta/Pagina5.aspx" title="Página5" description="Navegar para a página5" roles="" />
<siteMapNode url="subpasta/Pagina6.aspx" title="Página6" description="Navegar para a página6" roles="" />
</siteMapNode>
</siteMap>


Como é possível observar, se necessitarmos de definir mais do que um role temos de utilizar um dos dois separadores possíveis: vírgula ( , ) ou ponto e vírgula ( ; ). Esta informação foi obtida através do .Net Reflector pelo que poderá haver uma ou outra alteração pontual na versão final (apesar de tentar encontrar informação sobre este assunto na documentação, a verdade é que fiquei de mãos a abanar).

Na realidade, só encontrei um controlo que foi feito explicitamente para ser utilizado com o ficheiro de navegação web.sitemap. Estou a falar do novo controlo SiteMapPath. Este controlo é perfeito para auxiliar o utilizador a situar-se num site, uma vez que com ele podemos indicar os locais por onde o utilizador já passou (esta definição é feita a nível da hierarquia definida no ficheiro web.sitemap, que se encontra na raiz). Se ainda não experimentaram, tentem lá navegar ao longo das páginas e reparem no controlo que está situado ao topo...como podem verificar, ele fornece indicação sobre a localização da página actual, comparando-a com a hierarquia definida no ficheiro de navegação.


SiteMapDataSource - acesso universal à informação fornecida pelo web.sitemap

Ao consultarem o (pouco) código que acompanha o site1, podem verificar que, apesar da minha afirmação anterior, existem várias páginas com controlos que são (mais ou menos) preenchidos de acordo com a informação que se encontra no ficheiro de navegação. Então como é que isso é possível? A resposta é simples: a nova framework introduz o conceito de DataSource. São alguns os componentes que implementam este interface. Entre eles podemos encontrar o SiteMapDataSource. Esta classe contém algumas propriedades interessantes:


  • FlatDepth: indica os níveis da hierarquia que devem ser mostrados. O valor por defeito é -1, que indica que não há limite em relação à hierarquia que deve ser apresentada;

  • ParentLevelsDisplayed: indica o número de nós pai que devem ser mostrados;

  • SiteMapViewType: define a forma como os nós são mostrados. Por defeito, são mostrados hierarquicamente (ou seja, esta propriedade assume o valor Tree); contudo, podemos também atribuir os valores Flat (neste caso, os nós são todos apresentados como se estivessem definidos no mesmo nível) e Path (mostra apenas os dados de forma hierárquica entre o nó actual e a raiz do documento de navegação);

  • StartingDepth: indica o nível a partir do qual devem ser obtidos os nós definidos no ficheiro de navegação. Por defeito, é utilizado o valor -1, mas se necessitarmos de, por exemplo, indicar a raiz, podemos atribuir o valor 0, e por aí fora (claro que o -1 já inclui a raiz, pelo que não será necessário indicar este valor de forma explicita se pretendermos visualizar todos os nós a partir da raiz).

Para além destas propriedades, este controlo apresenta outras, cujas definições podem ser encontradas na ajuda da MSDN. Os controlos que efectuam data binding relacionam-se com estes elementos através de uma nova propriedade designada de DataSourceId. Portanto, para apresentarmos os itens definidos num ficheiro de navegação, basta colocarmos um controlo do tipo SiteMapDataSource e utilizarmos as propriedades DataSourceId dos restantes controlos estabelecermos esse relacionamento. O excerto seguinte ilustra essa operação:


<asp:Menu ID="_menu" Runat="Server" BackColor="LightGoldenrodYellow" BorderWidth="1px" Orientation="Horizontal" DataSourceID="_xmlSource">
<DynamicHoverStyle BackColor="Gainsboro" ForeColor="DarkBlue" />
</asp:Menu>
<asp:SiteMapDataSource id="_xmlSource" Runat="Server" StartFromCurrentNode="false" ShowStartingNode="false" />


Num próximo artigo irei abordar esta nova forma de aceder à base de dados.


Tudo bem, mas...

Mas e como é que isto funciona? Ao que parece, quando a aplicação Web é inicializada, a framework Asp.Net instancia um objecto do tipo SiteMap, que é constituído por vários elementos do tipo SiteMapNode. A classe SiteMap contém um conjunto de propriedades estáticas que permitem aceder ao provider actual (Provider), ao nó raiz (RootNode) e ao nó actual (CurrentNode).

Por defeito, o Asp.Net utiliza o provider XmlSiteProvider que obtém a sua informação a partir de um ficheiro chamado web.sitemap, situado na raiz do site.


Isto é interessante, mas tenho o meu menu armazenado na base e dados!

E como é que faço para que a informação relativa à navegação tenha origem numa base de dados ou num ficheiro de xml com uma estrutura diferente? Simples: é necessário construir o nosso próprio provider e indicá-lo através do ficheiro de configuração do nosso site Web.

O projecto site2 exemplifica a obtenção de um menu de navegação a partir de informação armazenada numa base de dados. A base de dados contém apenas uma tabela, que contém os campos IdNo, Titulo, Descricao, Url, IdNoPai.

A criação de um provider customizado implica a criação de uma nova classe que deverá implementar a classe abstracta SiteMapProvider. Temos de implementar obrigatoriamente os seguintes membros:


  • RootNode: indica o nó de topo do provider actual;

  • GetRootNodeCore: permite a um provider pai construir uma hierarquia de forma a obter um novo nó na referência de providers que estão a ser utilizados;

  • FindSiteMapNode: obtém o nó representado pela página no url indicado;

  • GetChildNodes: colecção de SiteMapNodes (SiteMapNodeCollection) que contém os nós filho do nó indicado;

  • GetParentNode: devolve o nó pai do elemento actual;

O sample que acompanha este artigo implementa todos os elementos referidos. Após implementarmos este novo provider, temos de indicar que queremos utilizá-lo. Como sempre, este tipo de indicações terá de ser fornecido no ficheiro de configuração. No nosso exemplo, obtemos o seguinte:


<siteMap defaultProvider="DbProvider">
<providers>
<add name="DbProvider" type="DBSiteMapProvider" cnnString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\Control Articles\Asp.Net2 1\Code\site2\navigation.mdb;"/>
</providers>
</siteMap>


Portanto, nada de mais...já agora, podemos também remover explicitamente um provider utilizando a tag remove. Já agora, e voltando a uma questão levantada anteriormente, se for necessário modificar o ficheiro que contém a definição, então podemos recorrer ao seguinte código (copy/paste directo da documentação):


<configuration>
<system.web>
<siteMap defaultProvider="XmlSiteMapReader">
<providers>
<add
name=" XmlSiteMapReader"
type="XmlSiteMapProvider, System.Web, Version=1.1.3300.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
siteMapFile="my.sitemap"
description="XmlSiteMapProvider that loads my.sitemap"/>
</siteMap>
</system.web>
</configuration>


Algumas nós

O código que acompanha utiliza outra das novidades do Asp.Net 2. Estou a falar da nova pasta Code. Agora basta colocarmos os nossos ficheiros no interior desta pasta que estes são compilados automaticamente sem termos de efectuar qualquer acção adicional. Portanto, este código tem um funcionamento semelhante à pasta bin, só que podemos colocar ficheiros com código.

Um dos aspectos importantes a ter em atenção é o facto de não podermos colocar ficheiros escritos em diferentes linguagens no interior desta pasta. Contudo, se for necessário conter ficheiros escritos em linguagens diferentes, então podemos utilizar subpastas e agrupar esses ficheiros em cada subpasta de acordo com a linguagem. Nesse caso, temos ainda de recorrer ao ficheiro de configuração para definir cada subpasta como uma unidade de compilação separa através dos elementos <compilation>, <codeSubDirectories> et al. A documentação contém uma descrição completa destas features.

Conclusões finais

Com este artigo começámos a introduzir algumas das novidades da nova plataforma asp.net. As novidades são tantas e boas que hoje tive de optar por fazer apenas uma breve introdução aos novos controlos de navegação.


Onde estamos?

Bem, por hoje é tudo. Como é possível verificar, a nova framework contém muitas e boas novidades. No próximo artigo vamos continuar a apresentar as novidades desta framework, com especial atenção aos novos controlos de ligação a base de dados.

Por favor enviem-me as vossas opiniões/sugestões/críticas/correcções para progC@netmadeira.com.

Fiquem bem e boa programação! Até à próxima.

Leiam o meu blog em: http://weblogs.pontonetpt.com/luisabreu


Written By: labreu
Date Posted: 4/14/2006
Number of Views: 739

Return