quarta-feira, 4 de julho de 2007

Entendendo, executando e agendando as atualizações do data warehouse do Team Foundation Server

Olá.

Depois de quase um mês sem escrever para o blog, venho trazer uma dica muito boa para quem está trabalhando com o Team Foundation Server.

Após instalarmos o TFS e criar nossos primeiros projetos percebemos que os relatórios exibidos nos portais dos projetos estavam desatualizados.

Antes de prosseguirmos com o artigo, dê uma olhada na figura abaixo. Ela representa como estão estruturados os bancos de dados do TFS bem como sua relação com o warehouse de onde os relatórios do Reporting Service acessam os dados.




Todo relatório do TFS possui em seu cabeçalho a informação “Last Warehouse Update” e percebemos que se iam vários dias sem que o warehouse fosse atualizado.

Após estudar mais a fundo a documentação do TFS descobri que, por padrão, o warehouse deveria ser atualizado automaticamente a cada 3.600 segundos, ou seja, 1 hora.
Para verificar o tempo deste agendamento, consulte a tabela _WarehouseConfig no banco de dados TFSWarehouse em seu servidor SQL Server do Team Foundation Server.
O campo RunIntervalSeconds informa a quantidade de segundos do agendamento.

Exemplo:
select * from _WarehouseConfig

Não aconselho alterar diretamente as tabelas dos bancos de dados do TFS. Caso necessitemos alterar a freqüência de execução da atualização do warehouse podemos fazer isso por meio dos web services expostos pelo TFS.
O web service responsável pelo gerenciamento do warehouse é o
http://localhost:8080/Warehouse/v1.0/warehousecontroller.asmx
e este web service expõe, dentre outros métodos, o método “ChangeSetting”.
Este método possui dois parâmetros: settingID e newValue.
Para alterar o intervalo de atualização do warehouse passe como parâmetros, respectivamente, RunIntervalSeconds e o número de segundos desejado.

Este web service também expõe o método “Run” que pode ser chamado a qualquer momento e não necessita de parâmetros. Ao executar este método as atualizações do warehouse são executadas imediatamente.
Caso você force a as atualizações do warehouse chamando o método “Run”, saiba que não necessariamente você terá seu portal de projetos atualizado imediatamente. Isto ocorre porque, por padrão, os relatórios do TFS no Reporting Service estão configurados para armazenar cache de 30 minutos. Isto quer dizer que, ou você aguarda no máximo mais meia hora para ver os novos dados ou altera as configurações do relatório desejado no Reporting Service.

Porém o problema pode não estar na execução do web method. Você chama o “Run” e tudo é atualizado normalmente só que esta atualização continua não acontecendo no intervalo de segundos configurado.

Este problema pode ser originado por várias razões. Aconselho uma visita a este link:
Troubleshooting the Data Warehouse

Também sugiro uma visita a How to: Use Web Services to Enable and Configure Trace for Team Foundation Server Components que orienta sobre como ativar o trace de um componente do Team Foundation Server.

Porém o nosso problema aqui era outro e não constava dos links que indiquei acima.

Quem realiza a atualização periódica do warehouse é um serviço do TFS chamado TFSServiceScheduler. Este serviço pode ser gerenciado pelo Services na área administrativa do Windows. Seu executável está localizado em <"diretório do TFS">\TFSServerScheduler.

Dentro desta pasta existe também um arquivo de configuração chamado TFSServerScheduler.exe.config. No nosso caso, neste arquivo, existia uma tag de configuração chamada “BisDomainUrl”. Verificando a documentação percebi que esta tag deveria ser trocada por “TFSNameUrl”.

Apensas alterei esta chave e o agendamento começou a funcionar perfeitamente, de acordo com o tempo determinado pelo RunIntervalSeconds.

Por enquanto é só.

Até o próximo post.

segunda-feira, 11 de junho de 2007

Mantendo a rolagem da página entre postbaks usando MaintainScrollPositionOnPostback

Olá.

Hoje venho apenas trazer uma dica rápida.

Supondo que tenhamos um formulário muito grande, que extrapola o tamanho vertical da tela, ele será exibido no navegador com a barra de rolagem do lado direito da tela.
Ao preencher as informações do formulário a aplicação muitas vezes necessita realizar algum ou vários postbacks.
Logo, é necessário mantermos o foco no local onde o usuário está trabalhando, sem que ele seja obrigado a rolar a página todas as vezes que a página for recarregada.

No ASP.Net 1.0 e 1.1 utilizávamos a opção “SmartNavigation” da diretiva Page em cada página que desejássemos adicionar este comportamento.
Caso desejável poderíamos incluir uma opção no web.config para habilitar tal opção para toda a aplicação:

<page smartNavigation="true" />

O SmartNavigation trabalhava com IFrames para conseguir tal comportamento.

No ASP.Net 2.0 o SmartNavigation foi substituído pela opção “MaintainScrollPositionOnPostback”.

MaintainScrollPositionOnPostback aceita true ou false e mantém a posição da rolagem da página entre os pastbacks da mesma sem usar o recurso de IFrame.

Abraços e até o próximo post.

sexta-feira, 8 de junho de 2007

Definindo Media Type usando Themes, Skins e CSS

Olá.

Quem já trabalha com Themes e Skins provavelmente sabe como o ASP.Net 2.0 se comporta.

Basicamente, o que acontece é que, quando uma página utiliza um certo Theme, o ASP.Net automaticamente registra todos os Cascading Style Sheets (CSS) do Theme em questão.
Não há necessidade de usarmos a tag “link” do HTML para todas as folhas de estilo que temos em nossa aplicação.

Isso é particularmente importante quanto temos mais de uma folha de estilo definindo classes com o mesmo nome mas que devem ser carregadas condicionalmente, de acordo com o Theme utilizado. Basta que coloquemos cada folha de estilo correspondente ao Theme dentro de sua respectiva pasta.

Quando o ASP.Net constrói a página, além de aplicar o Theme desejado, ele registra todos os “.css” que estão na pasta do respectivo Theme.

Seria perfeito não fosse o fato de que, muitas vezes necessitamos ter estilos distintos para cada tipo de mídia como, por exemplo, um estilo para exibição na tela e outro para impressão.

Normalmente registraríamos o “.css” desta maneira:

<link href="App_Themes/Default/Print.css" type="text/css" rel="stylesheet" media="print" />
<link href="App_Themes/Default/Screen.css" type="text/css" rel="stylesheet" media="screen" />

Acontece que, ao registrar a folha de estilo automaticamente, o ASP.Net não permite que definamos o Media Type.

Ele simplesmente registra os “.css” como abaixo:

<link href="App_Themes/Default/Print.css" type="text/css" rel="stylesheet" />
<link href="App_Themes/Default/Screen.css" type="text/css" rel="stylesheet" />

Uma das soluções que encontramos foi criar uma classe herdada de HTMLHead que adicionasse alguma lógica para que o registro das folhas de estilo fosse feito corretamente.
Quem quiser se aventurar por esta solução visite o link The Problems with Themes, Skins, and Cascading Style Sheets (CSS) in ASP.NET 2.0 – Defining a Media Type(s).

Os problemas que vejo nesta solução, apesar de funcionar de maneira esperada, é que tiramos a decisão do registro dos estilos das mãos dos designers e levamos para o programador.

A solução que mais se aproxima do mundo ideal é dada pela própria W3C na definição dos Media Types em seu site.

Pela definição do W3C, uma folha de estilo pode possuir rules do tipo @media.

Desta forma, trabalharíamos da seguinte maneira:

@media print {
BODY { font-size: 10pt }
}
@media screen {
BODY { font-size: 12pt }
}

Na verdade, nem precisamos separar os estilos para tela e para impressão em dois arquivos. Eles podem ser definidos em um único “.css”, onde os estilos referentes a “screen” e “print” estão em suas respectivas rules.
Talvez valha separar os estilos em arquivos por mídia apenas por uma questão de organização, mas não por obrigação.

Por enquanto é só.

Abraços e até o próximo post.

terça-feira, 29 de maio de 2007

Get Latest Version automático no CheckOut

Olá.

Muitas empresas já estão implantando o Team Foundation Server e, pelo que tenho percebido, as grandes dificuldades são principalmente quanto à diferença de paradigma e cultura, principalmente no que se refere ao Source Control.
Um dos pontos que mais incomodam os desenvolvedores acostumados ao Visual Source Safe é o fato do Visual Studio não pegar automaticamente a última versão do arquivo quando da realização do check out.

Os desenvolvedores do Team Foundation têm argumentos bem sólidos para este comportamento:

It turns out that this is by design, so let me explain the reasoning behind
it. When you perform a get operation to populate your workspace with a set
of files, you are setting yourself up with a consistent snapshot from source
control. Typically, the configuration of source on your system represents
a point in time snapshot of files from the repository that are known to work
together, and therefore is buildable and testable.
As a developer working in
a workspace, you are isolated from the changes being made by other
developers. You control when you want to accept changes from other
developers by performing a get operation as appropriate. Ideally when you
do this, you'll update the entire configuration of source, and not just one or
two files. Why? Because changes in one file typically depend on
corresponding changes to other files, and you need to ensure that you've still
got a consistent snapshot of source that is buildable and testable.
This is
why the checkout operation doesn't perform a get latest on the files being
checked out. Updating that one file being checked out would violate the
consistent snapshot philosophy and could result in a configuration of source
that isn't buildable and testable. As an alternative, Team Foundation
forces users to perform the get latest operation at some point before they
checkin their changes. That's why if you attempt to checkin your changes,
and you don't have the latest copy, you'll be prompted with the resolve
conflicts dialog.

