Delen via


Wachtrijen voor dode letters

Het DeadLetter-voorbeeld laat zien hoe u berichten verwerkt en verwerkt die niet zijn bezorgd. Deze is gebaseerd op het transacted MSMQ Binding-voorbeeld . 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.

Notitie

In dit voorbeeld ziet u elke wachtrij met dode letters die alleen beschikbaar is in Windows Vista. Het voorbeeld kan worden gewijzigd voor het gebruik van de standaardsysteembrede wachtrijen voor MSMQ 3.0 op Windows Server 2003 en Windows XP.

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.

Omdat communicatie in de wachtrij een bepaalde hoeveelheid slaapstand kan omvatten, kunt u een time-to-live-waarde aan het bericht koppelen om ervoor te zorgen dat het bericht niet wordt bezorgd bij de toepassing als het voorbij de tijd is gegaan. Er zijn ook gevallen waarin een toepassing moet worden geïnformeerd of de bezorging van een bericht is mislukt. In al deze gevallen, zoals wanneer de time-to-live van het bericht is verlopen of de bezorging van het bericht is mislukt, wordt het bericht in een wachtrij met dode brieven geplaatst. De verzendende toepassing kan de berichten vervolgens lezen in de wachtrij voor dode brieven en corrigerende acties uitvoeren die variëren van geen actie tot het corrigeren van de redenen voor mislukte bezorging en het opnieuw verzenden van het bericht.

De wachtrij met dode letters in de NetMsmqBinding binding wordt uitgedrukt in de volgende eigenschappen:

  • DeadLetterQueue eigenschap voor het uitdrukken van het soort wachtrij met dode letters dat door de client is vereist. Deze opsomming heeft de volgende waarden:

  • None: Er is geen wachtrij met dode letters vereist voor de client.

  • System: De wachtrij met dead-letter van het systeem wordt gebruikt om dode berichten op te slaan. De wachtrij met dead-letter van het systeem wordt gedeeld door alle toepassingen die op de computer worden uitgevoerd.

  • Custom: Er wordt een aangepaste wachtrij met dead-letter opgegeven met behulp van de CustomDeadLetterQueue eigenschap gebruikt om dode berichten op te slaan. Deze functie is alleen beschikbaar op Windows Vista. Dit wordt gebruikt wanneer de toepassing een eigen wachtrij voor dode letters moet gebruiken in plaats van deze te delen met andere toepassingen die op dezelfde computer worden uitgevoerd.

  • CustomDeadLetterQueue eigenschap voor het uitdrukken van de specifieke wachtrij die moet worden gebruikt als een wachtrij met dode letters. Dit is alleen beschikbaar in Windows Vista.

In dit voorbeeld verzendt de client een batch berichten naar de service vanuit het bereik van een transactie en geeft een willekeurige lage waarde op voor 'time-to-live' voor deze berichten (ongeveer 2 seconden). De client geeft ook een aangepaste wachtrij voor dead-letter op die moet worden gebruikt om de berichten in de wachtrij te plaatsen die zijn verlopen.

De clienttoepassing kan de berichten in de wachtrij met dode letters lezen en het bericht opnieuw verzenden of de fout corrigeren waardoor het oorspronkelijke bericht in de wachtrij met dode letters werd geplaatst en het bericht verzenden. In het voorbeeld geeft de client een foutbericht weer.

Het servicecontract is IOrderProcessor, zoals wordt weergegeven in de volgende voorbeeldcode.

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

De servicecode in het voorbeeld is die van de Transacted MSMQ Binding.

Communicatie met de service vindt plaats binnen het bereik van een transactie. De service leest berichten uit de wachtrij, voert de bewerking uit en geeft vervolgens de resultaten van de bewerking weer. De toepassing maakt ook een wachtrij voor onbestelbare berichten voor onbestelbare berichten.

//The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.

