Palestra TechEd 2007

Como mencionei aqui, eu palestrei no TechEd Brasil 2007, falando sobre algumas funcionalidades do ASP.NET 2.0. Para isso, eu fiz uma aplicação de exemplo para demonstrar tais funcionalidades e estou disponibilizando aqui para download. Com relação ao PPT eu ainda não tenho permissão para publicar e, assim que a puder, eu postarei aqui o link até o mesmo.

Gostaria de agradecer publicamente a todos que estiveram presentes. Obrigado em especial ao Leonardo Tolomelli, Cezar Guimarães e Rogério Cordeiro que me deram esta oportunidade e também ao Roberto Fonseca, que me ajudou imensamente durante o evento/palestra.

PageAsyncTasks vs. Páginas Assíncronas

Uma pergunta muito pertinente que me fizeram durante a palestra, mais precisamente quando estava falando sobre as páginas assíncronas, é se é ou não possível definir um timeout para a execução da mesma.

Desta forma apenas, não. Para isso, você deve utilizar as chamadas Tarefas Assíncronas. Basicamente ela tem o mesmo conceito das páginas assíncronas, mas permite a definição/suporte de timeout (em segundos), propagação do contexto de segurança para as chamadas assíncronas e, finalmente, a possibilidade de execução paralela das tarefas (pois podemos adicionar N tarefas em cada página).

Abaixo segue a implementação básica desta funcionalidade:

<%@ Page Async=”true” AsyncTimeout=”15″ … %>

protected void Page_Load(object sender, EventArgs e)
{
    this.RegisterAsyncTask(
        new PageAsyncTask(
            new BeginEventHandler(Inicio),
            new EndEventHandler(Fim),
            new EndEventHandler(ExcedeuTimeout),
            null,
            true)); //Processamento paralelo (default é false)

    this.ExecuteRegisteredAsyncTasks();               
}

private IAsyncResult Inicio(object sender, EventArgs e, AsyncCallback callback, object state) { }

private void Fim(IAsyncResult result) { }

private void ExcedeuTimeout(IAsyncResult result) { }

Novas Funcionalidades do ASP.NET 3.5

Com todo este barulho em volta do Visual Studio .NET 2008 + .NET Framework 3.5, muitos me perguntam quais são as mudanças/melhorias que o ASP.NET teve na versão 3.5.

Para quem acompanha desde as primeiras versões, a mudança do ASP.NET 1.x para a 2.0 foi enorme. Novos controles (databinding declarativo (SqlDataSource, ObjectDataSource, etc.), XXXView, etc.) e funcionalidades (Membership, Roles, WebParts, MasterPages, etc.) deram muito mais produtividade aos desenvolvedores Web que utilizam essa plataforma.

Já na versão 3.5, as mudanças são mais leves, bem mais leves. Chamaria a atenção para:

  • AJAX Integrado: Agora voce já tem embutido no VS.NET 2008 o suporte ao framework do AJAX, sem a necessidade de instalar isso a parte, como acontecia no VS.NET 2005.
  • ListView: Trata-se de um DataList/Repeater melhorado que permite a exibição de registros assim como o GridView, só que utilizando templates e agrupamento dos dados.
  • DataPager: Este controle traz a funcionalidade de paginação para os controles data-bound (como o ListView), permitindo voce customizar se quer a navegação das páginas em botões ou números. Uma das funcionalidades interessantes que este controle proporciona, é a possibilidade de definirmos a página atual via QueryString (GET).

Se falarmos de Visual Studio 2008 + .NET Framework 3.5, eu teria que prolongar muito o post. Se quiserem analisar tais funcionalidades, podem consultar este link.

TechEd Brasil 2007

Bem, como todo mundo já sabe, de 5 a 7 de dezembro acontece em São Paulo o TechEd Brasil e, ao contrário dos anos anteriores, este ano estarei efetuando uma palestra na sala 7 do dia 07/12, das 09:15 as 10:30hs.

