Delen via


Transport: WSE 3.0 TCP-interoperabiliteit

Het voorbeeld van het WSE 3.0 TCP-interoperabiliteitstransport laat zien hoe u een TCP-duplexsessie implementeert als een aangepast WCF-transport (Windows Communication Foundation). Ook ziet u hoe u de uitbreidbaarheid van de kanaallaag kunt gebruiken om via de kabel te interfaceren met bestaande geïmplementeerde systemen. De volgende stappen laten zien hoe u dit aangepaste WCF-transport bouwt:

  1. Te beginnen met een TCP-socket maakt u client- en server-implementaties van die gebruikmaken van IDuplexSessionChannel DIME-frames om berichtgrenzen af te bakenen.

  2. Maak een kanaalfactory die verbinding maakt met een WSE TCP-service en berichten verzendt via de client IDuplexSessionChannel.

  3. Maak een kanaallistener om binnenkomende TCP-verbindingen te accepteren en bijbehorende kanalen te produceren.

  4. Zorg ervoor dat eventuele netwerkspecifieke uitzonderingen worden genormaliseerd naar de juiste afgeleide klasse van CommunicationException.

  5. Voeg een bindingselement toe waarmee het aangepaste transport wordt toegevoegd aan een kanaalstack. Zie [Een bindingselement toevoegen] voor meer informatie.

IDuplexSessionChannel maken

De eerste stap bij het schrijven van het WSE 3.0 TCP-interoperabiliteitstransport is het maken van een implementatie van IDuplexSessionChannelSocketeen . WseTcpDuplexSessionChannel afgeleid van ChannelBase. De logica van het verzenden van een bericht bestaat uit twee hoofdonderdelen: (1) Het bericht coderen in bytes en (2) die bytes inlijsten en verzenden op de draad.

ArraySegment<byte> encodedBytes = EncodeMessage(message);

WriteData(encodedBytes);

Bovendien wordt een vergrendeling genomen zodat de Send()-aanroepen de garantie IDuplexSessionChannel op volgorde behouden, en zodat aanroepen naar de onderliggende socket correct worden gesynchroniseerd.

WseTcpDuplexSessionChannel gebruikt een MessageEncoder voor het vertalen van een Message naar en van byte[]. Omdat het een transport is, WseTcpDuplexSessionChannel is ook verantwoordelijk voor het toepassen van het externe adres waarmee het kanaal is geconfigureerd. EncodeMessage bevat de logica voor deze conversie.

this.RemoteAddress.ApplyTo(message);

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

Zodra de code Message is gecodeerd in bytes, moet deze worden verzonden op de kabel. Hiervoor is een systeem vereist voor het definiëren van berichtgrenzen. WSE 3.0 gebruikt een versie van DIME als frameprotocol. WriteData kapselt de framelogica in om een byte[] in een set DIME-records te verpakken.

De logica voor het ontvangen van berichten is vergelijkbaar. De belangrijkste complexiteit is het verwerken van het feit dat een socket-leesbewerking minder bytes kan retourneren dan is aangevraagd. Als u een bericht wilt ontvangen, WseTcpDuplexSessionChannel leest u bytes van de draad af, ontsleutelt u de DIME-frame en gebruikt u vervolgens de functie voor het omzetten van de MessageEncoder byte[] in een Message.

Bij de basis WseTcpDuplexSessionChannel wordt ervan uitgegaan dat deze een aangesloten socket ontvangt. De basisklasse verwerkt het afsluiten van sockets. Er zijn drie plaatsen die interface met socketsluiting:

  • OnAbort -- sluit de socket geforceerd (harde sluiting).

  • Sluit op [Begin]Sluiten -- sluit de socket correct (zacht sluiten).

  • Sessie. CloseOutputSession : sluit de uitgaande gegevensstroom af (half gesloten).

Channel Factory

De volgende stap bij het schrijven van het TCP-transport is het maken van een implementatie van IChannelFactory clientkanalen.

  • WseTcpChannelFactory is afgeleid van ChannelFactoryBase<IDuplexSessionChannel>. Het is een fabriek die overschrijft OnCreateChannel om clientkanalen te produceren.

protected override IDuplexSessionChannel OnCreateChannel(EndpointAddress remoteAddress, Uri via)

{

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

}

  • ClientWseTcpDuplexSessionChannel voegt logica toe aan de basis WseTcpDuplexSessionChannel om op channel.Open dat moment verbinding te maken met een TCP-server. Eerst wordt de hostnaam omgezet in een IP-adres, zoals wordt weergegeven in de volgende code.

hostEntry = Dns.GetHostEntry(Via.Host);

  • Vervolgens wordt de hostnaam verbonden met het eerste beschikbare IP-adres in een lus, zoals wordt weergegeven in de volgende code.

