Nuno Gomes /*Aventuras e Desventuras de um programador*/

var assuntos = new { Linguagem = "C#", Tecnologia = "ASP.NET" };

Abril 2009 - Posts

Controlos ASP.NET – Problema com Validadores (NetFx 1.1 versus NetFx 2.0+)

A última intervenção que fiz no motor do PontoNetPT permitiu-me encontrar mais um problema relacionado com o ID dos controlos (não sei se a questão dos ID é uma paixão ou uma obcessão mas a verdade é que é um tema recorrente).

Tal como expliquei antes, o motor do PontoNetPT está compilado para NetFX 1.1 mas o servidor actual não possuir esta versão instalada, i.e., estamos a correr uma aplicação 1.1 sobre a 2.0 ;-).

Este não é um cenário recomendado pois a versão 2.0 quebrou alguns comportamentos da 1.1 … mas como estamos perante um cenário de transição é aceitável.

Relativamente aos controlos de validação houve alterações na forma como a informação é agregada no lado do cliente:

Cenário NetFx 1.1

Toda a informação necessária para realizar a validação no lado do cliente é guardada em atributos do elemento Html que representa o validador.

Cenário NetFx 2.0+

A mesma informação passou a ser renderizada através de ExpandoAttributes, i.e., passou a existir um objecto javascript que agrega esta informação.

À primeira vista esta alteração parece não trazer problemas, passando apenas por uma estratégia diferente de guardar a informação necessária, no entanto, esconde um problema relacionado com a convenção de nomenclatura usada nos atributos de elementos Html e nas variáveis de javascript.

O problema

Com a migração da aplicação deixou de ser prossivel adicionar comentários aos posts, isto porque todas as *.aspx que tinham validadores disparavam um erro de javascript.

O primeiro erro ocorria sempre na seguinte declaração:

var ctl00_pageBody-2_RequiredFieldValidator1 = document.all ? document.all["ctl00_pageBody-2_RequiredFieldValidator1"] : document.getElementById("ctl00_pageBody-2_RequiredFieldValidator1");

Olhando com atenção o erro é óbvio, o caracter ‘-‘ é um operador de javascript e como tal não pode ser usado no nome de uma variável.

Tal como referi, na NetFx 1.1 este objecto não existia e toda a informação era guardada sob a forma de atributos do elemento Html que representava o validador.

Por outro lado, não encontro nenhuma boa razão para justificar a atribuição do valor “pageBody-2” ao ID de um controlo, no entanto este é um valor absolutamente válido e não viola nenhuma regra que eu conheça (ou melhor … não violava … a partir de agora passou a violar).

A solução

Bom, a solução é simples … alterar o ID por forma a não conter o caracter ‘-‘.

No meu caso, e porque o mundo é invariavelmente mais complicado, o ID era gerado dinamicamente num método privado de uma classe base interna …

A única solução prática foi fazer override ao método PreRender da página e substituir o padrão ‘_pageBody-‘ por ‘_pageBody_‘.

Eu sei que esta é uma solução feia e nada performante ... eu não gosto dela … mas sendo uma solução de curto prazo até à migração para CS é um compromisso aceitável.

As Soluções

Existem duas abordagens para resolver esta questão, tanto podemos forçar os validadores a renderizar atributos Html como podemos remover os caracteres indesejados do ID.

A primeira é naturalmente a melhor, principalmente nesta situação que temos uma aplicação antiga, no entanto é uma alteração global da aplicação.

Instruir os validadores a renderizar atributos Html

Os validadores .Net estão preparados para operar num modo ‘Legacy’, mas para habilitar este funcionamento é necessário alterar os modo de funcionamento da aplicação. Para habilitar este funcionamento alteramos o web.config da seguinte forma:

<system.web>
    <xhtmlConformance mode="Legacy"/>

Embora esta seja a solução que prefiro, optei por usar a outra alternativa simplesmente porque não conheço o suficiente para avaliar o impacto global que esta alteração pode envolver. O que eu procurava era uma alteração cirúrgica para resolver um problema específico e localizado sem envolver efeitos colaterais.

Alterar o ID dos controlos

Esta abordagem requer a normalização do ID de todos os controlos que contribuem para a hierarquia de cada validador, para desta forma evitar problemas de nomenclatura Javascript. É de esperar que desta forma o tempo dispendido seja mais elevado, no entanto, não é espectável qualquer problema.

Bom, essa espectativa acabou por não se cumprir, sendo que encontrar o local exacto onde este ID estava a ser criado foi uma tarefa maçadora e demorada.

