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:
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.
Skapa en kanalfabrik som ansluter till en WSE TCP-tjänst och skickar inramade meddelanden via klientens IDuplexSessionChannel.
Skapa en kanallyssnare för att acceptera inkommande TCP-anslutningar och skapa motsvarande kanaler.
Se till att alla nätverksspecifika undantag normaliseras till lämplig härledd klass för CommunicationException.
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ätterOnCreateChannel
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 basenWseTcpDuplexSessionChannel
för att ansluta till en TCP-server vidchannel.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 WseTcpTransportBindingElement
bindningselementet , 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
- 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.
När du har installerat
TcpSyncStockService
exemplet gör du följande:TcpSyncStockService
Öppna i Visual Studio. (Den TcpSyncStockService-exemplet installeras med WSE 3.0. Det är inte en del av det här exemplets kod.)Ange StockService-projektet som startprojekt.
Ö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.tryck på F5 för att starta
TcpSyncStockService
. Tjänsten startar i ett nytt konsolfönster.Öppna det här TCP-transportexemplet i Visual Studio.
Uppdatera variabeln "värdnamn" i TestCode.cs så att den matchar datornamnet som kör
TcpSyncStockService
.tryck på F5 för att starta TCP-transportexemplet.
TCP-transporttestklienten startar i en ny konsol. Klienten begär aktiekurser från tjänsten och visar sedan resultatet i konsolfönstret.