IPAddress address = hostEntry.AddressList[i];

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

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

  • Als onderdeel van het kanaalcontract worden domeinspecifieke uitzonderingen verpakt, zoals SocketException in CommunicationException.

Kanaallistener

De volgende stap bij het schrijven van het TCP-transport is het maken van een implementatie voor het accepteren van IChannelListener serverkanalen.

  • WseTcpChannelListener is afgeleid van ChannelListenerBase<IDuplexSessionChannel> en overschrijft On[Begin]Open and On[Begin]Close om de levensduur van de listen socket te bepalen. In OnOpen wordt een socket gemaakt om te luisteren op IP_ANY. Geavanceerdere implementaties kunnen ook een tweede socket maken om te luisteren op IPv6. Ze kunnen ook toestaan dat het IP-adres wordt opgegeven in de hostnaam.

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

Wanneer een nieuwe socket wordt geaccepteerd, wordt een serverkanaal geïnitialiseerd met deze socket. Alle invoer en uitvoer zijn al geïmplementeerd in de basisklasse, dus dit kanaal is verantwoordelijk voor het initialiseren van de socket.

Een bindingselement toevoegen

Nu de factory's en kanalen zijn gebouwd, moeten ze worden blootgesteld aan de ServiceModel-runtime via een binding. Een binding is een verzameling bindingselementen die de communicatiestack vertegenwoordigt die is gekoppeld aan een serviceadres. Elk element in de stack wordt vertegenwoordigd door een bindingselement.

In het voorbeeld is WseTcpTransportBindingElementhet bindingselement , dat is afgeleid van TransportBindingElement. Het ondersteunt IDuplexSessionChannel en overschrijft de volgende methoden om de factory's te bouwen die aan onze binding zijn gekoppeld.

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

}

Het bevat ook leden voor het BindingElement klonen en retourneren van ons schema (wse.tcp).

De WSE TCP-testconsole

Testcode voor het gebruik van dit voorbeeldtransport is beschikbaar in TestCode.cs. De volgende instructies laten zien hoe u het WSE-voorbeeld TcpSyncStockService instelt.

De testcode maakt een aangepaste binding die gebruikmaakt van MTOM als codering en WseTcpTransport als transport. Er wordt ook ingesteld dat de AddressingVersion voldoet aan WSE 3.0, zoals wordt weergegeven in de volgende code.

CustomBinding binding = new CustomBinding();

MtomMessageEncodingBindingElement mtomBindingElement = new MtomMessageEncodingBindingElement();

mtomBindingElement.MessageVersion = MessageVersion.Soap11WSAddressingAugust2004;

binding.Elements.Add(mtomBindingElement);

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

Het bestaat uit twee tests: één test stelt een getypte client in met behulp van code die is gegenereerd op basis van de WSE 3.0 WSDL. De tweede test maakt gebruik van WCF als zowel de client als de server door berichten rechtstreeks boven op de kanaal-API's te verzenden.

Bij het uitvoeren van het voorbeeld wordt de volgende uitvoer verwacht.

Client:

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

Het voorbeeld instellen, bouwen en uitvoeren

  1. Als u dit voorbeeld wilt uitvoeren, moet WSE (Web Services Enhancements) 3.0 voor Microsoft .NET en het WSE-voorbeeld TcpSyncStockService zijn geïnstalleerd.

Notitie

Omdat WSE 3.0 niet wordt ondersteund in Windows Server 2008, kunt u het TcpSyncStockService voorbeeld niet installeren of uitvoeren op dat besturingssysteem.

  1. Nadat u het TcpSyncStockService voorbeeld hebt geïnstalleerd, gaat u als volgt te werk:

    1. Open het TcpSyncStockService bestand in Visual Studio. (De TcpSyncStockService-voorbeeld is geïnstalleerd met WSE 3.0. Het maakt geen deel uit van de code van dit voorbeeld.)

    2. Stel het StockService-project in als het opstartproject.

    3. Open StockService.cs in het StockService-project en markeer het kenmerk [Policy] voor de StockService klasse. Hierdoor wordt de beveiliging van het voorbeeld uitgeschakeld. Hoewel WCF kan samenwerken met beveiligde WSE 3.0-eindpunten, is beveiliging uitgeschakeld om dit voorbeeld gericht te houden op het aangepaste TCP-transport.

    4. druk op F5 om het TcpSyncStockService. De service wordt gestart in een nieuw consolevenster.

    5. Open dit TCP-transportvoorbeeld in Visual Studio.

    6. Werk de variabele hostnaam in TestCode.cs bij zodat deze overeenkomt met de computernaam waarop de TcpSyncStockServicecomputer wordt uitgevoerd.

    7. druk op F5 om het TCP-transportvoorbeeld te starten.

    8. De TCP-transporttestclient wordt gestart in een nieuwe console. De client vraagt aandelenkoersen van de service aan en geeft vervolgens de resultaten weer in het consolevenster.