Dienst-KanalebenenprogrammierungService Channel-Level Programming

In diesem Thema wird beschrieben, wie eine Windows Communication Foundation (WCF)-Dienst-Anwendung ohne Schreiben der System.ServiceModel.ServiceHost und der zugehörigen Objektmodelle.This topic describes how to write a Windows Communication Foundation (WCF) service application without using the System.ServiceModel.ServiceHost and its associated object model.

Empfangen von MeldungenReceiving Messages

Um bereit zu sein, Meldungen zu empfangen und zu verarbeiten, sind die folgenden Schritte erforderlich:To be ready to receive and process messages, the following steps are required:

  1. Erstellen Sie eine Bindung.Create a binding.

  2. Erstellen Sie einen Kanallistener.Build a channel listener.

  3. Öffnen Sie den Kanallistener.Open the channel listener.

  4. Lesen Sie die Anforderung, und senden Sie eine Antwort.Read the request and send a reply.

  5. Schließen Sie alle Kanalobjekte.Close all channel objects.

Erstellen einer BindungCreating a Binding

Der erste Schritt beim Lauschen und Empfangen von Meldungen ist das Erstellen einer Bindung.The first step in listening for and receiving messages is creating a binding. Im Lieferumfang von WCF sind verschiedenen integrierter und vom System bereitgestellte Bindungen, die direkt durch Instanziierung verwendet werden können.WCF ships with several built-in or system-provided bindings that can be used directly by instantiating one of them. Außerdem können Sie eigene benutzderdefinierte Bindungen durch Instanziieren einer CustomBinding-Klasse erstellen. Diese Aufgabe übernimmt beispielsweise der Code im Programmbeispiel 1.In addition, you can also create your own custom binding by instantiating a CustomBinding class which is what the code in listing 1 does.

Das Codebeispiel unten erstellt eine Instanz von System.ServiceModel.Channels.CustomBinding und fügt ein System.ServiceModel.Channels.HttpTransportBindingElement zur Elementesammlung hinzu, die einer Sammlung von Bindungselementen entspricht, die zum Erstellen des Kanalstapels verwendet werden.The code example below creates an instance of System.ServiceModel.Channels.CustomBinding and adds an System.ServiceModel.Channels.HttpTransportBindingElement to its Elements collection which is a collection of binding elements that are used to build the channel stack. Da die Elementesammlung in diesem Beispiel nur das HttpTransportBindingElement aufweist, hat der resultierende Kanalstapel nur einen HTTP-Transportkanal.In this example, because the elements collection has only the HttpTransportBindingElement, the resulting channel stack has only the HTTP transport channel.

Erstellen eines Kanallisteners.Building a ChannelListener

Rufen Sie nach dem Erstellen einer Bindung, wir System.ServiceModel.Channels.Binding.BuildChannelListener zum Erstellen des kanallisteners, wobei der Typparameter der zu erstellenden kanalform ist.After creating a binding, we call System.ServiceModel.Channels.Binding.BuildChannelListener to build the channel listener where the type parameter is the channel shape to create. In diesem Beispiel wird System.ServiceModel.Channels.IReplyChannel verwendet, da eingehende Meldungen in einem Anforderungs-/Antwort-Meldungsaustauschmuster abgehört werden sollen.In this example we are using System.ServiceModel.Channels.IReplyChannel because we want to listen for incoming messages in a request/reply message exchange pattern.

IReplyChannel wird zum Empfangen von Anforderungsmeldungen und Senden von Antwortnachrichten verwendet.IReplyChannel is used for receiving request messages and sending back reply messages. Durch das Aufrufen von IReplyChannel.ReceiveRequest wird ein System.ServiceModel.Channels.IRequestChannel zurückgegeben, der zum Empfang der Anforderungsmeldung und zum Senden einer Antwortmeldung verwendet werden kann.Calling IReplyChannel.ReceiveRequest returns an System.ServiceModel.Channels.IRequestChannel, which can be used to receive the request message and to send back a reply message.

Beim Erstellen des Listeners wird die Netzwerkadresse übergeben, die dieser abhört, in diesem Fall http://localhost:8080/channelapp.When creating the listener, we pass the network address on which it listens, in this case http://localhost:8080/channelapp. Allgemein unterstützt jeder Transportkanal mindestens ein Adressenschema. So unterstützt beispielsweise der HTTP-Transport HTTP- und HTTPS-Schemas.In general, each transport channel supports one or possibly several address schemes, for example, the HTTP transport supports both http and https schemes.

