自訂 Demux

這個範例會示範 MSMQ 訊息標頭如何對應至不同的服務作業,以便讓使用 MsmqIntegrationBinding 的 Windows Communication Foundation (WCF) 服務不會受限於使用一項服務作業,如 訊息佇列至 Windows Communication FoundationWindows Communication Foundation 至訊息佇列 範例所示。

這個範例中的服務是自我裝載的主控台應用程式,可讓您觀察接收佇列訊息的服務。

服務合約為 IOrderProcessor,這會定義適合與佇列搭配使用的單向服務。

[ServiceContract]
[KnownType(typeof(PurchaseOrder))]
[KnownType(typeof(String))]
public interface IOrderProcessor
{
    [OperationContract(IsOneWay = true, Name = "SubmitPurchaseOrder")]
    void SubmitPurchaseOrder(MsmqMessage<PurchaseOrder> msg);

    [OperationContract(IsOneWay = true, Name = "CancelPurchaseOrder")]
    void CancelPurchaseOrder(MsmqMessage<string> ponumber);
}

MSMQ 訊息沒有 Action 標頭。無法將不同的 MSMQ 訊息自動對應至作業合約。因此,這時只能有一個作業合約。為了克服這項限制,服務會實作 IDispatchOperationSelector 介面的 SelectOperation 方法。SelectOperation 方法能夠讓服務將指定的訊息標頭對應至特定服務作業。在這個範例中,訊息的標籤標頭會對應至服務作業。作業合約的 Name 參數會判定必須將指定訊息標籤分派到其中的服務作業。例如,如果訊息的標籤標頭包含 "SubmitPurchaseOrder",就會叫用 "SubmitPurchaseOrder" 服務作業。

public class OperationSelector : IDispatchOperationSelector
{
    public string SelectOperation(ref System.ServiceModel.Channels.Message message)
    {
        MsmqIntegrationMessageProperty property = MsmqIntegrationMessageProperty.Get(message);
        return property.Label;
    }
}

服務必須實作 IContractBehavior 介面的 ApplyDispatchBehavior 方法,如下列範例程式碼所示。這會將自訂 OperationSelector 套用至服務架構分派執行階段。

void IContractBehavior.ApplyDispatchBehavior(ContractDescription description, ServiceEndpoint endpoint, DispatchRuntime dispatch)
{
    dispatch.OperationSelector = new OperationSelector();
}

在執行至 OperationSelector 之前,訊息必須通過發送器的 ContractFilter。根據預設,如果在服務實作之任何合約上都找不到訊息的動作,該訊息就會遭到拒絕。為了避免這項檢查,我們會實作名為 MatchAllFilterBehaviorIEndpointBehavior,此行為會藉由套用 MatchAllMessageFilter 讓任何訊息通過 ContractFilter,如下列所示。

public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher)
{
    endpointDispatcher.ContractFilter = new MatchAllMessageFilter();
}

當服務接收到訊息時,便會使用該標籤標頭提供的資訊分派適當的服務作業。訊息本文會還原序列化為 PurchaseOrder 物件,如下列範例程式碼所示。

[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SubmitPurchaseOrder(MsmqMessage<PurchaseOrder> msg)
{
    PurchaseOrder po = (PurchaseOrder)msg.Body;
    Random statusIndexer = new Random();
    po.Status = (OrderStates)statusIndexer.Next(3);
    Console.WriteLine("Processing {0} ", po);
}

服務會自我裝載。使用 MSMQ 時,必須事先建立使用的佇列。這個動作可手動或透過程式碼完成。在這個範例中,該服務包含的程式碼會檢查佇列的存在,並在佇列不存在時建立佇列。佇列名稱會從組態檔中讀取。

public static void Main()
{
    // Get MSMQ queue name from app settings in configuration
    string queueName = ConfigurationManager.AppSettings["orderQueueName"];

    // Create the transacted MSMQ queue if necessary.
    if (!MessageQueue.Exists(queueName))
        MessageQueue.Create(queueName, true);

    // Create a ServiceHost for the CalculatorService type.
    using (ServiceHost serviceHost = new ServiceHost(typeof(OrderProcessorService)))
    {               
        ServiceEndpoint endpoint = serviceHost.Description.Endpoints[0];
        endpoint.Behaviors.Add(new MatchAllFilterBehavior());

        //Open the ServiceHost 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.ReadLine();

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

MSMQ 佇列名稱是指定在組態檔的 appSettings 區段中。

ms752265.note(zh-tw,VS.90).gif注意:
佇列名稱會使用點 (.)來代表本機電腦,並在其路徑中使用反斜線分隔符號。WCF 端點位址會指定 msmq.formatname 配置,並使用 localhost 表示本機電腦。在配置後面的是根據 MSMQ 格式名稱定址方針而正確格式化的佇列位址。

<appSettings>
    <!-- Use appSetting to configure the MSMQ queue name. -->
    <add key="queueName" value=".\private$\Orders" />
</appSettings>
ms752265.note(zh-tw,VS.90).gif注意:
這個範例需要安裝訊息佇列 (本頁面可能為英文)。

啟動服務,並執行用戶端。

下列輸出會顯示在用戶端上。

Placed the order:Purchase Order: 28fc457a-1a56-4fe0-9dde-156965c21ed6
        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
Cancelled the Order: 28fc457a-1a56-4fe0-9dde-156965c21ed6
Press <ENTER> to terminate client.

下列輸出一定會出現在服務上。

The service is ready.
Press <ENTER> to terminate service.
Processing Purchase Order: 28fc457a-1a56-4fe0-9dde-156965c21ed6
        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: Shipped
Purchase Order 28fc457a-1a56-4fe0-9dde-156965c21ed6 is cancelled

若要設定、建置及執行範例

  1. 請確定您已執行 Windows Communication Foundation 範例的單次安裝程序

  2. 若要建置方案的 C# 或 Visual Basic .NET 版本,請遵循建置 Windows Communication Foundation 範例中的指示。

  3. 若要在單一或跨機器的組態中執行本範例,請遵循執行 Windows Communication Foundation 範例中的指示。

若要跨機器執行範例

  1. 將語言特定資料夾下 \service\bin\ 資料夾中的服務程式檔複製到服務機器中。

  2. 將語言特定資料夾下 \client\bin\ 資料夾中的用戶端程式檔案複製到用戶端機器中。

  3. 在 Client.exe.config 檔案中,變更 orderQueueName 以取代 "." 指定服務機器名稱。

  4. 在服務機器上,從命令提示字元啟動 Service.exe。

  5. 在用戶端機器上,從命令提示字元啟動 Client.exe。

請參閱

其他資源

Queuing in WCF
訊息佇列

Send comments about this topic to Microsoft.
© 2007 Microsoft Corporation. All rights reserved.