Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Safe Module Loading #210

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,23 @@ public void TwoModulesWithSameNamesAreNotSupported()
moduleLoadingAction.ShouldThrow<NotSupportedException>();
}

[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()
{
Expand Down Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions src/Ninject/INinjectSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ public interface INinjectSettings
/// <value><c>true</c> if null is allowed as injected value otherwise false.</value>
bool AllowNullInjection { get; set; }

/// <summary>
/// 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.
/// </summary>
/// <value><c>true</c>Module is loaded only if it has not been loaded; otherwise, <c>false</c>.</value>
bool LoadModuleIfNotLoaded { get; set; }

/// <summary>
/// Gets the value for the specified key.
/// </summary>
Expand Down
10 changes: 9 additions & 1 deletion src/Ninject/KernelConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,15 @@ public void Load(IEnumerable<INinjectModule> 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);
Expand Down
14 changes: 14 additions & 0 deletions src/Ninject/NinjectSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,20 @@ public bool AllowNullInjection
set { this.Set("AllowNullInjection", value); }
}

/// <summary>
/// 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.
/// </summary>
/// <value><c>true</c>Module is loaded only if it has not been loaded; otherwise, <c>false</c>.</value>
public bool LoadModuleIfNotLoaded
{
get { return this.Get("LoadModuleIfNotLoaded", false); }
set { this.Set("LoadModuleIfNotLoaded", value); }
}

/// <summary>
/// Gets the value for the specified key.
/// </summary>
Expand Down
27 changes: 27 additions & 0 deletions src/Ninject/Syntax/ModuleLoadExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,33 @@ public static void Load(this IKernelConfiguration kernelConfiguration, params IN
kernelConfiguration.Load(modules);
}

/// <summary>
/// Creates a new instance of the module and loads it into the kernel if it is not loaded.
/// </summary>
/// <typeparam name="TModule">The type of module.</typeparam>
/// <param name="kernelConfiguration">The kernel configuration into which the module is loaded.</param>
public static void LoadIfNotLoaded<TModule>(this IKernelConfiguration kernelConfiguration)
where TModule : INinjectModule, new()
{
kernelConfiguration.LoadIfNotLoaded(new TModule());
}

/// <summary>
/// Loads the module(s) into the kernel if the module is not loaded.
/// </summary>
/// <param name="kernelConfiguration">The kernel configuration.</param>
/// <param name="modules">The modules to load into which the modules are loaded.</param>
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
/// <summary>
/// Loads modules from the files that match the specified pattern(s).
Expand Down