segunda-feira, 9 de novembro de 2009

Como compilar projetos do Visual Studio para diferentes versões do .NET Framework

Estamos criando uma aplicação WPF no Visual Studio 2010 (beta 1), mas o Blend 3 não carrega assemblies compilados para .NET Framework 4.0. Então na máquina do nosso designer (chique hein), que é quem usa o Blend, tivemos que compilar uma versão do projeto para o Framework 3.5.
Um parêntesis: na nossa equipe temos um designer, um gerente de produto e um gerente de projetos. QUEM É QUE CODIFICA, meu Deus? Depois os cara ficam surpreso porque o projeto está atrasado…
Achamos um artigo falando sobre uma opção do MSBuild – o engine de compilação automatizada da Microsoft – para gerar código para uma versão específica do .NET Framework: /toolsversion. Eu achava que o MSBuild (de uma breve experiência anterior) era uma ferramenta super difícil de se trabalhar, mas a integração dele com projetos do Visual Studio tornou a tarefa ridiculamente fácil. Criamos um .bat que recompila todos os projetos da solução. Um trecho dele está a seguir:
msbuild StorageClient\StorageClient.csproj /toolsversion:3.5 /verbosity:quiet
if ERRORLEVEL 1 goto erro
O MSBuild reconhece arquivos de projeto do Visual Studio, e já ativa o compilador correspondente. A opção /toolsversion indica para qual Framework o código deve ser gerado (valores permitidos: 2.0, 3.0, 3.5 e 4.0), e sobrepõe a definição no arquivo de projeto. O if seguinte checa se a saída do MSBuild foi 1 – o que sinaliza erro. Desta forma você pode abortar a compilação dos outros projetos da solução (usando o bom (?) e velho goto).
Também vamos usar esta solução na geração das tabelas no Azure Development Storage, pois o DevTableGen – o utilitário que gera as tabelas – não suporta assemblies do Framework 4.0.
O diretório do MSBuild não está no path default de uma janela de linha de comando, então use o Visual Studio 2010 Command Prompt (grupo de programas do VS 2010 > Visual Studio 2010 Tools), que já tem o MSBuild no seu path.

sexta-feira, 6 de novembro de 2009

Chave Duplicada no Azure Table Storage

Mais uma da série “Azure: Pense Numas Mensagenzinhas de Erro RUINS”. Como testar por tentativa de inserção de linhas duplicadas no Azure Table Storage?

Como o Azure é REST-based, as mensagens de erro tem que seguir a semântica REST (falei um pouco sobre isto em outro post). Então quando você tenta inserir uma linha com chave (PartitionKey e RowKey, mas como elas identificam unicamente uma linha, vou chamá-las só de chave) idêntica a outra que já está armazenada no Table Storage do Azure, ele retorna um erro HTTP 409. De acordo com a definição do protocolo HHTP no site do W3C,

10.4.10 409 Conflict
The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request.

Bem, o “recurso” – a tabela no Azure – está em um “estado” – já existe uma linha com a chave igual à linha que estou tentando inserir – que conflita com o “pedido” – o INSERT da linha com chave duplicada. Realmente, como no caso do erro 404 quando não localizo uma linha procurando pela chave (o outro post citado acima), faz sentido “de um ponto de vista REST”. Mas de novo, se estou incluindo uma linha em uma tabela, esperaria algo do tipo “Chave primária duplicada”, e não “HTTP 409 – Conflict”.

Mas como dizem aqui no cerrado, “Whatever”. O try/catch para interceptar esse erro é:

contexto.AddObject("Usuarios", novoUsuario);

try

{
contexto.SaveChanges();
}
catch (System.Data.Services.Client.DataServiceRequestException erro)
{
// DataServiceRequestException é só um wrapper para o "erro de verdade",
// que fica em DataServiceRequestException.InnerException
System.Data.Services.Client.DataServiceClientException erroMesmo =
erro.InnerException as System.Data.Services.Client.DataServiceClientException;
if ((erroMesmo != null) && (erroMesmo.StatusCode == 409))
{
// HTTP status code 409: Conflict. Na criação de uma nova linha em uma tabela
// do Table Storage do Azure, se a linha sendo incluída tem Partition Key e
// Row Key identicas a uma linha já existente, é retornado o erro 409.
throw new Exception(string.Format("Já existe uma linha com a chave ({0},{1})",
novoUsuario.PartitionKey, novoUsuario.RowKey));
}
else
throw; // Outro erro – joga a batata quente pra cima
}