From 1ac9db445ba2342b1d8bd76d31309bbc09ca89bb Mon Sep 17 00:00:00 2001 From: kevindaub Date: Sun, 24 Apr 2016 19:34:05 -0400 Subject: [PATCH] Added Safe Module Loading - Added extension method to safely load a module by first checking if it was already loaded. - Added setting to safely load a module by first checking if it was already loaded. --- .../WhenLoadIsCalledWithModule.cs | 38 +++++++++++++++++++ src/Ninject/INinjectSettings.cs | 10 +++++ src/Ninject/KernelConfiguration.cs | 10 ++++- src/Ninject/NinjectSettings.cs | 14 +++++++ src/Ninject/Syntax/ModuleLoadExtensions.cs | 27 +++++++++++++ 5 files changed, 98 insertions(+), 1 deletion(-) diff --git a/src/Ninject.Test/Integration/ModuleLoadingTests/WhenLoadIsCalledWithModule.cs b/src/Ninject.Test/Integration/ModuleLoadingTests/WhenLoadIsCalledWithModule.cs index 0b37a1d2..3e0615d5 100644 --- a/src/Ninject.Test/Integration/ModuleLoadingTests/WhenLoadIsCalledWithModule.cs +++ b/src/Ninject.Test/Integration/ModuleLoadingTests/WhenLoadIsCalledWithModule.cs @@ -76,6 +76,23 @@ public void TwoModulesWithSameNamesAreNotSupported() moduleLoadingAction.ShouldThrow(); } + [Fact] + public void TwoModulesWithSameNamesDoesNotLoadSecondModule() + { + const string ModuleName = "SomeModuleName"; + var moduleMock1 = this.CreateModuleMock(ModuleName); + var module1 = moduleMock1.Object; + var moduleMock2= this.CreateModuleMock(ModuleName); + var module2 = moduleMock2.Object; + + this.Kernel.LoadIfNotLoaded(module1); + this.Kernel.LoadIfNotLoaded(module2); + + this.Kernel.GetModules().Should().BeEquivalentTo(module1); + moduleMock1.Verify(x => x.OnLoad(this.Kernel), Times.Once()); + moduleMock2.Verify(x => x.OnLoad(this.Kernel), Times.Never()); + } + [Fact] public void ModuleWithSameNameCanBeLoadedAfterTheFirstIsUnloaded() { @@ -114,6 +131,27 @@ public void ModulesAreVerifiedAfterAllModulesAreLoaded() orderStringBuilder.ToString().Should().Be("LoadModule1 LoadModule2 VerifyModule VerifyModule "); } + + [Fact] + public void ModulesAreVerifiedAfterAllModulesAreLoadedExcludingPreviouslyLoadedModules() + { + var moduleMock1 = this.CreateModuleMock("SomeName1"); + var moduleMock2 = this.CreateModuleMock("SomeName1"); + var moduleMock3 = this.CreateModuleMock("SomeName2"); + var orderStringBuilder = new StringBuilder(); + + moduleMock1.Setup(m => m.OnLoad(this.Kernel)).Callback(() => orderStringBuilder.Append("LoadModule1 ")); + moduleMock3.Setup(m => m.OnLoad(this.Kernel)).Callback(() => orderStringBuilder.Append("LoadModule2 ")); + moduleMock1.Setup(m => m.OnVerifyRequiredModules()).Callback(() => orderStringBuilder.Append("VerifyModule ")); + moduleMock3.Setup(m => m.OnVerifyRequiredModules()).Callback(() => orderStringBuilder.Append("VerifyModule ")); + + this.Kernel.Settings.LoadModuleIfNotLoaded = true; + this.Kernel.Load(moduleMock1.Object, moduleMock2.Object, moduleMock3.Object); + + orderStringBuilder.ToString().Should().Be("LoadModule1 LoadModule2 VerifyModule VerifyModule "); + moduleMock2.Verify(m => m.OnLoad(this.Kernel), Times.Never()); + moduleMock2.Verify(m => m.OnVerifyRequiredModules(), Times.Never()); + } } } #endif diff --git a/src/Ninject/INinjectSettings.cs b/src/Ninject/INinjectSettings.cs index 1fbe9540..144f85eb 100644 --- a/src/Ninject/INinjectSettings.cs +++ b/src/Ninject/INinjectSettings.cs @@ -90,6 +90,16 @@ public interface INinjectSettings /// true if null is allowed as injected value otherwise false. bool AllowNullInjection { get; set; } + /// + /// Gets or sets a value indicating whether only unloaded modules be loaded. + /// If the module is not loaded, it will load the module; otherwise, it will skip + /// loading the module. + /// By default this is disabled and whenever a module is loaded and has already been + /// loaded, an exception is thrown. + /// + /// trueModule is loaded only if it has not been loaded; otherwise, false. + bool LoadModuleIfNotLoaded { get; set; } + /// /// Gets the value for the specified key. /// diff --git a/src/Ninject/KernelConfiguration.cs b/src/Ninject/KernelConfiguration.cs index ccd0a72c..a88dae05 100644 --- a/src/Ninject/KernelConfiguration.cs +++ b/src/Ninject/KernelConfiguration.cs @@ -147,7 +147,15 @@ public void Load(IEnumerable m) if (this.modules.TryGetValue(module.Name, out existingModule)) { - throw new NotSupportedException(ExceptionFormatter.ModuleWithSameNameIsAlreadyLoaded(module, existingModule)); + if (this.Settings.LoadModuleIfNotLoaded) + { + // Go to next module because this one was loaded + continue; + } + else + { + throw new NotSupportedException(ExceptionFormatter.ModuleWithSameNameIsAlreadyLoaded (module, existingModule)); + } } module.OnLoad(this); diff --git a/src/Ninject/NinjectSettings.cs b/src/Ninject/NinjectSettings.cs index 53ebc0f4..85a08be5 100644 --- a/src/Ninject/NinjectSettings.cs +++ b/src/Ninject/NinjectSettings.cs @@ -158,6 +158,20 @@ public bool AllowNullInjection set { this.Set("AllowNullInjection", value); } } + /// + /// Gets or sets a value indicating whether only unloaded modules be loaded. + /// If the module is not loaded, it will load the module; otherwise, it will skip + /// loading the module. + /// By default this is disabled and whenever a module is loaded and has already been + /// loaded, an exception is thrown. + /// + /// trueModule is loaded only if it has not been loaded; otherwise, false. + public bool LoadModuleIfNotLoaded + { + get { return this.Get("LoadModuleIfNotLoaded", false); } + set { this.Set("LoadModuleIfNotLoaded", value); } + } + /// /// Gets the value for the specified key. /// diff --git a/src/Ninject/Syntax/ModuleLoadExtensions.cs b/src/Ninject/Syntax/ModuleLoadExtensions.cs index a124468e..cdad8885 100644 --- a/src/Ninject/Syntax/ModuleLoadExtensions.cs +++ b/src/Ninject/Syntax/ModuleLoadExtensions.cs @@ -42,6 +42,33 @@ public static void Load(this IKernelConfiguration kernelConfiguration, params IN kernelConfiguration.Load(modules); } + /// + /// Creates a new instance of the module and loads it into the kernel if it is not loaded. + /// + /// The type of module. + /// The kernel configuration into which the module is loaded. + public static void LoadIfNotLoaded(this IKernelConfiguration kernelConfiguration) + where TModule : INinjectModule, new() + { + kernelConfiguration.LoadIfNotLoaded(new TModule()); + } + + /// + /// Loads the module(s) into the kernel if the module is not loaded. + /// + /// The kernel configuration. + /// The modules to load into which the modules are loaded. + public static void LoadIfNotLoaded(this IKernelConfiguration kernelConfiguration, params INinjectModule[] modules) + { + foreach (var module in modules) + { + if (kernelConfiguration.HasModule(module.Name)) + { + kernelConfiguration.Load(module); + } + } + } + #if !NO_ASSEMBLY_SCANNING /// /// Loads modules from the files that match the specified pattern(s).