WCF & MSMQ

Hace unas semanas hablaba con un compañero acerca de como implementar una aplicación con acceso  a MSMQ y tras una larga discusión, en un intento de conseguir pensar en el mejor camino de lograrlo, pensé en hacerlo con WCF, y,  ¿Que mejor forma de probarlo que haciendo un ejemplo o proyecto? , pues, e aquí el motivo de este post.

Os dejo el conjunto de pasos seguidos:

Pasos:

  • Generar una estructura en Visual Studio similar a la siguiente:

  • Añadir el siguiente código a la interfaz, fichero IService1.cs
[ServiceContract] public interface IService1 { [OperationContract(IsOneWay = true, Action = "*")] void Send(MsmqMessage<Persona> msg); }
  • Añadir el siguiente código al servicio Service1.cs
public class Service1 : IService1 { [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)] public void Send(MsmqMessage<Persona> message) { Persona msg = (Persona)message.Body; Console.WriteLine("Persona: [{0} {1}; ({2})] ", msg.Nombre, msg.Apellidos, msg.OtraCosaMariposa); } }
  •   En el fichero Program.cs del proyecto WcfMsmqHost añadir lo siguiente:
static void Main(string[] args) { string msmqPath = ConfigurationManager.AppSettings["baseAddress"]; if (!MessageQueue.Exists(msmqPath)) MessageQueue.Create(msmqPath); Uri baseAddress = new Uri(String.Format("msmq.formatname:DIRECT=OS:{0}", msmqPath)); using (ServiceHost serviceHost = new ServiceHost(typeof(Service1), baseAddress)) { serviceHost.Authorization.PrincipalPermissionMode = System.ServiceModel.Description.PrincipalPermissionMode.None; serviceHost.Open(); Console.WriteLine("Servicio listo."); Console.WriteLine("Pulsa <INTRO> para finalizar."); Console.ReadLine(); serviceHost.Close(); } }
  • El fichero de configuración del servidor deberá contener esto:
<appSettings> <add key="baseAddress" value=".private$MyTest33"/> </appSettings> <system.serviceModel> <bindings> <msmqIntegrationBinding> <binding name="NewBinding0" exactlyOnce="false" useSourceJournal="false" useMsmqTracing="true"> <security mode="None"> <transport msmqAuthenticationMode="None" /> </security> </binding> </msmqIntegrationBinding> </bindings> <services> <service name="WcfMsmqHost.Service1"> <endpoint address="" binding="msmqIntegrationBinding" bindingConfiguration="NewBinding0" contract="WcfMsmqIntegration.IService1" /> </service> </services> </system.serviceModel>
  • Finalmente la función Main, en Program.cs del proyecto de test debe contener algo similar a esto:
string msmqPath = ConfigurationManager.AppSettings["baseAddress"]; MsmqIntegrationBinding binding = new MsmqIntegrationBinding(); EndpointAddress address = new EndpointAddress( String.Format(@"msmq.formatname:DIRECT=OS:{0}", msmqPath)); ChannelFactory<IService1> channelFactory = new ChannelFactory<IService1>(binding, address); // None, porque MQM no esta en Active Directory binding.Security.Mode = MsmqIntegrationSecurityMode.None; IService1 channel = channelFactory.CreateChannel(); Persona msg = new Persona(); msg.Nombre = "Juan Luis"; msg.Apellidos = "Guerrero"; msg.OtraCosaMariposa = "elGuerre"; MsmqMessage<Persona> message = new MsmqMessage<Persona>(msg); using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required)) { channel.Send(message); scope.Complete(); }
  • Y el fichero de configuración del cliente deberá contener:
<configuration> <appSettings> <add key="baseAddress" value=".private$MyTest33"/> </appSettings> </configuration>

No olvidar incluir los espacios de nombre:

using System.ServiceModel; using System.Messaging; using System.ServiceModel.MsmqIntegration;

Y ni que decir tiene que la clase Persona (Persona.cs) contiene  tres propiedades públicas sin más; Nombre, Apellidos y OtraCosaMariposa, incluso, no será necesario establecer el atributo DataContract.

 

Por otro lado y durante la configuración del ejemplo nos podemos encontrar con alguno errores y que detallo a continuación:

Caso 1:

serviceHost.Open: Binding validation failed because the binding’s ExactlyOnce property is set to true while the destination queue is non-transactional. The service host cannot be opened. Resolve this conflict by setting the ExactlyOnce property to false or creating a transactional queue for this binding.

