Aracılığıyla paylaş


İleti Aktarımı Hatalarını İşlemek için Teslim Edilemeyen İletiler Sırası Kullanma

Kuyruğa alınan iletiler teslimi başarısız olabilir. Bu başarısız iletiler bir teslim edilemeyen ileti kuyruğuna kaydedilir. Başarısız teslim, ağ hataları, silinen kuyruk, tam kuyruk, kimlik doğrulama hatası veya zamanında teslim edilememesi gibi nedenlerden kaynaklanabilir.

Alıcı uygulama bunları zamanında kuyruktan okumazsa, kuyruğa alınan iletiler uzun süre kuyrukta kalabilir. Bu davranış zamana duyarlı iletiler için uygun olmayabilir. Zamana duyarlı iletilerin kuyruğa alınan bağlamada ayarlanmış bir Yaşam Süresi (TTL) özelliği vardır. Bu özellik, iletilerin süresi dolmadan önce kuyrukta ne kadar süre bulunabileceğini gösterir. Süresi dolan iletiler, teslim edilemeyen ileti kuyruğu olarak adlandırılan özel bir kuyruğa gönderilir. İletiler, kuyruk kotasını aşma veya kimlik doğrulama hatası gibi başka nedenlerle de teslim edilemeyen bir kuyruğa yerleştirilebilir.

Genellikle uygulamalar, teslim edilemeyen ileti kuyruğundan gelen iletileri ve hata nedenlerini okumak için dengeleme mantığı yazar. Telafi mantığı, hatanın nedenlerine bağlıdır. Örneğin, kimlik doğrulama hatası durumunda, iletiyle birlikte eklenen sertifikayı düzeltebilir ve iletiyi yeniden gönderebilirsiniz. Hedef kuyruk kotaya ulaşıldığı için teslim başarısız olduysa, kota sorununun çözülmüş olması umuduyla teslimi yeniden gerçekleştirebilirsiniz.

Kuyruğa alma sistemlerinin çoğu, bu sistemden gelen tüm başarısız iletilerin depolandığı sistem genelinde bir teslim edilemeyen ileti kuyruğuna sahiptir. Message Queuing (MSMQ) iki sistem genelinde teslim edilemeyen ileti kuyruğu sağlar: işlem kuyruğuna teslim edilemeyen iletileri depolayan işlem sistemi genelindeki bir teslim edilemeyen ileti kuyruğu ve işlem dışı kuyruğa teslim edilemeyen iletileri depolayan işlemsel olmayan sistem genelinde bir teslim edilemeyen ileti kuyruğu. İki istemci iki farklı hizmete ileti gönderiyorsa ve bu nedenle WCF'deki farklı kuyruklar göndermek için aynı MSMQ hizmetini paylaşıyorsa, sistem teslim edilemeyen ileti kuyruğunda bir ileti karışımına sahip olmak mümkündür. Bu her zaman en uygun değildir. Bazı durumlarda (örneğin güvenlik), bir istemcinin bir teslim edilemeyen ileti kuyruğundan başka bir istemcinin iletilerini okumasını istemeyebilirsiniz. Paylaşılan bir teslim edilemeyen ileti kuyruğu, istemcilerin gönderdiği bir iletiyi bulmak için kuyruğa göz atmalarını da gerektirir. Bu, teslim edilemeyen ileti kuyruğundaki ileti sayısına bağlı olarak çok pahalı olabilir. Bu nedenle, WCF'deNetMsmqBindingMsmqIntegrationBinding, ve Windows Vista'daki MSMQ'da özel bir teslim edilemeyen ileti kuyruğu (bazen uygulamaya özgü bir teslim edilemeyen ileti kuyruğu olarak da adlandırılır) sağlanır.

Özel teslim edilemeyen ileti kuyruğu, iletileri göndermek için aynı MSMQ hizmetini paylaşan istemciler arasında yalıtım sağlar.

Windows Server 2003 ve Windows XP'de, Windows Communication Foundation (WCF), kuyruğa alınan tüm istemci uygulamaları için sistem genelinde bir teslim edilemeyen ileti kuyruğu sağlar. Windows Vista'da WCF, kuyruğa alınan her istemci uygulaması için bir teslim edilemeyen ileti kuyruğu sağlar.

Teslim Edilemeyen İleti Kuyruğunun Kullanımını Belirtme

Teslim edilemeyen bir kuyruk, gönderen uygulamanın kuyruk yöneticisindedir. Süresi dolmuş veya aktarım veya teslim başarısız olan iletileri depolar.

Bağlama aşağıdaki teslim edilemeyen kuyruk özelliklerine sahiptir:

Teslim Edilemeyen İleti Kuyruğundan İletileri Okuma

Bir teslim edilemeyen ileti kuyruğundaki iletileri okuyan bir uygulama, aşağıdaki küçük farklılıklar dışında uygulama kuyruğundan okuyan bir WCF hizmetine benzer:

  • Sistem işlemsel teslim edilemeyen ileti kuyruğundan gelen iletileri okumak için, Tekdüzen Kaynak Tanımlayıcısı (URI) şu biçimde olmalıdır: net.msmq://localhost/system$; DeadXact.

  • Sistem işlem dışı teslim edilemeyen ileti kuyruğundan gelen iletileri okumak için URI şu biçimde olmalıdır: net.msmq://localhost/system$; DeadLetter.

  • Özel bir teslim edilemeyen ileti kuyruğundan gelen iletileri okumak için URI'nin formda olması gerekir:net.msmq://localhost/private/<custom-dlq-name> burada custom-dlq-name özel teslim edilemeyen ileti kuyruğunun adıdır.

Kuyrukları ele alma hakkında daha fazla bilgi için bkz . Hizmet Uç Noktaları ve Kuyruk Adresleme.

Alıcıdaki WCF yığını, hizmetin dinlediği adreslerle iletideki adresle eşleşir. Adresler eşleşiyorsa, ileti gönderilir; değilse, ileti gönderilmez. Bu durum, teslim edilemeyen ileti kuyruğundaki iletiler genellikle teslim edilemeyen ileti kuyruğu hizmetine değil hizmete giderildiğinden, teslim edilemeyen ileti kuyruğundan okurken sorunlara neden olabilir. Bu nedenle, teslim edilemeyen ileti kuyruğundan okuma hizmetinin, yığına kuyruktaki tüm iletileri adresten bağımsız olarak eşleştirmesini belirten bir adres filtresi ServiceBehavior yüklemesi gerekir. Özellikle, teslim edilemeyen ileti kuyruğundan iletileri okuyan hizmete parametresiyle bir Any eklemeniz ServiceBehavior gerekir.

Teslim Edilemeyen İleti Kuyruğundan Zehirli İleti İşleme

Zehirli ileti işleme, bazı koşullarla birlikte teslim edilemeyen ileti kuyruklarında kullanılabilir. Sistem kuyruklarından alt kuyruklar oluşturamadığınızdan, sistem teslim edilemeyen ileti kuyruğundan okurken , ReceiveErrorHandling olarak Moveayarlanamaz. Özel bir teslim edilemeyen ileti kuyruğundan okuyorsanız alt kuyruklarınız olabileceğini ve bu nedenle Move zehirli ileti için geçerli bir değerlendirme olduğunu unutmayın.

ReceiveErrorHandling özel teslim edilemeyen ileti kuyruğundan okurken olarak ayarlandığındaReject, zehirli ileti sistem teslim edilemeyen ileti kuyruğuna konur. Sistem teslim edilemeyen ileti kuyruğundan okuma yapılırsa, ileti bırakılır (temizlenir). MSMQ'daki sistem teslim edilemeyen ileti kuyruğundan yapılan bir reddetme, iletiyi bırakır (temizler).

Örnek

Aşağıdaki örnekte, bir teslim edilemeyen ileti kuyruğunun nasıl oluşturulacağı ve süresi dolan iletileri işlemek için nasıl kullanılacağı gösterilmektedir. Örnek, Nasıl yapılır: WCF Uç Noktalarıyla Kuyruğa Alınan İletileri Değiştirme başlığı altındaki örneği temel alır. Aşağıdaki örnekte, her uygulama için bir teslim edilemeyen ileti kuyruğu kullanan sipariş işleme hizmetine istemci kodunun nasıl yazılması gösterilmektedir. Örnekte, teslim edilemeyen ileti kuyruğundan iletilerin nasıl işlendiği de gösterilmektedir.

Aşağıda, her uygulama için bir teslim edilemeyen ileti kuyruğu belirten bir istemcinin kodu yer alır.

using System;
using System.ServiceModel.Channels;
using System.Configuration;
//using System.Messaging;
using System.ServiceModel;
using System.Transactions;

namespace Microsoft.ServiceModel.Samples
{
    
    //The service contract is defined in generatedProxy.cs, generated from the service by the svcutil tool.

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

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

            OrderProcessorClient client = new OrderProcessorClient("OrderProcessorEndpoint");
        try
            {	

                // 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();
            }
            catch(TimeoutException timeout)
            {
        Console.WriteLine(timeout.Message);
                client.Abort();
        }
            catch(CommunicationException conexcp)
            {
        Console.WriteLine(conexcp.Message);
                client.Abort();
        }

            Console.WriteLine();
            Console.WriteLine("Press <ENTER> to terminate client.");
            Console.ReadLine();
        }
    }
}
Imports System.ServiceModel.Channels
Imports System.Configuration
'using System.Messaging;
Imports System.ServiceModel
Imports System.Transactions

Namespace Microsoft.ServiceModel.Samples

    'The service contract is defined in generatedProxy.cs, generated from the service by the svcutil tool.

    'Client implementation code.
    Friend Class Client
        Shared Sub Main()
            ' Get MSMQ queue name from appsettings in configuration.
            Dim deadLetterQueueName As String = ConfigurationManager.AppSettings("deadLetterQueueName")

            ' Create the transacted MSMQ queue for storing dead message if necessary.
            If (Not System.Messaging.MessageQueue.Exists(deadLetterQueueName)) Then
                System.Messaging.MessageQueue.Create(deadLetterQueueName, True)
            End If


            Dim client As New OrderProcessorClient("OrderProcessorEndpoint")
            Try


                ' Create the purchase order.
                Dim po As New PurchaseOrder()
                po.CustomerId = "somecustomer.com"
                po.PONumber = Guid.NewGuid().ToString()

                Dim lineItem1 As New PurchaseOrderLineItem()
                lineItem1.ProductId = "Blue Widget"
                lineItem1.Quantity = 54
                lineItem1.UnitCost = 29.99F

                Dim lineItem2 As New PurchaseOrderLineItem()
                lineItem2.ProductId = "Red Widget"
                lineItem2.Quantity = 890
                lineItem2.UnitCost = 45.89F

                po.orderLineItems = New PurchaseOrderLineItem(1) {}
                po.orderLineItems(0) = lineItem1
                po.orderLineItems(1) = lineItem2

                'Create a transaction scope.
                Using scope As New TransactionScope(TransactionScopeOption.Required)
                    ' Make a queued call to submit the purchase order.
                    client.SubmitPurchaseOrder(po)
                    ' Complete the transaction.
                    scope.Complete()
                End Using


                client.Close()
            Catch timeout As TimeoutException
                Console.WriteLine(timeout.Message)
                client.Abort()
            Catch conexcp As CommunicationException
                Console.WriteLine(conexcp.Message)
                client.Abort()
            End Try

            Console.WriteLine()
            Console.WriteLine("Press <ENTER> to terminate client.")
            Console.ReadLine()
        End Sub
    End Class
End Namespace

İstemci yapılandırma dosyasının kodu aşağıdadır.

Aşağıda, teslim edilemeyen bir kuyruktan gelen iletileri işleyen bir hizmet kodu yer alır.

using System;
using System.ServiceModel.Description;
using System.Configuration;
using System.Messaging;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Transactions;

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

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

        [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 the application 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();

                // Close the ServiceHostBase to shutdown the service.
                serviceHost.Close();
            }
        }
    }
}

Imports System.ServiceModel.Description
Imports System.Configuration
Imports System.Messaging
Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports System.Transactions

Namespace Microsoft.ServiceModel.Samples
    ' Define a service contract. 
    <ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples")> _
    Public Interface IOrderProcessor
        <OperationContract(IsOneWay:=True)> _
        Sub SubmitPurchaseOrder(ByVal po As PurchaseOrder)
    End Interface

    ' 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
        Implements IOrderProcessor
        Private orderProcessorService As OrderProcessorClient
        Public Sub New()
            orderProcessorService = New OrderProcessorClient("OrderProcessorEndpoint")
        End Sub

        <OperationBehavior(TransactionScopeRequired:=True, TransactionAutoComplete:=True)> _
        Public Sub SimpleSubmitPurchaseOrder(ByVal po As PurchaseOrder)
            Console.WriteLine("Submitting purchase order did not succeed ", po)
            Dim mqProp As MsmqMessageProperty = TryCast(OperationContext.Current.IncomingMessageProperties(MsmqMessageProperty.Name), MsmqMessageProperty)

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

        <OperationBehavior(TransactionScopeRequired:=True, TransactionAutoComplete:=True)> _
        Public Sub SubmitPurchaseOrder(ByVal po As PurchaseOrder) Implements IOrderProcessor.SubmitPurchaseOrder
            Console.WriteLine("Submitting purchase order did not succeed ", po)
            Dim mqProp As MsmqMessageProperty = TryCast(OperationContext.Current.IncomingMessageProperties(MsmqMessageProperty.Name), 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 OrElse mqProp.DeliveryFailure = DeliveryFailure.ReceiveTimeout Then
                ' 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 the application queue.
                orderProcessorService.SubmitPurchaseOrder(po)
                Console.WriteLine("Purchase order resent")
            End If
        End Sub

        ' Host the service within this EXE console application.
        Public Shared Sub Main()
            ' Create a ServiceHost for the PurchaseOrderDLQService type.
            Using serviceHost As New ServiceHost(GetType(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()

                ' Close the ServiceHostBase to shutdown the service.
                serviceHost.Close()
            End Using
        End Sub
    End Class
End Namespace

Aşağıdakiler, teslim edilemeyen ileti kuyruğu hizmeti yapılandırma dosyasının kodudur.

Ayrıca bkz.