sexta-feira, 15 de janeiro de 2010

Problemas com datas em javascript

 

A tempos atrás, construí um WebControl de entrada de data, com calendário vinculado estilo redoma. Toda a montagem do calendário é feito via javascript, com vários cálculos com datas.

Acontece que fazer operações com objetos Date() no javascript envolve fazer contas em milisegundos. Então, se você quisesse fazer um cálculo para pegar o próximo dia a partir de uma data, a maneira sugerida é usar

var objData = new Date();

objData.setMilliseconds(objData.getMilliseconds()  +  86400000);

Onde 86400000 = total de milisegundos de um dia.

Daí, o mais natural, para mim, foi fazer 2 prototypes de métodos, para extender o objeto Date:

Date.prototype.addMilliseconds = function(value) { 
                                                                     
this.setMilliseconds(this.getMilliseconds() + value); 
                                                                    
return this; };

Date.prototype.addDays = function(value) {
                                                                   
this.addMilliseconds((value * 86400000));
                                                                   
return this;}

Pensando que isto havia resolvido o meu problema, me deparei com erros na renderização de dias em outubro e fevereiro. Analisando o problema, vi que em 2 datas em específico (17/Outubro e 20/Fevereiro), a soma de 1 dia retornava 17/10/2009 23:00 ao invés do dia 18, e o mesmo ocorria em fevereiro.

Verificando a documentação, constatei que o objeto Date() é vinculado a configuração de ajuste automático de horário de verão do sistema operacional. E que, quando este parâmetro estava desligado, o cálculo funcionava corretamente.

Como meu cálculo não faz nenhum tratamento com a parte de horário da data, o que fiz foi acrescentar uma condição ao addDays:

Date.prototype.addDays = function(value) {var dia = this.getDate();
                                                                                 var mes = this.getMonth();
                                                                                  var ano = this.getFullYear();
                                                                                  this.addMilliseconds((value * 86400000));   

                                                                               if (dia == this.getDate() &&
                                                                                    mes == this.getMonth() &&
                                                                                   ano == this.getFullYear()) 
                                                                                                this.addMilliseconds((3600000 * 2));
                                                                              return this;}

Ou seja, caso o meu cálculo de próximo dia retornou o mesmo dia, mês e ano originais, somo 2 horas ao período, retornando uma data correta.

quinta-feira, 14 de janeiro de 2010

Chamando um WebService via URL

Dia destes, defrontei-me com a necessidade de efetuar a chamada de um webservice sem parâmetros, de maneira indireta (sem referência).

Os passos para isto são:

a) Criar um HttpWebRequest, para a URL completa (incluindo o nome do método).
b) O método para o WebRequest é POST.

Segue o método simples que eu construí para isto:

using System.Net;
using System.IO;

public static String EfetuarDowloadViaHttpRequest(String URL)
{
String strRet = String.Empty;

try
{

HttpWebRequest con = (HttpWebRequest)HttpWebRequest.Create(URL);
con.ContentLength = 0;
con.Method = "POST";

using (StreamReader rd = new StreamReader(con.GetResponse().GetResponseStream()))
{
strRet = rd.ReadToEnd();
}

return strRet;
}
catch (Exception erro)
{
throw new ApplicationException(String.Format("(EfetuarDowloadViaHttpRequest)Erro ao efetuar download a partir da URL {0}: {1}", URL, erro.Message), erro);
}
}


Claro que isto apenas visa demonstrar a solução, algumas adaptações podem ser necessárias a sua realidade.

Abraço.

quinta-feira, 7 de janeiro de 2010

Interpretando regras dinamicamente com C#, IronRuby e JScript

Desenvolvo sistemas profissionalmente desde 1989, ou seja, já se vão quase 21 anos. Diversas linguagens, sistemas operacionais, e ambientes de desenvolvimento no curriculum. Quando começei a desenvolver, não havia recursos, o Brasil possuia reserva de mercado de informática, o que nos levava a trabalhar com microcomputadores que seriam menos poderosos que qualquer celular de hoje em dia. Um HD de 10MB era um luxo caríssimo, e os sistemas eram construídos para ocuparem no máximo 640kb de RAM. Quando foi lançado o disquete de 3 1/2, lembro-me de ter conversado com um colega: "Quando vamos precisar de um deste? É um mini-HD!!!".

Como linguagens de programação, desenvolviamos em Assembly, C, C++, Pascal, o Delphi não estava disponível, e praticamente ninguém havia ainda tido contato com nenhuma versão preliminar do Windows. Mas a grande vedete das linguagens usadas profissionalmente era o Clipper, sem dúvidas.

O Clipper, além de ter vínculo com um banco de dados nativo (DBF, padrão usado no DBASE), tinha uma série de recursos bons, e podia-se fazer misérias com ele, usando ou não a integração com C e Assembly através das bibliotecas .pll (um precursor do conceito de dll). Um dos recursos que sempre existiu no Clipper era o do Eval, onde se podia executar um código em tempo de execução e pegar seu retorno, e, a partir da versão 5.0, o uso dos blocos de código (algo muito parecido com os Func ou Predicate do .NET atual).

Na época, construía sistemas de epidemiologia médica, e outros para controle de acidentes de trabalho e trânsito. O que era meio que um lugar comum era a grande mutabilidade das regras de extração de dados, o que demandava uma série de relatórios. E um, em específico, que visava a extração de dados de procedimentos médicos para o reembolso pelo SUS, tinha suas regras alteradas quase todos os meses, e sempre gerava uma bela dor de cabeça.

Então, na época, resolvi o problema com a criação de uma base de dados de regras, onde os parâmetros de extração eram alimentados mês a mês, usando como padrão o que se tinha no mês anterior, com reaproveitamento total de fórmulas e regras, mudando apenas o código das regras que sofreram impacto. Então, através do uso do eval (para compilar a regra), e do bloco de código (para usar a regra compilada pelo eval dentro do mesmo), tornando a extração dos dados dinâmica.

Depois disto, já construí uma miríade de outros sistemas, e, invariavelmente, entre um e outro, me deparei com a necessidade de usar regras dinâmicas ou fórmulas, e sempre lamentei o fato que tal ferramenta estava indisponível, sendo necessário lançar mão de outros recursos para obter o mesmo resultado.

No .NET, já utilizei soluções onde havia a codificação de código dinâmico através dos recursos do CodeDom. Havia sempre muito trabalho, mas, com um certo encapsulamento em uma classe genérica, ficou até tranquilo de usar.

Nos últimos tempos, muitas novas linguagens foram agregadas a família .NET, como o F#, e uma destas gratas surpresas foi o IronRuby, ainda em beta, mas muito eficiente. Para este exemplo, utilizei a versão mais atual do IronRuby (http://www.ironruby.net/Download), e o Visual Studio 2008. No entanto, o exemplo funciona perfeitamente no Visual Studio 2010 Beta 2.

É preciso descompactar o IronRuby para o C:\ruby. Seguindo o conselho de vários fóruns, é bom que seja respeitado este diretório.

O exemplo consistirá em criar uma classe utilitária chamada RubyEval, que contemplará 2 métodos específicos:

a) EvalRegra -> Um método destinado a validar regras de negócio, recebendo um determinado tipo como parâmetro, e validando a regra de acordo com as propriedades que este tipo pode conter.

Para nosso exemplo, utilizaremos instâncias da classe

public class RegTeste {
public int Codigo{get;set;}
public decimal ValorSalario { get; set; }
public String Nome { get; set; }
}



Uma expressão de negócio válida, por exemplo, poderia ser algo como "e.ValorSalario > 1000". O método retorna true ou false, indicando que a regra é válida.

b) EvalExpressao -> Um método destinado a receber uma fórmula, executar e retornar o valor obtido. Por exemplo, "1000 * 2000".

Vale ressaltar que estamos falando como fins de EXEMPLO, ou seja, o uso desta abordagem em soluções de mundo real deve ser adaptado a sua realidade.

Criando o projeto

Inicie um novo projeto no Visual Studio 2008 (console, test application), e adicione as seguintes DLLs da pasta c:\ruby\bin: IronRuby.Dll, IronRuby.Libraries.dll, Microsoft.Dynamic.dll, Microsoft.Scripting.Core.dll, Microsoft.Scripting.dll.

Criando a classe RubyEval

A primeira parte deste exemplo (a criação do ScriptEngine para o IronRuby) pode ser encontrado em diversas fontes de pesquisa de forma praticamente igual, e basicamente não vai mudar. Então, vamos lá.

Adicione uma nova classe chamada RubyEval, e a seguinte instrução

using Microsoft.Scripting.Hosting;

Isto serve para podermos ter acesso ao ScriptEngine e ao ScriptRuntime. Deixei, de propósito, sem adicionar o using para o IronRuby.

Primeiro, vamos adicionar a variável estática

protected static ScriptEngine _localscEngine;

Que são estáticas por motivo de performance, e não precisarmos criar a todo o momento a instância do ScriptEngine. Em seguida, temos 2 opções: um construtor estático para RubyEval, ou a criação de uma propriedade estática para obter o ScriptEngine do Ruby. Optei pela primeira alternativa.

Adicione o código abaixo:

static RubyEval()
{
var setup = new ScriptRuntimeSetup();
setup.LanguageSetups.Add(
new LanguageSetup(
"IronRuby.Runtime.RubyContext, IronRuby",
"IronRuby 1.0",
new[] { "IronRuby", "Ruby", "rb" },
new[] { ".rb" }));
var runtime = ScriptRuntime.CreateRemote(AppDomain.CurrentDomain, setup);
_localscEngine = runtime.GetEngine("Ruby");
}


Apesar de termos propriedades que não vamos usar (por exemplo, não vamos abrir arquivos de código com a extensão .rb), os parâmetros são necessários.

Agora, vamos ver o código dos 2 métodos:

public static bool EvalRegra(T dadoEntrada, String codigoRegra)
{
string source = String.Format("Proc.new {{ |e| {0} }}", codigoRegra);
ScriptSource scriptSource = _localscEngine.CreateScriptSourceFromString(source);
var proc = (IronRuby.Builtins.Proc)scriptSource.Execute();
Predicate predicate = p => (bool)proc.Call(p);
return predicate(dadoEntrada);
}


Para a execução do código, vamos receber um determinado T dadoEntrada, e o código por extenso da regra (aderente a sintaxe que o IronRuby pode interpretar). A partir da nossa variável estática _localScEngine, que foi inicializada pelo construtor estático, compilamos o código.

A chamada a Execute() retorna um objeto, que é uma Proc do IronRuby. Então, o que temos a fazer é criar um Predicate, que recebe um objeto do tipo T e retorna bool para a execução do código da regra.

O segundo método é mais simples:

public static T EvalExpressao(String codigoExpressao)
{
ScriptSource scriptSource = _localscEngine.CreateScriptSourceFromString(codigoExpressao);
return (T) scriptSource.Execute();
}


Como receberemos uma fórmula, a chamada a Execute retorna o resultado da execução da mesma.

Para fins de encapsulamento, vamos definir um terceiro método que recebe uma lista de regras a verificar para um mesmo objeto, e retorna true apenas se todas as regras forem contempladas:

public static bool EvalRegras(T dadoEntrada, List listaRegras)
{
bool bRet = true;
foreach (var regra in listaRegras)
{
bRet &= EvalRegra(dadoEntrada, regra);
if (!bRet) break;
}
return bRet;
}


Um teste para as nossas rotinas

Primeiramente, vamos criar uma lista de objetos RegTeste (citado acima):

List lista = new List{
new RegTeste{ Codigo=1,Nome="José",ValorSalario=12211.00M},
new RegTeste{ Codigo=2,Nome="José Maria",ValorSalario=9883.00M} ,
new RegTeste{ Codigo=3,Nome="Maria José",ValorSalario=8828.00M},
new RegTeste{ Codigo=4,Nome="Alessandro",ValorSalario=2235.00M}};


Agora, vamos criar uma lista de regras a verificar (Imagine a lista vinda de uma tela de pesquisa, ou lida de um banco de dados, por exemplo):

List regras = new List { "e.ValorSalario > 3000",
"e.Nome.Contains(\"Maria\")" };


Com RubyEval e Linq, podemos fazer a aplicação do filtro facilmente como abaixo:

foreach(var reg in lista.Where(d=> RubyEval.EvalRegras(d,regras)))
{
Console.WriteLine(reg.Nome);
}


O uso do segundo método é mais direto:

var res = RubyEval.EvalExpressao("1020202020.00 * 22232323");





Uma segunda opção para EvalExpressao, sem o IronRuby


Outra opção para fazer um clone de EvalExpressao é o uso do JScript.

Adicione as seguintes referências a seu projeto: Microsoft.Vsa, Microsoft.JScript.

Adicione a seguinte classe:

using JS = Microsoft.JScript;

public class JScriptEval
{
private static JS.Vsa.VsaEngine _localEngine = JS.Vsa.VsaEngine.CreateEngine();
public static T EvalExpressao(String expressao)
{
var res = Microsoft.JScript.Eval.JScriptEvaluate(expressao, _localEngine);
return (T) Convert.ChangeType(res, typeof(T));
}
}


Daí, podemos usar uma fórmula como abaixo (atentando para o fato que a sintaxe deve ser compatível com o JScript):

var res2 = JScriptEval.EvalExpressao("Math.pow(1212123,3)");

Conclusão

Com o uso das novas linguagens dinâmicas (e aos recursos do .NET FrameWork), é possível implementarmos métodos para interpretação de código em tempo de execução, o que pode acrescentar tremenda flexibilidade ao nosso aplicativo. No entanto, como qualquer recurso, deve-se levar em consideração o custo-benefício da utilização do mesmo, visto que, independente do tempo ser mínimo (em razão dos recursos que possuímos hoje em dia, de processador e memória), em processos pesados este tempo pode ser determinante. Nem sempre uma grande flexibilidade é premissa. Use com critério, e divirta-se!

Forte Abraço !

sexta-feira, 13 de novembro de 2009

Serialização binária

Aqui, mais uma da toolbox: serialização de objeto e deserialização binária.

O objeto em questão deve possuir o atributo [Serializable].

public static byte[] serializarObjeto(object objetoSerializar)
{
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bin = new
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
System.IO.MemoryStream bufMemoria = new System.IO.MemoryStream();
bin.Serialize(bufMemoria, objetoSerializar);
return bufMemoria.ToArray();
}


public static object deserializarObjeto(byte[] conteudo)
{
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bin = new
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
System.IO.MemoryStream bufMemoria = new System.IO.MemoryStream(conteudo);
object objetoRetornar = bin.Deserialize(bufMemoria);
return objetoRetornar;
}

quinta-feira, 5 de novembro de 2009

Consultando a fila MSMQ, em busca de uma mensagem pelo label ou conteúdo do Body.

Deparei-me com a necessidade de procurar por uma determinada mensagem na fila MSMQ, para saber se a rotina destino já havia consumido a mesma.

Felizmente, temos o Linq:

public Message MensagemPeloLabel(String labelMensagem)
{
MessageQueue msmqFila = new MessageQueue(this.NomeFila);
msmqFila.MessageReadPropertyFilter.SetAll();
msmqFila.Formatter = new ActiveXMessageFormatter();

return (from Message msg in msmqFila where msg.Label.Equals(labelMensagem, StringComparison.CurrentCultureIgnoreCase) select msg).FirstOrDefault();
}


public Message[] MensagensPorConteudo(String fragmentoMensagem)
{
MessageQueue msmqFila = new MessageQueue(this.NomeFila);
msmqFila.MessageReadPropertyFilter.SetAll();
msmqFila.Formatter = new ActiveXMessageFormatter();

return (from Message msg in msmqFila where msg.Body.ToString().IndexOf(fragmentoMensagem, StringComparison.CurrentCultureIgnoreCase)!=-1 select msg).ToArray();
}

Revisão da função de leitura de mensagens da classe genérica de acesso ao MSMQ.

Dei uma revisada nas funções que usei no artigo anterior, agora ficou mais enxuto:


private Message obtemMensagem(MessageEnumerator msmqEnumerator,
MessageQueueTransaction msmqTransacao)
{
Message msmqRetorno;
if (msmqTransacao != null)
msmqRetorno = msmqEnumerator.RemoveCurrent(msmqTransacao);
else
msmqRetorno = msmqEnumerator.RemoveCurrent();
return msmqRetorno;

}


A função acima faz uso diretamente do RemoveCurrent, que já devolve a mensagem corrente do MessageEnumerator.

No método de leitura, um pouco de revisão não faz mal a ninguém:


public void receberMensagens(MSMQProcessaOcorrencia metodoProcessar)
{
MessageQueue msmqFila = null;
MessageQueueTransaction msmqTransacao = null;
MessageEnumerator msmqEnumerator = null;
bool retornoProcessamento = false;

try
{
msmqFila = new MessageQueue(this.NomeFila);
msmqFila.Formatter = new ActiveXMessageFormatter();
msmqFila.MessageReadPropertyFilter.SetAll();
msmqEnumerator = msmqFila.GetMessageEnumerator2();

if (msmqEnumerator.MoveNext())
{
while (msmqEnumerator.Current != null)
{
retornoProcessamento = false;
try
{

if (this.Transacional)
{
msmqTransacao = new MessageQueueTransaction();
msmqTransacao.Begin();
}

Message msmqMensagemCorrente = this.obtemMensagem(msmqEnumerator, msmqTransacao);
if (msmqMensagemCorrente == null) continue;
retornoProcessamento = (metodoProcessar != null) ? metodoProcessar(msmqMensagemCorrente) : true;

}
catch (Exception)
{
retornoProcessamento = false;
}
finally
{
if (this.Transacional)
{
if (retornoProcessamento) msmqTransacao.Commit();
else msmqTransacao.Abort();
msmqTransacao = null;
}
}

}
}

}
catch (MessageQueueException erro)
{
if (erro.MessageQueueErrorCode != MessageQueueErrorCode.IOTimeout)
throw erro;
}
catch (Exception erro)
{
throw erro;
}
finally
{
if (msmqTransacao != null) msmqTransacao.Abort();
if (msmqFila != null) msmqFila.Close();
}

}



O tratamento da MessageQueueException, ignorando quando é MessageQueueErrorCode.IOTimeout, é imprescindível, para que a rotina chamadora não tenha uma profusão de erros ocasionados pela leitura da propriedade MessageQueueEnumerator.Current, que retorna esta exception quando terminamos de varrer o enumerator inteiro.

segunda-feira, 15 de junho de 2009

Obtem o equivalente a um SELECT COUNT(*) de várias tabelas ao mesmo tempo

Muitas vezes, estamos na situação de exportar um grande número de tabelas de um banco para o outro, mas não sabemos quais selecionar da lista, porque não temos a visualização de quais tabelas possuem efetivamente linhas a exportar.
Você pode fazer um bom e velho cursor, no Sql Server, e para cada tabela executar e exibir um SELECT COUNT(*) ou um sp_spaceused para cada uma das tabelas encontradas.
Abaixo, segue um SELECT que faz exatamente isto, de uma tacada só:


SELECT object_name(object_id),
TOTAL = SUM (
CASE
WHEN (index_id < 2) THEN row_count
ELSE 0
END
)
FROM sys.dm_db_partition_stats
WHERE object_id in (select id from sysobjects where type='U')
group by object_id
having SUM (
CASE WHEN (index_id < 2) THEN rowcount
ELSE 0
END
) > 0