Delen via


Afhandeling van gifberichten in MSMQ 4.0

Het MSMQ4-voorbeeld laat zien hoe u de verwerking van gifberichten in een service uitvoert. Dit voorbeeld is gebaseerd op het transacted MSMQ Binding-voorbeeld . In dit voorbeeld wordt de netMsmqBinding. De service is een zelf-hostende consoletoepassing waarmee u de service die berichten in de wachtrij ontvangt, kunt observeren.

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.

Een gifbericht is een bericht dat herhaaldelijk wordt gelezen uit een wachtrij wanneer de service die het bericht leest, het bericht niet kan verwerken en daarom de transactie beëindigt waaronder het bericht wordt gelezen. In dergelijke gevallen wordt het bericht opnieuw geprobeerd. Dit kan theoretisch voor altijd doorgaan als er een probleem is met het bericht. Dit kan alleen gebeuren wanneer u transacties gebruikt om uit de wachtrij te lezen en de servicebewerking aan te roepen.

Op basis van de versie van MSMQ ondersteunt de NetMsmqBinding beperkte detectie tot volledige detectie van gifberichten. Nadat het bericht is gedetecteerd als vergiftigd, kan het op verschillende manieren worden afgehandeld. Nogmaals, op basis van de versie van MSMQ ondersteunt de NetMsmqBinding beperkte verwerking tot volledige verwerking van gifberichten.

In dit voorbeeld ziet u de beperkte giffaciliteiten op het Windows Server 2003- en Windows XP-platform en de volledige giffaciliteiten op Windows Vista. In beide steekproeven is het doel het gifbericht uit de wachtrij te verplaatsen naar een andere wachtrij. Die wachtrij kan vervolgens worden onderhouden door een gifberichtservice.

MSMQ v4.0 Gifverwerkingsmonster

In Windows Vista biedt MSMQ een gifsubquentijnfaciliteit die kan worden gebruikt om gifberichten op te slaan. In dit voorbeeld ziet u de best practice voor het omgaan met gifberichten met Behulp van Windows Vista.

De detectie van gifberichten in Windows Vista is geavanceerd. Er zijn drie eigenschappen die helpen bij detectie. Het ReceiveRetryCount is het aantal keren dat een bepaald bericht opnieuw wordt gelezen uit de wachtrij en naar de toepassing wordt verzonden voor verwerking. Een bericht wordt opnieuw gelezen uit de wachtrij wanneer het in de wachtrij wordt geplaatst, omdat het bericht niet naar de toepassing kan worden verzonden of de toepassing de transactie terugdraait in de servicebewerking. MaxRetryCycles is het aantal keren dat het bericht wordt verplaatst naar de wachtrij voor opnieuw proberen. Wanneer ReceiveRetryCount dit is bereikt, wordt het bericht verplaatst naar de wachtrij voor opnieuw proberen. De eigenschap RetryCycleDelay is de tijdsvertraging waarna het bericht wordt verplaatst van de wachtrij voor opnieuw proberen naar de hoofdwachtrij. Het ReceiveRetryCount is opnieuw ingesteld op 0. Het bericht wordt opnieuw geprobeerd. Als alle pogingen om het bericht te lezen zijn mislukt, wordt het bericht gemarkeerd als vergiftigd.

Zodra het bericht is gemarkeerd als vergiftigd, wordt het bericht afgehandeld volgens de instellingen in de ReceiveErrorHandling opsomming. Ga als volgende te werk om de mogelijke waarden te herhalen:

  • Fout (standaard): Fout bij de listener en ook de servicehost.

  • Neerzetten: het bericht verwijderen.

  • Verplaatsen: Het bericht verplaatsen naar het gifbericht. Deze waarde is alleen beschikbaar op Windows Vista.

  • Weigeren: Als u het bericht wilt weigeren, stuurt u het bericht terug naar de wachtrij met dode brieven van de afzender. Deze waarde is alleen beschikbaar op Windows Vista.

Het voorbeeld demonstreert het gebruik van de Move verwijdering voor het gifbericht. Move zorgt ervoor dat het bericht wordt verplaatst naar de gif-subquee.

Het servicecontract is IOrderProcessor, waarmee een eenrichtingsservice wordt gedefinieerd die geschikt is voor gebruik met wachtrijen.

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

De servicebewerking geeft een bericht weer waarin staat dat deze de bestelling verwerkt. Om de functionaliteit van gifberichten te demonstreren, genereert de SubmitPurchaseOrder servicebewerking een uitzondering om de transactie terug te draaien bij een willekeurige aanroep van de service. Hierdoor wordt het bericht weer in de wachtrij geplaatst. Uiteindelijk wordt het bericht gemarkeerd als gif. De configuratie is ingesteld om het gifbericht naar de gif-subquee te verplaatsen.

// Service class that implements the service contract.
// Added code to write output to the console window.
public class OrderProcessorService : IOrderProcessor
{
    static Random r = new Random(137);

    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void SubmitPurchaseOrder(PurchaseOrder po)
    {

        int randomNumber = r.Next(10);

        if (randomNumber % 2 == 0)
        {
            Orders.Add(po);
            Console.WriteLine("Processing {0} ", po);
        }
        else
        {
            Console.WriteLine("Aborting transaction, cannot process purchase order: " + po.PONumber);
            Console.WriteLine();
            throw new Exception("Cannot process purchase order: " + po.PONumber);
        }
    }

    public static void OnServiceFaulted(object sender, EventArgs e)
    {
        Console.WriteLine("Service Faulted");
    }

    // 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 (!System.Messaging.MessageQueue.Exists(queueName))
            System.Messaging.MessageQueue.Create(queueName, true);

        // Get the base address that is used to listen for WS-MetaDataExchange requests.
        // This is useful to generate a proxy for the client.
        string baseAddress = ConfigurationManager.AppSettings["baseAddress"];

        // Create a ServiceHost for the OrderProcessorService type.
        ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService), new Uri(baseAddress));

        // Hook on to the service host faulted events.
        serviceHost.Faulted += new EventHandler(OnServiceFaulted);

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

        if(serviceHost.State != CommunicationState.Faulted) {
            serviceHost.Close();
        }

    }
}

De serviceconfiguratie bevat de volgende eigenschappen van gifberichten: receiveRetryCount, maxRetryCycles, retryCycleDelayen receiveErrorHandling zoals wordt weergegeven in het volgende configuratiebestand.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <!-- Use appSetting to configure MSMQ queue name. -->
    <add key="queueName" value=".\private$\ServiceModelSamplesPoison" />
    <add key="baseAddress" value="http://localhost:8000/orderProcessor/poisonSample"/>
  </appSettings>
  <system.serviceModel>
    <services>
      <service
              name="Microsoft.ServiceModel.Samples.OrderProcessorService">
        <!-- Define NetMsmqEndpoint -->
        <endpoint address="net.msmq://localhost/private/ServiceModelSamplesPoison"
                  binding="netMsmqBinding"
                  bindingConfiguration="PoisonBinding"
                  contract="Microsoft.ServiceModel.Samples.IOrderProcessor" />
      </service>
    </services>

    <bindings>
      <netMsmqBinding>
        <binding name="PoisonBinding"
                 receiveRetryCount="0"
                 maxRetryCycles="1"
                 retryCycleDelay="00:00:05"
                 receiveErrorHandling="Move">
        </binding>
      </netMsmqBinding>
    </bindings>
  </system.serviceModel>
</configuration>

Berichten uit de wachtrij voor gifberichten verwerken

De gifberichtservice leest berichten uit de uiteindelijke gifberichtenwachtrij en verwerkt deze.

Berichten in de wachtrij voor gifberichten zijn berichten die zijn geadresseerd aan de service die het bericht verwerkt. Dit kan afwijken van het service-eindpunt voor gifberichten. Wanneer de service voor gifberichten berichten uit de wachtrij leest, vindt de WCF-kanaallaag 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 gifberichtservice. Als u het bericht wilt blijven ontvangen, zelfs als het bericht is geadresseerd aan een ander eindpunt, moeten we een ServiceBehavior adres toevoegen aan filteradressen waarbij het criterium voor overeenkomst overeenkomt met een service-eindpunt waarnaar het bericht is geadresseerd. Dit is vereist voor het verwerken van berichten die u hebt gelezen uit de wachtrij voor gifberichten.

De implementatie van de gifberichtservice zelf is vergelijkbaar met de service-implementatie. Het implementeert het contract en verwerkt de orders. Het codevoorbeeld is als volgt.

// Service class that implements the service contract.
// Added code to write output to the console window.
[ServiceBehavior(AddressFilterMode=AddressFilterMode.Any)]
public class OrderProcessorService : IOrderProcessor
{
    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
    public void SubmitPurchaseOrder(PurchaseOrder po)
    {
        Orders.Add(po);
        Console.WriteLine("Processing {0} ", po);
    }

    public static void OnServiceFaulted(object sender, EventArgs e)
    {
        Console.WriteLine("Service Faulted...exiting app");
        Environment.Exit(1);
    }

    // Host the service within this EXE console application.
    public static void Main()
    {

        // Create a ServiceHost for the OrderProcessorService type.
        ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService));

        // Hook on to the service host faulted events.
        serviceHost.Faulted += new EventHandler(OnServiceFaulted);

        serviceHost.Open();

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

        // Close the ServiceHostBase to shutdown the service.
        if(serviceHost.State != CommunicationState.Faulted)
        {
            serviceHost.Close();
        }
    }

In tegenstelling tot de orderverwerkingsservice die berichten uit de bestelwachtrij leest, leest de gifberichtservice berichten uit de gif-wachtrij. De gifwachtrij is een subquee van de hoofdwachtrij, heet 'gif' en wordt automatisch gegenereerd door MSMQ. Geef de naam van de hoofdwachtrij op, gevolgd door een ';' en de naam van de submap, in dit geval -'gif', zoals wordt weergegeven in de volgende voorbeeldconfiguratie.

Notitie

In het voorbeeld voor MSMQ v3.0 is de naam van de gifwachtrij geen subwachtrij, in plaats van de wachtrij waarnaar we het bericht hebben verplaatst.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="Microsoft.ServiceModel.Samples.OrderProcessorService">
        <!-- Define NetMsmqEndpoint -->
        <endpoint address="net.msmq://localhost/private/ServiceModelSamplesPoison;poison"
                  binding="netMsmqBinding"
                  contract="Microsoft.ServiceModel.Samples.IOrderProcessor" >
        </endpoint>
      </service>
    </services>

  </system.serviceModel>
</configuration>

Wanneer u het voorbeeld uitvoert, worden de activiteiten van de client, service en gifberichtservice weergegeven in consolevensters. U ziet dat de service berichten van de client ontvangt. Druk in elk consolevenster op Enter om de services af te sluiten.

De service begint met het uitvoeren, verwerken van orders en begint willekeurig met het beëindigen van de verwerking. Als het bericht aangeeft dat de bestelling is verwerkt, kunt u de client opnieuw uitvoeren om een ander bericht te verzenden totdat u ziet dat de service daadwerkelijk een bericht heeft beëindigd. Op basis van de geconfigureerde gifinstellingen wordt het bericht eenmaal geprobeerd voor verwerking voordat het naar de uiteindelijke gifwachtrij wordt verplaatst.

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

Processing Purchase Order: 0f063b71-93e0-42a1-aa3b-bca6c7a89546
        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

Processing Purchase Order: 5ef9a4fa-5a30-4175-b455-2fb1396095fa
        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

Aborting transaction, cannot process purchase order: 23e0b991-fbf9-4438-a0e2-20adf93a4f89

Start de gifberichtservice om het vergiftigde bericht uit de gifwachtrij te lezen. In dit voorbeeld leest de service gifberichten het bericht en verwerkt het. U kunt zien dat de inkooporder die is beëindigd en vergiftigd, wordt gelezen door de gifberichtdienst.

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

Processing Purchase Order: 23e0b991-fbf9-4438-a0e2-20adf93a4f89
        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 zodat deze overeenkomen met de werkelijke hostnaam in plaats van localhost en volgt u de instructies in Het uitvoeren van de Windows Communication Foundation-voorbeelden.

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

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 bindingConfiguration van het eindpunt in te stellen.

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

    Notitie

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

  3. Om Meta Data Exchange te laten werken, registreren we een URL met http-binding. Hiervoor moet de service worden uitgevoerd in een opdrachtvenster met verhoogde bevoegdheid. Anders krijgt u een uitzondering zoals: Unhandled Exception: System.ServiceModel.AddressAccessDeniedException: HTTP could not register URL http://+:8000/ServiceModelSamples/service/. Your process does not have access rights to this namespace (see https://go.microsoft.com/fwlink/?LinkId=70353 for details). ---> System.Net.HttpListenerException: Access is denied.