Delen via


Transacted MSMQ Binding

Het transacted-voorbeeld laat zien hoe u getransacteerde communicatie in de wachtrij uitvoert met behulp van Message Queuing (MSMQ).

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.

Wanneer transacties worden gebruikt voor het verzenden en ontvangen van berichten, zijn er eigenlijk twee afzonderlijke transacties. Wanneer de client berichten verzendt binnen het bereik van een transactie, is de transactie lokaal voor de client en de clientwachtrijbeheerder. Wanneer de service berichten ontvangt binnen het bereik van de transactie, is de transactie lokaal voor de service en de ontvangende wachtrijbeheerder. Het is erg belangrijk om te onthouden dat de client en de service niet deelnemen aan dezelfde transactie; In plaats daarvan gebruiken ze verschillende transacties bij het uitvoeren van hun bewerkingen (zoals verzenden en ontvangen) met de wachtrij.

In dit voorbeeld verzendt de client een batch berichten naar de service vanuit het bereik van een transactie. De berichten die naar de wachtrij worden verzonden, worden vervolgens ontvangen door de service binnen het transactiebereik dat door de service is gedefinieerd.

Het servicecontract is IOrderProcessor, zoals wordt weergegeven in de volgende voorbeeldcode. De interface definieert een eenrichtingsservice die geschikt is voor gebruik met wachtrijen.

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

Het servicegedrag definieert een bewerkingsgedrag met TransactionScopeRequired ingesteld op true. Dit zorgt ervoor dat hetzelfde transactiebereik dat wordt gebruikt om het bericht op te halen uit de wachtrij wordt gebruikt door resourcebeheerders die door de methode worden geopend. Het garandeert ook dat als de methode een uitzondering genereert, het bericht wordt geretourneerd naar de wachtrij. Zonder dit bewerkingsgedrag in te stellen, maakt een kanaal in de wachtrij een transactie om het bericht uit de wachtrij te lezen en het automatisch door te voeren voordat de bewerking wordt verzonden, zodat het bericht verloren gaat als de bewerking mislukt. Het meest voorkomende scenario is dat servicebewerkingen worden opgenomen in de transactie die wordt gebruikt om het bericht uit de wachtrij te lezen, zoals wordt weergegeven in de volgende code.

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

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 de service code om te controleren op het bestaan van de wachtrij en de wachtrij te maken als deze niet bestaat. De naam van de wachtrij wordt gelezen uit het configuratiebestand. Het basisadres wordt gebruikt door het hulpprogramma ServiceModel Metadata Utility (Svcutil.exe) om de proxy voor de service te genereren.

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

De naam van de MSMQ-wachtrij wordt opgegeven in een app Instellingen sectie van het configuratiebestand, zoals wordt weergegeven in de volgende voorbeeldconfiguratie.

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

Notitie

De wachtrijnaam gebruikt een punt (.) voor de lokale computer en backslash-scheidingstekens in het pad bij het maken van de wachtrij met behulp van System.Messaging. Het WCF-eindpunt (Windows Communication Foundation) maakt gebruik van het wachtrijadres met het net.msmq-schema, gebruikt localhost om de lokale computer aan te geven en gebruikt slashes in het pad.

De client maakt een transactiebereik. Communicatie met de wachtrij vindt plaats binnen het bereik van de transactie, waardoor deze wordt behandeld als een atomische eenheid waarin alle berichten naar de wachtrij worden verzonden of geen van de berichten naar de wachtrij worden verzonden. De transactie wordt doorgevoerd door het aanroepen van Complete het transactiebereik.

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

Als u wilt controleren of transacties werken, wijzigt u de client door commentaar te maken van het transactiebereik, zoals wordt weergegeven in de volgende voorbeeldcode, de oplossing opnieuw te bouwen en de client uit te voeren.

//scope.Complete();

Omdat de transactie niet is voltooid, worden de berichten niet naar de wachtrij verzonden.

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. Houd er rekening mee dat omdat wachtrijen in gebruik zijn, de client en service niet tegelijkertijd actief hoeven te zijn. U kunt de client uitvoeren, de client afsluiten en vervolgens de service starten en de berichten nog steeds ontvangen.

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

Het voorbeeld instellen, compileren en uitvoeren

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

  2. Als de service eerst wordt uitgevoerd, wordt gecontroleerd of de wachtrij aanwezig is. Als de wachtrij niet aanwezig is, maakt de service er een. U kunt de service eerst uitvoeren om de wachtrij te maken of u kunt er een maken via MSMQ Queue Manager. Volg deze stappen om een wachtrij te maken in Windows 2008.

    1. Open Serverbeheer in Visual Studio 2012.

    2. Vouw het tabblad Functies uit.

    3. Klik met de rechtermuisknop op Persoonlijke berichtenwachtrijen en selecteer Nieuwe, Privéwachtrij.

    4. Schakel het selectievakje Transactioneel in.

    5. Voer de ServiceModelSamplesTransacted naam in van de nieuwe wachtrij.

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

  4. Als u het voorbeeld wilt uitvoeren in een configuratie van éé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 en MsmqAuthenticationModeMsmqProtectionLevel. De verificatiemodus is standaard 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 te bieden. 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 of zonder Active Directory-integratie

  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 op zoals wordt weergegeven in de volgende voorbeeldconfiguratiecode.

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

    Notitie

    Instelling security mode is None gelijk aan MsmqAuthenticationModeinstelling , MsmqProtectionLevelen Message beveiliging op None.