服務通道層級的程式設計

本主題描述如何撰寫 Windows Communication Foundation (WCF) 服務應用程式,而不使用 System.ServiceModel.ServiceHost 及其關聯的物件模型。

接收訊息

以下為準備接收和處理訊息時所需的步驟:

  1. 建立繫結。

  2. 建置通道接聽程式。

  3. 開啟通道接聽程式。

  4. 讀取要求並傳送回覆。

  5. 關閉所有通道物件。

建立繫結。

接聽與接收訊息的第一步,就是建立繫結。 WCF 隨附幾個內建或系統提供的繫結,您可以具現化其中一個來直接使用。 此外,您也可以產生 CustomBinding 類別來建立自己的自訂繫結 (清單 1 中的程式碼也會執行相同作業)。

下列的程式碼範例會建立 System.ServiceModel.Channels.CustomBinding 的執行個體,並將 System.ServiceModel.Channels.HttpTransportBindingElement 新增至其項目集合 (用來建置通道堆疊的繫結項目集合)。 在此範例中,由於項目集合只具有 HttpTransportBindingElement,因此結果通道堆疊也只有 HTTP 傳輸通道。

建置 ChannelListener

在建立繫結後,我們可以呼叫 Binding.BuildChannelListener 來建置通道接聽程式,其中的型別參數就是要建立的通道類型。 在此範例中,我們會使用 System.ServiceModel.Channels.IReplyChannel,因為我們想要以要求/回覆訊息交換模式來接聽傳入訊息。

IReplyChannel 會被用來接收要求訊息與傳回回覆訊息。 呼叫 IReplyChannel.ReceiveRequest 會傳回 System.ServiceModel.Channels.IRequestChannel,以便用來接收要求訊息並傳回回覆訊息。

在建立接聽程式時,我們會傳送接聽程式所接聽的網路位址,在此範例為 http://localhost:8080/channelapp。 一般來說,每個傳輸通道都支援一到數個位址配置,例如,HTTP 傳輸同時支援 http 和 https 配置。

在建立接聽程式時,我們同時會傳送空的 System.ServiceModel.Channels.BindingParameterCollection。 繫結參數機制會負責將控制接聽程式建置方式的參數傳送出去。 我們的範例並未使用此類參數,因此我們會傳送空的集合。

接聽傳入訊息

接著,我們會在接聽程式上呼叫 ICommunicationObject.Open 並開始接受通道。 IChannelListener<TChannel>.AcceptChannel 的行為將視傳輸為連線導向還是沒有連線模式而定。 如果是連線導向傳輸,AcceptChannel 會在新的連線要求進入時才停止封鎖,這時它會傳回一個代表該項新連線的新通道。 如果是沒有連線的傳輸,例如 HTTP,則 AcceptChannel 會立即傳回由傳輸接聽程式所建立,且是唯一的通道。

在此範例中,接聽程式會傳回可實作 IReplyChannel 的通道。 為了在此通道上接收訊息,首先我們必須在其上呼叫 ICommunicationObject.Open,以將之轉換成準備通訊的狀態。 接著我們會呼叫 ReceiveRequest 並在訊息抵達之前進行封鎖。

讀取要求並傳送回覆

ReceiveRequest 傳回 RequestContext,我們會透過其 RequestMessage 屬性來取回接收的訊息。 我們會寫出訊息的行動與本文內容 (我們假定是字串)。

在此情況下,為了傳送回覆,我們會建立新的回覆訊息並傳回要求中所收到的字串資料。 接著,我們會呼叫 Reply 來傳送回覆訊息。

關閉物件

為避免洩漏資源,請在不再需要時,關閉通訊期間所使用的物件,這點請您務必注意。 在此範例中,我們會關閉要求訊息、要求內容、通道和接聽程式。

下列程式碼範例示範基本服務,其中的通道接聽程式只會收到一個訊息。 真實的服務會在服務結束之前持續接受通道並接收訊息。

using System;
using System.ServiceModel.Channels;
namespace ProgrammingChannels
{
class Service
{
static void RunService()
{
    //Step1: Create a custom binding with just TCP.
    BindingElement[] bindingElements = new BindingElement[2];
    bindingElements[0] = new TextMessageEncodingBindingElement();
    bindingElements[1] = new HttpTransportBindingElement();

    CustomBinding binding = new CustomBinding(bindingElements);

    //Step2: Use the binding to build the channel listener.
    IChannelListener<IReplyChannel> listener =
          binding.BuildChannelListener<IReplyChannel>(
             new Uri("http://localhost:8080/channelapp"),
           new BindingParameterCollection());

    //Step3: Listening for messages.
    listener.Open();
    Console.WriteLine(
           "Listening for incoming channel connections");
    //Wait for and accept incoming connections.
    IReplyChannel channel = listener.AcceptChannel();
    Console.WriteLine("Channel accepted. Listening for messages");
    //Open the accepted channel.
    channel.Open();
    //Wait for and receive a message from the channel.
    RequestContext request= channel.ReceiveRequest();
    //Step4: Reading the request message.
    Message message = request.RequestMessage;
    Console.WriteLine("Message received");
    Console.WriteLine("Message action: {0}",
                          message.Headers.Action);
    string data=message.GetBody<string>();
    Console.WriteLine("Message content: {0}",data);
    //Send a reply.
    Message replymessage=Message.CreateMessage(
        binding.MessageVersion,
        "http://contoso.com/someotheraction",
         data);
    request.Reply(replymessage);
    //Step5: Closing objects.
    //Do not forget to close the message.
    message.Close();
    //Do not forget to close RequestContext.
    request.Close();
    //Do not forget to close channels.
    channel.Close();
    //Do not forget to close listeners.
    listener.Close();
}
public static void Main()
{
    Service.RunService();
    Console.WriteLine("Press enter to exit");
    Console.ReadLine();
}
}
}
Imports System.ServiceModel.Channels

Namespace ProgrammingChannels
    Friend Class Service

        Private Shared Sub RunService()

            'Step1: Create a custom binding with just TCP.
            Dim bindingElements(1) As BindingElement = {New TextMessageEncodingBindingElement(), _
                                                        New HttpTransportBindingElement()}

            Dim binding As New CustomBinding(bindingElements)

            'Step2: Use the binding to build the channel listener.         
            Dim listener = binding.BuildChannelListener(Of IReplyChannel)(New Uri("http://localhost:8080/channelapp"), _
                                                                          New BindingParameterCollection())

            'Step3: Listening for messages.
            listener.Open()
            Console.WriteLine("Listening for incoming channel connections")

            'Wait for and accept incoming connections.
            Dim channel = listener.AcceptChannel()
            Console.WriteLine("Channel accepted. Listening for messages")

            'Open the accepted channel.
            channel.Open()

            'Wait for and receive a message from the channel.
            Dim request = channel.ReceiveRequest()

            'Step4: Reading the request message.
            Dim message = request.RequestMessage
            Console.WriteLine("Message received")
            Console.WriteLine("Message action: {0}", message.Headers.Action)
            Dim data = message.GetBody(Of String)()
            Console.WriteLine("Message content: {0}", data)
            'Send a reply.
            Dim replymessage = Message.CreateMessage(binding.MessageVersion, _
                                                     "http://contoso.com/someotheraction", data)
            request.Reply(replymessage)
            'Step5: Closing objects.
            'Do not forget to close the message.
            message.Close()
            'Do not forget to close RequestContext.
            request.Close()
            'Do not forget to close channels.
            channel.Close()
            'Do not forget to close listeners.
            listener.Close()
        End Sub

        Public Shared Sub Main()

            Service.RunService()
            Console.WriteLine("Press enter to exit")
            Console.ReadLine()

        End Sub

    End Class
End Namespace