segunda-feira, 11 de junho de 2007
Mantendo a rolagem da página entre postbaks usando MaintainScrollPositionOnPostback
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
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
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 behindPorém, muitas vezes, eles não têm conseguindo convencer a comunidade muito bem.
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 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
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
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:
<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.
<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:
- Iniciamos o bloco que pode retornar um erro que queremos tratar com “BEGIN TRY”;
- Escrevemos nosso código normalmente, inclusive com a inicialização da transação e o “COMMIT TRANSACTION” no final;
- Finalizamos o bloco com “END TRY”;
- Abrimos o bloco de tratamento de erros com “BEGIN CATCH”;
- Escrevemos nosso código de tratamento do erro;
- 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
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.