Compartir a través de


Correlación del mensaje

Download sample

Este ejemplo muestra cómo una aplicación Message Queue Server (MSMQ) puede enviar un mensaje de MSMQ a un servicio Windows Communication Foundation (WCF) y cómo los mensajes se pueden poner en correlación entre las aplicaciones del remitente y el receptor en un escenario de solicitud/respuesta. Este ejemplo utiliza el enlace msmqIntegrationBinding. El servicio en este caso es una aplicación de consola autoalojada que le permite observar el servicio que recibe los mensajes en cola.

El servicio procesa el mensaje recibido del remitente y envía de vuelta un mensaje de respuesta al remitente. El remitente pone en correlación la respuesta que recibió con la solicitud que envió en un principio. Las propiedades MessageID y CorrelationID del mensaje se utilizan para poner en correlación los mensajes de respuesta y solicitud.

El contrato de servicio IOrderProcessor define una operación de servicio unidireccional que sea adecuada para su uso cuando se coloque en la cola. Un mensaje de MSMQ no tiene un encabezado Acción, por lo que no es posible asignar automáticamente mensajes de MSMQ diferentes a contratos de operación. Por consiguiente, puede haber sólo un contrato de operación en este caso. Si desea definir más contratos de operación en el servicio, la aplicación debe proporcionar información como qué encabezado en el mensaje de MSMQ (por ejemplo, la etiqueta o correlationID) se puede utilizar para decidir qué contrato de operación enviar. Esto se muestra en Demux personalizado.

El mensaje de MSMQ no contiene información sobre qué encabezados están asignados a los distintos parámetros del contrato de operación. Por consiguiente, puede haber sólo un parámetro en el contrato de la operación. El parámetro es del tipo MsmqMessageMsmqMessage<T>, que contiene el mensaje de MSMQ subyacente. El tipo "T" en la clase MsmqMessage<T> representa los datos que se serializan en el cuerpo del mensaje de MSMQ. En este ejemplo, el tipo PurchaseOrder se serializa en el cuerpo del mensaje de MSMQ.

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
[ServiceKnownType(typeof(PurchaseOrder))]
public interface IOrderProcessor
{
    [OperationContract(IsOneWay = true, Action = "*")]
    void SubmitPurchaseOrder(MsmqMessage<PurchaseOrder> msg);
}

La operación del servicio procesa la orden de compra, muestra su contenido y su estado en la ventana de la consola del servicio. OperationBehaviorAttribute configura la operación que dar de alta en una transacción con la cola y marcar la transacción como completada cuando vuelve la operación. PurchaseOrder contiene los detalles de la orden que debe ser procesada por el servicio.

// Service class that implements the service contract.
public class OrderProcessorService : IOrderProcessor
{
   [OperationBehavior(TransactionScopeRequired = true, 
          TransactionAutoComplete = true)]
   public void SubmitPurchaseOrder(MsmqMessage<PurchaseOrder> ordermsg)
   {
       PurchaseOrder po = (PurchaseOrder)ordermsg.Body;
       Random statusIndexer = new Random();
       po.Status = PurchaseOrder.OrderStates[statusIndexer.Next(3)];
       Console.WriteLine("Processing {0} ", po);
       //Send a response to the client that the order has been received 
         and is pending fullfillment. 
       SendResponse(ordermsg);
    }

    private void SendResponse(MsmqMessage<PurchaseOrder> ordermsg)
    {
        OrderResponseClient client = new OrderResponseClient("OrderResponseEndpoint");
        
        //Set the correlation ID such that the client can correlate the response to the order.
        MsmqMessage<PurchaseOrder> orderResponsemsg = new MsmqMessage<PurchaseOrder>(ordermsg.Body);
        orderResponsemsg.CorrelationId = ordermsg.Id;
        using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
        {
            client.SendOrderResponse(orderResponsemsg);
            scope.Complete();
        }

        client.Close();
    }
}

El servicio utiliza un OrderResponseClient de cliente personalizado para enviar el mensaje de MSMQ a la cola. Dado que la aplicación que recibe y procesa el mensaje es una aplicación MSMQ y no una aplicación WCF, no hay ningún contrato de servicios implícito entre las dos aplicaciones. Así que no podemos crear ningún proxy utilizando la herramienta Svcutil.exe en este escenario.

El proxy personalizado es esencialmente el mismo para todas las aplicaciones WCF que utilizan el enlace msmqIntegrationBinding para enviar mensajes. A diferencia de otros servidores proxy, no incluye ningún intervalo de operaciones de servicio. Sólo es una operación de envío de mensaje.

[System.ServiceModel.ServiceContractAttribute(Namespace = "http://Microsoft.ServiceModel.Samples")]
public interface IOrderResponse
{

    [System.ServiceModel.OperationContractAttribute(IsOneWay = true, Action = "*")]
    void SendOrderResponse(MsmqMessage<PurchaseOrder> msg);
}

public partial class OrderResponseClient : System.ServiceModel.ClientBase<IOrderResponse>, IOrderResponse
{

    public OrderResponseClient()
    { }

    public OrderResponseClient(string configurationName)
        : base(configurationName)
    { }

    public OrderResponseClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress address)
        : base(binding, address)
    { }

    public void SendOrderResponse(MsmqMessage<PurchaseOrder> msg)
    {
        base.Channel.SendOrderResponse(msg);
    }
}

El servicio se autoaloja. Al utilizar el transporte de integración de MSMQ, se debe crear con antelación la cola utilizada. Esto se puede hacer manualmente o a través de código. En este ejemplo, el servicio contiene el código System.Messaging para comprobar la existencia de la cola y crearla si fuera necesaria. El nombre de la cola se lee desde el archivo de configuración.

public static void Main()
{
       // Get the MSMQ queue name from application settings in configuration.
      string queueName = 
                ConfigurationManager.AppSettings["orderQueueName"];
      // Create the transacted MSMQ queue if necessary.
      if (!MessageQueue.Exists(queueName))
                MessageQueue.Create(queueName, true);
     // Create a ServiceHost for the OrderProcessorService type.
     using (ServiceHost serviceHost = new 
                   ServiceHost(typeof(OrderProcessorService)))
     {
            serviceHost.Open();
            // The service can now be accessed.
            Console.WriteLine("The service is ready.");
            Console.WriteLine("Press <ENTER> to terminate service.");
            Console.ReadLine();
            // Close the ServiceHost to shutdown the service.
            serviceHost.Close();
      }
}

La cola de MSMQ a la que se envían las solicitudes de la orden se especifica en la sección appSettings del archivo de configuración. Los extremos de servicio y cliente se definen en la sección de system.ServiceModel del archivo de configuración. Ambos especifican el enlace msmqIntegrationbinding.

<appSettings>
  <add key="orderQueueName" value=".\private$\Orders" />
</appSettings>

<system.serviceModel>
  <client>
    <endpoint    name="OrderResponseEndpoint" 
              address="msmq.formatname:DIRECT=OS:.\private$\OrderResponse"
              binding="msmqIntegrationBinding"
              bindingConfiguration="OrderProcessorBinding" 
              contract="Microsoft.ServiceModel.Samples.IOrderResponse">
    </endpoint>
  </client>

  <services>
    <service 
      name="Microsoft.ServiceModel.Samples.OrderProcessorService">
      <endpoint address="msmq.formatname:DIRECT=OS:.\private$\Orders"
                            binding="msmqIntegrationBinding"
                bindingConfiguration="OrderProcessorBinding" 
                contract="Microsoft.ServiceModel.Samples.IOrderProcessor">
      </endpoint>
    </service>
  </services>

  <bindings>
    <msmqIntegrationBinding>
      <binding name="OrderProcessorBinding" >
        <security mode="None" />
      </binding>
    </msmqIntegrationBinding>
  </bindings>

</system.serviceModel>

La aplicación cliente utiliza System.Messaging para enviar un mensaje duradero y transaccional a la cola. El cuerpo del mensaje contiene la orden de compra.

static void PlaceOrder()
{
    //Connect to the queue
    MessageQueue orderQueue = 
            new MessageQueue(
                    ConfigurationManager.AppSettings["orderQueueName"]) 
    // Create the purchase order.
    PurchaseOrder po = new PurchaseOrder();
    po.CustomerId = "somecustomer.com";
    po.PONumber = Guid.NewGuid().ToString();
    PurchaseOrderLineItem lineItem1 = new PurchaseOrderLineItem();
    lineItem1.ProductId = "Blue Widget";
    lineItem1.Quantity = 54;
    lineItem1.UnitCost = 29.99F;

    PurchaseOrderLineItem lineItem2 = new PurchaseOrderLineItem();
    lineItem2.ProductId = "Red Widget";
    lineItem2.Quantity = 890;
    lineItem2.UnitCost = 45.89F;

    po.orderLineItems = new PurchaseOrderLineItem[2];
    po.orderLineItems[0] = lineItem1;
    po.orderLineItems[1] = lineItem2;

    Message msg = new Message();
    msg.UseDeadLetterQueue = true;
    msg.Body = po;

    //Create a transaction scope.
    using (TransactionScope scope = new    
     TransactionScope(TransactionScopeOption.Required))
    {
        // Submit the purchase order.
        orderQueue.Send(msg, MessageQueueTransactionType.Automatic);
        // Complete the transaction.
        scope.Complete();
    }
    //Save the messageID for order response correlation.
    orderMessageID = msg.Id;
    Console.WriteLine("Placed the order, waiting for response...");
}

La cola de MSMQ de la que se reciben las respuestas del pedido se especifica en una sección appSettings del archivo de configuración, tal y como se muestra en la configuración de ejemplo siguiente.

Nota

El nombre de la cola usa un punto (.) para el equipo local y separadores de barra diagonal inversa en su ruta de acceso. La dirección de extremo WCF especifica un esquema de msmq.formatname y utiliza el "host local" para el equipo local. Un nombre de formato correctamente formado sigue msmq.formatname en el URI según las instrucciones de MSMQ.

<appSettings>
    <add key=" orderResponseQueueName" value=".\private$\Orders" />
</appSettings>

La aplicación cliente guarda messageID del mensaje de solicitud de la orden que envía al servicio y espera una respuesta de éste. Una vez que la respuesta llega a la cola, el cliente la pone en correlación con el mensaje de la orden que envió utilizando la propiedad correlationID del mensaje, que contiene el messageID del mensaje de la orden que el cliente envió al servicio en un principio.

static void DisplayOrderStatus()
{
    MessageQueue orderResponseQueue = new 
     MessageQueue(ConfigurationManager.AppSettings            
                  ["orderResponseQueueName"]);
    //Create a transaction scope.
    bool responseReceived = false;
    orderResponseQueue.MessageReadPropertyFilter.CorrelationId = true;
    while (!responseReceived)
    {
       Message responseMsg;
       using (TransactionScope scope2 = new  
         TransactionScope(TransactionScopeOption.Required))
       {
          //Receive the Order Response message.
          responseMsg = 
              orderResponseQueue.Receive
                   (MessageQueueTransactionType.Automatic);
          scope2.Complete();
     }
     responseMsg.Formatter = new 
     System.Messaging.XmlMessageFormatter(new Type[] { 
         typeof(PurchaseOrder) });
     PurchaseOrder responsepo = (PurchaseOrder)responseMsg.Body;
    //Check if the response is for the order placed.
    if (orderMessageID == responseMsg.CorrelationId)
    {
       responseReceived = true;
       Console.WriteLine("Status of current Order: OrderID-{0},Order 
            Status-{1}", responsepo.PONumber, responsepo.Status);
    }
    else
    {
       Console.WriteLine("Status of previous Order: OrderID-{0},Order  
            Status-{1}", responsepo.PONumber, responsepo.Status);
    }
  }
}

Al ejecutar el ejemplo, las actividades del servicio y del cliente se muestran en las ventanas de la consola del cliente y del servicio. Podrá observar que el servicio recibe los mensajes del cliente y envía una respuesta a éste. El cliente muestra la respuesta recibida del servicio. Presione ENTRAR en cada ventana de la consola para cerrar el servicio y el cliente.

Nota

Este ejemplo requiere la instalación de Message Queue Server (MSMQ). Vea las instrucciones de instalación de MSMQ en el sección Vea también.

Para configurar, generar y ejecutar el ejemplo

  1. Asegúrese de que ha realizado el Procedimiento de instalación único para ejemplos de Windows Communication Foundation.

  2. Para generar el código C# o Visual Basic .NET Edition de la solución, siga las instrucciones de Generación de ejemplos de Windows Communication Foundation.

  3. Para ejecutar el ejemplo en una configuración de equipos única, siga las instrucciones de Ejecución de ejemplos de Windows Communication Foundation.

Para ejecutar el ejemplo en los equipos

  1. Copie los archivos de programa de servicio de la carpeta \service\bin\, bajo la carpeta específica del lenguaje, al equipo del servicio.

  2. Copie los archivos de programa del cliente de la carpeta \client\bin\, bajo la carpeta específica del lenguaje, al equipo del cliente.

  3. En el archivo Client.exe.config, cambie orderQueueName para especificar el nombre de equipo del servicio en lugar de ".".

  4. En el archivo Service.exe.config, cambie la dirección del extremo de cliente para especificar el nombre del equipo cliente en lugar de ".".

  5. En el equipo del servicio, inicie Service.exe desde un símbolo del sistema.

  6. En el equipo cliente, inicie Client.exe desde el símbolo del sistema.

Consulte también

Otros recursos

Queuing in WCF
Message Queue Server

Footer image

Copyright © 2007 Microsoft Corporation. Reservados todos los derechos.