Beispiel #1
0
        public void Build(Action <ContainerRegistrar> action, ConfigurationStore configStore)
        {
            var builder = new ContainerRegistrar();

            builder.RegisterComponents(Lifetime.Scoped, Assembly.GetExecutingAssembly());
            builder.RegisterService(CreateConnection, Lifetime.Scoped);
            builder.RegisterService(CreateTaskInvoker, Lifetime.Singleton);
            builder.RegisterInstance(Startup.ConnectionFactory);
            action(builder);

            RegisterBuiltInComponents(builder);
            RegisterQueues(builder);

            builder.RegisterService(x => Container, Lifetime.Singleton);
            builder.RegisterService(x => x);
            builder.RegisterConcrete <AnalysisDbContext>();
            builder.RegisterInstance(configStore);
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
            builder.RegisterControllers(Assembly.GetExecutingAssembly());

            var ioc = builder.Build();

            DependencyResolver.SetResolver(new GriffinDependencyResolver(ioc));
            GlobalConfiguration.Configuration.DependencyResolver = new GriffinWebApiDependencyResolver2(ioc);
            Container = new GriffinContainerAdapter(ioc);
        }
        public void Build(Action <ContainerRegistrar> action, ConfigurationStore configStore)
        {
            var builder = new ContainerRegistrar();

            //need to invoke first to allow plug-ins to override default behavior.
            action(builder);

            builder.RegisterComponents(Lifetime.Scoped, Assembly.GetExecutingAssembly());
            builder.RegisterService(CreateUnitOfWork, Lifetime.Scoped);
            builder.RegisterService(CreateTaskInvoker, Lifetime.Singleton);
            builder.RegisterService(CreateConnection, Lifetime.Transient);

            RegisterBuiltInComponents(builder);
            RegisterQueues(builder);

            builder.RegisterService(x => Container, Lifetime.Singleton);
            builder.RegisterService(x => x);
            builder.RegisterService(CreateAnalysisDbContext);
            builder.RegisterInstance(configStore);
            builder.RegisterType(typeof(IConfiguration <>), typeof(ConfigWrapper <>), Lifetime.Transient);
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
            builder.RegisterControllers(Assembly.GetExecutingAssembly());

            builder.RegisterService(x => configStore.Load <BaseConfiguration>());
            var ioc = builder.Build();

            DependencyResolver.SetResolver(new GriffinDependencyResolver(ioc));
            GlobalConfiguration.Configuration.DependencyResolver = new GriffinWebApiDependencyResolver2(ioc);
            Container = new GriffinContainerAdapter(ioc);
        }
            public void Should_Resolve_Last_Registration_Of_Instance_When_Requesting_Single_Registration()
            {
                // Given
                var builder   = new ContainerRegistrar();
                var instance1 = Substitute.For <IFoo>();
                var instance2 = Substitute.For <IFoo>();

                builder.RegisterInstance(instance1).Singleton();
                builder.RegisterInstance(instance2).Singleton();
                var container = builder.Build();

                // When
                var result = container.Resolve <IFoo>();

                // Then
                Assert.Same(instance2, result);
            }
            public void Should_Resolve_All_Instances_When_Requesting_Enumerable_Of_Registration()
            {
                // Given
                var builder   = new ContainerRegistrar();
                var instance1 = Substitute.For <IFoo>();
                var instance2 = Substitute.For <IFoo>();

                builder.RegisterInstance(instance1).Singleton();
                builder.RegisterInstance(instance2).Singleton();
                var container = builder.Build();

                // When
                var result = container.Resolve <IEnumerable <IFoo> >().ToList();

                // Then
                Assert.Equal(2, result.Count);
                Assert.Contains(result, instance => instance == instance1);
                Assert.Contains(result, instance => instance == instance2);
            }
        public void TestSingleton()
        {
            var registrar = new ContainerRegistrar();

            registrar.RegisterInstance <MySelf>(new MySelf());
            registrar.RegisterConcrete <OneDepencency>(Lifetime.Singleton);
            var container = registrar.Build();

            container.Resolve <OneDepencency>();
        }
        public void DispatchReal()
        {
            var handler = Substitute.For<IExecuteQuery<FakeQuery, string>>();
            var registrar = new ContainerRegistrar();
            registrar.RegisterInstance(handler);

            var dispatcher = new QueryDispatcher(registrar.Build());
            dispatcher.Execute(new FakeQuery());

        }
