Microsoft, o Asp.Net e Open Source

04/04/2012

Em uma decisão histórica (pelo menos eu considero assim) a Microsoft está tornando definitivamente Open Source, o Asp.Net MVC, a API Web e o Razor. Essa decisão foi tomada recentemente e muda significativamente o rumo dessas tecnologias para as próximas versões do .Net.

Maiores detalhes com Scott Guthrie e em Asp.Net Open Source.


Considerações de Segurança sobre o View State

03/03/2012

O ViewState tem um sido um importante recurso no desenvolvimento .Net por agilizar o armazenamento de estado e colaborar para liberar o servidor dessa tarefa. Mantendo informações automaticamente no cliente, temos um desenvolvimento simplificado e ganhamos um ponto na questão da escalabilidade. Mas, como nada é perfeito, o ViewState em contra-partida pode trazer problemas de performance na execução de suas páginas, o que torna importante conhecer alguns detalhes relativos a sua otimização/proteção.

Protegendo informações

Tipicamente, informações no ViewState são mantidas aparentemente em um formato ilegível, como abaixo:

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKLTU2ODgwMzc3NQ9kFgICAw9kFgICAw8PFgIeBFRleHQFGVRlcm1pbmFkby4gOTAwMDAxIGxpbmhhcy5kZGQ=" />

Podemos imaginar que os dados estão criptografados pelo seu formato, mas não é o que ocorre. Os dados do ViewState são codificados em Base64-Encoding e um código Hash é criado por padrão para essa codificação. O papel desse Hash é evitar o chamado Tampering, onde o dado original é modificado no cliente. Se isso acontecer, o ASP.Net tem condições de determinar através da verificação do Hash, se o ViewState foi alterado indevidamente. O uso do Hash é padrão, mas pode ser configurado através do elemento EnableViewStateMac por página:

<%@ Page EnableViewStateMac="false" %>

Ou para a toda a aplicação no Web.config:

<configuration>
<system.web>
<pages enableViewStateMac="false" />
</system.web>
</configuration>

Embora o Hashing ofereça um meio de determinar se algo foi alterado indevidamente, o ViewState ainda pode ser revertido. É aí que entra um outro elemento de configuração do ViewState chamado ViewStateEncryptionMode. Esse elemento possui três valores: Auto, Always e Never. O valor padrão é Auto e significa que o ViewState inteiro será criptografado automaticamente. Isso ocorre quando alguns controles manipulam informações sensíveis, por exemplo DataKeys representando identificadores de um item em um GridView. Always significa que o ViewState será criptografado sempre e Never, nunca será criptografado.

No valor Auto, se algum controle executar o método RegisterRequiresViewStateEncryption, isso significa que o ViewState deve ser criptografado. Mas observe que se a página estiver configurada como Never, esse pedido do controle será ignorado, portanto, leve isso em consideração se for criar um controle que use o ViewState para armazenamento de dados sensíveis. Note que nada muda no acesso ao ViewState programaticamente, pois o ASP.Net se encarrega de criptografar e decriptografar os dados.

Os algoritmos válidos para criptografia e seus parâmetros podem ser consultados no MSDN.

Para configurar a criptografia do ViewState podemos usar a diretiva Page:

<%@ Page ViewStateEncryptionMode=”Always” %>

Ou para toda a aplicação no Web.config:

<configuration>
<system.web>
<pages viewStateEncryptionMode="Always" />
</system.web>
</configuration>

Agora compare o ViewState de exemplo no início do post, com esse que agora está criptografado:

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="K9qLC8ZS0lbgrMl12I3eu4y7uyzwL3DyjgCFrWCCe1PJyoYF5i9HYxRvE6qeRxCEjOV8BgfkpXcnOVRiBBEClbsoFSMltoIs8nDiewuzBFjGTuO42+WQc3QzBy+P3ri+pXhY4cLbU9RW3zK4d0SLWz6i0wqvJ/NPyOrRwlgmI51X+OYvuyEbID53YZ5t1FR4" />

Bem diferente não? :-)