Außerdem wird beim Erstellen des Listeners eine leere System.ServiceModel.Channels.BindingParameterCollection übergeben.We also pass an empty System.ServiceModel.Channels.BindingParameterCollection when creating the listener. Ein Bindungsparameter ist ein Mechanismus, um Parameter zu übergeben, die steuern, wie der Listener erstellt werden soll.A binding parameter is a mechanism to pass parameters that control how the listener should be built. In diesem Beispiel werden keine solchen Parameter verwendet, daher wird eine leere Auflistung übergeben.In our example, we are not using any such parameters so we pass an empty collection.

Abhören von eingehenden NachrichtenListening for Incoming Messages

Dann wird ICommunicationObject.Open auf dem Listener aufgerufen und damit begonnen, Kanäle zu akzeptieren.We then call ICommunicationObject.Open on the listener and start accepting channels. Das Verhalten von IChannelListener<TChannel>.AcceptChannel hängt davon ab, ob der Transport verbindungsorientiert oder verbindungslos ist.The behavior of IChannelListener<TChannel>.AcceptChannel depends on whether the transport is connection-oriented or connection-less. Bei einem verbindungsorientierten Transport blockiert AcceptChannel, bis eine neue Verbindungsanforderung eingeht. Dann wird ein neuer Kanal zurückgegeben, der diese neue Verbindung darstellt.For connection-oriented transports, AcceptChannel blocks until a new connection request comes in at which point it returns a new channel that represents that new connection. Bei einem verbindungslosen Transport, wie z. B. HTTP, gibt AcceptChannel unverzüglich den einzigen Kanal zurück, den der Transportlistener erstellt.For connection-less transports, such as HTTP, AcceptChannel returns immediately with the one and only channel that the transport listener creates.

In diesem Beispiel gibt der Listener einen Kanal zurück, der IReplyChannel implementiert.In this example, the listener returns a channel that implements IReplyChannel. Um Meldungen auf diesem Kanal zu empfangen, wird zuerst ICommunicationObject.Open aufgerufen, um ihn in einen kommunikationsbereiten Status zu versetzen.To receive messages on this channel we first call ICommunicationObject.Open on it to place it in a state ready for communication. Dann wird ReceiveRequest aufgerufen, der blockiert, bis eine Nachricht eingeht.We then call ReceiveRequest which blocks until a message arrives.

Lesen der Anforderung und Senden einer AntwortReading the Request and Sending a Reply

Wenn ReceiveRequest einen RequestContext zurückgibt, geht die empfangene Meldung mithilfe der RequestMessage-Eigenschaft ein.When ReceiveRequest returns a RequestContext, we get the received message using its RequestMessage property. Die Aktion und der Textinhalt der Meldung (es wird angenommen, dass es sich um eine Zeichenfolge handelt) wird geschrieben.We write out the message’s action and body content, (which we assume is a string).

Zum Senden einer Antwort wird eine neue Antwortmeldung erstellt, in diesem Fall durch Zurücksenden der Zeichenfolgendaten, die in der Anforderung eingegangen sind.To send a reply, we create a new reply message in this case passing back the string data we received in the request. Dann wird Reply aufgerufen, um die Antwortmeldung zu senden.We then call Reply to send the reply message.

Schließen von ObjektenClosing Objects

Um Ressourcenverluste zu vermeiden, sollten Sie in Kommunikationsvorgängen verwendete Objekte schließen, wenn sie nicht mehr benötigt werden.To avoid leaking resources, it is very important to close objects used in communications when they are no longer required. In diesem Beispiel werden die Anforderungsmeldung, der Anforderungskontext, der Kanal und der Listener geschlossen.In this example we close the request message, the request context, the channel and the listener.

Im folgenden Codebeispiel wird ein grundlegender Dienst, in dem ein Kanallistener nur eine Nachricht empfängt, veranschaulicht.The following code example shows a basic service in which a channel listener receives only one message. Ein wirklicher Dienst akzeptiert Kanäle und empfängt Meldungen, bis der Dienst beendet wird.A real service keeps accepting channels and receiving messages until the service exits.

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