Acabei por descobrir o que o ‘pageBody-2’ era um UserControl,  carregado dinamicamente  e cujo ID era também ele gerado dinamicamente. Infelizmente, esta manipulação do ID era realizada num método privado de uma classe base interna.

A única solução prática foi fazer override ao método PreRender da página e substituir o padrão ‘_pageBody-‘ por ‘_pageBody_‘.

Eu sei que esta é uma solução feia e nada eficiente... eu não gosto dela … mas sendo uma solução de curto prazo até à migração para CS é um compromisso aceitável.

A reter

Nunca usar no ID de controlos Server-Side caracteres que, tal como o ‘-‘, tenham sigificado especial em javascript. Desta forma vão evitar surpresas desagradáveis.

Posted: 27-4-2009 22:39 por Nuno Gomes | with 2 comment(s)
Filed under: ,
PONTONETPT – Adição de comentários

Olá pessoal,

Como alguns devem ter notado, com a migração para o novo servidor tinhamos perdido a capacidade de adicionar comentários.

Pois bem, essa capacidade está restabelecida desde ontem.

Posted: 26-4-2009 21:51 por Nuno Gomes | with 1 comment(s)
Filed under:
PontoNetPt - O desafio (Parte 1)

Como alguns de vocês já devem ter reparado, tenho andado ocupado com a migração da comunidade.

Este é um desafio que o meu grande amigo Paulo Morgado me lançou, e sabem como é, um bom desafio não dá para resistir.

O desafio é simples .... migrar o PontoNetPT de .Text para CS, mas como todos os desafios é vencido em pequenas etapas.

Neste caso as etapas são as seguintes e como sabem não foram ainda todas ultrapassadas:

  1. Migrar o PontoNetPT para o novo servidor e garantir o pleno funcionamento
  2. Testar metodologias de migração de conteúdos entre o .Text v0.91 e o CS
  3. Instalar CS
  4. Migrar todos os conteúdos para CS e descontinuar o .Text

Naturalmente, cada uma destas etapas apresenta dificuldades distintas.

Relativamente ao 1. o principal problema esteve relacionado com o runtime do ASP.NET. O João Cardoso migrou a aplicação para o novo servidor mas a compilação da aplicação resultava sempre no seguinte erro:

/Skins/blue/Controls/EntryList.ascx(1): error ASPPARSE: Ambiguous match found.

[AmbiguousMatchException]: Ambiguous match found.
  at System.RuntimeType.GetField(String name, BindingFlags bindingAttr)

  at System.Web.UI.Util.GetNonPrivateFieldType(Type classType, String fieldName) [...]

Eu e o Paulo, já tinhamos visto alguns erros semelhantes a este e desconfiamos de imediato que a aplicação estava a ser compilada em vb.NET e não C#.

"Reflectindo" um pouco sobre o assunto encontramos este código no componente que dava erro:

public class EntryList : BaseControl
{
    [...]
    private EntryCollection entries;
    protected Repeater Entries;
    [...]

A classe EntryList é usada pelo UserControl EntryList.

Embora alguns erros tenham sido ultrapassados removendo todas as referências "vb" este problema persistia. A análise do Paulo mostrou o seguinte:

  1. se existirem apenas membros não públicos com o mesmo nome embora com capitalização diferente o método System.RuntimeType.GetField devolve uma AmbiguousMatchException
  2. se um dos membros com mesmo nome for publico o método consegue executar com sucesso

Graças a esta análise não foi dificil ultrapassar esta questão, bastando para tal criar uma classe que estende a EntryList e expõe como membro público a propriedade que de facto queremos que o Runtime resolva correctamente e esconder a propriedade da base. A classe é a seguinte:

public class EntryList : global::Dottext.WebUI.Controls.EntryList

{

public new Repeater Entries

{

get { return base.Entries; }

set { base.Entries = value; }

}

}

Naturalmente, foi necessário alterar o UserControl para passar a usar esta classe 'kittada' e não a original.

Posted: 14-4-2009 9:13 por Nuno Gomes | with no comments
Filed under:
PONTONETPT - Nova opção de Administração

Caros amigos,

Já está disponivel a funcionalidade "Export to BlogML" nas opções de administração.

Aconselho a que cada um de vós use esta funcionalidade e guarde o xml gerado como backup.

Informem-me se tiverem algum problema ou quiserem partilhar o sucesso ;-)

Posted: 13-4-2009 21:28 por Nuno Gomes | with no comments
Filed under: