Udostępnij za pośrednictwem


Obsługa zanieczyszczonych komunikatów w usłudze MSMQ 4.0

Przykład MSMQ4 pokazuje, jak wykonać obsługę komunikatów trucizny w usłudze. Ten przykład jest oparty na przykładzie powiązania transacted MSMQ . W tym przykładzie użyto .netMsmqBinding Usługa jest aplikacją konsolową self-hosted, aby umożliwić obserwowanie usługi odbierających komunikaty w kolejce.

W komunikacji w kolejce klient komunikuje się z usługą przy użyciu kolejki. Mówiąc dokładniej, klient wysyła komunikaty do kolejki. Usługa odbiera komunikaty z kolejki. W związku z tym usługa i klient nie muszą być uruchomione w tym samym czasie, aby komunikować się przy użyciu kolejki.

Komunikat trucizny jest komunikatem, który jest wielokrotnie odczytywany z kolejki, gdy usługa odczytująca komunikat nie może przetworzyć komunikatu i w związku z tym kończy transakcję, w ramach której jest odczytywany komunikat. W takich przypadkach komunikat zostanie ponowiony ponownie. Teoretycznie może to trwać na zawsze, jeśli istnieje problem z komunikatem. Może to wystąpić tylko wtedy, gdy używasz transakcji do odczytu z kolejki i wywoływania operacji usługi.

Na podstawie wersji MSMQ narzędzie NetMsmqBinding obsługuje ograniczone wykrywanie do pełnego wykrywania komunikatów o truciznach. Po wykryciu wiadomości jako zatrutej można go obsłużyć na kilka sposobów. Ponownie, na podstawie wersji MSMQ, NetMsmqBinding obsługuje ograniczoną obsługę do pełnej obsługi zatrutych komunikatów.

Ta próbka ilustruje ograniczone urządzenia trucizny dostępne na platformie Windows Server 2003 i Windows XP oraz pełne urządzenia trucizny dostępne w systemie Windows Vista. W obu próbkach celem jest przeniesienie komunikatu trucizny z kolejki do innej kolejki. Kolejka ta może być następnie serwisowana przez usługę komunikatów trucizny.

Przykład obsługi trucizny MSMQ v4.0

W systemie Windows Vista, MSMQ zapewnia zatrutą funkcję kolejki, która może służyć do przechowywania zatrutych komunikatów. W tym przykładzie przedstawiono najlepsze rozwiązanie w zakresie radzenia sobie z komunikatami o truciznach przy użyciu systemu Windows Vista.

Wykrywanie komunikatów trucizny w systemie Windows Vista jest wyrafinowane. Istnieją 3 właściwości, które ułatwiają wykrywanie. Parametr ReceiveRetryCount jest liczbą ponownych odczytów z kolejki i wysyłanych do aplikacji w celu przetworzenia. Komunikat jest odczytywany ponownie z kolejki, gdy jest umieszczany z powrotem w kolejce, ponieważ nie można wysłać komunikatu do aplikacji lub aplikacja cofa transakcję w operacji usługi. MaxRetryCycles to liczba przesłonięć komunikat do kolejki ponawiania. Po ReceiveRetryCount osiągnięciu komunikat zostanie przeniesiony do kolejki ponawiania. Właściwość RetryCycleDelay jest opóźnieniem czasu, po którym komunikat jest przenoszony z kolejki ponawiania prób z powrotem do kolejki głównej. Wartość ReceiveRetryCount jest resetowany do 0. Komunikat zostanie ponowiony. Jeśli wszystkie próby odczytania komunikatu nie powiodły się, komunikat zostanie oznaczony jako zatruty.

Gdy komunikat zostanie oznaczony jako zatruty, komunikat jest traktowany zgodnie z ustawieniami w wyliczenia ReceiveErrorHandling . Aby powtórzyć możliwe wartości:

  • Błąd (wartość domyślna): aby uszkodzić odbiornik, a także hosta usługi.

  • Upuść: aby usunąć komunikat.

  • Przenieś: Aby przenieść komunikat do podzapytania komunikatu trucizny. Ta wartość jest dostępna tylko w systemie Windows Vista.

  • Odrzuć: aby odrzucić komunikat, wysłanie wiadomości z powrotem do kolejki utraconych wiadomości nadawcy. Ta wartość jest dostępna tylko w systemie Windows Vista.

