Udostępnij za pośrednictwem


Programowanie na poziomie kanału usługi

W tym temacie opisano sposób pisania aplikacji usługi Windows Communication Foundation (WCF) bez używania i skojarzonego System.ServiceModel.ServiceHost z nim modelu obiektów.

Odbieranie komunikatów

Aby przygotować się do odbierania i przetwarzania komunikatów, wymagane są następujące kroki:

  1. Utwórz powiązanie.

  2. Skompiluj odbiornik kanału.

  3. Otwórz odbiornik kanału.

  4. Przeczytaj żądanie i wyślij odpowiedź.

  5. Zamknij wszystkie obiekty kanału.

Tworzenie powiązania

Pierwszym krokiem podczas nasłuchiwania i odbierania komunikatów jest utworzenie powiązania. Program WCF jest dostarczany z kilkoma wbudowanymi lub dostarczonymi przez system powiązaniami, które mogą być używane bezpośrednio przez utworzenie wystąpienia jednego z nich. Ponadto można również utworzyć własne powiązanie niestandardowe, tworząc wystąpienie klasy CustomBinding, która jest tym, co robi kod na liście 1.

Poniższy przykład kodu tworzy wystąpienie System.ServiceModel.Channels.CustomBinding elementu i dodaje element System.ServiceModel.Channels.HttpTransportBindingElement do kolekcji Elements, która jest kolekcją elementów powiązania używanych do kompilowania stosu kanału. W tym przykładzie, ponieważ kolekcja elementów ma tylko stos kanału HttpTransportBindingElement, wynikowy stos kanału ma tylko kanał transportu HTTP.

Tworzenie obiektu ChannelListener

Po utworzeniu powiązania wywołujemy Binding.BuildChannelListener metodę kompilowania odbiornika kanału, w którym parametr typu jest kształtem kanału do utworzenia. W tym przykładzie używamy System.ServiceModel.Channels.IReplyChannel funkcji , ponieważ chcemy nasłuchiwać przychodzących wiadomości we wzorcu wymiany komunikatów żądań/odpowiedzi.

IReplyChannel służy do odbierania komunikatów żądań i wysyłania zwrotnych wiadomości odpowiedzi. Wywołanie IReplyChannel.ReceiveRequest zwraca element System.ServiceModel.Channels.IRequestChannel, który może służyć do odbierania wiadomości żądania i wysyłania z powrotem wiadomości odpowiedzi.

Podczas tworzenia odbiornika przekazujemy adres sieciowy, na którym nasłuchuje, w tym przypadku http://localhost:8080/channelapp. Ogólnie rzecz biorąc, każdy kanał transportu obsługuje jeden lub prawdopodobnie kilka schematów adresów, na przykład transport HTTP obsługuje zarówno schematy http, jak i https.

Przekazujemy również wartość pustą System.ServiceModel.Channels.BindingParameterCollection podczas tworzenia odbiornika. Parametr powiązania to mechanizm przekazywania parametrów kontrolujących sposób tworzenia odbiornika. W naszym przykładzie nie używamy żadnych takich parametrów, więc przekazujemy pustą kolekcję.

Nasłuchiwanie przychodzących komunikatów

Następnie wywołujemy ICommunicationObject.Open odbiornik i rozpoczynamy akceptowanie kanałów. Zachowanie funkcji IChannelListener<TChannel>.AcceptChannel zależy od tego, czy transport jest zorientowany na połączenie, czy bez połączenia. W przypadku transportu AcceptChannel zorientowanego na połączenie bloki są blokowane do momentu wystąpienia nowego żądania połączenia, w którym zwraca nowy kanał reprezentujący to nowe połączenie. W przypadku transportu bez połączenia, takiego jak HTTP, AcceptChannel zwraca natychmiast z jednym i jedynym kanałem tworzonym przez odbiornik transportu.

W tym przykładzie odbiornik zwraca kanał, który implementuje IReplyChannelelement . Aby odbierać komunikaty w tym kanale, najpierw wywołujemy ICommunicationObject.Open je, aby umieścić je w stanie gotowym do komunikacji. Następnie wywołujemy ReceiveRequest bloki do momentu odebrania komunikatu.

Odczytywanie żądania i wysyłanie odpowiedzi

Gdy ReceiveRequest zwraca wartość RequestContext, otrzymujemy otrzymany komunikat przy użyciu jego RequestMessage właściwości. Zapisujemy akcję i zawartość treści wiadomości (zakładamy, że jest to ciąg).

Aby wysłać odpowiedź, w tym przypadku utworzymy nową wiadomość odpowiedzi, przekazując dane ciągu otrzymane w żądaniu. Następnie wywołujemy metodę Reply wysyłania wiadomości odpowiedzi.

Zamykanie obiektów

Aby uniknąć wycieku zasobów, bardzo ważne jest zamknięcie obiektów używanych w komunikacji, gdy nie są już wymagane. W tym przykładzie zamykamy komunikat żądania, kontekst żądania, kanał i odbiornik.

Poniższy przykład kodu przedstawia podstawową usługę, w której odbiornik kanału odbiera tylko jeden komunikat. Prawdziwa usługa utrzymuje akceptowanie kanałów i odbieranie komunikatów do momentu zakończenia działania usługi.

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