//Client implementation code.
class Client
{
    static void Main()
    {
        // Get MSMQ queue name from app settings in configuration
        string deadLetterQueueName = ConfigurationManager.AppSettings["deadLetterQueueName"];

        // Create the transacted MSMQ queue for storing dead message if necessary.
        if (!MessageQueue.Exists(deadLetterQueueName))
            MessageQueue.Create(deadLetterQueueName, true);

        // Create a proxy with given client endpoint configuration
        OrderProcessorClient client = new OrderProcessorClient("OrderProcessorEndpoint");

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

        client.Close();

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

De configuratie van de client geeft een korte duur aan voor het bericht om de service te bereiken. Als het bericht niet kan worden verzonden binnen de opgegeven duur, verloopt het bericht en wordt het verplaatst naar de wachtrij met dode letters.

Notitie

Het is mogelijk dat de client het bericht binnen de opgegeven tijd aan de servicewachtrij levert. Om ervoor te zorgen dat u de service met een dode letter in actie ziet, moet u de client uitvoeren voordat u de service start. Er treedt een time-out op voor het bericht en wordt bezorgd bij de service met dode brieven.

De toepassing moet definiëren welke wachtrij moet worden gebruikt als wachtrij met dode letters. Als er geen wachtrij is opgegeven, wordt de standaard transactionele wachtrij voor dead-letter gebruikt om dode berichten in de wachtrij te plaatsen. In dit voorbeeld geeft de clienttoepassing een eigen wachtrij met onbestelbare letters op.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <!-- use appSetting to configure MSMQ Dead Letter queue name -->
    <add key="deadLetterQueueName" value=".\private$\ServiceModelSamplesOrdersAppDLQ"/>
  </appSettings>

  <system.serviceModel>
    <client>
      <!-- Define NetMsmqEndpoint -->
      <endpoint name="OrderProcessorEndpoint"
                address="net.msmq://localhost/private/ServiceModelSamplesDeadLetter"
                binding="netMsmqBinding"
                bindingConfiguration="PerAppDLQBinding"
                contract="IOrderProcessor" />
    </client>

    <bindings>
      <netMsmqBinding>
        <binding name="PerAppDLQBinding"
                 deadLetterQueue="Custom"
                 customDeadLetterQueue="net.msmq://localhost/private/ServiceModelSamplesOrdersAppDLQ"
                 timeToLive="00:00:02"/>
      </netMsmqBinding>
    </bindings>
  </system.serviceModel>

</configuration>

De berichtenservice voor onbestelbare berichten leest berichten uit de wachtrij voor onbestelbare berichten. De dead-letter message service implementeert het IOrderProcessor contract. De implementatie ervan is echter niet om orders te verwerken. De dead-letter message service is een clientservice en heeft niet de mogelijkheid om orders te verwerken.

Notitie

De wachtrij met dode letters is een clientwachtrij en is lokaal voor clientwachtrijbeheer.

De implementatie van de dead-letter message service controleert om de reden dat de bezorging van een bericht is mislukt en neemt corrigerende maatregelen. De reden voor een berichtfout wordt vastgelegd in twee opsommingen en DeliveryFailureDeliveryStatus. U kunt de MsmqMessageProperty code ophalen uit de OperationContext code die wordt weergegeven in de volgende voorbeeldcode:

public void SubmitPurchaseOrder(PurchaseOrder po)
{
    Console.WriteLine("Submitting purchase order did not succeed ", po);
    MsmqMessageProperty mqProp =
                  OperationContext.Current.IncomingMessageProperties[
                  MsmqMessageProperty.Name] as MsmqMessageProperty;
    Console.WriteLine("Message Delivery Status: {0} ",
                                                mqProp.DeliveryStatus);
    Console.WriteLine("Message Delivery Failure: {0}",
                                               mqProp.DeliveryFailure);
    Console.WriteLine();
    …
}

Berichten in de wachtrij voor onbestelbare berichten zijn berichten die zijn geadresseerd aan de service die het bericht verwerkt. Wanneer de berichtenservice berichten uit de wachtrij leest, vindt de WCF-kanaallaag (Windows Communication Foundation) daarom de niet-overeenkomende eindpunten en verzendt het bericht niet. In dit geval wordt het bericht geadresseerd aan de orderverwerkingsservice, maar wordt het ontvangen door de berichtenservice met een onbestelbare brief. Als u een bericht wilt ontvangen dat is geadresseerd aan een ander eindpunt, wordt een adresfilter opgegeven dat overeenkomt met een adres in de ServiceBehavior. Dit is vereist voor het verwerken van berichten die worden gelezen uit de wachtrij voor onbestelbare berichten.

In dit voorbeeld wordt het bericht opnieuw verzonden door de service voor onbestelbare berichten als er een time-out optreedt voor het bericht. Om alle andere redenen wordt de bezorgingsfout weergegeven, zoals wordt weergegeven in de volgende voorbeeldcode:

// Service class that implements the service contract.
// Added code to write output to the console window.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Single, AddressFilterMode=AddressFilterMode.Any)]
public class PurchaseOrderDLQService : IOrderProcessor
{
    OrderProcessorClient orderProcessorService;
    public PurchaseOrderDLQService()
    {
        orderProcessorService = new OrderProcessorClient("OrderProcessorEndpoint");
    }

    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void SubmitPurchaseOrder(PurchaseOrder po)
    {
        Console.WriteLine("Submitting purchase order did not succeed ", po);
        MsmqMessageProperty mqProp = OperationContext.Current.IncomingMessageProperties[MsmqMessageProperty.Name] as MsmqMessageProperty;

        Console.WriteLine("Message Delivery Status: {0} ", mqProp.DeliveryStatus);
        Console.WriteLine("Message Delivery Failure: {0}", mqProp.DeliveryFailure);
        Console.WriteLine();

        // resend the message if timed out
        if (mqProp.DeliveryFailure == DeliveryFailure.ReachQueueTimeout ||
            mqProp.DeliveryFailure == DeliveryFailure.ReceiveTimeout)
        {
            // re-send
            Console.WriteLine("Purchase order Time To Live expired");
            Console.WriteLine("Trying to resend the message");

            // reuse the same transaction used to read the message from dlq to enqueue the message to app. queue
            orderProcessorService.SubmitPurchaseOrder(po);
            Console.WriteLine("Purchase order resent");
        }
    }

    // Host the service within this EXE console application.
    public static void Main()
    {
        // Create a ServiceHost for the PurchaseOrderDLQService type.
        using (ServiceHost serviceHost = new ServiceHost(typeof(PurchaseOrderDLQService)))
        {
            // Open the ServiceHostBase to create listeners and start listening for messages.
            serviceHost.Open();

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

In het volgende voorbeeld ziet u de configuratie voor een bericht met een dode letter:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service
          name="Microsoft.ServiceModel.Samples.PurchaseOrderDLQService">
        <!-- Define NetMsmqEndpoint in this case, DLQ end point to read messages-->
        <endpoint address="net.msmq://localhost/private/ServiceModelSamplesOrdersAppDLQ"
                  binding="netMsmqBinding"
                  bindingConfiguration="DefaultBinding"
                  contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
      </service>
    </services>

    <client>
      <!-- Define NetMsmqEndpoint -->
      <endpoint name="OrderProcessorEndpoint"
                 address="net.msmq://localhost/private/ServiceModelSamplesDeadLetter"
                 binding="netMsmqBinding"
                 bindingConfiguration="SystemDLQBinding"
                 contract="IOrderProcessor" />
    </client>

    <bindings>
      <netMsmqBinding>
        <binding name="DefaultBinding" />
        <binding name="SystemDLQBinding"
                 deadLetterQueue="System"/>
      </netMsmqBinding>
    </bindings>
  </system.serviceModel>
</configuration>

Bij het uitvoeren van het voorbeeld zijn er drie uitvoerbare bestanden om te zien hoe de wachtrij met dode letters werkt voor elke toepassing; de client, service en een service met een dode letter die voor elke toepassing wordt gelezen uit de wachtrij voor dead-letter en het bericht opnieuw naar de service verzendt. Dit zijn allemaal consoletoepassingen met uitvoer in consolevensters.

Notitie

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. Start de service en sluit deze af, zodat de wachtrij kan worden gemaakt.

Wanneer de client wordt uitgevoerd, wordt het bericht weergegeven:

Press <ENTER> to terminate client.

De client heeft geprobeerd het bericht te verzenden, maar met een korte time-out is het bericht verlopen en wordt het nu in de wachtrij voor dode letters voor elke toepassing geplaatst.

Vervolgens voert u de service voor dode letters uit, waarmee het bericht wordt gelezen en de foutcode wordt weergegeven en het bericht opnieuw wordt verzonden naar de service.

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

Submitting purchase order did not succeed
Message Delivery Status: InDoubt
Message Delivery Failure: ReachQueueTimeout

Purchase order Time To Live expired
Trying to resend the message
Purchase order resent

De service wordt gestart en vervolgens het bericht opnieuw gelezen en verwerkt.

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

Processing Purchase Order: 97897eff-f926-4057-a32b-af8fb11b9bf9
        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 met één of meerdere computers, wijzigt u de wachtrijnamen op de juiste manier door localhost te vervangen door de volledige naam van de computer en volgt u de instructies in het uitvoeren van de Windows Communication Foundation-voorbeelden.

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

  1. Als uw computer geen deel uitmaakt van een domein, schakelt u transportbeveiliging uit door de verificatiemodus en het beveiligingsniveau in te stellen op None zoals wordt weergegeven in de volgende voorbeeldconfiguratie:

    <bindings>
        <netMsmqBinding>
            <binding name="TransactedBinding">
                <security mode="None"/>
            </binding>
        </netMsmqBinding>
    </bindings>
    

    Zorg ervoor dat het eindpunt is gekoppeld aan de binding door het kenmerk van bindingConfiguration het eindpunt in te stellen.

  2. Zorg ervoor dat u de configuratie wijzigt op de DeadLetterService, server en de client voordat u het voorbeeld uitvoert.

    Notitie

    Instelling security mode is None gelijk aan instelling MsmqAuthenticationModeen MsmqProtectionLevelMessage beveiliging op None.

Opmerkingen

Standaard is beveiliging ingeschakeld bij het netMsmqBinding bindingstransport. Twee eigenschappen, MsmqAuthenticationMode en MsmqProtectionLevelsamen bepalen het type transportbeveiliging. De verificatiemodus is standaard ingesteld op Windows en het beveiligingsniveau is ingesteld op Sign. MsMQ moet deel uitmaken van een domein om de verificatie- en ondertekeningsfunctie op te geven. Als u dit voorbeeld uitvoert op een computer die geen deel uitmaakt van een domein, krijgt u de volgende foutmelding: 'Het interne berichtwachtrijcertificaat van de gebruiker bestaat niet'.