Dela via


Transport: WSE 3.0 TCP-samverkan

Exemplet WSE 3.0 TCP Interoperability Transport visar hur du implementerar en TCP-duplex-session som en anpassad WCF-transport (Windows Communication Foundation). Det visar också hur du kan använda utökningsbarheten för kanallagret för att gränssnitt över kabeln med befintliga distribuerade system. Följande steg visar hur du skapar den här anpassade WCF-transporten:

  1. Börja med en TCP-socket och skapa klient- och serverimplementeringar av IDuplexSessionChannel som använder DIME-inramning för att avgränsa meddelandegränser.

  2. Skapa en kanalfabrik som ansluter till en WSE TCP-tjänst och skickar inramade meddelanden via klientens IDuplexSessionChannel.

  3. Skapa en kanallyssnare för att acceptera inkommande TCP-anslutningar och skapa motsvarande kanaler.

  4. Se till att alla nätverksspecifika undantag normaliseras till lämplig härledd klass för CommunicationException.

  5. Lägg till ett bindningselement som lägger till den anpassade transporten i en kanalstacken. Mer information finns i [Lägga till ett bindningselement].

Skapa IDuplexSessionChannel

Det första steget i att skriva WSE 3.0 TCP Interoperability Transport är att skapa en implementering av IDuplexSessionChannel ovanpå en Socket. WseTcpDuplexSessionChannel härleds från ChannelBase. Logiken för att skicka ett meddelande består av två huvuddelar: (1) Koda meddelandet i byte och (2) rama in dessa byte och skicka dem på tråden.

ArraySegment<byte> encodedBytes = EncodeMessage(message);

WriteData(encodedBytes);

Dessutom tas ett lås så att Send()-anropen bevarar IDuplexSessionChannel-in-order-garantin och så att anrop till den underliggande socketen synkroniseras korrekt.

WseTcpDuplexSessionChannel använder en MessageEncoder för att översätta till Message och från byte[]. Eftersom det är en transport ansvarar WseTcpDuplexSessionChannel även för att tillämpa fjärradressen som kanalen har konfigurerats med. EncodeMessage kapslar in logiken för den här konverteringen.

this.RemoteAddress.ApplyTo(message);

return encoder.WriteMessage(message, maxBufferSize, bufferManager);

När koden Message är kodad i byte måste den överföras på kabeln. Detta kräver ett system för att definiera meddelandegränser. WSE 3.0 använder en version av DIME som sitt inramningsprotokoll. WriteData kapslar in inramningslogik för att omsluta en byte[] till en uppsättning DIME-poster.

Logiken för att ta emot meddelanden är liknande. Den största komplexiteten är att hantera det faktum att en socketläsning kan returnera färre byte än vad som begärdes. Om du vill ta emot ett meddelande WseTcpDuplexSessionChannel läser du byte från tråden, avkodar DIME-inramningen och använder MessageEncoder sedan för att omvandla bytet[] till en Message.

WseTcpDuplexSessionChannel Basen förutsätter att den tar emot en ansluten socket. Basklassen hanterar socketavstängning. Det finns tre platser som gränssnitt med socket stängning:

  • OnAbort – stäng socketen ospårigt (hårt nära).

  • På[Begin]Close -- stäng socketen graciöst (mjuk stängning).

  • Session. CloseOutputSession – stäng av den utgående dataströmmen (halvstängt).

Kanalfabrik

Nästa steg i att skriva TCP-transporten är att skapa en implementering av IChannelFactory för klientkanaler.

  • WseTcpChannelFactory härleds från ChannelFactoryBase<IDuplexSessionChannel>. Det är en fabrik som åsidosätter OnCreateChannel för att skapa klientkanaler.

protected override IDuplexSessionChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via)

{

return new ClientWseTcpDuplexSessionChannel(encoderFactory, bufferManager, remoteAddress, via, this);

}

  • ClientWseTcpDuplexSessionChannel lägger till logik i basen WseTcpDuplexSessionChannel för att ansluta till en TCP-server vid channel.Open tidpunkten. Först matchas värdnamnet till en IP-adress, enligt följande kod.

hostEntry = Dns.GetHostEntry(Via.Host);

  • Sedan är värdnamnet anslutet till den första tillgängliga IP-adressen i en loop, enligt följande kod.

IPAddress address = hostEntry.AddressList[i];

socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

socket.Connect(new IPEndPoint(address, port));

  • Som en del av kanalkontraktet omsluts alla domänspecifika undantag, till exempel SocketException i CommunicationException.

Kanallyssnare

