ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c# – Ninject动态绑定到实现

2019-06-09 06:55:17  阅读:233  来源: 互联网

标签:c ninject ninject-extensions ninject-conventions


关于SO的几个问题是相似的,但不完全是我正在寻找的.我想基于运行时条件进行Ninject绑定,这在启动时是不可预知的.关于动态绑定的SO的其他问题围绕基于配置文件或某些类似的绑定 – 我需要在处理特定实体的数据时基于数据库值有条件地发生.例如.,

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

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

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

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变量/ ctor参数更改为ISomeEntityService组件,则无法绑定导出层.似乎我错过了配置绑定以使其工作的最后一步.有什么想法吗?

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

更新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:忽略Update 2中绑定的问题.看来我在Ninject中发现了一个与引用库中有多个绑定模块有关的错误.模块A的更改,即使从未通过断点命中,也会使用不同的模块B明确地破坏项目.

解决方法:

重要的是要注意,虽然实际的“条件匹配”是运行时条件,但实际上您事先知道可能的匹配集(至少在构建容器时启动时) – 这可以通过使用约定来证明.这就是条件/上下文绑定的含义(在Ninject WIKI中有描述,并在几个问题中有所介绍).所以你实际上不需要在任意运行时间进行绑定,而只需要在任意时间进行分辨率/选择(分辨率实际上可以提前完成=>提前失败).

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

>在启动时创建所有绑定
>提前失败:验证启动时的绑定(通过实例化所有绑定的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可以注入到任何组件中,就像“必需”一样使用:

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

标签:c,ninject,ninject-extensions,ninject-conventions
来源: https://codeday.me/bug/20190609/1203306.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有