Delen via


Sessies en wachtrijen

In het sessievoorbeeld ziet u hoe u een set gerelateerde berichten in de wachtrij kunt verzenden en ontvangen via het MSMQ-transport (Message Queuing). In dit voorbeeld wordt de netMsmqBinding binding gebruikt. De service is een zelf-hostende consoletoepassing waarmee u de service die berichten in de wachtrij ontvangt, kunt observeren.

Notitie

De installatieprocedure en build-instructies voor dit voorbeeld bevinden zich aan het einde van dit onderwerp.

Bij communicatie in de wachtrij communiceert de client met de service via een wachtrij. De client verzendt precies berichten naar een wachtrij. De service ontvangt berichten uit de wachtrij. De service en client hoeven daarom niet tegelijkertijd te worden uitgevoerd om te communiceren met behulp van een wachtrij.

Soms verzendt een client een set berichten die aan elkaar in een groep zijn gerelateerd. Wanneer berichten samen of in een opgegeven volgorde moeten worden verwerkt, kan een wachtrij worden gebruikt om ze te groeperen voor verwerking door één ontvangende toepassing. Dit is met name belangrijk wanneer er verschillende ontvangende toepassingen zijn op een groep servers en het is noodzakelijk om ervoor te zorgen dat een groep berichten wordt verwerkt door dezelfde ontvangende toepassing. Sessies in de wachtrij zijn een mechanisme dat wordt gebruikt voor het verzenden en ontvangen van een gerelateerde set berichten die allemaal tegelijk moeten worden verwerkt. Voor sessies in de wachtrij is een transactie vereist om dit patroon weer te geven.

In het voorbeeld verzendt de client een aantal berichten naar de service als onderdeel van een sessie binnen het bereik van één transactie.

Het servicecontract is IOrderTaker, waarmee een eenrichtingsservice wordt gedefinieerd die geschikt is voor gebruik met wachtrijen. Het SessionMode gebruikte contract dat in de volgende voorbeeldcode wordt weergegeven, geeft aan dat de berichten deel uitmaken van de sessie.

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

De service definieert servicebewerkingen op een zodanige manier dat de eerste bewerking in een transactie wordt opgenomen, maar de transactie niet automatisch voltooit. Volgende bewerkingen worden ook opgenomen in dezelfde transactie, maar worden niet automatisch voltooid. De laatste bewerking in de sessie voltooit de transactie automatisch. Dezelfde transactie wordt dus gebruikt voor verschillende bewerkingsvocations in het servicecontract. Als een van de bewerkingen een uitzondering genereert, wordt de transactie teruggedraaid en wordt de sessie weer in de wachtrij geplaatst. Wanneer de laatste bewerking is voltooid, wordt de transactie doorgevoerd. De service gebruikt PerSession als de InstanceContextMode service voor het ontvangen van alle berichten in een sessie op hetzelfde exemplaar van de service.

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

De service wordt zelf gehost. Wanneer u het MSMQ-transport gebruikt, moet de gebruikte wachtrij vooraf worden gemaakt. Dit kan handmatig of via code. In dit voorbeeld bevat System.Messaging de service code om te controleren of de wachtrij bestaat en maakt deze, indien nodig. De naam van de wachtrij wordt gelezen uit het configuratiebestand met behulp van de AppSettings klasse.

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

De naam van de MSMQ-wachtrij wordt opgegeven in een app Instellingen sectie van het configuratiebestand. Het eindpunt voor de service wordt gedefinieerd in de sectie system.serviceModel van het configuratiebestand en geeft de netMsmqBinding binding op.

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

De client maakt een transactiebereik. Alle berichten in de sessie worden verzonden naar de wachtrij binnen het transactiebereik, waardoor deze worden behandeld als een atomische eenheid waarin alle berichten slagen of mislukken. De transactie wordt vastgelegd door aan te roepen 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();
}

Notitie

U kunt slechts één transactie gebruiken voor alle berichten in de sessie en alle berichten in de sessie moeten worden verzonden voordat u de transactie doorvoert. Als u de client sluit, wordt de sessie gesloten. Daarom moet de client worden gesloten voordat de transactie is voltooid om alle berichten in de sessie naar de wachtrij te verzenden.

Wanneer u het voorbeeld uitvoert, worden de client- en serviceactiviteiten weergegeven in zowel de service- als clientconsolevensters. U ziet dat de service berichten van de client ontvangt. Druk in elk consolevenster op Enter om de service en client af te sluiten. Omdat wachtrijen in gebruik zijn, hoeven de client en service niet tegelijkertijd actief te zijn. U kunt de client uitvoeren, de client afsluiten en vervolgens de service starten en de berichten nog steeds ontvangen.

Op de client.

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

Press <ENTER> to terminate client.

Op de service.

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

Het voorbeeld instellen, bouwen en uitvoeren

  1. Zorg ervoor dat u de eenmalige installatieprocedure voor de Windows Communication Foundation-voorbeelden hebt uitgevoerd.

  2. Als u de C#-, C++- of Visual Basic .NET-editie van de oplossing wilt bouwen, volgt u de instructies in het bouwen van de Windows Communication Foundation-voorbeelden.

  3. Als u het voorbeeld wilt uitvoeren in een configuratie met één of meerdere computers, volgt u de instructies in Het uitvoeren van de Windows Communication Foundation-voorbeelden.

NetMsmqBindingStandaard is transportbeveiliging ingeschakeld. Er zijn twee relevante eigenschappen voor MSMQ-transportbeveiliging, namelijk, MsmqAuthenticationMode en MsmqProtectionLevel. standaard is de verificatiemodus ingesteld op Windows en het beveiligingsniveau is ingesteld op Sign. MsMQ moet deel uitmaken van een domein en moet de active directory-integratieoptie voor MSMQ zijn geïnstalleerd om de verificatie- en ondertekeningsfunctie op te geven. Als u dit voorbeeld uitvoert op een computer die niet aan deze criteria voldoet, krijgt u een foutmelding.

Het voorbeeld uitvoeren op een computer die is gekoppeld aan een werkgroep

  1. Als uw computer geen deel uitmaakt van een domein of geen Active Directory-integratie heeft geïnstalleerd, schakelt u transportbeveiliging uit door de verificatiemodus en het beveiligingsniveau in te None stellen, zoals wordt weergegeven in de volgende voorbeeldconfiguratie.

    <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. Zorg ervoor dat u de configuratie op zowel de server als de client wijzigt voordat u het voorbeeld uitvoert.

    Notitie

    Het instellen van de beveiligingsmodus None is gelijk aan MsmqAuthenticationModeinstelling, MsmqProtectionLevelen Message beveiliging op None.