Efter lanceringen af mit webcast på detskerher.com (direkte link til video), så tænkte det var smart at forklare eller uddybe nogen af punkterne i videoen.

[ServiceContract(CallbackContract = typeof(IChat))]
Ovenstående er vores definering af vores servicekontrakt. Det eneste "mystiske" her, er vores brug af typeof(IChat) i CallbackContract parametren. Grundet den er der, er et krav fra vores to-vej kanal, DuplexChannelFactory. WCF skal derfor vide hvilken grænseflade den kan snakke med i begge ender, og derfor skal vi angive vores callback kontrakt. I vores eksempel definerer vi en IChat i begge ender, således WCF kan udnytte to-vejs kanalen til at kommunikere vores beskeder begge veje.

[OperationContract(IsOneWay = true)]
For hver metode der defineres, skal vi fortælle WCF at OperationContract er en-vejs. Fjerner jeg den fra Join metoden, får jeg følgende runtime-fejl:
"Contract requires Request/Reply, but Binding 'NetPeerTcpBinding' doesn't support it or isn't configured properly to support it."
Det vi har defineret er en normal "Request/Reply" -metode, som fejlen også angiver. NetPeerTcpBinding understøtter bare ikke dette, da de metoder vi skal benytte, kun skal være en-vejs. Det giver desuden en funktionalitet svarende til asynkrone kald, således at når vi kalder metoden, så returneres der faktisk med det samme. WCF vil efter metode kaldet tage over, og sørge for beskeden bliver sendt via netværket.

interface IChatChannel : IChat, IClientChannel
IClientChannel giver muligheden for at vi som klienter kan udnytte kommunikationen vi opretter. Interfacet er desuden basis for klienter i WCF, som giver den basale klientfunktionalitet som beskrevet i: Client Architecture
Ved at samle IChat og IClientChannel, får vi en samlet mulighed for at kommunikere med andre noder, og vi får det igennem vores standard interface IChat.

InstanceContext context = new InstanceContext(this);
DuplexChannelFactory<IChatChannel> factory = new DuplexChannelFactory<IChatChannel>(context, "ChatEndpoint");
_chatChannel = factory.CreateChannel();

Den første linie definerer stedet for hvor callback beskeder håndteres. Dvs. når WCF får besked fra en anden node, skal vi angive hvor beskederne skal afleveres. I vores service kontrakt, definerede vi hvilken Callback kontrakt der benyttes (IChat). I linien skal vi angive den instans, som implementerer IChat interfacet, hvilket i dette tilfælde er this objektet.
Den anden linie erklærer vores to-vej kanal, hvor vi benytter vores IChatChannel som vores generiske type hertil. Parametre til constructoren er vores kontekst oprettet i første linie, og vores endpoint defineret i vores app.config fil.
Det er først i 3. linie vores DuplexChannelFactory kommer til udtryk, idet vi kalder CreateChannel på vores factory. CreateChannel returnerer en type, som angivet i oprettelsen af DuplexChannelFactory. Herefter får vi en mulighed for at kommunikere med andre noder igennem vores _chatChannel variabel, som er en instans af to-vejs kommunikationen på netværket. Hvem man har kontakt til, sørger WCF for.

app.config
<system.serviceModel>
    <client>
      <endpoint name="ChatEndpoint"
                address="net.p2p://clausn.dk/MyChat"
                binding="netPeerTcpBinding"
                bindingConfiguration="ChatBinding"
                contract="Chat.Service.IChat" />
    </client>
    <bindings>
      <netPeerTcpBinding>
        <binding name="ChatBinding"
                 port="0">
          <security mode="None" />
          <resolver mode="Pnrp" />
        </binding>
      </netPeerTcpBinding>
    </bindings>
  </system.serviceModel>
Ved et hurtigt kig på koden, er der ikke noget der stikker ud, som er specielt indviklet. Endpointet der først defineres navngives, og skal stemme overens med det andet argument til DuplexChannelFactory. Adressen er derimod lidt mere kryptisk, idet der altid skal angives net.p2p:// foran sit namespace. Herefter kan man angive hvad som helst, men jeg har angivet noget, som jeg ikke tror andre har brugt. Binding skal altid væres netPeerTcpBinding, for at benytte WCF's P2P funktionalitet. BindingConfiguration er et navn, som man selv definerer, og som beskrives under bindings. Contract er det fulde namespace til din service kontrakt, som du vil have din applikation overholder.
Under bindings, angiver vi netPeerTcpBinding, og herunder en ny binding med navn ChatBinding. Vi sætter porten til 0, således WCF selv definerer hvilke porte vores klient vil lytte på, således vi har mulighed for at køre flere klienter på samme maskine. Herefter fjerner vi sikkerheden, og sætter resolveren til Pnrp. Herved siger vi at klienterne skal gøre brug af den indbyggede resolver i Vista, og gør at vi ikke skal tage os af den magiske opkobling af klienter.

Ved at tilføje et par attributter til din servicekontrakt og 3 liniers kode, har vi oprettet en chat, som benytter P2P funktionaliteten i WCF. Eksemplet kan selvfølgelig udvides, men det giver en kort intro til, at I forhånbenligt at fået blod på tanden til at prøve noget mere.

Jeg har herunder vedhæftet klienten, som jeg refererer til sidst i mit webcast.
Chat.zip