Nästa steg i att skriva TCP-transporten är att skapa en implementering av IChannelListener för att acceptera serverkanaler.

  • WseTcpChannelListener härleds från ChannelListenerBase<IDuplexSessionChannel> och åsidosätter On[Begin]Open and On[Begin]Close för att kontrollera livslängden för dess lyssningssocket. I OnOpen skapas en socket för att lyssna på IP_ANY. Mer avancerade implementeringar kan också skapa en andra socket för att lyssna på IPv6. De kan också tillåta att IP-adressen anges i värdnamnet.

IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Any, uri.Port);

this.listenSocket = new Socket(localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

this.listenSocket.Bind(localEndpoint);

this.listenSocket.Listen(10);

När en ny socket godkänns initieras en serverkanal med den här socketen. Alla indata och utdata har redan implementerats i basklassen, så den här kanalen ansvarar för att initiera socketen.

Lägga till ett bindningselement

Nu när fabrikerna och kanalerna har skapats måste de exponeras för ServiceModel-körningen via en bindning. En bindning är en samling bindningselement som representerar kommunikationsstacken som är associerad med en tjänstadress. Varje element i stacken representeras av ett bindningselement.

I exemplet är WseTcpTransportBindingElementbindningselementet , som härleds från TransportBindingElement. Den stöder IDuplexSessionChannel och åsidosätter följande metoder för att skapa de fabriker som är associerade med vår bindning.

public IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)

{

return (IChannelFactory<TChannel>)(object)new WseTcpChannelFactory(this, context);

}

public IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)

{

return (IChannelListener<TChannel>)(object)new WseTcpChannelListener(this, context);

}

Den innehåller också medlemmar för att BindingElement klona och returnera vårt schema (wse.tcp).

WSE TCP-testkonsolen

Testkod för att använda den här exempeltransporten finns i TestCode.cs. Följande instruktioner visar hur du konfigurerar WSE-exemplet TcpSyncStockService .

Testkoden skapar en anpassad bindning som använder MTOM som kodning och WseTcpTransport som transport. Den konfigurerar också AddressingVersion så att den överensstämmer med WSE 3.0, enligt följande kod.

CustomBinding binding = new CustomBinding();

MtomMessageEncodingBindingElement mtomBindingElement = new MtomMessageEncodingBindingElement();

mtomBindingElement.MessageVersion = MessageVersion.Soap11WSAddressingAugust2004;

binding.Elements.Add(mtomBindingElement);

binding.Elements.Add(new WseTcpTransportBindingElement());

Den består av två tester – ett test konfigurerar en typad klient med hjälp av kod som genereras från WSE 3.0 WSDL. Det andra testet använder WCF som både klient och server genom att skicka meddelanden direkt ovanpå kanalens API:er.

När du kör exemplet förväntas följande utdata.

Klient:

Calling soap://stockservice.contoso.com/wse/samples/2003/06/TcpSyncStockService

Symbol: FABRIKAM
        Name: Fabrikam, Inc.
        Last Price: 120

Symbol: CONTOSO
        Name: Contoso Corp.
        Last Price: 50.07
Press enter.

Received Action: http://SayHello
Received Body: to you.
Hello to you.
Press enter.

Received Action: http://NotHello
Received Body: to me.
Press enter.

Server:

Listening for messages at soap://stockservice.contoso.com/wse/samples/2003/06/TcpSyncStockService

Press any key to exit when done...

Request received.
Symbols:
        FABRIKAM
        CONTOSO

Konfigurera, skapa och köra exemplet

  1. Om du vill köra det här exemplet måste du ha Web Services Enhancements (WSE) 3.0 för Microsoft .NET och WSE-exemplet TcpSyncStockService installerat.

Kommentar

Eftersom WSE 3.0 inte stöds på Windows Server 2008 kan du inte installera eller köra TcpSyncStockService exemplet på operativsystemet.

  1. När du har installerat TcpSyncStockService exemplet gör du följande:

    1. TcpSyncStockService Öppna i Visual Studio. (Den TcpSyncStockService-exemplet installeras med WSE 3.0. Det är inte en del av det här exemplets kod.)

    2. Ange StockService-projektet som startprojekt.

    3. Öppna StockService.cs i StockService-projektet och kommentera ut attributet [Policy] för StockService klassen. Detta inaktiverar säkerheten från exemplet. WCF kan samverka med WSE 3.0-säkra slutpunkter, men säkerheten inaktiveras för att hålla det här exemplet fokuserat på den anpassade TCP-transporten.

    4. tryck på F5 för att starta TcpSyncStockService. Tjänsten startar i ett nytt konsolfönster.

    5. Öppna det här TCP-transportexemplet i Visual Studio.

    6. Uppdatera variabeln "värdnamn" i TestCode.cs så att den matchar datornamnet som kör TcpSyncStockService.

    7. tryck på F5 för att starta TCP-transportexemplet.

    8. TCP-transporttestklienten startar i en ny konsol. Klienten begär aktiekurser från tjänsten och visar sedan resultatet i konsolfönstret.