在Ninject的所有程序集中加载模块

本文关键字:程序集 集中 加载 模块 程序 Ninject | 更新日期: 2023-09-27 18:12:22

我在我的项目中有几个类库,所有都使用Ninject IoC容器。我想一次加载StandardKernel中的所有模块,只要找到INinjectModule。所以我使用:

var kernel = new StandardKernel();
kernel.Load(AppDomain.CurrentDomain.GetAssemblies())

但由于某些原因,这不起作用。有人能帮忙吗?

在Ninject的所有程序集中加载模块

嗯,这种情况经常发生在声明了绑定,但加载了其他模块,而该模块试图解析尚未加载的绑定时。这是因为List<INinjectModule>可能没有按正确的顺序排列。

如果你认为是这样的话。

我们的想法是,我们将有一个bootstapper为每个程序集,其中引导程序将负责加载模块在其逻辑顺序。

让我们考虑一个bootstrapper的接口(我们将使用它在程序集中查找bootstrapper)

public interface INinjectModuleBootstrapper
{
    IList<INinjectModule> GetModules();
}

现在考虑您的DataAccess程序集,实现INinjectModuleBootstrapper:

public class DataAccessBootstrapper : INinjectModuleBootstrapper
{
    public IList<INinjectModule> GetModules()
    {
        //this is where you will be considering priority of your modules.
        return new List<INinjectModule>()
                   {
                       new DataObjectModule(),
                       new RepositoryModule(),
                       new DbConnectionModule()
                   };
        //RepositoryModule cannot be loaded until DataObjectModule is loaded
        //as it is depended on DataObjectModule and DbConnectionModule has
        //dependency on RepositoryModule
    }
}

这就是为所有程序集定义Bootstrapper的方式。现在,从程序启动开始,我们需要加载所有模块的StandardKernel。我们将这样写:

var assemblies = AppDomain.CurrentDomain.GetAssemblies();
return BootstrapHelper.LoadNinjectKernel(assemblies);

我们的BootstrapperHelper类是:

public static class BootstrapHelper
{
    public static StandardKernel LoadNinjectKernel(IEnumerable<Assembly> assemblies)
    {
        var standardKernel = new StandardKernel();
        foreach (var assembly in assemblies)
        {
            assembly
                .GetTypes()
                .Where(t =>
                       t.GetInterfaces()
                           .Any(i =>
                                i.Name == typeof(INinjectModuleBootstrapper).Name))
                .ToList()
                .ForEach(t =>
                             {
                                 var ninjectModuleBootstrapper =
                                     (INinjectModuleBootstrapper)Activator.CreateInstance(t);
                                 standardKernel.Load(ninjectModuleBootstrapper.GetModules());
                             });
        }
        return standardKernel;
    }
}

你应该检查的另一件事是,如果扩展了NinjectModule的类是公共的,否则它将不会在程序集中可见。

我认为使用CurrentDomain.GetAllAssemblies()不是一个好主意,因为不是所有的项目程序集都可以在程序启动时加载(有些程序集可以在用户操作中加载,例如或其他事件)。在这种情况下,您将对依赖项有空引用异常。

您可以使用反射来查找和实例化Ninject模块:

BuildManager.GetReferencedAssemblies()
    .Cast<Assembly>()
    .SelectMany(a => a.DefinedTypes)
    .Where(t => typeof(INinjectModule).IsAssignableFrom(t))
    .Select(t => (INinjectModule)Activator.CreateInstance(t))