如何让Ninject在模块被重复加载时立即抛出异常?
Great question—this is exactly the kind of elusive, intermittent bug that can waste hours of debugging time. The good news is you can absolutely enforce a "fail fast" rule when a Ninject module tries to load twice. Here are two reliable approaches:
1. Custom Base Module with Load Tracking
Create a reusable base module class that tracks which module types have already been loaded. Derive all your modules (like CoreModule and WebAPIModule) from this base class to automatically get duplicate-checking behavior:
using Ninject.Modules; using System; using System.Collections.Generic; public abstract class SafeNinjectModule : NinjectModule { // Static set to track loaded module types across the app private static readonly HashSet<Type> _loadedModuleTypes = new HashSet<Type>(); public sealed override void Load() { var currentModuleType = GetType(); // Try to add the module type to the set—if it fails, it's already loaded if (!_loadedModuleTypes.Add(currentModuleType)) { throw new InvalidOperationException( $"Module '{currentModuleType.FullName}' is being loaded for the second time. " + "Duplicate module loads cause unpredictable behavior and are not allowed."); } // Delegate to the derived module's actual load logic LoadModule(); } // Derived modules implement this instead of overriding Load() protected abstract void LoadModule(); }
How to Use It
Update your existing modules to inherit from SafeNinjectModule and move your original Load() code into LoadModule():
public class CoreModule : SafeNinjectModule { protected override void LoadModule() { // Your original CoreModule bindings go here Bind<ISomeService>().To<SomeServiceImpl>(); } } public class WebAPIModule : SafeNinjectModule { // Your dependency module field public override IEnumerable<INinjectModule> Modules => new[] { new CoreModule() }; protected override void LoadModule() { // Your WebAPIModule bindings go here Bind<IWebService>().To<WebServiceImpl>(); } }
The first time a module loads, it gets added to the static set. The second time Load() is called, the Add() method returns false, triggering an immediate exception that points directly to the duplicate load.
2. Kernel-Level Module Load Tracking
If you can't modify your module base classes (e.g., for third-party modules), you can hook into Ninject's ModuleLoaded event on the kernel itself to track and block duplicates:
using Ninject; using Ninject.Modules; using System; using System.Collections.Generic; // Initialize your kernel var kernel = new StandardKernel(); var loadedModules = new HashSet<Type>(); // Subscribe to the ModuleLoaded event to check for duplicates kernel.ModuleLoaded += (sender, eventArgs) => { var moduleType = eventArgs.Module.GetType(); if (!loadedModules.Add(moduleType)) { throw new InvalidOperationException( $"Duplicate module detected: '{moduleType.FullName}'. " + "This module has already been loaded into the kernel."); } }; // Load your modules as usual kernel.Load<WebAPIModule>();
This approach checks every module that gets loaded into the kernel, regardless of how it's loaded (directly, via dependencies, etc.). It's a great option for global enforcement without changing existing module code.
Key Notes
- Both methods use a static
HashSet<Type>to track loaded modules, which ensures even if modules are loaded through different paths (e.g., direct load + dependency load), duplicates are caught immediately. - The immediate exception eliminates those "sometimes works, sometimes doesn't" bugs by failing fast instead of letting duplicate bindings cause subtle runtime issues.
内容的提问来源于stack exchange,提问作者Sean Sherman