Porém, muitas vezes, eles não têm conseguindo convencer a comunidade muito bem.

Por isso existem algumas iniciativas de confecção de plug-in para o Visual Studio que adicionam o comportamento ao mesmo.

Após instalar e testar alguns, percebemos que o melhor é o TFS GetLatest (http://blogs.microsoft.co.il/files/folders/leon/entry10828.aspx).

O melhor deste plug-in é que, configurados o servidor e a porta do Team Foundation Server, toda a ação de Get Latest Version é transparente quando o usuário realiza algum Check Out.

Abraços e até o próximo post.

quinta-feira, 24 de maio de 2007

No symbols have been loaded for this document

Olá.

Venho hoje falar rapidamente sobre um problema que vez ou outra ocorre quando queremos depurar nosso projeto e utilizarmos breakpoints.
O que o ocorre é que o Visual Studio simplesmente não para em algum breakpoint e este fica com o símbolo vazado e um ícone de alerta.
Ao passarmos o mouse sobre o ícone do breakpoint podemos notar a mensagem: “No symbols have been loaded for this document”.

O que ocorre é que o timestamp do arquivo “.pdb” gerado é diferente do timestamp da DLL ou exe.
Na maioria das vezes basta utilizarmos o recurso “Rebuild Solution” da solução ou “Rebuild” do projeto, para solucionarmos o problema.
Outras vezes é necessário que acessemos o diretório Debug do projeto e apaguemos o arquivo “. pdb".
Ao apagarmos este arquivo, o compilador, é obrigado a gerar um novo.

Por hoje é só.

Abraços e até o próximo post.

quinta-feira, 17 de maio de 2007

Referência circular usando Master Page e User Control

Olá.

Depois que a Microsoft nos disponibilizou as master pages nossa vida melhorou bastante. Mesmo com alguns contratempos a simples possibilidade de realizarmos herança visual em nossas páginas já é recompensador e, como todo bom recurso, tenho usado e abusado do mesmo.

Dentre os “abusos” posso citar a confecção de master pages de outras master pages (tenho casos de quatro níveis de herança) e controles que estão tanto na master page quanto na página que a implementa.

Este último “abuso” me causou bastante dor de cabeça.
Ainda não sei exatamente onde estava o problema, pois necessito estudar a fundo o modelo de compilação do ASP.NET 2.0.

Lembremos que houve uma mudança no sistema de compilação do ASP.NET.
Nas versões anteriores ao Visual Studio 2005 nossos sites eram projetos do tipo Web Project e agora temos o conceito de Web Site. Por haver material farto na internet sobre este assunto, vou diretamente ao meu problema, mas antes, segue link para quem quiser se aprofundar:

Compilando aplicações ASP.NET 2.0 - Mudanças no Modelo de Código e Compilação

Nota importante: para quem sente saudades ou necessita trabalhar como antigamente, o Service Pack 1 do Visual Studio 2005 adiciona um novo, porém velho conhecido, tipo de projeto: o Web Project. Mas ao trabalhar com este tipo de projeto você perderá uma série de vantagens dos Web Sites, como por exemplo, mudar algo no codebehind ou outra classe e não precisar recompilar.

Quando necessitei usar um mesmo controle de usuário (user control) na master page e na página (content place holder) recebi erros de referência circular.

Depois de algum tempo pesquisando postei minha dúvida no fórum da MSDN e obtive uma resposta quase que imediatamente. A sugestão era, ao invés de registrar o controle em cada página (na master page e na página), eu o registrasse no web.config, desta forma:

<configuration>
<system.web>
<pages>
<controls>
<add tagPrefix="IW" tagName="ctrPesquisas" src="~/Controles/ctrPesquisas.ascx"/>
</controls>
</pages>
</system.web>
</configuration>


Tal solução funcionou perfeitamente para o meu problema.

De maneira básica, os problemas de referência circular não necessariamente ocorrem diretamente entre páginas, controles e master pages.
Segundo o modelo de compilação padrão as classes em uma mesma pasta são compiladas em uma mesma DLL.
Vejam o exemplo visual abaixo:

No caso apresentado a ClasseA possui uma referência à ClasseC e a ClasseD possui uma referência para a ClasseB. Note que não há qualquer referência circular direta entre as classes, porém há uma referência circular entre as dll’s geradas porque a DLL1 referencia a DLL2 e a DLL2 referencia a DLL1.

Conhecendo este comportamento podemos adotar estratégias para evitar tais referências, como, por exemplo, movendo alguma das classes para outra pasta provocando assim a criação de uma terceira DLL e evitando a referência circular.

De maneira mais radical, poderemos utilizar a diretiva batch da tag compilation do web.config que força a criação de uma DLL para cada classe, página, controle e demais componentes.

<configuration>
<system.web>
<compilation batch="false">
</compilation>
</system.web>
</configuration>

Abraços e até o próximo post.

quinta-feira, 26 de abril de 2007

Usando try...catch no SQL Server 2005

Olá.
Venho hoje falar sobre este novo recurso da linguagem Transact-SQL (T-SQL) do SQL Server 2005.

Nas versões anteriores do SQL Server a única maneira de se trabalhar com exceções era o famoso @@ERROR.
Usávamos este recurso principalmente quando tínhamos uma transação. Era comum que, após iniciarmos a transação, tivéssemos que incluir abaixo de cada linha com potencial de erro o seguinte código:

IF @@ERROR > 0
ROLLBACK TRANSACTION

O tratamento de erros desta maneira possuía várias desvantagens, dentre elas posso citar:

  • Ter de escrever este código em cada linha que poderia ocasionar em um erro;
  • A variável @@ERROR era reinicializada após qualquer outro comando;
  • Os erros não poderiam ser capturados e tratados pelo próprio código (procedure), ou seja, após realizarmos o “ROLLBACK” o erro era lançado para a próxima procedure ou para a aplicação da pilha;


A grande mudança no T-SQL é que agora podemos tratar os erros de um trecho de código quase da mesma forma que fazemos no VB.Net ou no C#.

O procedimento é bem simples:

  1. Iniciamos o bloco que pode retornar um erro que queremos tratar com “BEGIN TRY”;
  2. Escrevemos nosso código normalmente, inclusive com a inicialização da transação e o “COMMIT TRANSACTION” no final;
  3. Finalizamos o bloco com “END TRY”;
  4. Abrimos o bloco de tratamento de erros com “BEGIN CATCH”;
  5. Escrevemos nosso código de tratamento do erro;
  6. Fechamos o bloco de tratamento de erros com “END CATCH”;

É muito importante atentar para o fato de que, ao capturar uma exceção em um bloco CATCH, o SQL Server não a lança para quem chamou o código. Isto quer dizer que, se você necessitar que o erro seja lançado para o caller é necessário utilizar do nosso velho conhecido RAISERROR.

Veja um exemplo de código de como isto pode ser feito:

begin try
begin transaction
seu código vem aqui
commit transaction
end try
begin catch
declare
@ErrorMessage nvarchar(4000)
declare @ErrorSeverity int
declare @ErrorState int

select
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE()

rollback transaction

RAISERROR
(@ErrorMessage, @ErrorSeverity, @ErrorState)
end catch

Você notou as novas funções de erro?
Bem mais informativas que a antiga @@ERROR.

No SQL Server 2005, as seguintes funções são utilizadas para obter mais detalhes dos erros:

ERROR_NUMBER()
ERROR_SEVERITY()
ERROR_STATE()
ERROR_PROCEDURE()
ERROR_LINE()
ERROR_MESSAGE()

Além de fornecer detalhes sobre o erro ocorrido, estas funções têm como vantagem o fato de não serem reinicializadas após uma linha qualquer de comando executado, como acontecia com o @@ERROR.

A grande vantagem do TRY...CATCH é que, além de deixar o código mais robusto, podemos separar o que é a lógica do negócio do tratamento dos possíveis erros.

Diminuímos a quantidade de código escrito e temos uma melhor legibilidade.

Mais informações em Using TRY...CATCH in Transact-SQL.

Abraços e até o próximo post.

sexta-feira, 20 de abril de 2007

Método Page_Load é disparado duas vezes

Olá. Venho hoje compartilhar uma solução para um problema muito estranho ocorrido após a migração de alguns projetos web do Visual Studio 2003 para o Visual Studio 2005.
Basicamente o que ocorria é que os webforms migrados disparavam seu método Page_Load duas vezes em uma requisição.
Após algumas pesquisas no Google e na própria MSDN todas as soluções apontavam que o problema estava na propriedade “AutoEventWireup” da página. Esta propriedade, segundo os posts, estaria configurada como “True” quando na verdade o correto seria “False”.
Estaria tudo resolvido não fosse o fato de que nas minhas páginas esta propriedade já estava em “False”.
O mais interessante é que as novas páginas criadas já no Visual Studio 2005 não apresentavam o mesmo problema.
Por algum tempo fiquei a tentar contornar este problema até que, por fim, notei uma pequena diferença na declaração do método Page_Load.

Vejam a diferença:

- Método Page_Load de uma página migrada do VS2003 para o VS2005

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load, Me.Load

- Método Page_Load de uma página nova no VS2005

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Load

Notaram que no primeiro caso o método Page_Load “escuta” dois eventos, um referente ao Load do MyBase e outro referente ao Load da própria página?

Para tentar chegar à raiz do problema, criei um novo projeto web no VS2003 e notei que nele, uma nova página criada, o Page_Load escuta o MyBase.Load, enquanto que no VS2005 o Page_Load escuta o Me.Load.
Isto se dá basicamente por causa da mudança que houve no modelo de compilação do ASP.Net 2.0. Enquanto no VS2003 uma nova página era criada com duas classes, uma para a página e outra para o codebehind, no VS2005 a página e o codebehind são a mesma classe.
No VS2003 era usado o sistema de herança entre as duas classes, daí a necessidade de se escutar o evento Load do MyBase. Já o VS2005 usa o novo recurso de classes parciais onde ambos, página e codebehind, pertencem à mesma classe.
O recurso de classes parciais nada mais é que poder escrever uma mesma classe em diversos arquivos. Este recurso soluciona vários problemas ocorridos até então como, por exemplo, a separação de um código gerado automaticamente (por uma ferramenta qualquer) de um código criado pelo desenvolvedor. Até então, quando gerávamos novamente o código automático, tínhamos que tomar o cuidado de separar e reescrever no novo arquivo o código criado pelo desenvolvedor.

Para mais informações sobre classes parciais, acesse este artigo da MSDN: http://www.microsoft.com/brasil/msdn/Tecnologias/vbnet/vs04k1.mspx#EFB. Além de classes parciais são abordadas outras mudanças ocorridas no Visual Basic 2005.

Outros problemas encontrados com a migração de projetos VS2003 para o VS2005 são relatados por Ben Aminnia em http://www.pointercorp.com/Convert_ASPDOTNET_11_20.htm.

Boa migração e até o próximo post.

segunda-feira, 16 de abril de 2007

O projeto LINQ

Hoje, arrumando os livros de minha estante, deparei-me com uma publicação que recebi do Alexandre Nardi, Arquiteto de Soluções da Microsoft Brasil, em um evento realizado aqui em Brasília no ano passado.
Nesta publicação estão textos cuidadosamente selecionados pela equipe da MSDN Brasil que abordam desde expansão do Agile para adequação ao CMMI Nível 3, até os novos recursos de segurança dos dados com o SQL Server 2005.
Todos estes textos podem ser encontrados em www.microsoft.com/brasil/msdn/arquitetura, porém o que mais me chamou a atenção neste momento foi o artigo “O Projeto LINQ - .NET Language Integrated Query” (www.microsoft.com/brasil/msdn/Tecnologias/arquitetura/LINQ.mspx).
O artigo foi exemplarmente escrito em setembro de 2005 e, apesar do tempo passado, continua sendo uma excelente fonte para compreensão do que vem a ser o LINQ e de como esta tecnologia vai impactar na maneira como programamos e tratamos os dados relacionais.
Neste processo de compreensão do LINQ tem-se como conseqüência a compreensão da dimensão e da importância de alguns novos recursos das linguagens C# e VB.Net, como por exemplo os tipos genéricos, métodos e classes anônimas e operadores de consulta ou agregação. Alguns destes recursos já estão a nossa disposição (principalmente em C#), mas para todos os outros deveremos esperar o Visual Basic 9.0 e o C# 3.0.
Boa leitura e até o próximo post.

Estréia

Olá, esta é a primeira postagem de muitas que virão.
Como citado na apresentação do blog, este espaço não possui qualquer pretensão maior a não ser trazer informações relevantes nas áreas as quais se propõe. Não esperem encontrar aqui textos que já foram exaustivamente explorados por outros sites. Também não esperem uma periodicidade alemã na publicação dos textos porque nem sempre terei algo tão relevante que mereça virar um post. Mas podem contar que cada informação, cada parágrafo e cada dica possuirão relevância e, de preferência, abordarão uma solução para um problema real sofrido por mim como desenvolvedor no dia-a-dia.
Desde já agradeço a atenção e a paciência e espero contribuir um pouquinho que seja para esta grande comunidade. Abraços e até o primeiro texto técnico.