Ler um DateTime, passo por JSON, com Javascript

August 7th, 2009

O título é algo confuso, mas o problema é pertinente. Quando se utiliza JSON para transmitir dados entre servidor e browser-cliente, enquanto a generalidade de objectos serializáveis são convertidos correctamente (um inteiro é um inteiro, uma string é uma string…), os valores de datas não são convertidos como um tipo Date do javascript, nem DateTime do .NET. A generalidade dos valores passos no JSON são convertidos para uma forma literal correspondente – os números numa sequência de caracteres numéricos, as strings como sequência de caracteres, etc. Mas para o tipo que representa uma data, simplesmente não existe um literal único – basta pensar que há dezenas de formas de representar uma data – só a parte do calendário, ou com hora, ou com variações de barras e hifens, ou com a troca de texto e ordem com base em culturas variadas.

Na serialização JSON do .NET, a Microsoft decidiu adoptar uma convenção para enviar os dados num formato literal – a data é representada pelo número de milissegundos desde a data de referência de 1 de Janeiro de 1970. O formato em que é enviado é:

/Date(xxxxxxxxxxxxx)/

Evidentemente, esta string não é uma data por si só, apenas uma representação literal (e independente de constrangimentos culturais). Necessitamos de converter os ticks numa data. No javascript o único método de conversão que temos é a função Date(), que funciona como construtor do objecto da Data. Dos vários overloads que existem, há um que recebe o número de milisegundos desde 1 de Janeiro de 1970, tal como o número que recebemos da resposta JSON!

Sendo assim, podemos usar a seguinte função para obter a estrutura da Data, a partir do literal devolvido pelo servidor:

function GetJSDateFromNET(netDateString) {
    var myregexp = /\d{13}/;
    var match = myregexp.exec(netDateString);
    if (match != null) {
        return new Date(parseInt(match[0]));
    } else {
        return null;
    }
}

Assim, com o valor devolvido pode-se fazer algo do género:

...
var data = GetJSDateFromNET(valorDataJSON);
alert(data.getYear());
...

A função, reutilizável, permite ler correctamente o literal de data enviado pelo servido, e processar a data do lado do cliente.

referencias:
An Introduction to JSON @ MSDN
Encosia

Limitações do IIS 7 no Windows Vista

September 17th, 2008

É pelo menos a segunda vez que tenho que enfrentar problemas de limitações do sistema operativo, e é nesta altura que mais detesto a Microsoft e o seu sistema operativo. Mas enfim, são as regras do jogo que nos impõe. E é nesta altura que gostava que o mundo fosse o Ubuntu.. hehehe

Desta vez, no desenvolvimento de uma aplicação que faz grande uso de serviços, e até encadeamento de acessos. Em termos de produção, trata-se de um sistema distribuído, mas todo o desenvolvimento é efectuado numa só máquina, com os diversos serviços integrados em directorias virtuais com se fossem servidores distintos. Uma abstracção que permite-me ter alguma flexibilidade no desenvolvimento da(s) aplicação(ões).

Esta abordagem tem, no entanto, problemas associadas. Cada chamada a um serviço é uma chamada na contagem, e porque o processo exige pedidos síncronos, o anterior tem que aguardar pela resposta do seguinte. Após horas a batalhar com a questão e após um esforço grande de logging, encontrei o local do problema – uma operação que teoricamente é simples e rápida, mas que exigia um pedido a um serviço. O tempo de execução entre a chamada anterior e a seguinte era sempre de 1m30s. Só depois deste periodo (em que a aplicação dava um timeout, nas camadas superiores) é que os pedidos em espera eram executados (quase instantaneamente).

O giro disto tudo, e o que me levou a desconfiar do IIS / Vista foi o facto de este problema surgir apenas com o acesso à aplicação via IIS. Usando o servidor de desenvolvimento do Visual Studio, o pedido passava sempre, sem problemas. Detectado o ponto de falha, e com este conhecimento da potencial falha, um pouco de pesquisa no Google apresenta a causa. IIS 7 em Vista Home Premium.

O Home Premium admite sevrir páginas e desenvolvimento para aplicações simples, sem dúvida. E até agora só encontrei dois problemas com ele em termos de desenvolvimento. Mas para algumas aplicações mais complexa como o caso da minha torna-se problemático e é muito díficil encontrar o bicho que causa o problema.

Em Stuff that Just Works, de Cal Zant há uma página que apresenta o conjunto de limitações que as versões do Windows apresentam. Com o XP Pro, e IIS 6, a limitação era de 1 site e 10 ligações concorrentes. O XP, versões básicas, não permitiam o IIS. Com o vista, mais ou menos a mesma situação surge – para as versões Business e superiores, o numero de ligações concorrentes são ilimitadas, mas passou a haver limite no numero de pedidos simultâneos, e a restrição do número de sites desapareceu.

Já com o Home Basic Premium, que é o unico dos Home a suportar o IIS, a intenção é suportar as necessidades de desenvolvimento casual e portanto entram as limitações – processamento de três pedidos em simultâneo e sem o suporte a configurações de segurança avançadas – exactamente os dois pontos problemáticos para mim…

Em termos de mudança relativo ao IIS 6 no XP Pro, enquanto neste era possível que apenas 10 utilizares dessem inicio a sessão (mas podendo fazer quantos pedidos quisesse), com o IIS 7 em Vista, podem estar ligados quantos quiserem, mas apenas 10 (ou 3) pedidos estarão a ser processados em qualquer momento e as restantes permanecem em fila de espera o que permite que os utilizadores se mantenham ligados à aplicação, mas eventualmente com demora na resposta. No meu caso, como os 3 em execução estavam dependentes de um 4 que estava em espera, apenas o timeout do primeiro permitiu a continuação da execução.

Acredito que sejam limitações impostas pela Microsoft para de alguma forma puxar as empresas a comprarem as versões de servidor (em termos de ambiente de utilização) e para o programador mover-se para um SO “mais completo”. Mas que são situações chatas (e caras), lá isso são!!!

Em IIS.Net, há ainda a lista completa das diferenças do IIS entre versões do Vista…

Caching em WebMethods

August 23rd, 2008

O objecto Cache do System.Web.Caching é muito funcional e poderoso na gestão de dados aplicacionais no ASP.Net. Uso-o frequentemente em aplicações, como modo de persistir dados nas camadas superiores permitindo acelerar alguns processos, especialmente quando os dados vão ser usados continuamente durante um curto período de tempo e em diversas páginas ou com operações de paginação e exportação de dados de uma GridView.

Há naturalmente vantagens e desvantagens em usar a Cache do .Net para armazenar dados. A Cache é efectivamente rápida. Muito mais rápida que o ViewState, por exemplo, e faz uma melhor gestão de grandes quantidades de dados que a objecto de Session. Permite também gerir o tempo de vida e modo de remoção dos dados. No entanto, a cache está disponível a todos os utilizadores, pelo que é necessário ter algum cuidado a gerir as chaves usada para armazenar os valores, se bem que esta característica até é vantajosa em muitas situações.

Enquanto que em páginas (ou melhor, classes herdadas da classe Page) o objecto Cache está imediatamente disponível, o mesmo não é tão verdade para WebServices. WebServices permite algumas estratégias de Caching, sendo a principal a cache de saída (output caching), em que a resposta do WebMethod é armazenado em cache durante um determinado período. Por exemplo:

[WebMethod(CacheDuration=60)]
public string DevolveString()
{
   string palavra
   //processamento (...)
   return palavra;
}

Irá devolver a mesma string durante os 60 segundos posterior à chamada, e determinado pelo uso de “CacheDuration=60” no atributo do WebMethod.

Mas e se quisermos utilizar a cache da mesma forma que é usada nas páginas, com recurso a métodos (estáticos?) para inserir e obter valores? Enquanto que escrever:

Cache.Insert("objectoAinserir", obj); //insere a instância obj na cache

é válida nas classes das páginas, o mesmo não é verdade num WebMethod. Aliás, no VS, para que o IDE reconheça o objecto Cache, é necessário inserir a referencia ao System.Web.Caching, e mesmo assim os métodos não são disponibilizados pelo IDE. Instanciar a cache com algo do género

System.Web.Caching.Cache cache = new System.Web.Caching.Cache();

é válido quer no IDE, quer em runtime, qualquer tentativa de atribuir ou obter um valor usando cache.Get(…) ou cache.Insert(…) levantam excepções.

A solução passa emtão por ir buscar o objecto de Cache a outro local, nomeadamente ao HttpRuntime. Deste modo, no WebMethod, já é possivel inserir e obter valores dentro de um método (que não é necessáriamente a resposta do método) e persisti-lo para utilizar com outros métodos ou até outros utilizadores.

[WebMethod]
public void TestMethod()
{
   int a = 1;
   HttpRuntime.Cache.Insert("A", a);
}
 
[WebMethod]
public int TestMethod2()
{
   return (int)HttpRuntime.Cache.Get("A");
}

O código anterior é exemplo de como utilizar a Cache do HttpRuntime. No TestMethod() é armazenado um valor na cache, e considerando que este é executado antes do TestMethod2(), ao chamar o TestMethod2() o valor presente na cache será recuperada e retornada, permitindo persistir dados entre métodos, especialmente quando volumosos, e que pode evitar trocas de dados lentos entre camadas aplicacionais ou serviços.