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.