Beispiel #7
0
        public void DispatchReal()
        {
            var handler   = Substitute.For <IExecuteQuery <FakeQuery, string> >();
            var registrar = new ContainerRegistrar();

            registrar.RegisterInstance(handler);

            var dispatcher = new QueryDispatcher(registrar.Build());

            dispatcher.Execute(new FakeQuery());
        }
        public void RegisterServiceAsInstance()
        {
            var registrar = new ContainerRegistrar(Lifetime.Transient);
            registrar.RegisterInstance<IThinkNot>(new Will());
            registrar.RegisterConcrete<InstanceSubject>();

            var c = registrar.Build();
            var actual = c.Resolve<InstanceSubject>();

            Assert.NotNull(actual);
            Assert.IsAssignableFrom<InstanceSubject>(actual);
        }
Beispiel #9
0
        public void RegisterServiceAsInstance()
        {
            var registrar = new ContainerRegistrar(Lifetime.Transient);

            registrar.RegisterInstance <IThinkNot>(new Will());
            registrar.RegisterConcrete <InstanceSubject>();

            var c      = registrar.Build();
            var actual = c.Resolve <InstanceSubject>();

            Assert.NotNull(actual);
            Assert.IsAssignableFrom <InstanceSubject>(actual);
        }
Beispiel #10
0
        public static void RegisterHandler(this ContainerRegistrar registrar, object handler)
        {
            registrar.RegisterInstance(handler.GetType(), handler);
            var reg  = registrar.Registrations.First(x => x.Services.Any(y => y == handler.GetType()));
            var bajs = handler.GetType().GetInterfaces();

            foreach (var b in bajs)
            {
                if (b.IsConstructedGenericType)
                {
                    reg.AddService(b);
                }
            }
        }
            public void Should_Resolve_The_Same_Instances_When_Resolving_Registered_Instance()
            {
                // Given
                var builder  = new ContainerRegistrar();
                var instance = Substitute.For <IFoo>();

                builder.RegisterInstance(instance).Singleton();
                var container = builder.Build();

                // When
                var first  = container.Resolve <IFoo>();
                var second = container.Resolve <IFoo>();

                // Then
                Assert.Same(instance, first);
                Assert.Same(instance, second);
            }
        public void TestSingleton()
        {
            var registrar = new ContainerRegistrar();
            registrar.RegisterInstance<MySelf>(new MySelf());
            registrar.RegisterConcrete<OneDepencency>(Lifetime.Singleton);
            var container = registrar.Build();

            container.Resolve<OneDepencency>();
        }
