Sdílet prostřednictvím


Programování služby Channel-Level

Toto téma popisuje, jak napsat aplikaci služby Wcf (Windows Communication Foundation) bez použití System.ServiceModel.ServiceHost a přidruženého objektového modelu.

Příjem zpráv

K tomu, aby bylo možné přijímat a zpracovávat zprávy, jsou potřeba následující kroky:

  1. Vytvořte vazbu.

  2. Vytvořte posluchač kanálu.

  3. Otevřete naslouchající kanál.

  4. Přečtěte si žádost a odešlete odpověď.

  5. Zavřete všechny objekty kanálu.

Vytvoření vazby

Prvním krokem při naslouchání a příjmu zpráv je vytvoření vazby. WCF se dodává s několika integrovanými nebo systémovými vazbami, které lze použít přímo vytvořením instance jedné z nich. Kromě toho můžete také vytvořit vlastní vazbu vytvořením instance třídy CustomBinding, jak to dělá kód ve výpisu 1.

Následující příklad kódu vytvoří instanci System.ServiceModel.Channels.CustomBinding a přidá System.ServiceModel.Channels.HttpTransportBindingElement do své kolekce Elements, která je kolekcí vazebních prvků, jež se používají k sestavení zásobníku kanálu. V tomto příkladu, protože kolekce prvků má pouze HttpTransportBindingElement, výsledný zásobník kanálu má pouze přenosový kanál HTTP.

Vytvoření prvku ChannelListener

Po vytvoření vazby voláme Binding.BuildChannelListener, abychom vytvořili posluchač kanálu, kde je typový parametr tvarem kanálu, který se má vytvořit. V tomto příkladu používáme System.ServiceModel.Channels.IReplyChannel, protože chceme naslouchat příchozím zprávům v modelu výměny zpráv požadavků a odpovědí.

IReplyChannel slouží k příjmu zpráv žádostí a odesílání zpráv zpětné odpovědi. Volání IReplyChannel.ReceiveRequest vrátí System.ServiceModel.Channels.IRequestChannel, který lze použít k přijetí zprávy žádosti a k odeslání zprávy odpovědi.

Při vytváření nasluchače předáváme síťovou adresu, na které naslouchá, v tomto případě http://localhost:8080/channelapp. Obecně platí, že každý přenosový kanál podporuje jedno nebo možná několik schémat adres, například přenos HTTP podporuje schémata http i https.

Při vytváření nasluchače také předáme prázdnou System.ServiceModel.Channels.BindingParameterCollection. Vázací parametr je mechanismus pro předávání parametrů, které určují, jak by měl být posluchač zkonstruován. V našem příkladu nepoužíváme žádné takové parametry, takže předáváme prázdnou kolekci.

Naslouchání příchozím zprávům

Potom zavoláme ICommunicationObject.Open u posluchače a začneme přijímat kanály. Chování IChannelListener<TChannel>.AcceptChannel závisí na tom, zda je přenos orientovaný na připojení nebo bez připojení. U přenosů orientovaných na připojení AcceptChannel blokuje, dokud nepřijde nový požadavek na připojení; poté vrátí nový kanál, který představuje toto nové připojení. Pro přenosy bez připojení, jako je HTTP, AcceptChannel okamžitě vrátí pouze jeden kanál, který naslouchací proces vytvoří.

V tomto příkladu posluchač vrátí kanál, který implementuje IReplyChannel. Pro příjem zpráv na tomto kanálu nejprve voláme ICommunicationObject.Open, aby se uvedl do stavu připraveného ke komunikaci. Potom zavoláme ReceiveRequest, který blokuje, dokud zpráva nedorazí.

Čtení žádosti a odeslání odpovědi

Když ReceiveRequest vrátí RequestContext, získáme přijatou zprávu pomocí vlastnosti RequestMessage. Zapíšeme akci zprávy a obsah textu (což předpokládáme, že je řetězec).

Abychom mohli poslat odpověď, vytvoříme v tomto případě novou zprávu odpovědi, která předává zpět řetězcová data, která jsme dostali v požadavku. Poté zavoláme Reply, abychom odeslali odpověď.

Zavírání objektů

Aby nedocházelo k úniku prostředků, je velmi důležité zavřít objekty používané při komunikaci, pokud už nejsou potřeba. V tomto příkladu zavřeme zprávu požadavku, kontext požadavku, kanál a posluchač.

Následující příklad kódu ukazuje jednoduchou službu, ve které naslouchací kanál přijímá pouze jednu zprávu. Skutečná služba přijímá kanály a přijímá zprávy, dokud služba nedokončí.

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