Se você estiver analisando uma aplicação quanto à segurança, cabe avaliar a proteção do ViewState dentro da perspectiva STRIDE. Considere que medidas de proteção podem trazer problemas de performance à aplicação e isso não será diferente com o ViewState.


Erro de Compilação BC31019: Unable to write to output file

09/09/2011

Em qualquer software há erros em que a descrição do erro é suficiente para identificar sua causa, e outros cuja descrição e/ou solução aparentemente não tem relação. Um erro relativamente comum que se enquadra no último caso é o erro BC31019: Unable to write to output file ‘<arquivo>‘: <erro>. Uma das situações que provoca esse erro durante a compilação é a impossibilidade do Visual Studio gravar informações em arquivos .pdb. Quando isso ocorre a mensagem de erro BC31019 toma a seguinte forma:

Unable to write to output file 'C:\Projeto\App.pdb': Unspecified error.

Durante a compilação, se um erro desse tipo é encontrado, o Visual Studio exibe a ocorrência do erro na Task List. Uma tentativa imediata de descobrir o problema seria clicar o botão direito do mouse sobre a entrada de erro e selecionar a opção Show Error Help, como mostrado na figura abaixo:

Erro BC31019
Erro BC31019 na Task List

A documentação fala sobre a possibilidade de uma outra aplicação estar usando o mesmo arquivo no momento da compilação e sugere verificar os atributos do arquivo, o que seria útil caso o arquivo estivesse marcado como Read Only. Mas, e se o problema não tiver nenhuma relação imediata com o que diz a documentação? Temos então um mistério.

Controladores de Versão

Em projetos em equipe a utilização de um software para controle de versões é fundamental. Por mais firmes que sejam porém, sempre há a possibilidade de um bug ou de falha humana. Imagine portanto, que no momento de um check-in ocorra um problema com o controlador de versão e um ou mais arquivos não sejam corretamente armazenados ou ainda, que o desenvolvedor cometeu uma falha. Pois essa também pode ser a causa de um erro BC31019: o compilador está tentando compilar um arquivo referenciado no projeto, mas que não se encontra fisicamente na sua estrutura. Quando esse problema ocorre, o Visual Studio marca o arquivo faltante com um ícone de aviso contendo uma placa amarela com exclamação e levanta o erro BC31019. A solução portanto é remover esse arquivo do seu projeto ou acertar a sua referência no controle de versão para depois baixá-lo novamente. Quando todos os arquivos referenciados estiverem presentes, a compilação ocorrerá normalmente. Eis uma situação um tanto quanto diferente do que diz a documentação…

Note que esse erro é relativamente comum em ambientes controlados mas pode ocorrer fora dele também. A solução porém, é a mesma.

Alternativas
Encontrar o(s) arquivo(s) faltante(s) é uma questão de percorrer a solução e observar se algum arquivo apresenta o ícone de falta de referência e acertá-la. Mas dependendo do tamanho do projeto esse pode ser um processo tedioso. Uma alternativa pode ser abrir o arquivo .pdb em um editor de textos e procurar por entradas que mostrem o nome de um diretório do seu projeto. Normalmente nas primeiras linhas do arquivo .pdb você encontrará o nome do diretório e arquivo responsáveis pelo problema. Você pode então ir diretamente ao local indicado e verificar o nefasto arquivo.

Fica a dica: atenção nos arquivos referenciados no projeto!

Até a próxima!


Criando Arquivos XML Através de XML Literals

23/08/2011

O princípio de criação de um arquivo através de XML Literals é de que o conteúdo do arquivo seja construído já na forma em que será apresentado. Isso significa que o XML é escrito no código tal como será exibido no documento final. Além de tornar a criação do XML mais simples e reduzir a possibilidade de erros na criação dinâmica, isso permite também termos uma visão do XML ainda antes de sua geração. Vamos considerar o arquivo usado em meu artigo anterior para criação com XML Literals:

Imports System.Xml.Linq

Dim xdocLista As New XDocument
Dim xelConteudo As XElement = Nothing