A palestra chama Deep Dive em ASP.NET 2.0 onde, pretendo abordar algumas features do ASP.NET 2.0 que são desconhecidas por muitos, funcionalidades que são um tanto quanto interessantes mas que, com a correria do dia-a-dia, muitas vezes passam desapercebidas. Além da palestra, terá uma porção de Ask-the-Experts espalhadas pelo evento e, em algumas delas irei participar mas, que até então não sei exatamente o horário/local.

Será uma boa oportunidade para conhecer as pessoas que apenas conheço virtualmente. Se voce estiver no TechEd e estiver disposto a bater um papo, pode me contactar para isso.

Final de Semana

Neste fim de semana chuvoso e decidi fazer/ler algumas coisas que estavam pendentes. Vamos lá:

  1. Finalmente li a revista Mundo Dot Net (ainda bem que ela é bimestral :)). Destaques para a matéria que o Tarifa e o Alfred escreveram sobre o .NET Framework 3.5 e o VS.NET 2008 e para o Eduardo Miranda,  escreveu sobre IoC, assunto qual é ainda bastante desconhecido.
  2. Li um artigo muito interessante (e polemico) que o Dennes Torres escreveu sobre as coisas que ninguém sabe sobre a Microsoft.
  3. Fui visitar a reformulada Saraiva Mega Store no Shopping Iguatemi em Campinas. A loja ficou muito bonita e bastante tecnológica. Como de costume, fui na seção de livros de informática e lá tinha um livro sobre ASP.NET AJAX que pretendo ler. Eu quero comprá-lo e fui até aqueles leitores de código de barras para ver o seu valor e, para minha surpresa, o livro estava aproximadamente R$ 120,00 :|. Uma fábula! Na Amazon.com está US$ 26.00. É realmente muito triste ver como as coisas são caras aqui no Brasil :(.

Propriedade ApplicationName

Quando instalamos a estrutura de Membership do ASP.NET 2.0, temos uma tabela que armazena o nome das aplicações (aspnet_Applications) que estão sendo acomodadas dentro daquele servidor SQL Server. Essa tabela possui uma coluna chamada ApplicationName e, se valor é exposto através de uma propriedade estática, também chamada ApplicationName, da classe Membership.

A propriedade ApplicationName da classe Membership trata-se de uma propriedade de escrita/leitura. Sendo assim, voce pode alterar o nome da aplicação em tempo de execução e, a partir dai, passar a executar todos os métodos baseados nesta aplicação. Eis um exemplo:

Response.Write(Membership.ValidateUser(“israel”, “passw0rd”).ToString());
Membership.ApplicationName = “NomeDaOutraAplicacao”;
Response.Write(Membership.ValidateUser(“israel”, “passw0rd”).ToString());

Apesar de funcionar, devemos nos atentar a questão do acesso em um ambiente multithreading, como é o caso do ASP.NET. Como a estrutura de Provider Model armazena e compartilha uma única instancia do provider ativo (padrão Singleton), a alteração em um local refletirá em todas as requisições e, conseqüentemente, podemos ter comportamentos inesperados. Geralmente isso só funcionaria em uma aplicação administrativa, que permitisse apenas um único usuário por vez acessando-a.

Credenciais de ASP.NET para ASP

Recentemente estive envolvido em um problema que muita gente acredito já ter passado. Trata-se de enviar dados de uma página ASP.NET para uma página ASP que encontra-se dentro da mesma aplicação (mesmo diretório virtual). Para ser mais preciso, precisava enviar dados as credenciais de acesso (login) para a página ASP.

Para enviar os parametros, poderia ser via querystrings ou cookies, mas lembrando que é preciso aplicar algum algoritmo de criptografia para garantir que nenhum espião consiga interceptar o processo e, consequentemente, visualizar o que está ali dentro. Para tornar as coisas um pouco mais complicadas, a solução mais interessante é mandar esses dados via headers, para ficar “mais seguro”. Como tudo está no mesmo servidor/aplicação, a solução para isso é criar um handler, herdando de DefaultHttpHandler que, por sua vez, fornece uma propriedade chamada ExecuteUrlHeaders que permite adicionar valores nos headers. O código abaixo ilustra essa classe:

public class TransferHandler : DefaultHttpHandler
{
    public TransferHandler() { }

    public override string OverrideExecuteUrlPath()
    {
        base.ExecuteUrlHeaders.Add(“AppUserName”,
            base.Context.User.Identity.Name);
        return null;
    }
}

O arquivo Web.Config fica:

<httpHandlers>
  <add path=”*.asp” type=”TransferHandler” verb=”GET,HEAD,POST” validate=”true”/>
</httpHandlers>

Com isso, todas as requisições para as página *.asp serão interceptadas por esse handler que fará o trabalho de capturar a informação de login, e enviá-la para a página *.asp. Com isso, nas páginas *.asp podemos fazer:

Response.Write Request.ServerVariables(“HTTP_APPUSERNAME”)

Lembre-se que o ideal é aplicar um algoritmo de criptografia/hash para “salgar” as coisas. O hash, ao meu ver, seria mais interessante, já que voce define uma chave privada (que somente voce conhece) e a utiliza para efetuar o hash do valor. Isole essa classe em um componente e exponha-o via COM, para que voce consiga acessá-lo na aplicação ASP. Neste caso, voce poderá enviar, via headers, o valor puro e também um novo item que é o resultado hash desse valor. Quando chegar na página de destino, voce pega ambos os dados, e valida através do mesmo componente (e mesmo algoritmo), para verificar se o valor não foi alterado durante a sua viagem.

Barrando acesso à elementos/atributos

Recentemente estive envolvido em um projeto simples mas um tanto quanto interessante. Estávamos fazendo a configuração de um servidor Web e todas as aplicações ASP.NET 2.0 que ali seriam hospedadas devem utilizar uma mesma base de dados para as funcionalidades de Membership, Roles e Profile.

A questão é que as aplicações podem ter um arquivo Web.Config e customizar essas configurações em cada uma delas. Só que isso não seria permitido. A solução foi até mais simples do que imaginava e, me forçou a olhar para alguns atributos que nunca prestei a devida atenção até então. Todos os elementos que são colocados nos arquivos de configuração herdam (diretamente ou indiretamente) da classe ConfigurationElement. Essa classe possui 5 principais propriedades (ou atributos):

  • lockAllAttributesExcept: Informa que todos os atributos de um elemento serão bloqueados, com exceção dos atributos que estão contidos nesta lista.
  • lockAllElementsExcept: Informa que todos os elementos de um elemento “pai” serão bloqueados, com exceção dos elementos que estão contidos nesta lista.
  • lockAttributes: Bloqueia apenas os atributos contidos nesta lista.
  • lockElements: Bloqueia apenas os elementos contidos nesta lista.
  • lockItem: Bloqueia o item como um tudo e, conseqüentemente, todos os seus “filhos”.

Para que fosse possível isso, editamos o arquivo Machine.Config e lá colocamos todas as configurações necessárias para que as aplicações pudessem herdar as configurações estipuladas para Membership, Roles e Profile e não ter direito de sobrescreve-las. Com isso, o arquivo Machine.Config fica definido como:

<?xml version=”1.0″>
<configuration>
  <connectionStrings>
    <add
        name=”LocalSqlServer”
        connectionString=”CONN_STRING”
        providerName=”System.Data.SqlClient”
        lockItem=”true” />
  </connectionStrings>
  <system.web>
    <membership defaultProvider=”AspNetSqlMembershipProvider” lockAttributes=”defaultProvider”>
      <providers lockElements=”clear”>
        <add
            name=”AspNetSqlMembershipProvider”
            type=”System.Web.Security.SqlMembershipProvider, System.Web”
            connectionStringName=”LocalSqlServer”
            enablePasswordRetrieval=”false”
            enablePasswordReset=”true”
            requiresQuestionAndAnswer=”true”
            applicationName=”/”
            requiresUniqueEmail=”false”
            passwordFormat=”Hashed”
            maxInvalidPasswordAttempts=”5″
            minRequiredPasswordLength=”7″
            minRequiredNonalphanumericCharacters=”1″
            passwordAttemptWindow=”10″
            passwordStrengthRegularExpression=””
            lockAttributes=”connectionStringName;enablePasswordRetrieval;passwordFormat” />
      </providers>
    </membership>
  </system.web>
</configuration>

Obviamente que algumas aplicações devem customizar algum desses atributos e, justamente por isso, que nem todos os elementos/atributos foram bloqueados. Por exemplo, se desejar customizar o nome da aplicação no arquivo Web.Config de cada uma das aplicações, então podemos fazer:

<?xml version=”1.0″?>
<configuration>
    <system.web>
      <membership userIsOnlineTimeWindow=”10″>
        <providers>
          <remove name=”AspNetSqlMembershipProvider”/>
          <add
            name=”AspNetSqlMembershipProvider”
            type=”System.Web.Security.SqlMembershipProvider, System.Web”
            applicationName=”Teste” />
        </providers>
      </membership>
    </system.web>
</configuration>

Nada impede do desenvolvedor poder adicionar novos providers de memberships, roles e profiles mas, ele não poderá habilitá-lo, já que o atributo defaultProvider está bloqueado a nível superior. Um outro detalhe importante é podemos remover o provider especificado no arquivo Machine.Config através do elemento remove mas, sendo assim, ele não poderá utilizar as funcionalidades de Membership definidas para o servidor.

system.web/pages/namespaces

Há no ASP.NET uma possibilidades de adicionarmos no arquivo Web.Config da aplicação uma seção chamada namespaces, pertencente ao elemento pages. Um código de exemplo do mesmo é mostrado abaixo:

<configuration>
    <system.web>
      <pages>
        <namespaces>
          <add namespace=”System.IO”/>
          <add namespace=”System.Net.Mail”/>
        </namespaces>
      </pages>
    </system.web>
</configuration>

Várias pessoas acham que os namespaces ali colocados servem como uma “referencia global” para as todas as páginas da aplicação, ou seja, acreditam que poderão utilizar os tipos fornecidos por cada um deles (namespaces) em qualquer página/classe da aplicação.

Só que isso não é verdade. Os namespaces ali declarados são utilizados durante a pré-compilação do site, mais precisamente, quando voce utiliza o arquivo ASPX para colocar código HTML e também o código server-side e, neste caso, ele é serve como uso global. Essa é a forma de centralizar todos os namespaces utilizados pelas páginas. Cada um dos sub-elementos que estão ali correspondem a diretiva @ Import da página ASP.NET.

Propagando o contexto de segurança nas chamadas assíncronas

Nas versões anteriores do ASP.NET quando precisamos efetuar um processamento assíncrono através da Interface IHttpAsyncHandler, o método a ser disparado iria correr sob as credenciais do worker process, o que poderia causar problemas de segurança, já que o contexto de segurança da aplicação não era propagado para o processamento assíncrono.

O ASP.NET 2.0 resolve isso com as PageAsyncTasks onde, automaticamente, o contexto é propagado sem que o desenvolvedor precise se preocupar em escrever código para gerenciar isso.

Navegando pelo diretório do .NET Framework 2.0 em %windir%Microsoft.NETFrameworkv2.0 eu vi um arquivo que não conhecia: Aspnet.config. Este arquivo possui um elemento chamado runtime e, dentro dele, dois sub-elementos, a saber: legacyImpersonationPolicy e alwaysFlowImpersonationPolicy.

<?xml version=”1.0″ encoding=”UTF-8″ ?>
<configuration>
    <runtime>
        ……
        <legacyImpersonationPolicy enabled=”true”/>
        <alwaysFlowImpersonationPolicy enabled=”false”/>

    </runtime>
</configuration>

Para que o comportamento seja semelhante as versões anteriores, o elemento legacyImpersonationPolicy é definido como false e, sendo assim, o contexto não será propagado. Caso você não precise manter compartibilidade com aplicações em outras versões, você pode inverter os valores do atributo enabled de ambos elementos e, consequentemente, todo o contexto de segurança será propagado entre as chamadas assíncronas da aplicação, inclusive se utilizando a Interface IHttpAsyncHandler.