martes, 24 de junio de 2008

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:

[ServiceContract]
public interface IService1
{
[OperationContract(IsOneWay
= true, Action = "*")]
void Send(MsmqMessage<Persona> msg);
}




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);
}
}




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();
}
}




<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>



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();
}


<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, :-D


"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

Etiquetas: , ,


Comments:
Este comentario ha sido eliminado por un administrador del blog.
 
Publicar un comentario



<< Home

This page is powered by Blogger. Isn't yours?