Compartir a través de


Enlace MSMQ por transacciones

En el ejemplo Por transacciones, se muestra cómo llevar a cabo la comunicación en cola por transacciones mediante Message Queue Server (MSMQ).

Nota:

El procedimiento de instalación y las instrucciones de compilación de este ejemplo se encuentran al final de este tema.

En la comunicación con colas, el cliente se comunica con el servicio mediante una cola. Más precisamente, el cliente envía mensajes a una cola. El servicio recibe mensajes de la cola. El servicio y el cliente no se tienen que estar ejecutando simultáneamente para comunicarse mediante una cola.

Cuando las transacciones se usan para enviar y recibir mensajes, en realidad hay dos transacciones independientes. Cuando el cliente envía mensajes dentro del ámbito de una transacción, la transacción es local para el cliente y el administrador de colas de cliente. Cuando el servicio recibe mensajes dentro del ámbito de la transacción, la transacción es local para el servicio y el administrador de colas receptor. Es muy importante recordar que el cliente y el servicio no están participando en la misma transacción; más bien, están utilizando distintas transacciones al realizar sus operaciones (como enviar y recibir) con la cola.

En este ejemplo, el cliente envía un lote de mensajes al servicio desde el ámbito de una transacción. El servicio recibe a continuación los mensajes enviados a la cola dentro del ámbito de la transacción definido por el servicio.

El contrato de servicio es IOrderProcessor, como se muestra en el código de ejemplo siguiente. La interfaz define un servicio unidireccional adecuado para su uso con colas.

[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface IOrderProcessor
{
    [OperationContract(IsOneWay = true)]
    void SubmitPurchaseOrder(PurchaseOrder po);
}

El comportamiento del servicio define un comportamiento de operación con TransactionScopeRequired establecido en true. Esto garantiza que los administradores de recursos a los que el método tiene acceso utilizan el mismo ámbito de la transacción usado para recuperar el mensaje de la cola. También garantiza que si el método produce una excepción, el mensaje se devuelva a la cola. Sin establecer este comportamiento de operación, un canal en cola crea una transacción para leer el mensaje de la cola y lo confirma automáticamente antes de enviar de forma que, si se produce un error en la operación, se pierde el mensaje. El escenario más común es para que las operaciones de servicio den de alta en la transacción que se utiliza para leer el mensaje de la cola, tal y como se muestra en el código siguiente.

 // This service class that implements the service contract.
 // This added code writes output to the console window.
public class OrderProcessorService : IOrderProcessor
 {
     [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
     public void SubmitPurchaseOrder(PurchaseOrder po)
     {
         Orders.Add(po);
         Console.WriteLine("Processing {0} ", po);
     }
  …
}

El servicio se hospeda en sí mismo. Al utilizar el transporte de MSMQ, se debe crear la cola utilizada de antemano. Esto se puede hacer manualmente o a través del código. En este ejemplo, el servicio contiene código para comprobar la existencia de la cola y crear la cola si no existe. El nombre de la cola se lee del archivo de configuración. La herramienta de utilidad de metadatos ServiceModel (Svcutil.exe) usa la dirección base para generar el proxy para el servicio.

// Host the service within this EXE console application.
public static void Main()
{
    // Get the MSMQ queue name from appSettings in configuration.
    string queueName = ConfigurationManager.AppSettings["queueName"];

    // 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)))
    {
        // Open the ServiceHost to create listeners and start listening for messages.
        serviceHost.Open();

        // The service can now be accessed.
        Console.WriteLine("The service is ready.");
        Console.WriteLine("Press <ENTER> to terminate service.");
        Console.WriteLine();
        Console.ReadLine();

        // Close the ServiceHost to shut down the service.
        serviceHost.Close();
    }
}

El nombre de la cola MSMQ se especifica en la sección 'appSettings' del archivo de configuración, como se muestra en la siguiente configuración de ejemplo.

<appSettings>
    <add key="queueName" value=".\private$\ServiceModelSamplesTransacted" />
</appSettings>

Nota:

El nombre de la cola usa un punto (.) para el equipo local y separadores con barra diagonal inversa en su ruta de acceso al crear la cola mediante System.Messaging. El punto de conexión de Windows Communication Foundation (WCF) utiliza la dirección de la cola con el esquema net.msmq, usa el "localhost" para designar el equipo local y emplea barras diagonales en su ruta de acceso.

El cliente crea un ámbito de transacción. La comunicación con la cola tiene lugar dentro del ámbito de la transacción, provocando que se trate como una unidad atómica donde se envían todos los mensajes a la cola o no se envía ninguno. La transacción se confirma llamando a Complete en el ámbito de la transacción.

// Create a client.
OrderProcessorClient client = new OrderProcessorClient();

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

// Create a transaction scope.
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
    // Make a queued call to submit the purchase order.
    client.SubmitPurchaseOrder(po);
    // Complete the transaction.
    scope.Complete();
}

// Closing the client gracefully closes the connection and cleans up resources.
client.Close();

Console.WriteLine();
Console.WriteLine("Press <ENTER> to terminate client.");
Console.ReadLine();

Para comprobar que las transacciones funcionan, modifique el cliente comentando el ámbito de transacción como se muestra en el código de ejemplo siguiente, recompile la solución y ejecute el cliente.

//scope.Complete();

Dado que la transacción no se ha completado, los mensajes no se envían a la cola.

Al ejecutar el ejemplo, las actividades de cliente y servicio se muestran en las ventanas de servicio y consola de cliente. Puede ver que el servicio recibe mensajes del cliente. Presione ENTRAR en cada ventana de consola para apagar el servicio y el cliente. Tenga en cuenta que, dado que la espera está en uso, el cliente y el servicio no tienen que funcionar al mismo tiempo. Puede ejecutar el cliente, apagarlo y, a continuación, iniciar el servicio y seguir recibiendo los mensajes.

The service is ready.
Press <ENTER> to terminate service.

Processing Purchase Order: 7b31ce51-ae7c-4def-9b8b-617e4288eafd
        Customer: somecustomer.com
        OrderDetails
                Order LineItem: 54 of Blue Widget @unit price: $29.99
                Order LineItem: 890 of Red Widget @unit price: $45.89
        Total cost of this order: $42461.56
        Order status: Pending

Para configurar, compilar y ejecutar el ejemplo

  1. Asegúrese de que ha realizado el procedimiento de instalación única para los ejemplos de Windows Communication Foundation.

  2. Si el servicio se ejecuta primero, comprobará que la cola está presente. Si la cola no está presente, el servicio creará uno. Puede ejecutar primero el servicio para crear la cola o puede crear uno a través del Administrador de colas de MSMQ. Siga estos pasos para crear una cola en Windows 2008.

    1. Abra el Administrador del servidor en Visual Studio 2012.

    2. Expanda la pestaña Características.

    3. Haga clic con el botón derecho en Cola de mensajes privados y seleccione Nuevo, Cola privada.

    4. Active la casilla Transaccional.

    5. Escriba ServiceModelSamplesTransacted como nombre de la nueva cola.

  3. Para compilar el código C# o Visual Basic .NET Edition de la solución, siga las instrucciones de Building the Windows Communication Foundation Samples.

  4. Para ejecutar el ejemplo en una configuración de un solo equipo o entre equipos, siga las instrucciones de Ejecución de los ejemplos de Windows Communication Foundation.

De forma predeterminada, con NetMsmqBinding, la seguridad de transporte está habilitada. Hay dos propiedades relevantes para la seguridad de transporte de MSMQ, MsmqAuthenticationMode y MsmqProtectionLevel. De forma predeterminada, el modo de autenticación se establece Windows en y el nivel de protección se establece en Sign. Para que MSMQ proporcione la característica de autenticación y firma, debe formar parte de un dominio y la opción de integración de Active Directory para MSMQ debe estar instalada. Si ejecuta este ejemplo en un equipo que no cumple estos criterios, recibirá un error.

Para ejecutar el ejemplo en un equipo unido a un grupo de trabajo o sin integración de Active Directory

  1. Si el equipo no forma parte de un dominio o no tiene instalada la integración de Active Directory, desactive la seguridad de transporte estableciendo el modo de autenticación y el nivel None de protección en como se muestra en el siguiente código de configuración de ejemplo.

    <system.serviceModel>
      <services>
        <service name="Microsoft.ServiceModel.Samples.OrderProcessorService"
                 behaviorConfiguration="OrderProcessorServiceBehavior">
          <host>
            <baseAddresses>
              <add baseAddress="http://localhost:8000/ServiceModelSamples/service"/>
            </baseAddresses>
          </host>
          <!-- Define NetMsmqEndpoint. -->
          <endpoint
              address="net.msmq://localhost/private/ServiceModelSamplesTransacted"
              binding="netMsmqBinding"
              bindingConfiguration="Binding1"
           contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
          <!-- The mex endpoint is exposed at http://localhost:8000/ServiceModelSamples/service/mex. -->
          <endpoint address="mex"
                    binding="mexHttpBinding"
                    contract="IMetadataExchange" />
        </service>
      </services>
    
      <bindings>
        <netMsmqBinding>
          <binding name="Binding1">
            <security mode="None" />
          </binding>
        </netMsmqBinding>
      </bindings>
    
        <behaviors>
          <serviceBehaviors>
            <behavior name="OrderProcessorServiceBehavior">
              <serviceMetadata httpGetEnabled="True"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
    
      </system.serviceModel>
    
  2. Asegúrese de cambiar la configuración tanto en el servidor como en el cliente antes de ejecutar el ejemplo.

    Nota:

    Establecer security mode en None es equivalente a establecer MsmqAuthenticationMode, MsmqProtectionLevely Message seguridad en None.