Stack Overflow上有一些类似的问题,但并不是我要找的。我想根据运行时条件进行Ninject绑定,这在启动时是未知的。Stack Overflow上其他关于动态绑定的问题都是围绕着基于配置文件等进行绑定 - 我需要根据处理特定实体的数据时基于数据库值进行条件绑定。例如,
public class Partner
{
public int PartnerID { get; set; }
public string ExportImplementationAssembly { get; set; }
}
public interface IExport
{
void ExportData(DataTable data);
}
此外,我有两个实现了IExport接口的动态链接库(dlls)。
public PartnerAExport : IExport
{
private readonly _db;
public PartnerAExport(PAEntities db)
{
_db = db;
}
public void ExportData(DataTable data)
{
// export parter A's data...
}
}
然后针对伙伴B;
public PartnerBExport : IExport
{
private readonly _db;
public PartnerBExport(PAEntities db)
{
_db = db;
}
public void ExportData(DataTable data)
{
// export parter B's data...
}
}
当前的Ninject绑定为:
public class NinjectWebBindingsModule : NinjectModule
{
public override void Load()
{
Bind<PADBEntities>().ToSelf();
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
);
}
}
那么,我该如何设置绑定方式,以便我可以执行以下操作;
foreach (Partner partner in _db.Partners)
{
// pseudocode...
IExport exportModule = ninject.Resolve<IExport>(partner.ExportImplementationAssembly);
exportModule.ExportData(_db.GetPartnerData(partner.PartnerID));
}
这是否可能?看起来应该是可能的,但我不知道如何处理。上面的绑定配置对于静态绑定非常有效,但我需要在运行时解析一些东西。这是否可行,还是我必须绕过Ninject并使用老式反射来加载插件?如果是这样,我如何使用该方法通过Ninject解析任何构造函数参数,就像静态绑定的对象一样?
更新:我已经使用BatteryBackupUnit的解决方案更新了我的代码,现在我有以下内容;
Bind<PADBEntities>().ToSelf().InRequestScope();
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
.Configure(c => c.InRequestScope())
);
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.Modules.*.dll")
.SelectAllClasses()
.InheritedFrom<IExportService>()
.BindSelection((type, baseTypes) => new[] { typeof(IExportService) })
);
Kernel.Bind<IExportServiceDictionary>().To<ExportServiceDictionary>().InSingletonScope();
ExportServiceDictionary dictionary = KernelInstance.Get<ExportServiceDictionary>();
在2个测试模块中实例化导出实现可以正常工作并且成功实例化
PADBEntites
上下文。然而,我的服务层中的所有其他绑定现在都不再适用于系统的其余部分。同样,如果我将PADBEntities
变量/构造函数参数更改为ISomeEntityService
组件,则无法绑定导出层。似乎我缺少最后一步来配置绑定以使其正常工作。有什么想法吗?错误:“Error activating ISomeEntityService. No matching bindings are available and the type is not self-bindable”。
更新2:通过使用
BatteryBackupUnit
的解决方案进行了一些试验和错误,最终将其搞定,但我对跳跃的障碍不是很满意。欢迎任何更简洁的解决方案。我更改了原始约定绑定为:
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
);
转而更加冗长和明确;
Bind<IActionService>().To<ActionService>().InRequestScope();
Bind<IAuditedActionService>().To<AuditedActionService>().InRequestScope();
Bind<ICallService>().To<CallService>().InRequestScope();
Bind<ICompanyService>().To<CompanyService>().InRequestScope();
//...and so on for 30+ lines
虽然这不是我最喜欢的解决方案,但它可以与显式和基于约定的绑定一起使用,但不能与两个约定一起使用。有人能看出我的绑定有什么问题吗?
更新3:忽略更新2中的绑定问题。似乎我发现了Ninject的一个bug,与在引用库中有多个绑定模块有关。即使从未通过断点命中模块A的更改也会破坏明确使用不同模块B的项目。太难以理解了。
IExport
。对于第一种约定,您应该排除所有IExport
。我建议您创建一个新的问题,询问如何形成问题。也许像codereview或程序员这样的其他SE平台会更好。建议:为所有以“Service”结尾的类型制定一个约定,并特别绑定所有其他类型。此外,如果有更具体的绑定,它们可以放入特定程序集的NinjectModule
中。 - BatteryBackupUnitIExport
的上下文绑定以及如何设计传统绑定的问题应该分开。"如何设计"传统绑定不适合在SO上提问。具体问题=>如何排除某个类型是SO上的好问题。答案:您可以使用Where
过滤方法来排除所有实现IExport
的类型。有关约定的更多信息,请参见此处。 - BatteryBackupUnit