Este problema es debido a la propiedad “exactlyOnce” tiene el valor “true” y la cola no es transaccional para solucionarlo:

  1. Si la cola es transaccional entonces asignarle el valor “true” a esta propiedad.
  2. si la cola NO es transaccional asignarle el valor “false”.

Caso 2:

Binding validation failed because the binding’s MsmqAuthenticationMode property is set to WindowsDomain but MSMQ is installed with Active Directory integration disabled. The channel factory or service host cannot be opened.

En este caso la solución es evitar que el valor del modo de seguridad del binding sea “WindowsDomain”, puesto que la integración de MSMQ con Active Directory no ha sido instalada. Bastará, y si estamos en un dominio, con instalar esta integración desde los componentes de windows. Luego para nuestro caso, tanto cliente como servidor/host deberán establecer algunos valores:

Cliente en modo programático:

binding.Security.Mode = MsmqIntegrationSecurityMode.None;

Servidor mediante fichero de configuración:

<endpoint address="" binding="msmqIntegrationBinding" bindingConfiguration="NewBinding0" contract="WcfMsmqIntegration.IService1" />

El inconveniente de utilizar transacciones, si es que es un inconveniente, es el MSTC (Microsoft Transsaction Coordinator), que nos asegura la transaccionalidad de la operación de forma automática, pero que sin embargo, y dependiendo del entorno, es decir de la distribución entre servidores, podría resultar muy pesado e incluso no deseable. En caso de no hacer uso de la transaccionalidad, bastará con invocar de nuevo a nuestro “Sender” (envío de mensajes a MSMQ con WCF) desde el propio servidor/host y establecer un tratamiento adecuado y con esto estaría solucionado.

Finalmente y por ahora, he decir, que la ventaja de utilizar WCF para el tratamiento de colas MSMQ radica principalmente en la posibilidad de cambiar los bindings sin problema alguno, la trazabilidad totalmente automática, la seguridad de que todo va a funcionar a la primera, 😀

“Lo malo” puede ser que nos encontremos con que ya tenemos un sistema de colas MSMQ en un entorno de producción y que no podamos crear ningún servicio WCF, en tal caso, siempre podremos optar por crear un cliente WCF (ClientBase<T>), incluso también optar por el caso contrario, un servidor WCF y un cliente no WCF (System.Messaging).

http://www.cogin.com/mq/download.php

Un nuevo camino para el tratamiento de colas MSMQ.

saludos
Juanlu

3 comentarios en “WCF & MSMQ”

  1. Buenas tardes. Excelente su documento.
    Podria pedir su ayuda con algo:

    Estoy implementando un sistema que conecta otros sistemas. Este sistema podria decirse que es el orquestados del sistema en general. Por ejemplo: debo recibir unos archivos planos de un sistema, llevarlos a MS/SQL y luego procesar dicha informacion generando a partir de ella unos comandos que seran enviados a otras aplicaciones en formatos prestablecidos para unos, archivos texto, para otros archivos XML y para otros conexion a base de datos directa.
    Como veras, todos tienen caracteriticas que los diferencias.
    Adicional, otro sistema me enviara (al sistema orquestador) unas confirmaciones de que unas tareas se han terminado de ejcutar, puede que exitonasmen o puede que con error, pero a fin de cuentas, el sistema debera informar el resultado de la ejecusion al orquestador.
    Este tomara los archivos de contestacion, los llevara a su sistema de base de datos (MS/SQL), y realizara una logica con ellos.
    Otros sistemas, recibiran del orquestador, unos comandos y a medida que vanyan ejecutando las tareas representadas por dichos comandos, iran igaulmente que en el caso anterior, repondiendo mediante archivos de confirmacion y otros datos adicionales.
    El sistema es ASINCRONO, mientras y debrai estar en capacidad de recibir respuesta simultaneamente de cada subsistema y con base en esto tomar unas decisiones.

    Imagino que el unico sistema de manejo de colas para microsoft es MSMQ, pero la verdad estoy muy perdido de como se maneja, como se instala, si esto es una aplicacion que uno deba elaborar, o si debe ir algun componenete enbebido dentro de las aplicaciones (en este caso el orquestador) quien debe manejar la logia del MSMQ… En fin en conclusion, estoy perdido no solo conceptualmente, sino a nivel de arquitectura de la solucion de manejo de colas y como se debe integrar todo esto… Que me sugiere usted…

    Saludos, mil gracias.

    Fred Londoño Zuleta…

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *