次の方法で共有


サービス Channel-Level プログラミング

このトピックでは、 System.ServiceModel.ServiceHost とそれに関連付けられているオブジェクト モデルを使用せずに、Windows Communication Foundation (WCF) サービス アプリケーションを記述する方法について説明します。

受信、メッセージ

メッセージを受信して処理する準備を整えるためには、次の手順が必要です。

  1. バインドを作成します。

  2. チャネル リスナーを構築します。

  3. チャネル リスナーを開きます。

  4. 要求を読み取り、応答を送信します。

  5. すべてのチャネル オブジェクトを閉じます。

バインディングの作成

メッセージをリッスンして受信する最初の手順は、バインディングを作成することです。 WCF には、いずれかのインスタンス化によって直接使用できる、いくつかの組み込みまたはシステム提供のバインディングが付属しています。 さらに、リスト 1 のコードで実行される CustomBinding クラスをインスタンス化することで、独自のカスタム バインドを作成することもできます。

次のコード例では、 System.ServiceModel.Channels.CustomBinding のインスタンスを作成し、チャネル スタックの構築に使用されるバインド要素のコレクションである Elements コレクションに System.ServiceModel.Channels.HttpTransportBindingElement を追加します。 この例では、要素コレクションには HttpTransportBindingElementしかないため、結果のチャネル スタックには HTTP トランスポート チャネルのみが含まれます。

ChannelListener のビルド

バインディングを作成した後、 Binding.BuildChannelListener を呼び出して、型パラメーターが作成するチャネル図形であるチャネル リスナーを構築します。 この例では、要求/応答メッセージ交換パターンで受信メッセージをリッスンするため、 System.ServiceModel.Channels.IReplyChannel を使用しています。

IReplyChannel は、要求メッセージの受信と応答メッセージの送信に使用されます。 IReplyChannel.ReceiveRequestを呼び出すとSystem.ServiceModel.Channels.IRequestChannelが返されます。これは、要求メッセージの受信と応答メッセージの返送に使用できます。

リスナーを作成するときに、リッスンするネットワーク アドレスを渡します。この場合は http://localhost:8080/channelapp。 一般に、各トランスポート チャネルは 1 つまたは複数のアドレススキームをサポートします。たとえば、HTTP トランスポートは http スキームと https スキームの両方をサポートします。

また、リスナーの作成時に空の System.ServiceModel.Channels.BindingParameterCollection を渡します。 バインド パラメーターは、リスナーの構築方法を制御するパラメーターを渡すメカニズムです。 この例では、このようなパラメーターを使用していないため、空のコレクションを渡します。

受信メッセージのリッスン

その後、リスナーで ICommunicationObject.Open を呼び出し、チャネルの受け入れを開始します。 IChannelListener<TChannel>.AcceptChannelの動作は、トランスポートが接続指向であるか、接続レスであるかによって異なります。 接続指向トランスポートの場合、 AcceptChannel は、新しい接続要求が入るまでブロックし、その時点でその新しい接続を表す新しいチャネルを返します。 HTTP などの接続のないトランスポートの場合、 AcceptChannel は、トランスポート リスナーが作成した 1 つだけのチャネルで直ちに返されます。

この例では、リスナーは IReplyChannelを実装するチャネルを返します。 このチャネルでメッセージを受信するには、最初に ICommunicationObject.Open を呼び出して、通信の準備ができている状態にします。 次に、メッセージが到着するまでブロックする ReceiveRequest を呼び出します。

要求の読み取りと応答の送信

ReceiveRequestRequestContextを返すと、RequestMessage プロパティを使用して受信したメッセージを取得します。 メッセージのアクションと本文の内容 (文字列を想定) を書き出します。

返信を送信するために、この場合、要求で受信した文字列データを返す新しい応答メッセージを作成します。 次に、 Reply を呼び出して応答メッセージを送信します。

オブジェクトを閉じる

リソースのリークを回避するには、不要になった通信で使用されるオブジェクトを閉じるのが非常に重要です。 この例では、要求メッセージ、要求コンテキスト、チャネル、リスナーを閉じます。

次のコード例は、チャネル リスナーが 1 つのメッセージのみを受信する基本的なサービスを示しています。 実際のサービスは、サービスが終了するまでチャネルを受け入れ、メッセージを受信し続けます。

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: {message.Headers.Action}");
    string data=message.GetBody<string>();
    Console.WriteLine($"Message content: {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