Próbka pokazuje użycie Move dyspozycji dla komunikatu trucizny. Move powoduje przejście do podzapytania trucizny.

Kontrakt usługi to IOrderProcessor, który definiuje jednokierunkową usługę, która jest odpowiednia do użycia z kolejkami.

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

Operacja usługi wyświetla komunikat z informacją, że przetwarza zamówienie. Aby zademonstrować funkcjonalność komunikatu trucizny, SubmitPurchaseOrder operacja usługi zgłasza wyjątek umożliwiający wycofanie transakcji na losowym wywołaniu usługi. Powoduje to ponowne umieszczenie komunikatu w kolejce. W końcu wiadomość jest oznaczona jako trucizna. Konfiguracja jest ustawiona tak, aby przenieść komunikat trucizny do podzapytania trucizny.

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

    }
}

Konfiguracja usługi zawiera następujące właściwości komunikatu trucizny: receiveRetryCount, maxRetryCycles, retryCycleDelayi receiveErrorHandling , jak pokazano w poniższym pliku konfiguracji.

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

Przetwarzanie komunikatów z kolejki komunikatów trucizny

Zatruta usługa komunikatów odczytuje komunikaty z końcowej kolejki komunikatów trucizny i przetwarza je.

Komunikaty w kolejce komunikatów trucizny to komunikaty, które są adresowane do usługi, która przetwarza komunikat, co może różnić się od punktu końcowego usługi komunikatów otrucia. W związku z tym, gdy usługa komunikatów otrucia odczytuje komunikaty z kolejki, warstwa kanału WCF znajduje niezgodność w punktach końcowych i nie wysyła komunikatu. W takim przypadku komunikat jest kierowany do usługi przetwarzania zamówień, ale jest odbierany przez usługę komunikatów trucizny. Aby nadal otrzymywać komunikat, nawet jeśli komunikat jest adresowany do innego punktu końcowego, musimy dodać element do ServiceBehavior adresów filtrów, w których kryterium dopasowania jest zgodne z dowolnym punktem końcowym usługi, do którego jest skierowany komunikat. Jest to wymagane do pomyślnego przetwarzania komunikatów odczytywanych z kolejki komunikatów trucizny.

Sama implementacja usługi komunikatów o truciznze jest bardzo podobna do implementacji usługi. Implementuje kontrakt i przetwarza zamówienia. Przykładowy kod jest następujący.

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

W przeciwieństwie do usługi przetwarzania zamówień, która odczytuje komunikaty z kolejki zamówień, usługa komunikatów trucizny odczytuje komunikaty z pod kolejki trucizny. Kolejka trucizny jest pod kolejką kolejki głównej, nosi nazwę "trucizna" i jest automatycznie generowana przez MSMQ. Aby uzyskać do niego dostęp, podaj nazwę kolejki głównej, po której następuje ";" i nazwa kolejki podrzędnej, w tym przypadku -"trucizna", jak pokazano w poniższej konfiguracji przykładu.

Uwaga

W przykładzie dla msMQ w wersji 3.0 nazwa kolejki trucizny nie jest kolejką podrzędną, a nie kolejką, do którego przenieśliśmy komunikat.

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

Po uruchomieniu przykładu działania klienta, usługi i usługi komunikatów trucizny są wyświetlane w oknach konsoli. Usługa odbiera komunikaty od klienta. Naciśnij klawisz ENTER w każdym oknie konsoli, aby zamknąć usługi.

Usługa rozpoczyna działanie, przetwarzanie zamówień i losowe rozpoczyna przetwarzanie przetwarzania. Jeśli komunikat wskazuje, że przetworzył zamówienie, możesz ponownie uruchomić klienta, aby wysłać kolejny komunikat, dopóki usługa nie zakończy komunikatu. Na podstawie skonfigurowanych ustawień trucizny komunikat jest podejmowany raz na potrzeby przetwarzania przed przeniesieniem go do końcowej kolejki trucizny.

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

Uruchom usługę komunikatów trucizny, aby odczytać zatruty komunikat z kolejki trucizny. W tym przykładzie usługa komunikatów trucizny odczytuje komunikat i przetwarza go. Widać, że zamówienie zakupu, które zostało zakończone i zatrute, jest odczytywane przez usługę komunikatów trucizny.

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

Aby skonfigurować, skompilować i uruchomić przykład

  1. Upewnij się, że wykonano procedurę instalacji jednorazowej dla przykładów programu Windows Communication Foundation.

  2. Jeśli usługa jest uruchomiona jako pierwsza, sprawdzi, czy kolejka jest obecna. Jeśli kolejka nie jest obecna, usługa utworzy je. Możesz najpierw uruchomić usługę, aby utworzyć kolejkę, lub utworzyć jedną za pośrednictwem menedżera kolejki MSMQ. Wykonaj następujące kroki, aby utworzyć kolejkę w systemie Windows 2008.

    1. Otwórz Menedżer serwera w programie Visual Studio 2012.

    2. Rozwiń kartę Funkcje .

    3. Kliknij prawym przyciskiem myszy pozycję Kolejki komunikatów prywatnych, a następnie wybierz pozycję Nowa, Prywatna kolejka.

    4. Zaznacz pole Transakcyjne.

    5. Wprowadź ServiceModelSamplesTransacted jako nazwę nowej kolejki.

  3. Aby skompilować wersję rozwiązania w języku C# lub Visual Basic .NET, postępuj zgodnie z instrukcjami w temacie Building the Windows Communication Foundation Samples (Tworzenie przykładów programu Windows Communication Foundation).

  4. Aby uruchomić przykład w konfiguracji pojedynczego lub między komputerami, zmień nazwy kolejek, aby odzwierciedlić rzeczywistą nazwę hosta zamiast hosta lokalnego i postępuj zgodnie z instrukcjami w temacie Uruchamianie przykładów programu Windows Communication Foundation.

Domyślnie w przypadku netMsmqBinding transportu powiązania zabezpieczenia są włączone. Dwie właściwości MsmqAuthenticationMode i MsmqProtectionLevel, razem określają typ zabezpieczeń transportu. Domyślnie tryb uwierzytelniania jest ustawiony na Windows wartość , a poziom ochrony jest ustawiony na Signwartość . Aby usługa MSMQ zapewniała funkcję uwierzytelniania i podpisywania, musi być częścią domeny. Jeśli uruchomisz ten przykład na komputerze, który nie jest częścią domeny, zostanie wyświetlony następujący błąd: "Wewnętrzny certyfikat kolejkowania komunikatów użytkownika nie istnieje".

Aby uruchomić przykład na komputerze przyłączonym do grupy roboczej

  1. Jeśli komputer nie jest częścią domeny, wyłącz zabezpieczenia transportu, ustawiając tryb uwierzytelniania i poziom ochrony na, jak None pokazano w następującej przykładowej konfiguracji:

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

    Upewnij się, że punkt końcowy jest skojarzony z powiązaniem, ustawiając atrybut bindingConfiguration punktu końcowego.

  2. Przed uruchomieniem przykładu upewnij się, że konfiguracja zostanie zmieniona na serwerze PoisonMessageServer, serwerze i kliencie.

    Uwaga

    Ustawienie security mode wartości jest None równoważne ustawieniu MsmqAuthenticationMode, MsmqProtectionLeveli Message zabezpieczeń na Nonewartość .

  3. Aby program Meta Data Exchange działał, rejestrujemy adres URL za pomocą powiązania http. Wymaga to uruchomienia usługi w oknie polecenia z podwyższonym poziomem uprawnień. W przeciwnym razie otrzymasz wyjątek, taki jak: 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.