|
If you've been reading my series of blog posts on Ulysses Agenda, then you probably remember the following bit of code:
_auth = new NetLibImplementations.Authenticator();
_authSite = new InstanceContext(_auth);
_authChannelFactory = new DuplexChannelFactory<IAuthenticatorChannel>(_authSite, "AuthEndPoint");
_authProxy = (IAuthenticatorChannel)_authChannelFactory.CreateChannel();
What you didn't see what that this code relied on a big pile of XML in the App.config file, shown below:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint
name="ChatEndpoint"
address="net.p2p://ulyssesagenda/chat"
binding="netPeerTcpBinding"
bindingConfiguration="PeerBinding"
contract="UlyssesAgenda.NetworkLibrary.IChat"/>
<endpoint
name="AuthEndPoint"
address="net.p2p://ulyssesagenda/auth"
binding="netPeerTcpBinding"
bindingConfiguration="PeerBinding"
contract="UlyssesAgenda.NetworkLibrary.IAuthenticator" />
</client>
<bindings>
<netPeerTcpBinding>
<binding
name="PeerBinding"
port="8091"
maxReceivedMessageSize="2147483647" >
<security mode="None">
</security>
</binding>
</netPeerTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
There's a couple of problems with this scenario. The first problem is that if I need to dynamically open new channels at runtime with varying endpoints (such as having a player move in an out of galaxies, NPCs moving in an out of galaxies, etc) then there's really no way to do it using App.config. App.config only allows me to define static, persistent channels, not transient channels.
What I've done is refactored this so that there is no longer a dependency on the App.config file and all the channels are created and opened dynamically at runtime, and now I can set up a new channel and channel listener with the following two lines of code:
_auth = new UlyssesAgenda.UniverseServer.NetLibImplementations.Authenticator();
_authProxy = CommunicationCenter.OpenChannel<IAuthenticator, IAuthenticatorChannel>(
_auth, "net.p2p://ulyssesagenda/auth", 8091);
Here's the code for my OpenChannel<T,U> method, which does all the work of creating, configuring, and opening a channel at runtime:
public static U OpenChannel<T, U>(T sourceObject,
string p2pUrl,
int portNumber) where U: IClientChannel
{
InstanceContext sourceContext = new InstanceContext(sourceObject);
NetPeerTcpBinding binding = new NetPeerTcpBinding();
binding.Port = portNumber;
binding.Name = p2pUrl + "@" + portNumber.ToString();
binding.Security.Mode = SecurityMode.None;
binding.MaxReceivedMessageSize = 2147483647;
EndpointAddress address = new EndpointAddress(p2pUrl);
DuplexChannelFactory<U> sourceFactory = new DuplexChannelFactory<U>(sourceContext,
binding,
address);
U sourceProxy = (U)sourceFactory.CreateChannel();
sourceProxy.Open();
return sourceProxy;
}
What this refactor does is get me a little bit closer to where I need to be - a spot where I can write code that will dynamically bring up and shut down P2P channels at will at runtime to account for players moving in and out of galaxies, moving in and out of chat channels, and much more. With the dependency on statically defined App.config channels gone, the code for the game is much more dynamic and much more flexible.