Using Castle Windsor IOC Container with SuperSocket

Jul 23, 2012 at 8:33 PM

I'd like to use Castle Windsor to inject the dependencies I need for processing received socket commands.  The Socket Server engine dynamically loads the defined servers using the config file however, and its impossible for an inversion of control (IOC) container to statically resolve dependencies when the program starts up.  Do you have any examples of how to overcome this problem? It seems at the moment that I might have to rewrite the SocketServerManager class in the SocketEngine to use my IOC container to load the services rather than default SuperSocket implementation. 

Jul 23, 2012 at 11:58 PM
Edited Jul 23, 2012 at 11:58 PM

What I have found so far:

In SocketServerManager.cs there already exists a second Initialize method that takes as a parameter an IEnumerable of IAppServer instances:

public static bool Initialize(IEnumerable<IAppServer> servers)

This method appears to allow for IAppServer instances that have been previously resolved or statically declared to be loaded by socket server rather than using dynamic loading based on the config.  Unfortunately, this method is not useful out of the box, as it does not set the m_config member variable of the SocketServerManager class and there is an exception generated with the Start method in the SocketServerManager class attempts to use m_config.  

Furthermore, the Initalize method that requires only the IEnumerable does not call setup on the IAppServer instances.  It is required (as mentioned in the comments) that the instances must be setup.

 

My Solution:

I have not tested everything 100%, but thus far I have gotten things working by:

1) Adding an IConfig parameter to the aforementioned Initialize method and used that parameter to set the static member variable m_config

public static bool Initialize(IEnumerable<IAppServer> servers, IConfig config)
{
    m_config = config;
    ...
}

2) I modified the app.config and used a convention where the serviceName is the <servers> config is the typename of the actual concrete class that implements IAppServer.  In my worker role class ( I'm using Azure ), I load the server config and and copy the parameters to an instance of RootConfig.  I then Resolve each individual server config using the provided function and create a list of resolved server configs.  I am using Castle Windsor to inject via a property setter the list of IAppServer instances, and for each of those I search the config using LINQ in order to find the matching config (based on service name).  

My OnStart method now looks like: [Please excuse the mess]

       public bool OnStart()
        {
            LogUtil.Setup();

            // Set the maximum number of concurrent connections 
            ServicePointManager.DefaultConnectionLimit = 10000;

            // For information on handling configuration changes
            // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.

            var serverConfig = ConfigurationManager.GetSection("socketServer") as SocketServiceConfig;
            RootConfig rootConfig = new RootConfig();
            serverConfig.CopyPropertiesTo(rootConfig);

            List<IServerConfig> resolvedConfigs = new List<IServerConfig>();

            foreach(var servConfig in serverConfig.Servers)
            {
                resolvedConfigs.Add(ResolveServerConfig(servConfig));
            }
          
            foreach (IAppServer server in p_ServerList)
            {
                var config = from cfg in resolvedConfigs
                             where cfg.ServiceName == server.GetType().ToString()
                             select cfg;
                IServerConfig servConfig = config.FirstOrDefault();
                if (servConfig == null)
                    throw new Exception("Could not find proper config");
                server.Setup((IRootConfig)rootConfig, servConfig, SocketServerFactory.Instance);
            }
            
            if (!SocketServerManager.Initialize(p_ServerList, (IConfig)serverConfig))
            {
                Trace.WriteLine("Failed to initialize SuperSocket!", "Error");
                return false;
            }
                        
            /*
            var serverConfig = ConfigurationManager.GetSection("socketServer") as SocketServiceConfig;
            
            if (!SocketServerManager.Initialize(serverConfig, ResolveServerConfig))
            {
                Trace.WriteLine("Failed to initialize SuperSocket!", "Error");
                return false;
            }
             */

            if (!SocketServerManager.Start())
            {
                Trace.WriteLine("Failed to start SuperSocket!", "Error");
                return false;
            }

            //return base.OnStart();
            return true;
        }

 

This all seems a bit hacky, but perhaps is a step in the right direction.  If a SuperSocket dev / poweruser has any ideas how to make this better, please let me know.

Coordinator
Jul 24, 2012 at 2:35 AM

Yes, I also think you'd better create your own SocketServerManager. That's a little stupid that the SocketServerManager is a static class. In v1.5, we replaced SocketServerManager with Bootstrap.

Jul 24, 2012 at 5:37 PM

How many more beta releases do you expect there to before 1.5 is at least a release candidate?  We are probably 2 months out from deploying to a production environment and I want to make a decision about using 1.5 or sticking with 1.4.