Sdílet prostřednictvím


Programování služby na úrovni kanálů

Toto téma popisuje, jak psát aplikaci služby Wcf (Windows Communication Foundation) bez použití a jeho přidruženého System.ServiceModel.ServiceHost 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. Sestavte naslouchací proces kanálu.

  3. Otevřete naslouchací proces kanálu.

  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, která je to, co kód v výpisu 1 dělá.

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

Vytvoření prvku ChannelListener

Po vytvoření vazby voláme Binding.BuildChannelListener vytvoření naslouchacího procesu kanálu, kde je parametr typu obrazec 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 žádosti a odesílání zpětných odpovědí. Volání IReplyChannel.ReceiveRequest vrátí zprávu System.ServiceModel.Channels.IRequestChannel, která se dá použít k přijetí zprávy požadavku a k odeslání zprávy odpovědi.

Při vytváření naslouchacího procesu 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í naslouchacího procesu také předáme prázdnou System.ServiceModel.Channels.BindingParameterCollection . Parametr vazby je mechanismus pro předávání parametrů, které řídí, jak se má naslouchací proces sestavit. 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

Pak zavoláme ICommunicationObject.Open naslouchací proces a začneme přijímat kanály. Chování IChannelListener<TChannel>.AcceptChannel závisí na tom, zda je přenos orientovaný na spojení nebo méně připojení. V případě přenosů orientovaných na připojení blokuje bloky, AcceptChannel dokud se v daném okamžiku nepřijde nový požadavek na připojení, který vrátí nový kanál, který představuje toto nové připojení. Pro přenosy bez připojení, například HTTP, AcceptChannel se vrátí okamžitě s jedním a jediným kanálem, který transportní naslouchací proces vytvoří.

V tomto příkladu naslouchací proces vrátí kanál, který implementuje IReplyChannel. Pro příjem zpráv v tomto kanálu nejprve zavoláme ICommunicationObject.Open , abychom je umístili do stavu připraveného ke komunikaci. Potom zavoláme ReceiveRequest bloky, dokud zpráva nedorazí.

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

Když ReceiveRequest vrátíme RequestContextzprávu, dostaneme přijatou zprávu pomocí jeho RequestMessage vlastnosti. 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. Pak zavoláme Reply na odeslání odpovědi.

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 naslouchací proces.

Následující příklad kódu ukazuje základní službu, ve které naslouchací proces kanálu 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: {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