Relace a fronty

Ukázka relace ukazuje, jak odesílat a přijímat sadu souvisejících zpráv ve frontě komunikace přes přenos služby Řízení front zpráv (MSMQ). Tato ukázka používá netMsmqBinding vazbu. Služba je konzolová aplikace v místním prostředí, která umožňuje sledovat službu, která přijímá zprávy ve frontě.

Poznámka:

Postup nastavení a pokyny k sestavení pro tuto ukázku najdete na konci tohoto tématu.

Při frontové komunikaci klient komunikuje pomocí fronty se službou. Přesněji řečeno, klient odesílá zprávy do fronty. Služba přijímá zprávy z fronty. Služba a klient tedy nemusí být spuštěny současně, aby mohly komunikovat pomocí fronty.

Někdy klient odešle sadu zpráv, které spolu vzájemně souvisejí ve skupině. Pokud musí být zprávy zpracovány společně nebo v zadaném pořadí, lze frontu použít k jejich seskupování ke zpracování jednou přijímající aplikací. To je zvlášť důležité, pokud je na skupině serverů několik přijímajících aplikací a je nutné zajistit, aby stejná přijímající aplikace zpracovávala skupinu zpráv. Relace ve frontě jsou mechanismus, který slouží k odesílání a přijímání související sady zpráv, které se musí zpracovat najednou. Relace ve frontě vyžadují k zobrazení tohoto vzoru transakci.

V ukázce klient odešle do služby řadu zpráv v rámci relace v rámci rozsahu jedné transakce.

Kontrakt služby je IOrderTaker, který definuje jednosměrnou službu, která je vhodná pro použití s frontami. Použité SessionMode ve smlouvě zobrazené v následujícím vzorovém kódu označuje, že zprávy jsou součástí relace.

[ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode=SessionMode.Required)]
public interface IOrderTaker
{
    [OperationContract(IsOneWay = true)]
    void OpenPurchaseOrder(string customerId);

    [OperationContract(IsOneWay = true)]
    void AddProductLineItem(string productId, int quantity);

    [OperationContract(IsOneWay = true)]
    void EndPurchaseOrder();
}

Služba definuje operace služby takovým způsobem, že první operace se zapojuje do transakce, ale automaticky transakci nedokončí. Následné operace se také zapojí do stejné transakce, ale neukončují se automaticky. Poslední operace v relaci automaticky dokončí transakci. Proto se stejná transakce používá pro několik volání operací ve smlouvě o poskytování služby. Pokud některá z operací vyvolá výjimku, transakce se zruší a relace je vložena zpět do fronty. Po úspěšném dokončení poslední operace se transakce potvrdí. Služba používá PerSession jako InstanceContextMode pro přijímání všech zpráv v jedné relaci na stejnou instanci služby.

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class OrderTakerService : IOrderTaker
{
    PurchaseOrder po;

    [OperationBehavior(TransactionScopeRequired = true,
                                 TransactionAutoComplete = false)]
    public void OpenPurchaseOrder(string customerId)
    {
        Console.WriteLine("Creating purchase order");
        po = new PurchaseOrder(customerId);
    }

    [OperationBehavior(TransactionScopeRequired = true,
                                  TransactionAutoComplete = false)]
    public void AddProductLineItem(string productId, int quantity)
    {
        po.AddProductLineItem(productId, quantity);
        Console.WriteLine("Product " + productId + " quantity " +
                            quantity + " added to purchase order");
    }

    [OperationBehavior(TransactionScopeRequired = true,
                                  TransactionAutoComplete = true)]
    public void EndPurchaseOrder()
    {
       Console.WriteLine("Purchase Order Completed");
       Console.WriteLine();
       Console.WriteLine(po.ToString());
    }
}

Služba je hostovaná uživatelem. Při použití přenosu MSMQ je nutné předem vytvořit použitou frontu. Můžete to provést ručně nebo prostřednictvím kódu. V této ukázce kód v System.Messaging službě kontroluje, zda fronta existuje, a v případě potřeby ji vytváří. Název fronty se načte z konfiguračního souboru pomocí třídy AppSettings.

// Host the service within this EXE console application.
public static void Main()
{
    // Get MSMQ queue name from app settings 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 OrderTakerService type.
    using (ServiceHost serviceHost = new ServiceHost(typeof(OrderTakerService)))
    {
        // 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 shutdown the service.
        serviceHost.Close();
    }
}

Název fronty MSMQ se zadává v části appSettings konfiguračního souboru. Koncový bod pro službu je definován v části system.serviceModel konfiguračního souboru a určuje netMsmqBinding vazbu.

<appSettings>
  <!-- Use appSetting to configure MSMQ queue name. -->
  <add key="queueName" value=".\private$\ServiceModelSamplesSession" />
</appSettings>

<system.serviceModel>
  <services>
    <service name="Microsoft.ServiceModel.Samples.OrderTakerService"
        behaviorConfiguration="CalculatorServiceBehavior">
      ...
      <!-- Define NetMsmqEndpoint -->
      <endpoint address="net.msmq://localhost/private/ServiceModelSamplesSession"
                binding="netMsmqBinding"
                contract="Microsoft.ServiceModel.Samples.IOrderTaker" />
      ...
    </service>
  </services>
  ...
</system.serviceModel>

Klient vytvoří obor transakce. Všechny zprávy v relaci se odesílají do fronty v rámci oboru transakce, což způsobí, že se bude považovat za atomickou jednotku, kde všechny zprávy buď uspějí, nebo selžou. Transakce je potvrzena voláním Complete.

//Create a transaction scope.
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
    // Create a client with given client endpoint configuration.
    OrderTakerClient client = new OrderTakerClient("OrderTakerEndpoint");
    // Open a purchase order.
    client.OpenPurchaseOrder("somecustomer.com");
    Console.WriteLine("Purchase Order created");

    // Add product line items.
    Console.WriteLine("Adding 10 quantities of blue widget");
    client.AddProductLineItem("Blue Widget", 10);

    Console.WriteLine("Adding 23 quantities of red widget");
    client.AddProductLineItem("Red Widget", 23);

    // Close the purchase order.
    Console.WriteLine("Closing the purchase order");
    client.EndPurchaseOrder();

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

    // Complete the transaction.
    scope.Complete();
}

Poznámka:

Před potvrzením transakce můžete použít pouze jednu transakci pro všechny zprávy v relaci a všechny zprávy v relaci musí být odeslány. Zavření klienta relaci zavře. Proto musí být klient uzavřen před dokončením transakce, aby bylo možné odeslat všechny zprávy v relaci do fronty.

Při spuštění ukázky se aktivity klienta a služeb zobrazí v oknech služby i konzoly klienta. Můžete vidět, že služba přijímá zprávy od klienta. Stisknutím klávesy ENTER v každém okně konzoly vypnete službu a klienta. Protože je fronta v provozu, klient a služba nemusí být ve stejnou dobu uvedeny do provozu. Klienta můžete spustit, vypnout ho a pak spustit službu a stále přijímat její zprávy.

Na klientovi.

Purchase Order created
Adding 10 quantities of blue widget
Adding 23 quantities of red widget
Closing the purchase order

Press <ENTER> to terminate client.

Na službě

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

Creating purchase order
Product Blue Widget quantity 10 added to purchase order
Product Red Widget quantity 23 added to purchase order
Purchase Order Completed

Purchase Order: 7c86fef0-2306-4c51-80e6-bcabcc1a6e5e
        Customer: somecustomer.com
        OrderDetails
                Order LineItem: 10 of Blue Widget @unit price: $2985
                Order LineItem: 23 of Red Widget @unit price: $156
        Total cost of this order: $33438
        Order status: Pending

Nastavení, sestavení a spuštění ukázky

  1. Ujistěte se, že jste provedli instalační proceduru One-Time pro ukázky Windows Communication Foundation.

  2. Pokud chcete sestavit edici C#, C++ nebo Visual Basic .NET řešení, postupujte podle pokynů v části Sestavení ukázek Windows Communication Foundation.

  3. Pokud chcete spustit ukázku v konfiguraci pro jeden počítač nebo pro více počítačů, postupujte podle pokynů v Spuštění ukázek Windows Communication Foundation.

Ve výchozím nastavení NetMsmqBindingje povolené zabezpečení přenosu. Existují dvě relevantní vlastnosti zabezpečení přenosu MSMQ, a to MsmqAuthenticationMode a MsmqProtectionLevel.. Ve výchozím nastavení je režim ověřování nastaven na Windows a úroveň ochrany na Sign. Aby služba MSMQ poskytovala funkci ověřování a podepisování, musí být součástí domény a musí být nainstalovaná možnost integrace služby Active Directory pro MSMQ. Pokud tuto ukázku spustíte na počítači, který nesplňuje tato kritéria, zobrazí se chyba.

Spusťte ukázku na počítači připojeném k pracovní skupině

  1. Pokud váš počítač není součástí domény nebo nemá nainstalovanou integraci služby Active Directory, vypněte zabezpečení přenosu nastavením režimu ověřování a úrovně ochrany tak, jak None je znázorněno v následující ukázkové konfiguraci.

    <system.serviceModel>
      <services>
        <service name="Microsoft.ServiceModel.Samples.OrderTakerService"
                 behaviorConfiguration="OrderTakerServiceBehavior">
          <host>
            <baseAddresses>
              <add baseAddress=
             "http://localhost:8000/ServiceModelSamples/service"/>
            </baseAddresses>
          </host>
          <!-- Define NetMsmqEndpoint -->
          <endpoint
              address=
            "net.msmq://localhost/private/ServiceModelSamplesSession"
              binding="netMsmqBinding"
              bindingConfiguration="Binding1"
           contract="Microsoft.ServiceModel.Samples.IOrderTaker" />
          <!-- 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="OrderTakerServiceBehavior">
              <serviceMetadata httpGetEnabled="True"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
    
      </system.serviceModel>
    
  2. Před spuštěním ukázky nezapomeňte změnit konfiguraci na serveru i klientovi.

    Poznámka:

    Nastavení režimu zabezpečení tak, aby None odpovídalo nastavení MsmqAuthenticationMode, MsmqProtectionLevela Message zabezpečení na None.