xelConteudo = <som>
    <producoes>
        <album nome="Nothing Safe" artista="Alice in Chains" ano="1999">
            <selo>Sony Music Distribution</selo>
        </album>
        <album nome="Return of the Killer A's: The Best of Anthrax" artista="Anthrax" ano="1999">
            <selo>Beyond</selo>
        </album>
        </producoes>
    </som>

xdocLista = New XDocument(New XDeclaration("1.0", "UTF-8", "true"), xelConteudo)
xdocLista.Save("C:\Som.xml")

Note que um objeto do tipo XElement recebe um bloco XML de maneira explícita, contendo elementos filhos, atributos e valores. Em seguida, um objeto do tipo XDocument recebe o bloco anterior e salva o arquivo. Temos então um arquivo XML criado dinâmicamente de forma literal e salvo com o método Save do objeto XDocument. Atenção ao método Save pois ele irá sobrescrever o arquivo caso ele já exista.

Expressões

Na criação de documentos dinamicos, normalmente há dados vindos de fontes diferentes que serão combinados para a geração de um arquivo final. A sintaxe do XML Literals permite o uso de expressões para esse fim. Vejamos uma simples tela para entrada de dados:

Tela simples de entrada de dados

Tela simples de entrada de dados

A idéia é capturar os dados digitados pelo usuário e usá-los para definir um arquivo XML. Usando expressões, teríamos a combinação abaixo:

Private xdocSom As XDocument = Nothing
Private lstAlbuns As New List(Of XElement)

Private Sub cmdAdicionar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdAdicionar.Click
Dim xelAlbum As XElement = Nothing

xelAlbum = <album nome=<%= txtAlbum.Text %> artista=<%= txtArtista.Text %> ano=<%= txtAno.Text %>
              <selo<%= txtSelo.Text %></selo>
           </album>

lstAlbuns.Add(xelAlbum)

End Sub

No trecho acima, cada caixa de texto da tela tem seu valor associado ao XML através de uma expressão. A expressão <%= txtAlbum.Text %> por exemplo, significa que será colocado no valor do atributo nome, o que foi digitado na caixa de texto txtAlbum. Cada novo elemento criado é colocado em uma lista de XElement, que em seguida será usada na criação do XML, também através de uma expressão. Esse tipo de associação permite obter valores de fontes diversas e tê-los como parte do XML.

Private Sub cmdArquivo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdArquivo.Click
Dim xelConteudo As XElement = Nothing
xelConteudo = <som>
                <producoes>
                    <%= lstAlbuns %>
                </producoes>
              </som>

xdocSom = New XDocument(New XDeclaration("1.0", "UTF-8", "true"), xelConteudo)

If Not blnErrosXml Then
    xdocSom.Save("c:\Som.xml")
Else
    xdocSom = Nothing
    MessageBox.Show(strErroXml)
End If

End Sub

Expressões podem envolver também construções. No exemplo abaixo, a rotina que cria os albuns foi alterada para combinarmos expressões em um tratamento para verificar se o elemento selo foi informado. Como queremos entender que todo o elemento selo é opcional, Nothing é usado para ignorar esse elemento quando ele não é informado.

Private Sub cmdAdicionar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdAdicionar.Click
Dim xelAlbum As XElement = Nothing

xelAlbum = <album nome=<%= txtAlbum.Text %> artista=<%= txtArtista.Text %> ano=<%= txtAno.Text %>
              <%= If(String.IsNullOrEmpty(txtSelo.Text), Nothing, <selo><%= txtSelo.Text %></selo>) %>
           </album>

lstAlbuns.Add(xelAlbum)

End Sub

Namespaces

Outra característica muito interessante do XML Literals é a possibilidade de declararmos Namespaces tanto no XML diretamente, quanto através da cláusula Imports. Na primeira forma o atributo xmlns é escrito junto com o XML como em:
<som xmlns:info="http://rinaldoferreira.wordpress.com">

Na segunda forma, deve-se declarar o Namespace junto aos demais Imports da tela, porém seguindo a sintaxe do XML Literals como em:
Imports <xmlns:info="http://rinaldoferreira.wordpress.com">

Em ambos os casos o XML resultante conterá o Namespace informado e tags referentes ao Namespace poderão ser adicionadas ao documento, como no exemplo:

<som xmlns:info="http://rinaldoferreira.wordpress.com">
    <producoes>
        <album nome="Nothing Safe" artista="Alice in Chains" ano="1999">
            <selo>Sony Music Distribution</selo>
            <info:gravacao>
                <info:tempo>62:43</info:tempo>
                <info:faixas>15</info:faixas>
            </info:gravacao>
        </album>
        <album nome="Return of the Killer A's: The Best of Anthrax" artista="Anthrax" ano="1999">
            <selo>Beyond</selo>
            <info:gravacao>
                <info:tempo>74:50</info:tempo>
                <info:faixas>16</info:faixas>
            </info:gravacao>
        </album>
    </producoes>
</som>

XML Literals é um excelente recurso na maleta de ferramentas dos desenvolvedores VB.Net e como o XML assumiu lugar de destaque em nosso trabalho, as oportunidades para seu uso são vastas. E não falta imaginação :-)

Até breve!


Posters de Namespaces do .Net Framework

04/08/2011

A cada nova versão do .Net Framework há acrescimos e mudanças na Base Class Library, a parte central das classes disponíveis no .Net Framework. Para auxiliar na localização das classes mais importantes e das mais frequentemente utilizadas, a Microsoft costuma disponibilizar resumos dos principais namespaces e classes. Abaixo há uma lista resumida dos chamados Posters do .Net Framework a partir da versão 2.0:

Poster .Net Framework 2.0 (dotnetfx20poster)
Poster .Net Framework 3.0 (Windows_WinFX30_Poster)
Poster .Net Framework 3.5 (NET_35_Namespaces_Poster_JAN08)
Poster .Net Framework 4.0 (098-115952-NETFX4-Poster)

Esses são Posters relativos ao .Net Framework apenas, mas existem também Posters relacionados ao Visual Studio .Net, VB.Net e C#. Eles podem ser baixados diretamente do site de downloads da Microsoft.


Lendo Arquivos XML Através de XML Literals

26/07/2011

Uma característica muito interessante porém pouco utilizada no VB.Net são os XML Literals. Pegando carona na idéia do Linq, a equipe do VB.Net introduziu o XML Literals como forma de simplificar/flexibilizar a manipulação de dados XML em memória ou peristidos com uma sintaxe mais direta e que pode ser associada ao Linq to XML. Na sintaxe do XML Literals o XML é manipulado como se estivéssemos digitando diretamente XML ao invés de código que gere XML. Para entendermos melhor como isso funciona, vamos considerar um arquivo XML com a seguinte estrutura:


<?xml version="1.0" encoding="utf-8" ?>
<som>
<producoes>
<album nome="Nothing Safe" artista="Alice in Chains" ano="1999">
    <selo>Sony Music Distribution</selo>
</album>
<album nome="Return of the Killer A's: The Best of Anthrax" artista="Anthrax" ano="1999">
    <selo>Beyond</selo>
</album>
<album nome="Starfish" artista="The Church" ano="1988">
    <selo>Arista</selo>
</album>
<album nome="Collective Soul" artista="Collective Soul" ano="1995">
    <selo>Atlantic</selo>
</album>
</producoes>
</som>

Para trabalharmos esse arquivo em memória teremos que carregá-lo, mas ao invés de recorrermos ao System.Xml para isso, vamos usar XML Literals através do namespace System.Xml.Linq:

Dim xmlDoc As XDocument = XDocument.Load("C:\Som.xml")

A partir daí para ler elementos do arquivo, usamos XML Literals. Por exemplo, para identificar todos os selos presentes no arquivo podemos montar o código assim:

Debug.WriteLine("Selos:")
For Each xeAlbum As XElement In xmlDoc...<producoes >.<album>
    Debug.WriteLine(xeAlbum...<selo>.Value)
Next

No trecho acima, xmlDoc...<producoes> se refere à todos os elementos producoes que sejam descendentes do elemento raiz, enquanto .<album> representa um elemento album descendente de <producoes>. Percorremos então todos os albums de <producoes> lendo o valor do elemento <selo>. Agora considere o trecho abaixo:

Debug.WriteLine("Albuns:")
For Each xeAlbum As XElement In xmlDoc...<producoes>.<album>
    Debug.WriteLine(xeAlbum.@nome)
Next

Aqui a idéia é obter o nome de cada album. Como os nomes estão representados por atributos, utilizamos o caracter @ como em @nome para ler o valor do atributo. Se o objetivo for obter dados genéricos sobre os elementos, isso também é possível. Aqui obtemos o total de albuns existentes no arquivo:

Dim intAlbums As Integer = xmlDoc...<producoes>.<album>.Count

Linq to XML e XML Literals

O XML Literals incorpora os recursos do Linq de forma a simplificar ainda mais a leitura dos dados. Por exemplo, podemos localizar todos os albuns produzidos em um determinado ano usando expressões Lambda:

Dim enumAno = xmlDoc...<producoes>.<album>.Where(Function(a) a.@ano = 1999)
For Each xeAlbum In enumAno
    Debug.WriteLine(xeAlbum.@nome)
Next

Ou claúsulas Linq, como neste exemplo para localizar um album especifico trazendo seu nome e artista:

Dim xeItem = (From b In xmlDoc...<album> _
Where b.@nome.ToString.Contains("Starfish")).FirstOrDefault
Debug.WriteLine(String.Format("{0} - {1}", xeItem.@nome, xeItem.@artista))

Repare que em ambos os exemplos as variáveis são por inferência, do tipo IEnumerable(Of XElement) e XElement, o que desfaz a necessidade de declararmos o tipo do objeto. Na verdade, esse recurso pode ser desligado a nível de projeto ou módulo através da cláusula Option Infer Off, embora não seja exatamente necessário.

Vimos como ler dados em XML na memória utilizando Linq to XML e XML Literals. Para saber como criar aqrquivos XML usando XML Literals, leia o próximo artigo sobre o assunto.


Problemas com Sessão no ASP.NET 4.0

10/06/2011

Há diversas causas possíveis para perda de sessão no ASP.Net/IIS e recentemente encontrei mais uma. No processo de migração de uma aplicação do ASP.Net 2.0 para o ASP.Net 4.0 precisamos montar um Web.config compatível com o IIS6 e IIS7 simultaneamente. Uma das alterações nessa configuração foi definir a página padrão da aplicação como mostrado abaixo:

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
        <defaultDocument enabled="true">
            <files>
                <clear/>
                <add value="index.aspx" />
            </files>
        </defaultDocument>
</system.webServer>

Durante o tempo em que o elemento defaultDocument não existiu, a aplicação rodou normalmente tanto em Debug quanto em Release. Após a colocação do elemento defaultDocument a aplicação começou a apresentar problemas de perda de sessão a partir de uma página específica. De início não atribuí o problema ao novo elemento de configuração mas como não foi possível depurar o erro, retirei o elemento da configuração e a aplicação voltou a funcionar. Assim, procurei mais informações sobre o elemento defaultDocument e lendo o artigo Default Document <defaultDocument>, compreendi melhor o seu comportamento. O que de fato ocorreu é que essa página continha um controle Image com a Url vazia, pois estava aguardando a imagem final que seria colocada ali. Durante a requisição, como não havia uma Url para a imagem, a página usada como defaultDocument era executada em seu lugar, resetando os valores da variável de sessão original. O real problema portanto não era a perda da sessão mas o fato de que a página padrão estava sendo executada indevidamente. Após colocarmos uma Url para a imagem, o problema cessou.

Navegadores

Há uma questão interessante nesse problema e para o qual ainda não consegui uma resposta. Mesmo quando a imagem não possuía uma Url, a aplicação gerava erros no IE6, IE7 e IE8, mas funcionava normalmente no IE9 e FireFox. Com a colocação final da imagem a aplicação passou a funcionar em todos os navegadores. Assim que conseguir alguma informação sobre esse comportamento diferenciado entre os navegadores, atualizarei esse artigo. Até lá, muita atenção com Urls vazias…


Seguir

Obtenha todo post novo entregue na sua caixa de entrada.