【问题标题】:Loading modules in all assemblies in Ninject在 Ninject 的所有程序集中加载模块
【发布时间】:2023-04-09 07:08:01
【问题描述】:

我的项目中有几个类库,并且都使用Ninject IoC 容器。我想在找到INinjectModule 的任何地方一次将所有模块加载到StandardKernel 中。所以我用了:

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

但这由于某种原因不起作用。有人可以帮忙吗?

【问题讨论】:

  • 不确定您是否可以在一行中做到这一点。 stackoverflow.com/questions/1694640/…
  • 请检查 AppDomain.CurrentDomain.GetAssemblies() 返回的内容,可能您要查找的程序集尚未加载?
  • @tpeczek 我已经检查过了。我所有的程序集都在List 以及系统组件中
  • @JasonEvans 我试过了,但也没有用:(
  • @DelwarKhondokar 在这种情况下,我只能要求您检查您的模块是否是具有公共无参数构造函数的公共非抽象类。

标签: c# asp.net ninject


【解决方案1】:

好吧,这通常发生在声明绑定但加载其他模块时,该模块试图解析尚未加载的绑定。发生这种情况是因为List<INinjectModule> 的顺序可能不正确。

如果您认为是这种情况。遵循此决议。

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

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

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;
    }
}

【讨论】:

  • 精彩的答案!但是,在搜索了一段时间后,为什么在 Global.asax 的 Application_Start 上没有调用我所有的程序集,我发现了这个有趣的线程:stackoverflow.com/questions/18656821/…。不使用 AppDomain.CurrentDomain.GetAssemblies(),而是调用 var assembly = BuildManager.GetReferencedAssemblies();
【解决方案2】:

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

【讨论】:

  • 这拯救了我的一天:)
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多