使用Ninject进行依赖注入:解决重复模块加载错误及同名接口多实例注入问题
Great job figuring out the core fix for your multi-instance injection issue! Let's break down what was causing the error and solidify all the correct steps for your setup.
Why You Got the "Duplicate Module Load" Error
Looking at your original GetService<T> method, the problem is clear:
public static T GetService<T>( string pathDbError, string pathDbLog, Code _code,Code _code1) { var kernel = new StandardKernel( new DependecyInjection(pathDbError, pathDbLog, _code), new DependecyInjection(pathDbError, pathDbLog, _code1) ); return kernel.Get<T>(); }
You're instantiating two identical DependecyInjection modules and passing both to StandardKernel. Ninject throws that error because it detects the same module being registered multiple times—each module instance would try to re-bind the same services (like IDataBaseService, ISocketDeviceDal), causing binding conflicts.
Fix 1: Eliminate Duplicate Module Loading
Instead of creating two instances of your module, consolidate all your bindings into a single module instance. You can modify your module to accept both _codeLocal and _codeRemote parameters, then register both named IModbusActuatorService bindings within that single module.
For example, update your module's constructor:
public class DependecyInjection : NinjectModule { private readonly string _pathDbError; private readonly string _pathDbLog; private readonly Code _codeLocal; private readonly Code _codeRemote; public DependecyInjection(string pathDbError, string pathDbLog, Code codeLocal, Code codeRemote) { _pathDbError = pathDbError; _pathDbLog = pathDbLog; _codeLocal = codeLocal; _codeRemote = codeRemote; } public override void Load() { // Existing core bindings Bind<IDataBaseService>().To<DataBaseManager>().WithConstructorArgument("path", _pathDbLog); Bind<IDataBaseErrorService>().To<DataBaseErrorManager>().WithConstructorArgument("path", _pathDbError); Bind<ISocketDeviceDal>().To<SocketDeviceDal>(); Bind<IKamciAntennaService>().To<KamciAntennaManager>(); // Add both named bindings for IModbusActuatorService Bind<IModbusActuatorService>() .To<ModbusActuatorManager>() .InTransientScope() .Named("Local") .WithConstructorArgument("code", _codeLocal); Bind<IModbusActuatorService>() .To<ModbusActuatorManager>() .InTransientScope() .Named("Remote") .WithConstructorArgument("code", _codeRemote); } }
Then update your GetService<T> method to only load the module once:
public static T GetService<T>(string pathDbError, string pathDbLog, Code codeLocal, Code codeRemote) { var kernel = new StandardKernel(new DependecyInjection(pathDbError, pathDbLog, codeLocal, codeRemote)); return kernel.Get<T>(); }
Fix 2: Correct Multi-Instance Injection for IModbusActuatorService
Your modified code uses Ninject's [Named] attribute, which is the perfect approach here—let's clarify why each part matters:
Step 1: Mark Constructor Parameters with Names
public EsyonluAntennaManager( [Named("Local")]IModbusActuatorService dksEkbService1, [Named("Remote")] IModbusActuatorService dksEkbService2 ) { _dksEkbService1 = dksEkbService1; _dksEkbService2 = dksEkbService2; }
The [Named] attribute tells Ninject exactly which bound instance to inject for each parameter, so it doesn't get confused between two implementations of the same interface.
Step 2: Bind Instances with Matching Names + Proper Scope
Bind<IModbusActuatorService>().To<ModbusActuatorManager>().InTransientScope().Named("Remote").WithConstructorArgument("code", _codeRemote); Bind<IModbusActuatorService>().To<ModbusActuatorManager>().InTransientScope().Named("Local").WithConstructorArgument("code", _codeLocal);
InTransientScope(): Critical here because eachModbusActuatorManagerneeds a uniqueCodevalue. Transient scope ensures Ninject creates a new instance every time this binding is resolved, so the two services don't share state or the wrongCode..Named("X"): Matches the[Named("X")]attribute in your constructor, linking the parameter to the correct binding..WithConstructorArgument: Passes the specificCodevalue each instance needs.
Fix 3: Correct Injection for IKamciAntennaService
Your original binding Bind<IKamciAntennaService>().To<KamciAntennaManager>() is already valid—as long as KamciAntennaManager's constructor dependencies are all properly bound in your module.
If KamciAntennaManager has its own constructor parameters (e.g., it needs IDataBaseService or another dependency), just make sure those interfaces are bound in your DependecyInjection module the same way you did for your other services. If you ever need multiple instances of IKamciAntennaService, you can apply the same [Named] + named binding pattern you used for IModbusActuatorService.
Key Takeaways
- Never load the same Ninject module multiple times: This causes duplicate binding conflicts and the error you saw. Consolidate all bindings into a single module instance.
- Use named bindings for multiple instances of the same interface: Ninject's
[Named]attribute and.Named()binding method are the standard way to distinguish between different instances of the same interface. - Choose the right scope: Use
InTransientScope()when you need unique, independent instances; useInSingletonScope()only if you want a single shared instance across your application.
内容的提问来源于stack exchange,提问作者user14360671

