Megosztás:


Üzenet korrelációja

A MessageCorrelation minta bemutatja, hogy egy Message Queuing (MSMQ) alkalmazás hogyan küldhet MSMQ-üzenetet egy Windows Communication Foundation (WCF) szolgáltatásnak, és hogyan lehet korrelálni az üzeneteket a feladó és a fogadó alkalmazás között egy kérés/válasz forgatókönyvben. Ez a minta az msmqIntegrationBinding kötést használja. Ebben az esetben a szolgáltatás egy saját üzemeltetésű konzolalkalmazás, amely lehetővé teszi az üzenetsorba helyezett üzeneteket fogadó szolgáltatás megfigyelését. k

A szolgáltatás feldolgozza a feladótól kapott üzenetet, és visszaküld egy válaszüzenetet a feladónak. A feladó az általa eredetileg elküldött kérésre kapott választ korrelálja. Az MessageID és CorrelationID üzenet tulajdonságai a kérés- és válaszüzenetek korrelációjára szolgálnak.

A IOrderProcessor szolgáltatási szerződés egy egyirányú szolgáltatásműveletet határoz meg, amely alkalmas a sorba állításra. Az MSMQ-üzenetek nem rendelkeznek műveletfejléccel, így nem lehet különböző MSMQ-üzeneteket automatikusan hozzárendelni a műveleti szerződésekhez. Ezért ebben az esetben csak egy műveleti szerződés lehet. Ha további műveleti szerződéseket szeretne definiálni a szolgáltatásban, az alkalmazásnak meg kell adnia az MSMQ-üzenetben szereplő fejlécet (például a címkét vagy a korrelációs azonosítót) annak eldöntéséhez, hogy melyik műveleti szerződést küldje el.

Az MSMQ-üzenet azt sem tartalmazza, hogy mely fejlécek vannak leképezve a műveleti szerződés különböző paramétereihez. Ezért a műveleti szerződésben csak egy paraméter szerepelhet. A paraméter típusa MsmqMessage<T>a mögöttes MSMQ-üzenetet tartalmazza. Az osztály "T" típusa az MsmqMessage<T> MSMQ-üzenettörzsbe szerializált adatokat jelöli. Ebben a mintában a PurchaseOrder típus szerializálva lesz az MSMQ üzenettörzsében.

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

A szolgáltatásművelet feldolgozza a vásárlási rendelést, és megjeleníti a vásárlási rendelés tartalmát és állapotát a szolgáltatáskonzol ablakában. A OperationBehaviorAttribute művelet úgy konfigurálja a műveletet, hogy a várólistával rendelkező tranzakcióba lépjen be, és hogy a művelet visszatérésekor a tranzakció befejezettként legyen megjelölve. Ez PurchaseOrder tartalmazza a szolgáltatás által feldolgozandó rendelési adatokat.

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

A szolgáltatás egy egyéni ügyfél OrderResponseClient használatával küldi el az MSMQ-üzenetet az üzenetsorba. Mivel az üzenetet fogadó és feldolgozó alkalmazás nem WCF-alkalmazás, hanem MSMQ-alkalmazás, a két alkalmazás között nincs implicit szolgáltatási szerződés. Ezért ebben a forgatókönyvben nem tudunk proxyt létrehozni a Svcutil.exe eszközzel.

Az egyéni proxy lényegében ugyanaz az összes WCF-alkalmazás esetében, amely a kötést használja az msmqIntegrationBinding üzenetek küldésére. A többi proxytól eltérően nem tartalmaz szolgáltatásműveleteket. Csak küldési üzenet művelet.

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

A szolgáltatás saját üzemeltetésű. Az MSMQ integrációs átvitel használatakor a használt üzenetsort előre létre kell hozni. Ez manuálisan vagy kódon keresztül is elvégezhető. Ebben a mintában a szolgáltatás System.Messaging kódot tartalmaz az üzenetsor meglétének ellenőrzéséhez és szükség esetén annak létrehozásához. A sor nevét a konfigurációs fájlból olvassák be.

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

A rendelési kérelmeket küldő MSMQ-üzenetsor a konfigurációs fájl AppSettings szakaszában van megadva. Az ügyfél- és szolgáltatásvégpontok a konfigurációs fájl system.serviceModel szakaszában vannak definiálva. Mindkettő a msmqIntegrationBinding kötést adja meg.

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

Az ügyfélalkalmazás System.Messaging tartós és tranzakciós üzenetet küld az üzenetküldési sorba. Az üzenet törzse tartalmazza a megrendelést.

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

Az MSMQ-üzenetsor, amelyből a rendelési válaszok érkeznek, a konfigurációs fájl AppSettings szakaszában van megadva, ahogyan az az alábbi mintakonfigurációban látható.

Megjegyzés:

Az sor neve pontot (.) használ a helyi számítógéphez, és perjeleket az elérési útvonalában. A WCF végpontcíme egy msmq.formatname sémát határoz meg, és a helyi számítógéphez a "localhost" nevet használja. A megfelelően formázott formátumnév az msmq.formatname nevet követi az URI-ban az MSMQ-irányelveknek megfelelően.

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

Az ügyfélalkalmazás menti a messageID szolgáltatásnak küldött megrendeléskérési üzenetet, és megvárja a szolgáltatás válaszát. Amint egy válasz megérkezik az üzenetsorba, az ügyfél korrelálja azt a küldött megrendelési üzenettel az üzenet correlationID tulajdonságának segítségével, amely tartalmazza az ügyfél által eredetileg a szolgáltatásnak küldött megrendelési üzenet messageID-t.

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

A minta futtatásakor az ügyfél- és szolgáltatástevékenységek a szolgáltatás és az ügyfélkonzol ablakaiban is megjelennek. Láthatja, hogy a szolgáltatás üzeneteket fogad az ügyféltől, és választ küld az ügyfélnek. Az ügyfél megjeleníti a szolgáltatástól kapott választ. A szolgáltatás és az ügyfél leállításához nyomja le az ENTER billentyűt az egyes konzolablakokban.

Megjegyzés:

Ehhez a mintához a Message Queuing (MSMQ) telepítése szükséges. Tekintse meg az MSMQ telepítési utasításait a Lásd még szakaszban.

A minta beállítása, összeállítása és futtatása

  1. Győződjön meg arról, hogy elvégezte a Windows Communication Foundation-minták One-Time beállítási eljárását.

  2. Ha a szolgáltatást először futtatják, ellenőrzi, hogy az üzenetsor jelen van-e. Ha az üzenetsor nincs jelen, a szolgáltatás létrehoz egyet. Először futtathatja a szolgáltatást az üzenetsor létrehozásához, vagy létrehozhat egyet az MSMQ Queue Manageren keresztül. Az alábbi lépéseket követve hozzon létre egy sort a Windows Server 2008-ban.

    1. Nyissa meg a Kiszolgálókezelőt a Visual Studio 2012-ben.

    2. Nyissa meg a Funkciók lapot.

    3. Kattintson a jobb gombbal a Privát üzenetsorokelemre, és válassza Új, Privát üzenetsorlehetőséget.

    4. Jelölje be a Tranzakciós jelölőnégyzetet.

    5. Adja meg ServiceModelSamplesTransacted az új üzenetsor neveként.

  3. A megoldás C# vagy Visual Basic .NET kiadásának létrehozásához kövesse Windows Communication Foundation-mintákcímű témakör utasításait.

  4. A minta egyszámítógépes konfigurációban való futtatásához kövesse a Windows Communication Foundation-minták futtatására vonatkozó utasításokat.

A minta futtatása számítógépeken

  1. Másolja a szolgáltatásprogram fájljait a \service\bin\ mappából a nyelvspecifikus mappából a szolgáltatásszámítógépre.

  2. Másolja az ügyfélprogram fájljait a \client\bin\ mappából a nyelvspecifikus mappából az ügyfélszámítógépre.

  3. A Client.exe.config fájlban módosítsa az orderQueueName nevet úgy, hogy a "." helyett a szolgáltatásszámítógép nevét adja meg.

  4. A Service.exe.config fájlban módosítsa az ügyfélvégpont címét úgy, hogy a "." helyett az ügyfélszámítógép nevét adja meg.

  5. A szolgáltatásszámítógépen indítsa el a Service.exe parancssorból.

  6. Az ügyfélszámítógépen indítsa el a Client.exe parancssorból.

Lásd még