Beispiel #13
0
        public static int Main()
        {
            // Parse arguments.
            var args = ArgumentParser.Parse(
                QuoteAwareStringSplitter
                .Split(EnvironmentHelper.GetCommandLine())
                .Skip(1));

            if (args.ContainsKey(Constants.CommandLine.Debug))
            {
                Console.WriteLine($"Attach debugger to process {Process.GetCurrentProcess().Id} to continue. ..");
                while (!Debugger.IsAttached)
                {
                    Thread.Sleep(100);
                }
            }

            // Validate the port argument.
            if (!args.ContainsKey(Constants.CommandLine.Port) ||
                !int.TryParse(args[Constants.CommandLine.Port], out int port))
            {
                throw new ArgumentException("Port not specified or invalid.");
            }

            var loggerFactory = new LoggerFactory();

            if (args.ContainsKey(Constants.CommandLine.Verbose))
            {
                loggerFactory.AddProvider(new LoggerProvider());
            }

            var registrar = new ContainerRegistrar();

            registrar.RegisterModule(new CoreModule());
            registrar.RegisterModule(new BakeryModule(loggerFactory));

            // Build the container.
            using (var container = registrar.Build())
            {
                var fileSystem            = container.Resolve <IFileSystem>();
                var log                   = container.Resolve <ICakeLog>();
                var configurationProvider = container.Resolve <CakeConfigurationProvider>();
                var workingDirectory      = new DirectoryPath(System.IO.Directory.GetCurrentDirectory());

                var configuration = configurationProvider.CreateConfiguration(workingDirectory, args);

                // Rebuild the container for NuGet and Buffered File System.
                registrar = new ContainerRegistrar();
                registrar.RegisterInstance(configuration);
                registrar.RegisterModule(new NuGetModule(configuration));
                registrar.RegisterModule(new ScriptingModule(fileSystem, log));
                registrar.Builder.Update(container);

                var environment            = container.Resolve <ICakeEnvironment>();
                var aliasFinder            = container.Resolve <IScriptAliasFinder>();
                var processor              = container.Resolve <Core.Scripting.IScriptProcessor>();
                var aliasGenerator         = container.Resolve <ICakeAliasGenerator>();
                var loadDirectiveProviders = container.Resolve <IEnumerable <ILoadDirectiveProvider> >();

                // Rebuild the container for Cached Alias Finder.
                registrar = new ContainerRegistrar();
                registrar.RegisterModule(new CacheModule(aliasFinder, processor, environment, aliasGenerator, loadDirectiveProviders));
                registrar.Builder.Update(container);

                // Get Script generator.
                var scriptGenerator = container.Resolve <IScriptGenerationService>();

                environment.WorkingDirectory = workingDirectory;

                try
                {
                    using (var server = new ScriptGenerationServer(scriptGenerator, port, loggerFactory))
                    {
                        server.Start();

                        var cancel = new ManualResetEvent(false);

                        server.OnDisconnected  += (sender, e) => { cancel.Set(); };
                        Console.CancelKeyPress += (sender, e) =>
                        {
                            cancel.Set();
                            e.Cancel = true;
                        };

                        cancel.WaitOne();
                        server.Stop();
                    }
                }
                catch (Exception e)
                {
                    loggerFactory.CreateLogger <Program>().LogCritical(0, e, "Unhandled Exception");
                    throw;
                }
            }

            return(0);
        }
