Zacházení s nezpracovatelnými zprávami v MSMQ 4.0

Ukázka MSMQ4 ukazuje, jak ve službě provádět zpracování otrávené zprávy. Tato ukázka je založená na ukázce transacted MSMQ Binding . Tato ukázka používá .netMsmqBinding 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ě.

Ve frontě komunikace klient komunikuje se službou pomocí fronty. 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 proto nemusí být spuštěna ve stejnou dobu, aby komunikovaly pomocí fronty.

Jedovatá zpráva je zpráva, která se opakovaně čte z fronty, když služba čtení zprávy nemůže zpracovat zprávu, a proto ukončí transakci, pod kterou je zpráva přečtená. Vtakovýchch To může teoreticky pokračovat navždy, pokud je problém se zprávou. K tomu může dojít pouze při použití transakcí ke čtení z fronty a vyvolání operace služby.

Na základě verze MSMQ podporuje NetMsmqBinding omezenou detekci pro úplnou detekci jedových zpráv. Po zjištění otrávené zprávy je možné ji zpracovat několika způsoby. Opět, na základě verze MSMQ, NetMsmqBinding podporuje omezené zpracování na úplné zpracování jedových zpráv.

Tato ukázka ukazuje omezené zařízení jedu poskytované na platformě Windows Server 2003 a Windows XP a úplné zařízení jedu poskytované v systému Windows Vista. V obou ukázkách je cílem přesunout otrávenou zprávu z fronty do jiné fronty. Tuto frontu pak může obsluhovat služba otrávených zpráv.

Ukázka zpracování jedů MSMQ v4.0

V systému Windows Vista poskytuje MSMQ otrávený podkabíd, který lze použít k ukládání jedových zpráv. Tato ukázka ukazuje osvědčený postup při práci s otrávenými zprávami pomocí systému Windows Vista.

Detekce jedovatých zpráv v systému Windows Vista je sofistikovaná. K dispozici jsou 3 vlastnosti, které pomáhají s detekcí. Udává ReceiveRetryCount , kolikrát se daná zpráva znovu načte z fronty a odešle se do aplikace ke zpracování. Zpráva se znovu načte z fronty, když je vložena zpět do fronty, protože zprávu nelze odeslat do aplikace nebo aplikace vrátí transakce v operaci služby. MaxRetryCycles je počet, kolikrát se zpráva přesune do fronty opakování. Po ReceiveRetryCount dosažení se zpráva přesune do fronty opakování. Vlastnost RetryCycleDelay je časové zpoždění, po kterém se zpráva přesune z fronty opakování zpět do hlavní fronty. Hodnota ReceiveRetryCount je resetována na 0. Zpráva se zkusí znovu. Pokud všechny pokusy o přečtení zprávy selhaly, označí se zpráva jako otrávená.

Jakmile je zpráva označena jako otrávená, bude se zpráva zpracovávat podle nastavení v výčtu ReceiveErrorHandling . Opakování možných hodnot:

  • Chyba (výchozí): Selhání naslouchacího procesu a také hostitele služby.

  • Přetažení: Chcete-li zprávu odstranit.

  • Přesunout: Pokud chcete zprávu přesunout do podkady otrávené zprávy. Tato hodnota je k dispozici pouze v systému Windows Vista.

  • Odmítnout: Pokud chcete zprávu odmítnout, odešlete zprávu zpět do fronty nedoručených zpráv odesílatele. Tato hodnota je k dispozici pouze v systému Windows Vista.

Ukázka ukazuje použití Move dispozice pro zprávu o jedu. Move způsobí, že se zpráva přesune do podkapuly jedu.

Kontrakt služby je IOrderProcessor, který definuje jednosměrnou službu, která je vhodná pro použití s frontami.

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

Operace služby zobrazí zprávu, že zpracovává objednávku. Aby se ukázala funkce otrávené zprávy, SubmitPurchaseOrder vyvolá operace služby výjimku, která vrátí transakci při náhodném vyvolání služby. To způsobí, že se zpráva vrátí do fronty. Zpráva se nakonec označí jako jed. Konfigurace je nastavená tak, aby se zpráva o jedu přesunula do podkapuly jedu.

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

    }
}

Konfigurace služby obsahuje následující vlastnosti otrávené zprávy: receiveRetryCount, retryCycleDelaymaxRetryCycles, a receiveErrorHandling jak je znázorněno v následujícím konfiguračním souboru.

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

Zpracování zpráv z fronty otrávených zpráv

Služba otrávených zpráv čte zprávy z konečné fronty otrávených zpráv a zpracovává je.

Zprávy ve frontě jedovatých zpráv jsou zprávy adresované službě, která zprávu zpracovává, což se může lišit od koncového bodu služby otrávených zpráv. Proto když služba otrávených zpráv čte zprávy z fronty, vrstva kanálu WCF najde neshodu v koncových bodech a neodesílají zprávu. V tomto případě je zpráva adresována službě zpracování objednávek, ale přijímá se službou otrávených zpráv. Pokud chcete pokračovat v přijímání zprávy i v případě, že je zpráva adresovaná jinému koncovému bodu, musíme přidat ServiceBehavior adresu filtru, kde kritérium shody odpovídá jakémukoli koncovému bodu služby, na který je zpráva adresovaná. To je nutné k úspěšnému zpracování zpráv, které jste přečetli z fronty otrávených zpráv.

Implementace služby jedu zpráv je velmi podobná implementaci služby. Implementuje kontrakt a zpracovává objednávky. Příklad kódu je následující.

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

Na rozdíl od služby zpracování objednávek, která čte zprávy z fronty objednávek, služba jedových zpráv čte zprávy z podřadí jedu. Jedovatá fronta je podřadí hlavní fronty, jmenuje se "jed" a je automaticky generována nástrojem MSMQ. Pokud k němu chcete získat přístup, zadejte název hlavní fronty, za nímž následuje ";" a název podřadí, v tomto případě -"jed", jak je znázorněno v následující ukázkové konfiguraci.

Poznámka:

V ukázce pro MSMQ v3.0 není název jedové fronty podřadná fronta, spíše fronta, do které jsme zprávu přesunuli.

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

Při spuštění ukázky se v oknech konzoly zobrazí aktivity klienta, služby a otrávené zprávy. Můžete vidět, že služba přijímá zprávy od klienta. Služby vypnete stisknutím klávesy ENTER v každém okně konzoly.

Služba začne spouštět, zpracovávat objednávky a náhodně začne ukončovat zpracování. Pokud zpráva indikuje, že objednávku zpracovala, můžete klienta spustit znovu a odeslat další zprávu, dokud neuvidíte, že služba skutečně ukončila zprávu. Na základě nakonfigurovaného nastavení jedu se zpráva pokusí jednou zpracovat, než ji přesunete do konečné fronty jedu.

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

Spusťte službu otrávených zpráv, abyste přečetli otrávenou zprávu z fronty jedů. V tomto příkladu služba otrávené zprávy přečte zprávu a zpracuje ji. Mohli byste vidět, že nákupní objednávka, která byla ukončena a otrávená, přečte služba otrávených zpráv.

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

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

  1. Ujistěte se, že jste pro ukázky windows Communication Foundation provedli jednorázovou instalační proceduru.

  2. Pokud je služba spuštěná jako první, zkontroluje, jestli je fronta k dispozici. Pokud fronta není k dispozici, služba ji vytvoří. Službu můžete nejprve spustit, abyste vytvořili frontu, nebo ji můžete vytvořit prostřednictvím Správce front MSMQ. Podle těchto kroků vytvořte frontu v systému Windows 2008.

    1. Otevřete Správce serveru v sadě Visual Studio 2012.

    2. Rozbalte kartu Funkce.

    3. Klikněte pravým tlačítkem myši na Soukromé fronty zpráv a vyberte Nová soukromá fronta.

    4. Zaškrtněte políčko Transactional (Transakce).

    5. Zadejte ServiceModelSamplesTransacted jako název nové fronty.

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

  4. Pokud chcete spustit ukázku v konfiguraci jednoho nebo více počítačů, změňte názvy front tak, aby odrážely skutečný název hostitele místo místního hostitele, a postupujte podle pokynů v části Spuštění ukázek windows Communication Foundation.

Ve výchozím nastavení s přenosem vazby netMsmqBinding je povoleno zabezpečení. Dvě vlastnosti MsmqAuthenticationMode a MsmqProtectionLevelspolečně určují typ zabezpečení přenosu. Ve výchozím nastavení je režim ověřování nastavený Windows a úroveň ochrany je nastavena na Sign. Aby služba MSMQ poskytovala funkci ověřování a podepisování, musí být součástí domény. Pokud tuto ukázku spustíte v počítači, který není součástí domény, zobrazí se následující chyba: "Certifikát řízení front zpráv uživatele neexistuje".

Spuštění ukázky na počítači připojeném k pracovní skupině

  1. Pokud váš počítač není součástí domény, 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:

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

    Ujistěte se, že je koncový bod přidružený k vazbě nastavením atributu bindingConfiguration koncového bodu.

  2. Před spuštěním ukázky nezapomeňte změnit konfiguraci na serveru, serveru a klientovi.

    Poznámka:

    Nastavení security mode , které None odpovídá nastavení MsmqAuthenticationMode, MsmqProtectionLevela Message zabezpečení pro None.

  3. Aby mohla služba Meta Data Exchange fungovat, zaregistrujeme adresu URL s vazbou HTTP. To vyžaduje, aby služba běžela v příkazovém okně se zvýšenými oprávněními. V opačném případě se zobrazí výjimka, například: 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.