gpt4 book ai didi

c# - Ninject 动态绑定(bind)到实现

转载 作者:太空狗 更新时间:2023-10-29 23:13:48 25 4
gpt4 key购买 nike

Stack Overflow 上有几个类似但不完全是我要找的问题。我想根据运行时条件进行 Ninject 绑定(bind),这在启动时是未知的。关于动态绑定(bind)的 Stack Overflow 的其他问题围绕基于配置文件或类似文件的绑定(bind)展开——我需要它在处理特定实体的数据时基于数据库值有条件地发生。例如,

public class Partner
{
public int PartnerID { get; set; }
public string ExportImplementationAssembly { get; set; }
}

public interface IExport
{
void ExportData(DataTable data);
}

在其他地方,我有 2 个实现 IExport 的 dll

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 绑定(bind)是;

public class NinjectWebBindingsModule : NinjectModule
{
public override void Load()
{
Bind<PADBEntities>().ToSelf();
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
);
}
}

那么我该如何设置绑定(bind)才能做到这一点;

foreach (Partner partner in _db.Partners)
{
// pseudocode...
IExport exportModule = ninject.Resolve<IExport>(partner.ExportImplementationAssembly);
exportModule.ExportData(_db.GetPartnerData(partner.PartnerID));
}

这可能吗?似乎应该如此,但我不太清楚如何去做。上面的现有绑定(bind)配置适用于静态绑定(bind),但我需要一些我可以在运行时解决的问题。以上是可能的还是我只需要绕过 Ninject 并使用老式反射加载插件?如果是这样,我如何使用该方法通过 Ninject 解析任何构造函数参数,就像静态绑定(bind)对象一样?

更新:我已经用 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 上下文就好了。但是,我的服务层中的所有其他绑定(bind)现在不再适用于系统的其余部分。同样,如果我将 PADBEntities 变量/ctor 参数更改为 ISomeEntityService 组件,我将无法绑定(bind)导出层。看来我错过了配置绑定(bind)以完成这项工作的最后一步。有什么想法吗?

错误:“激活 ISomeEntityService 时出错。没有匹配的绑定(bind)可用且类型不可自绑定(bind)”

更新 2:最终使用 BatteryBackupUnit 的解决方案进行了一些试验和错误,但我对跳转思想不太满意。欢迎任何其他更简洁的解决方案。

我改变了原来的约定绑定(bind);

        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

这不是我最喜欢的解决方案,但它适用于显式绑定(bind)和基于约定的绑定(bind),但不适用于两种约定。任何人都可以看出我的绑定(bind)哪里出了问题吗?

更新 3:忽略更新 2 中的绑定(bind)问题。看来我在 Ninject 中发现了一个错误,该错误与引用库中的多个绑定(bind)模块有关。模块 A 中的更改,即使从未通过断点命中,也会显式地破坏使用不同模块 B 的项目。看图。

最佳答案

重要的是要注意,虽然实际的“条件匹配”是运行时条件,但您实际上提前知道了可能的匹配集(至少在构建容器时启动时)——使用约定证明了这一点.这就是条件/上下文绑定(bind)的意义所在(在 Ninject WIKI 中有描述,并在几个问题中有所涉及)。因此,您实际上不需要在任意运行时进行绑定(bind),而只需在任意时间进行解析/选择(解析实际上可以提前完成 => 提前失败)。

这是一个可能的解决方案,其特点是:

  • 在启动时创建所有绑定(bind)
  • 早期失败:启动时验证绑定(bind)(通过实例化所有绑定(bind)的 IExport)
  • 在任意运行时选择IExport

.

internal interface IExportDictionary
{
IExport Get(string key);
}

internal class ExportDictionary : IExportDictionary
{
private readonly Dictionary<string, IExport> dictionary;

public ExportDictionary(IEnumerable<IExport> exports)
{
dictionary = new Dictionary<string, IExport>();
foreach (IExport export in exports)
{
dictionary.Add(export.GetType().Assembly.FullName, export);
}
}

public IExport Get(string key)
{
return dictionary[key];
}
}

组合根:

// this is just going to bind the IExports.
// If other types need to be bound, go ahead and adapt this or add other bindings.
kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.InheritedFrom<IExport>()
.BindSelection((type, baseTypes) => new[] { typeof(IExport) }));

kernel.Bind<IExportDictionary>().To<ExportDictionary>().InSingletonScope();

// create the dictionary immediately after the kernel is initialized.
// do this in the "composition root".
// why? creation of the dictionary will lead to creation of all `IExport`
// that means if one cannot be created because a binding is missing (or such)
// it will fail here (=> fail early).
var exportDictionary = kernel.Get<IExportDictionary>();

现在 IExportDictionary 可以注入(inject)到任何组件中,就像“必需”一样使用:

foreach (Partner partner in _db.Partners)
{
// pseudocode...
IExport exportModule = exportDictionary.Get(partner.ExportImplementationAssembly);
exportModule.ExportData(_db.GetPartnerData(partner.PartnerID));
}

关于c# - Ninject 动态绑定(bind)到实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32437460/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com