Aracılığıyla paylaş


Ulaşılamayan Mektup Kuyrukları

DeadLetter örneği, teslim edilemeyen iletilerin nasıl ele alınacağını ve işleneceğini gösterir. İşlem Yapılan MSMQ Bağlama örneğini temel alır. Bu örnek bağlamayı netMsmqBinding kullanır. Hizmet, kuyruğa alınmış iletileri alan servisi takip etmenize olanak tanıyan kendi kendine barındırılan bir konsol uygulamasıdır.

Uyarı

Bu örnek için kurulum yordamı ve derleme yönergeleri bu konunun sonunda yer alır.

Uyarı

Bu örnek, yalnızca Windows Vista'da mevcut olan her bir uygulamaya ait teslim edilemeyen ileti kuyruğunu gösterir. Örnek, Windows Server 2003 ve Windows XP'de MSMQ 3.0 için sistem genelindeki varsayılan kuyrukları kullanacak şekilde değiştirilebilir.

Kuyruğa alınan iletişimde, istemci bir kuyruk kullanarak hizmetle iletişim kurar. Daha kesin olarak, istemci bir kuyruğa ileti gönderir. Hizmet kuyruktan iletiler alır. Bu nedenle hizmet ve istemcinin kuyruk kullanarak iletişim kurmak için aynı anda çalışması gerekmez.

Kuyruğa alınan iletişim belirli bir süre bekleme durumu içerebileceğinden, iletinin süresi dolmuşsa uygulamaya teslim edilmemesi için bir yaşam süresi değeri tanımlamak isteyebilirsiniz. Bir uygulamanın, bir iletinin teslim edilemediğini bilmesi gereken durumlar da mevcuttur. İletideki yaşam süresinin dolması veya iletinin teslim edilemediği durumlar gibi tüm bu durumlarda, ileti bir ölü mektup kuyruğuna alınır. Gönderici uygulama, daha sonra ölü mektup kuyruğundaki iletileri okuyabilir ve hiçbir işlem yapılmamasından başarısız teslimatın nedenlerini düzeltmeye ve mesajı yeniden göndermeye kadar değişen düzeltici eylemler gerçekleştirebilir.

Bağlantıdaki NetMsmqBinding ölü harf kuyruğu aşağıdaki özelliklerde ifade edilir:

  • DeadLetterQueue özelliği, istemcinin gerektirdiği teslim edilemeyen ileti kuyruğu türünü ifade eder. Bu numaralandırma aşağıdaki değerlere sahiptir:

  • None: İstemci için teslim edilemeyen ileti kuyruğu gerekmez.

  • System: Sistem dead-letter kuyruğu, ölü iletileri depolamak için kullanılır. Sistem teslim edilemeyen ileti kuyruğu, bilgisayarda çalışan tüm uygulamalar tarafından paylaşılır.

  • Custom: CustomDeadLetterQueue özelliği kullanılarak belirtilen özel bir ölü harf kuyruğu, ölü iletileri depolamak için kullanılır. Bu özellik yalnızca Windows Vista'da kullanılabilir. Bu, uygulamanın aynı bilgisayarda çalışan diğer uygulamalarla paylaşmak yerine kendi teslim edilemeyen ileti kuyruğunu kullanması gerektiğinde kullanılır.

  • CustomDeadLetterQueue özelliği, ölü mektup kuyruğu olarak kullanılacak belirli bir kuyruğu ifade eder. Bu yalnızca Windows Vista'da kullanılabilir.

Bu örnekte, istemci bir işlem kapsamından hizmete bir toplu ileti gönderir ve bu iletiler için rastgele olarak düşük bir "yaşam süresi" değeri (yaklaşık 2 saniye) belirtir. İstemci ayrıca süresi dolan iletileri kuyruklamak için kullanılacak özel bir ölü harf kuyruğu belirtir.

İstemci uygulaması, teslim edilemeyen ileti kuyruğundaki iletileri okuyabilir ve iletiyi göndermeyi yeniden deneyebilir veya özgün iletinin teslim edilemeyen ileti kuyruğuna yerleştirilmesine ve iletiyi göndermesine neden olan hatayı düzeltebilir. Örnekte istemci bir hata iletisi görüntüler.

Hizmet sözleşmesi, aşağıdaki örnek kodda gösterildiği gibi şeklindedir IOrderProcessor.

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

Örnekteki hizmet kodu, İşlem Yapılan MSMQ Bağlamasının kodudur.

Hizmetle iletişim bir işlem kapsamında gerçekleşir. Hizmet kuyruktan iletileri okur, işlemi gerçekleştirir ve işlemin sonuçlarını görüntüler. Uygulama ayrıca, ölü harf mesajları için bir ölü harf kuyruğu oluşturur.

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

İstemcinin yapılandırması, iletinin hizmete ulaşması için kısa bir süre belirtir. İleti belirtilen süre içinde iletilemezse, geçerliliğini yitirir ve ölü harfler kuyruğuna taşınır.

Uyarı

İstemcinin iletiyi belirtilen süre içinde hizmet kuyruğuna teslim etmek mümkündür. Ölü harf hizmetini çalışır durumda gördüğünüzden emin olmak için, hizmeti başlatmadan önce istemciyi çalıştırmanız gerekir. İleti zaman aşımına uğrar ve ölü mektup hizmetine teslim edilir.

Uygulamanın hangi kuyruğun teslim edilemeyen ileti kuyruğu olarak kullanılacağını belirlemesi gerekir. Herhangi bir kuyruk belirtilmezse, varsayılan sistem genelindeki işlemsel ölü harf kuyruk, ölü iletileri kuyruğa almak için kullanılır. Bu örnekte, istemci uygulaması kendi hata mesajı kuyruğunu belirtir.

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

Teslim edilemeyen ileti hizmeti, teslim edilemeyen ileti kuyruğundan iletileri okur. Gönderilemeyen mesaj hizmeti, IOrderProcessor sözleşmesini uygular. Ancak uygulamanın amacı, siparişleri işlemek değildir. Teslim edilemeyen ileti hizmeti bir istemci hizmetidir ve siparişleri işleme yeteneği yoktur.

Uyarı

Teslim edilemeyen ileti kuyruğu bir istemci kuyruğudur ve istemci kuyruğu yöneticisi için yereldir.

Ölü harf mesaj hizmeti uygulaması, bir iletinin neden teslim edilemediğini kontrol eder ve düzeltici önlemler alır. İleti hatasının nedeni, DeliveryFailure ve DeliveryStatus olmak üzere iki numaralandırma ile yakalanır. Aşağıdaki örnek kodda gösterildiği gibi MsmqMessageProperty öğesini OperationContext'den alabilirsiniz.

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

Ölü mektup kuyruğundaki iletiler, mesajı işleyen hizmete gönderilmiş olan iletilerdir. Bu nedenle, ölü harf mesaj hizmeti kuyruktan iletileri okuduğunda, Windows Communication Foundation (WCF) kanal tabakası uç noktalarda uyuşmazlığı bulur ve mesajı iletmez. Bu durumda, ileti sipariş işleme hizmetine yazılır, ancak ölü harf mesaj hizmeti tarafından alınır. Farklı bir uç noktaya yönelik bir ileti almak için, içinde herhangi bir adresle eşleşecek bir adres filtresi belirtilir ServiceBehavior. Bu, teslim edilemeyen ileti kuyruğundan okunan iletilerin başarıyla işlenmesi için gereklidir.

Bu örnekte, başarısızlığın nedeni iletinin zaman aşımına uğraması ise, ölü mektup iletisi servisi iletiyi yeniden gönderir. Diğer tüm nedenlerde, teslim başarısızlığı aşağıdaki örnek kodda gösterildiği gibi görüntülenir.

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

Aşağıdaki örnek, bir teslim edilemeyen iletinin yapılandırmasını gösterir:

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

Örneği çalıştırırken, her uygulama için teslim edilemeyen ileti kuyruğunun nasıl çalıştığını görmek üzere çalıştırılması gereken 3 yürütülebilir dosya vardır; bunlar, istemci, hizmet ve her uygulama için teslim edilemeyen ileti kuyruğundan okuyan ve iletiyi hizmete yeniden gönderen teslim edilemeyen ileti hizmetidir. Tümü konsol pencerelerinde çıkışı olan konsol uygulamalarıdır.

Uyarı

Kuyruğa alma kullanımda olduğundan istemci ve hizmetin aynı anda çalışır durumda olması gerekmez. İstemciyi çalıştırabilir, kapatabilir, ardından hizmeti başlatabilir ve yine de iletilerini alabilirsiniz. Kuyruğun oluşturulabilmesi için hizmeti başlatmanız ve kapatmanız gerekir.

İstemciyi çalıştırırken istemci şu iletiyi görüntüler:

Press <ENTER> to terminate client.

İstemci iletiyi göndermeye çalıştı. Ancak kısa bir zaman aşımı nedeniyle, ileti süresi doldu ve artık her uygulama için ölü-harf kuyruğunda sıraya alındı.

Ardından, teslim edilemeyen ileti hizmetini çalıştırarak iletileri okur, hata kodunu görüntüler ve iletiyi yeniden hizmete gönderirsiniz.

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

Hizmet başlatılır, sonra yeniden alınan ileti okunur ve işlenir.

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

Örneği ayarlamak, derlemek ve çalıştırmak için

  1. Windows Communication Foundation Örnekleri içinOne-Time Kurulum Yordamını yaptığınızdan emin olun.

  2. Hizmet önce çalıştırılırsa, kuyruğun mevcut olup olmadığını kontrol eder. Kuyruk mevcut değilse, hizmet tarafından bir kuyruk oluşturulacaktır. Kuyruğu oluşturmak için önce hizmeti çalıştırabilir veya MSMQ Kuyruk Yöneticisi aracılığıyla bir kuyruk oluşturabilirsiniz. Windows 2008'de kuyruk oluşturmak için bu adımları izleyin.

    1. Visual Studio 2012'de Sunucu Yöneticisi'nin açılması.

    2. Özellikler sekmesini genişletin.

    3. Özel İleti Kuyruklarısağ tıklayın ve Yeni, Özel Kuyrukseçin.

    4. İşlem kutusunu işaretleyin.

    5. Yeni kuyruğun adı olarak ServiceModelSamplesTransacted girin.

  3. Çözümün C# veya Visual Basic .NET sürümünü oluşturmak için Windows Communication Foundation Örneklerioluşturma başlığındaki yönergeleri izleyin.

  4. Örneği tek veya bilgisayarlar arası bir yapılandırmada çalıştırmak için sıra adlarını uygun şekilde değiştirin, localhost yerine bilgisayarın tam adını yazın ve Windows Communication Foundation Örneklerini Çalıştırma başlığı altında yer alan yönergeleri izleyin.

Örneği çalışma grubuna katılmış bir bilgisayarda çalıştırmak için

  1. Bilgisayarınız bir etki alanının parçası değilse, aşağıdaki örnek yapılandırmada gösterildiği gibi kimlik doğrulama modunu ve koruma düzeyini None olarak ayarlayarak aktarım güvenliğini kapatın:

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

    Uç noktanın özniteliğini ayarlayarak uç noktanın bindingConfiguration bağlamayla ilişkilendirildiğinden emin olun.

  2. Örneği çalıştırmadan önce DeadLetterService, sunucu ve istemci üzerindeki yapılandırmayı değiştirdiğinizden emin olun.

    Uyarı

    security mode'yi None olarak ayarlamak, MsmqAuthenticationMode, MsmqProtectionLevel ve Message güvenliğini None olarak ayarlamakla eşdeğerdir.

Yorumlar

Bağlama aktarımında netMsmqBinding varsayılan olarak güvenlik etkinleştirilir. İki özellik, MsmqAuthenticationMode ve MsmqProtectionLevel, aktarım güvenliğinin türünü birlikte belirler. Varsayılan olarak kimlik doğrulama modu Windows ve koruma düzeyi Sign olarak ayarlanır. MSMQ'nun kimlik doğrulama ve imzalama özelliğini sağlaması için bir etki alanının parçası olması gerekir. Bu örneği etki alanının parçası olmayan bir bilgisayarda çalıştırırsanız şu hatayı alırsınız: "Kullanıcının iç ileti kuyruğa alma sertifikası yok".