Beispiel #14
0
        private async void Startup()
        {
            // Print exception messages in English
            Thread.CurrentThread.CurrentUICulture     = CultureInfo.InvariantCulture;
            CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;

            // Set the AppDomain working directory to the current resource root
            Environment.CurrentDirectory = Path.GetFullPath(API.GetResourcePath(API.GetCurrentResourceName()));

            new Logger().Info($"NFive {typeof(Program).Assembly.GetCustomAttributes<AssemblyInformationalVersionAttribute>().First().InformationalVersion}");

            // TODO: Check and warn if local CitizenFX.Core.Server.dll is found

            var config = ConfigurationManager.Load <CoreConfiguration>("core.yml");

            // Use configured culture for output
            Thread.CurrentThread.CurrentCulture     = config.Locale.Culture.First();
            CultureInfo.DefaultThreadCurrentCulture = config.Locale.Culture.First();

            ServerConfiguration.Locale    = config.Locale;
            ServerLogConfiguration.Output = config.Log.Output;

            var logger = new Logger(config.Log.Core);

            API.SetGameType(config.Display.Game);
            API.SetMapName(config.Display.Map);

            // Setup RPC handlers
            RpcManager.Configure(config.Log.Comms, this.EventHandlers, this.Players);

            var events = new EventManager(config.Log.Comms);
            var comms  = new CommunicationManager(events);
            var rcon   = new RconManager(comms);

            // Load core controllers
            try
            {
                var dbController = new DatabaseController(new Logger(config.Log.Core, "Database"), ConfigurationManager.Load <DatabaseConfiguration>("database.yml"), comms);
                await dbController.Loaded();

                this.controllers.Add(new Name("NFive/Database"), new List <Controller> {
                    dbController
                });
            }
            catch (Exception ex)
            {
                logger.Error(ex, "Database connection error");
                logger.Warn("Fatal error, exiting");
                Environment.Exit(1);
            }

            var eventController = new EventController(new Logger(config.Log.Core, "FiveM"), comms);
            await eventController.Loaded();

            this.controllers.Add(new Name("NFive/RawEvents"), new List <Controller> {
                eventController
            });

            var sessionController = new SessionController(new Logger(config.Log.Core, "Session"), ConfigurationManager.Load <SessionConfiguration>("session.yml"), comms);
            await sessionController.Loaded();

            this.controllers.Add(new Name("NFive/Session"), new List <Controller> {
                sessionController
            });

            // Resolve dependencies
            var graph = DefinitionGraph.Load();

            // IoC
            var assemblies = new List <Assembly>();

            assemblies.AddRange(graph.Plugins.Where(p => p.Server?.Include != null).SelectMany(p => p.Server.Include.Select(i => Assembly.LoadFrom(Path.Combine("plugins", p.Name.Vendor, p.Name.Project, $"{i}.net.dll")))));
            assemblies.AddRange(graph.Plugins.Where(p => p.Server?.Main != null).SelectMany(p => p.Server.Main.Select(m => Assembly.LoadFrom(Path.Combine("plugins", p.Name.Vendor, p.Name.Project, $"{m}.net.dll")))));

            var registrar = new ContainerRegistrar();

            registrar.RegisterService <ILogger>(s => new Logger());
            registrar.RegisterInstance <IRconManager>(rcon);
            registrar.RegisterInstance <IBaseScriptProxy>(new BaseScriptProxy(this.EventHandlers, this.Exports, this.Players));
            registrar.RegisterInstance <ICommunicationManager>(comms);
            registrar.RegisterInstance <IClientList>(new ClientList(new Logger(config.Log.Core, "ClientList"), comms));
            registrar.RegisterPluginComponents(assemblies.Distinct());

            // DI
            var container = registrar.Build();

            var pluginDefaultLogLevel = config.Log.Plugins.ContainsKey("default") ? config.Log.Plugins["default"] : LogLevel.Info;

            // Load plugins into the AppDomain
            foreach (var plugin in graph.Plugins)
            {
                logger.Info($"Loading {plugin.FullName}");

                // Load include files
                foreach (var includeName in plugin.Server?.Include ?? new List <string>())
                {
                    var includeFile = Path.Combine("plugins", plugin.Name.Vendor, plugin.Name.Project, $"{includeName}.net.dll");
                    if (!File.Exists(includeFile))
                    {
                        throw new FileNotFoundException(includeFile);
                    }

                    AppDomain.CurrentDomain.Load(File.ReadAllBytes(includeFile));
                }

                // Load main files
                foreach (var mainName in plugin.Server?.Main ?? new List <string>())
                {
                    var mainFile = Path.Combine("plugins", plugin.Name.Vendor, plugin.Name.Project, $"{mainName}.net.dll");
                    if (!File.Exists(mainFile))
                    {
                        throw new FileNotFoundException(mainFile);
                    }

                    var asm = Assembly.LoadFrom(mainFile);

                    var sdkVersion = asm.GetCustomAttribute <ServerPluginAttribute>();

                    if (sdkVersion == null)
                    {
                        throw new Exception("Unable to load outdated SDK plugin");                         // TODO
                    }

                    if (sdkVersion.Target != SDK.Server.SDK.Version)
                    {
                        throw new Exception("Unable to load outdated SDK plugin");
                    }

                    var types = Assembly.LoadFrom(mainFile).GetTypes().Where(t => !t.IsAbstract && t.IsClass).ToList();

                    // Find migrations
                    foreach (var migrationType in types.Where(t => t.BaseType != null && t.BaseType.IsGenericType && t.BaseType.GetGenericTypeDefinition() == typeof(MigrationConfiguration <>)))
                    {
                        var configuration = (DbMigrationsConfiguration)Activator.CreateInstance(migrationType);
                        var migrator      = new DbMigrator(configuration);

                        if (!migrator.GetPendingMigrations().Any())
                        {
                            continue;
                        }

                        if (!ServerConfiguration.AutomaticMigrations)
                        {
                            throw new MigrationsPendingException($"Plugin {plugin.FullName} has pending migrations but automatic migrations are disabled");
                        }

                        foreach (var migration in migrator.GetPendingMigrations())
                        {
                            new Logger(config.Log.Core, "Database").Debug($"[{mainName}] Running migration: {migration}");

                            migrator.Update(migration);
                        }
                    }

                    // Find controllers
                    foreach (var controllerType in types.Where(t => t.IsSubclassOf(typeof(Controller)) || t.IsSubclassOf(typeof(ConfigurableController <>))))
                    {
                        var logLevel = config.Log.Plugins.ContainsKey(plugin.Name) ? config.Log.Plugins[plugin.Name] : pluginDefaultLogLevel;

                        var constructorArgs = new List <object>
                        {
                            new Logger(logLevel, plugin.Name)
                        };

                        // Check if controller is configurable
                        if (controllerType.BaseType != null && controllerType.BaseType.IsGenericType && controllerType.BaseType.GetGenericTypeDefinition() == typeof(ConfigurableController <>))
                        {
                            // Initialize the controller configuration
                            constructorArgs.Add(ConfigurationManager.InitializeConfig(plugin.Name, controllerType.BaseType.GetGenericArguments()[0]));
                        }

                        // Resolve IoC arguments
                        constructorArgs.AddRange(controllerType.GetConstructors()[0].GetParameters().Skip(constructorArgs.Count).Select(p => container.Resolve(p.ParameterType)));

                        Controller controller = null;

                        try
                        {
                            // Construct controller instance
                            controller = (Controller)Activator.CreateInstance(controllerType, constructorArgs.ToArray());
                        }
                        catch (Exception ex)
                        {
                            // TODO: Dispose of controller

                            logger.Error(ex, $"Unhandled exception in plugin {plugin.FullName}");
                        }

                        if (controller == null)
                        {
                            continue;
                        }

                        try
                        {
                            await controller.Loaded();

                            if (!this.controllers.ContainsKey(plugin.Name))
                            {
                                this.controllers.Add(plugin.Name, new List <Controller>());
                            }
                            this.controllers[plugin.Name].Add(controller);
                        }
                        catch (Exception ex)
                        {
                            // TODO: Dispose of controller

                            logger.Error(ex, $"Unhandled exception loading plugin {plugin.FullName}");
                        }
                    }
                }
            }

            await Task.WhenAll(this.controllers.SelectMany(c => c.Value).Select(s => s.Started()));

            rcon.Controllers = this.controllers;

            comms.Event(CoreEvents.ClientPlugins).FromClients().OnRequest(e => e.Reply(graph.Plugins));

            logger.Debug($"{graph.Plugins.Count.ToString(CultureInfo.InvariantCulture)} plugin(s) loaded, {this.controllers.Count.ToString(CultureInfo.InvariantCulture)} controller(s) created");

            comms.Event(ServerEvents.ServerInitialized).ToServer().Emit();

            logger.Info("Server ready");
        }
Beispiel #15
0
        private async void Startup()
        {
            // Set the AppDomain working directory to the current resource root
            Environment.CurrentDirectory = Path.GetFullPath(API.GetResourcePath(API.GetCurrentResourceName()));

            Logger.Initialize();
            new Logger().Info($"NFive {typeof(Program).Assembly.GetCustomAttributes<AssemblyInformationalVersionAttribute>().First().InformationalVersion}");

            var config = ConfigurationManager.Load <CoreConfiguration>("nfive.yml");

            ServerLogConfiguration.Output = config.Log.Output;
            //ServerConfiguration.LogLevel = config.Log.Level;

            var logger = new Logger(config.Log.Core);

            API.SetGameType(config.Display.Game);
            API.SetMapName(config.Display.Map);

            // Setup RPC handlers
            RpcManager.Configure(config.Log.Rpc, this.EventHandlers);

            // Client log mirroring
            new RpcHandler().Event("nfive:log:mirror").On(new Action <IRpcEvent, DateTime, LogLevel, string, string>((e, dt, level, prefix, message) =>
            {
                new Logger(LogLevel.Trace, $"Client#{e.Client.Handle}|{prefix}").Log(message, level);
            }));

            var events = new EventManager(config.Log.Events);
            var rcon   = new RconManager(new RpcHandler());

            // Load core controllers
            var dbController = new DatabaseController(new Logger(config.Log.Core, "Database"), events, new RpcHandler(), rcon, ConfigurationManager.Load <DatabaseConfiguration>("database.yml"));
            await dbController.Loaded();

            this.controllers.Add(new Name("NFive/Database"), new List <Controller> {
                dbController
            });

            var sessionController = new SessionController(new Logger(config.Log.Core, "Session"), events, new RpcHandler(), rcon, ConfigurationManager.Load <SessionConfiguration>("session.yml"));
            await sessionController.Loaded();

            this.controllers.Add(new Name("NFive/Session"), new List <Controller> {
                sessionController
            });

            // Resolve dependencies
            var graph = DefinitionGraph.Load();

            var pluginDefaultLogLevel = config.Log.Plugins.ContainsKey("default") ? config.Log.Plugins["default"] : LogLevel.Info;

            // IoC
            var assemblies = new List <Assembly>();

            assemblies.AddRange(graph.Plugins.Where(p => p.Server?.Include != null).SelectMany(p => p.Server.Include.Select(i => Assembly.LoadFrom(Path.Combine("plugins", p.Name.Vendor, p.Name.Project, $"{i}.net.dll")))));
            assemblies.AddRange(graph.Plugins.Where(p => p.Server?.Main != null).SelectMany(p => p.Server.Main.Select(m => Assembly.LoadFrom(Path.Combine("plugins", p.Name.Vendor, p.Name.Project, $"{m}.net.dll")))));

            var registrar = new ContainerRegistrar();

            registrar.RegisterService <ILogger>(s => new Logger());
            registrar.RegisterType <IRpcHandler, RpcHandler>();
            registrar.RegisterInstance <IEventManager>(events);
            registrar.RegisterInstance <IRconManager>(rcon);
            registrar.RegisterInstance <IClientList>(new ClientList(new Logger(config.Log.Core, "ClientList"), new RpcHandler()));
            registrar.RegisterSdkComponents(assemblies.Distinct());

            // DI
            var container = registrar.Build();

            // Load plugins into the AppDomain
            foreach (var plugin in graph.Plugins)
            {
                logger.Info($"Loading {plugin.FullName}");

                // Load include files
                foreach (var includeName in plugin.Server?.Include ?? new List <string>())
                {
                    var includeFile = Path.Combine("plugins", plugin.Name.Vendor, plugin.Name.Project, $"{includeName}.net.dll");
                    if (!File.Exists(includeFile))
                    {
                        throw new FileNotFoundException(includeFile);
                    }

                    AppDomain.CurrentDomain.Load(File.ReadAllBytes(includeFile));
                }

                // Load main files
                foreach (var mainName in plugin.Server?.Main ?? new List <string>())
                {
                    var mainFile = Path.Combine("plugins", plugin.Name.Vendor, plugin.Name.Project, $"{mainName}.net.dll");
                    if (!File.Exists(mainFile))
                    {
                        throw new FileNotFoundException(mainFile);
                    }

                    var types = Assembly.LoadFrom(mainFile).GetTypes().Where(t => !t.IsAbstract && t.IsClass).ToList();

                    // Find migrations
                    foreach (var migrationType in types.Where(t => t.BaseType != null && t.BaseType.IsGenericType && t.BaseType.GetGenericTypeDefinition() == typeof(MigrationConfiguration <>)))
                    {
                        var configuration = (DbMigrationsConfiguration)Activator.CreateInstance(migrationType);
                        var migrator      = new DbMigrator(configuration);

                        if (!migrator.GetPendingMigrations().Any())
                        {
                            continue;
                        }

                        if (!ServerConfiguration.AutomaticMigrations)
                        {
                            throw new MigrationsPendingException($"Plugin {plugin.FullName} has pending migrations but automatic migrations are disabled");
                        }

                        foreach (var migration in migrator.GetPendingMigrations())
                        {
                            new Logger(config.Log.Core, "Database").Debug($"[{mainName}] Running migration: {migration}");

                            migrator.Update(migration);
                        }
                    }

                    // Find controllers
                    foreach (var controllerType in types.Where(t => t.IsSubclassOf(typeof(Controller)) || t.IsSubclassOf(typeof(ConfigurableController <>))))
                    {
                        var logLevel = config.Log.Plugins.ContainsKey(plugin.Name) ? config.Log.Plugins[plugin.Name] : pluginDefaultLogLevel;

                        var constructorArgs = new List <object>
                        {
                            new Logger(logLevel, plugin.Name),
                            events,
                            new RpcHandler(),
                            rcon
                        };

                        // Check if controller is configurable
                        if (controllerType.BaseType != null && controllerType.BaseType.IsGenericType && controllerType.BaseType.GetGenericTypeDefinition() == typeof(ConfigurableController <>))
                        {
                            // Initialize the controller configuration
                            constructorArgs.Add(ConfigurationManager.InitializeConfig(plugin.Name, controllerType.BaseType.GetGenericArguments()[0]));
                        }

                        // Resolve IoC arguments
                        constructorArgs.AddRange(controllerType.GetConstructors()[0].GetParameters().Skip(constructorArgs.Count).Select(p => container.Resolve(p.ParameterType)));

                        Controller controller = null;

                        try
                        {
                            // Construct controller instance
                            controller = (Controller)Activator.CreateInstance(controllerType, constructorArgs.ToArray());
                        }
                        catch (Exception ex)
                        {
                            // TODO: Dispose of controller

                            logger.Error(ex, $"Unhandled exception in plugin {plugin.FullName}");
                        }

                        if (controller == null)
                        {
                            continue;
                        }

                        try
                        {
                            await controller.Loaded();

                            if (!this.controllers.ContainsKey(plugin.Name))
                            {
                                this.controllers.Add(plugin.Name, new List <Controller>());
                            }
                            this.controllers[plugin.Name].Add(controller);
                        }
                        catch (Exception ex)
                        {
                            // TODO: Dispose of controller

                            logger.Error(ex, $"Unhandled exception loading plugin {plugin.FullName}");
                        }
                    }
                }
            }

#pragma warning disable 4014
            foreach (var controller in this.controllers.SelectMany(c => c.Value))
            {
                controller.Started();
            }
#pragma warning restore 4014

            rcon.Controllers = this.controllers;

            new RpcHandler().Event(SDK.Core.Rpc.RpcEvents.ClientPlugins).On(e => e.Reply(graph.Plugins));

            events.Raise(ServerEvents.ServerInitialized);

            logger.Debug($"{graph.Plugins.Count} plugin(s) loaded, {this.controllers.Count} controller(s) created");
        }