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="https://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="https://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="https://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…