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

quinta-feira, 28 de maio de 2009

Retornando um objeto via LINQ, mas setando propriedades sem criar um novo objeto

Normalmente, com a sintaxe declarativa do Linq:


var valor = from obj in listaobjects
select obj;

Este exemplo acima retorna os itens da listaobjects, sem alterar nenhuma propriedade.

Agora, digamos que se quisesse setar a propriedade Nome do objeto, antes de retornar.

Via sintaxe em Extension Methods:

var valor = listaObjects.Select(x => x.Nome = "teste"; return x;};

Na sintaxe declarativa, pode-se fazê-lo via a (horrorosa) instrução abaixo:

var valor = from obj in listaObjects
select new itemRetorno{ Nome = "Teste", Endereco = obj.Endereco, ...};

Mas uma saída bem mais elegante seria a criação de um Extension Method baseado em um delegate, como o exemplo abaixo:


namespace System.Linq
{

public static class ExtensaoLinq
{
public delegate void Atualiza(T updater);
public static T Set(this T input, Atualiza atualizador)
{
atualizador(input);
return input;
}
}
}


Então, com isto, podemos escrever em sintaxe declarativa:

var valor = from obj in listaObjects
select obj.Set(obj => { obj.Nome = "Teste"; });

segunda-feira, 9 de fevereiro de 2009

Classe de acesso MSMQ

O MSMQ é o servidor nativo de troca de mensagens da Microsoft. Ele é disponibilizado juntamente com o CD de instalação do Windows, e sua instalação e configuração é extremamente fácil.

O MSMQ é uma solução prática (e barata), quando se deseja fazer o processamento assíncrono de mensagens entre aplicações. Um caso muito comum, é a integração de legados heterogêneos, onde podemos postar um texto (xml ou plain text) numa fila pré-definida, e o outro legado procede com a retirada da mensagem, e processamento. As filas MSMQ também podem conter objetos binários como mensagem.

Já desenvolvi diversas rotinas de processamento assíncrono com MSMQ, mas esta última que criei é a que considero a mais simples e prática, principalmente pelo baixo acoplamento.

Analisando a situação:

a) Filas MSMQ podem ser transacionais, ou não.

b) Normalmente, uma rotina que envia mensagens ao MSMQ deve garantir sua transação completa, por exemplo, você deseja que sua mensagem seja considerada enviada apenas depois de ter feito diversos processamentos, após a postagem na fila. Caso contrário, seu processamento poderá enviar 2x a mesma mensagem.
c) Da mesma maneira, uma rotina que retira mensagens do MSMQ deve garantir que a mensagem retirada foi corretamente processada.

Enunciado da solução:

a) A classe de processamento MSMQ não deve conter lógica explicita de processamento da mensagem postada, ou seja, você deve "plugar" o processamento relacionado ao pós-envio da mensagem para o método executar. O mesmo vale para o método de retirada de mensagens.
Para este código, foi adotado o ActiveXMessageFormatter, que usa um formato compatível com o antigo MSMQ ActiveX Component. Outros formatters podem ser usados, aliás, um bom exercício para uma extensão da classe seria poder determinar o tipo de formatter a utilizar.


b) A inteligência de processamento deve ser passada para os métodos, através de um delegate. Assim, temos 2 delegates distintos:


public delegate bool MSMQProcessaMensagemRecebida(Message mensagemAtual);

Onde Message é um objeto do namespace System.Messaging, que representa uma mensagem MSMQ.

public delegate bool MSMQProcessaAposMensagemEnviada(String corpoMensagem, String labelMensagem);

Onde são passados como parâmetro os mesmos conteúdos para o corpo da mensagem e o label. O Label é um identificador da mensagem, o mesmo aparece na visualização de mensagens da fila, e é, na maioria das vezes, alimentado com algum código que possa ser associado ao conteúdo postado.

Observem que os 2 delegates retornam um bool. Se o retorno for true, indica-se que o processamento foi completado com sucesso.


Segue o código da classe, comentado:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Messaging; // namespace que contempla as classes MSMQ

namespace RotinasGenericas

{
public class MSMQ
{

#region propriedades

public string NomeFila
{
get;
private set;
}

public bool Transacional
{
get;
private set;
}

#endregion

#region declaracao de delegates
public delegate bool MSMQProcessaMensagemRecebida(Message mensagemAtual);
public delegate bool MSMQProcessaAposMensagemEnviada(String corpoMensagem, String labelMensagem);
#endregion

public MSMQ(String nomeFila, bool bTransacional)
{

// passamos no construtor a característica de fazer um processamento transacional da mensagem enviada.
this.NomeFila = nomeFila;
this.Transacional = bTransacional;
}


// Processa, com base no enumerador de mensagens atual, a retirada da mesma, dentro de uma transação ou não.
// Retorna a mensagem da posição atual do enumerador.
private Message obtemMensagem(MessageEnumerator msmqEnumerator,
MessageQueueTransaction msmqTransacao)
{
Message msmqRetorno = msmqEnumerator.Current;
msmqRetorno.Formatter = new ActiveXMessageFormatter();
if (msmqTransacao != null)
msmqEnumerator.RemoveCurrent(msmqTransacao);
else
msmqEnumerator.RemoveCurrent();
return msmqRetorno;
}


///
/// Processa o recebimento de todas as mensagens represadas na fila do MSMQ
///

/// Delegate. Metodo que vai ser chamado, a cada mensagem lida da fila.
public void receberMensagens(MSMQProcessaMensagemRecebida metodoProcessar)
{
MessageQueue msmqFila = null;
MessageQueueTransaction msmqTransacao = null;
MessageEnumerator msmqEnumerator = null;
Message msmqMensagemCorrente = null;
bool retornoProcessamento = false;
try
{
msmqMensagemCorrente = null;
msmqFila = new MessageQueue(this.NomeFila); // abre a fila
msmqEnumerator = msmqFila.GetMessageEnumerator2(); // obtem o rol de mensagens atualmente postadas na fila.
retornoProcessamento = false; // variável de retorno do processamento

while (msmqEnumerator.MoveNext()) // enquanto existirem mensagens na fila
{

// abre-se a transação, caso a instância tenha sido criada como TRANSACIONAL
// Reparem, que temos uma transação para cada mensagem que iremos processar.
if (this.Transacional)
{
msmqTransacao = new MessageQueueTransaction();
msmqTransacao.Begin(); // Inicializa-se a transação.
}


// Obtemos a mensagem corrente da fila.
msmqMensagemCorrente = this.obtemMensagem(msmqEnumerator, msmqTransacao);


// CASO tenhamos passado uma instância do delegate de processamento, executamos a chamada do mesmo. Caso contrário, assumimos que o processamento foi terminado com sucesso.
retornoProcessamento = (metodoProcessar != null) ? metodoProcessar(msmqMensagemCorrente) : true;


// se estamos numa transação
if (this.Transacional)
{


// caso tenhamos processado com sucesso, fazemos o commit, e a mensagem é retirada da fila.
// caso contrário, é feito o Abort, e a mensagem permanece na fila.
if (retornoProcessamento) msmqTransacao.Commit();
else msmqTransacao.Abort();
msmqTransacao.Dispose();
msmqTransacao = null;
}


msmqMensagemCorrente.Dispose();
msmqMensagemCorrente = null;
}
}
catch (Exception erro)
{

// em caso de erro, é feito o abort da transação, e a mensagem permanece na fila.
if (msmqTransacao != null) msmqTransacao.Abort();
throw erro;
}
finally
{

// liberação dos recursos.
if (msmqMensagemCorrente!=null) msmqMensagemCorrente.Dispose();
if (msmqTransacao != null) msmqTransacao.Dispose();
if (msmqEnumerator != null) msmqEnumerator.Dispose();
if (msmqFila != null) msmqFila.Dispose();
msmqFila = null;
msmqEnumerator = null;
msmqMensagemCorrente = null;
msmqTransacao = null;
}
}



///
/// Processa o envio da mensagem enviada como parƒmetro.
///

/// Corpo da mensagem a enviar
/// Identificador da Mensagem
/// Metodo a processar, a cada mensagem enviada para a fila.
///
public bool enviarMensagem(String corpoMensagem, String labelMensagem,MSMQProcessaAposMensagemEnviada metodoProcessar)
{
bool boolRet = false;
MessageQueue msmqFila = null;
MessageQueueTransaction msmqTransacao = null;
try
{
msmqFila = new MessageQueue(this.NomeFila); // abre a fila.
msmqFila.Formatter = new ActiveXMessageFormatter();

if (this.Transacional)
{

// abre a transação
msmqTransacao = new MessageQueueTransaction();
msmqTransacao.Begin();
msmqFila.Send(corpoMensagem, labelMensagem, msmqTransacao);
}
else // envia sem transação.
msmqFila.Send(corpoMensagem, labelMensagem);


// caso tenhamos passado o delegate, processamos o mesmo. Caso contrário, assumimos true.
boolRet = (metodoProcessar != null) ? metodoProcessar(corpoMensagem,labelMensagem) : true;


// caso estejamos em transação, processamos o Commit ou Abort, dependendo do resultado do processamento.
if (this.Transacional)
{
if (boolRet) msmqTransacao.Commit();
else msmqTransacao.Abort();
}
}
catch (Exception err)
{

// caso tenha ocorrido um erro de processamento, e a mensagem tenha sido postada na fila, é feito o rollback da transação.
if (msmqTransacao != null)
{
if (msmqTransacao.Status == MessageQueueTransactionStatus.Pending)
msmqTransacao.Abort();
}
throw err;
}
finally
{
if (msmqTransacao != null) msmqTransacao.Dispose();
if (msmqFila != null) msmqFila.Dispose();
msmqFila = null;
msmqTransacao = null;
}
return boolRet;
}

}
}



Vejam que o código é muito simples, e os delegates garantem que o mesmo seja reutilizável por várias classes que precisem interagir com o MSMQ.

Abaixo, um exemplo da utilização da classe:
Temos um form, onde temos 2 caixas de texto, com os nomes das filas de envio e recebimento (por exemplo, .\private$\teste_envio e .\private$\teste_retorno), 2 caixas de texto, com o conteúdo da mensagem a enviar ou recebida, e 2 checkboxes, que indicam se o envio é transacional, ou não.



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;


namespace TesteEnvioMSMQ
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private bool AposEnvio(String corpoMensagem, String labelMensagem)
{
MessageBox.Show("Mensagem enviada com sucesso.");
return true;
}

private bool AposRetorno(System.Messaging.Message mensagem)
{
this.txtConteudoLido.Text = mensagem.Body.ToString();
return true;
}
private void btnEnviar_Click(object sender, EventArgs e)
{
CRK.FRT.BP.Generics.MSMQ objFila = new RotinasGenericas.MSMQ(this.txtFilaENVIO.Text, this.chkEnvioTransacional.Checked);
objFila.enviarMensagem(this.txtConteudoEnviar.Text, Guid.NewGuid().ToString(), new RotinasGenericas.MSMQ.MSMQProcessaAposMensagemEnviada (this.AposEnvio));
}
private void btnLer_Click(object sender, EventArgs e)
{
CRK.FRT.BP.Generics.MSMQ objFila = new RotinasGenericas.MSMQ(this.txtFilaRETORNO.Text, this.chkRetornoTransacional.Checked);
objFila.receberMensagens(new RotinasGenericas.MSMQ.MSMQProcessaMensagemRecebida(this.AposRetorno));
}
}
}



A codificação dos delegates ficam a critério do aplicativo cliente, o processamento do MSMQ fica encapsulado, e é completamente independente desta lógica.

Espero que seja de boa valia, para vocês.

Iniciando

Finalmente, depois de muito tempo, resolvi escutar meus companheiros e amigos, e começar a publicar um blog.
Neste blog, comentarei tecnologias, e apresentarei códigos e soluções.
Espero que seja de grande valia, para sua carreira.