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:
Te beginnen met een TCP-socket maakt u client- en server-implementaties van die gebruikmaken van IDuplexSessionChannel DIME-frames om berichtgrenzen af te bakenen.
Maak een kanaalfactory die verbinding maakt met een WSE TCP-service en berichten verzendt via de client IDuplexSessionChannel.
Maak een kanaallistener om binnenkomende TCP-verbindingen te accepteren en bijbehorende kanalen te produceren.
Zorg ervoor dat eventuele netwerkspecifieke uitzonderingen worden genormaliseerd naar de juiste afgeleide klasse van CommunicationException.
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 overschrijftOnCreateChannel
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 basisWseTcpDuplexSessionChannel
om opchannel.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 WseTcpTransportBindingElement
het 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
- 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.
Nadat u het
TcpSyncStockService
voorbeeld hebt geïnstalleerd, gaat u als volgt te werk: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.)Stel het StockService-project in als het opstartproject.
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.druk op F5 om het
TcpSyncStockService
. De service wordt gestart in een nieuw consolevenster.Open dit TCP-transportvoorbeeld in Visual Studio.
Werk de variabele hostnaam in TestCode.cs bij zodat deze overeenkomt met de computernaam waarop de
TcpSyncStockService
computer wordt uitgevoerd.druk op F5 om het TCP-transportvoorbeeld te starten.
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.