Загрузка модулей во всех сборках в Ninject - PullRequest
14 голосов
/ 26 октября 2011

У меня есть несколько библиотек классов в моем проекте, и все используют Ninject IoC контейнер.Я хотел загрузить все модули в StandardKernel за один раз, где бы INinjectModule не было найдено.Поэтому я использовал:

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

Но по какой-то причине это не работает.Кто-нибудь может помочь?

Ответы [ 4 ]

20 голосов
/ 26 октября 2011

Что ж, это часто случается, когда привязки объявляются, но другие модули загружаются там, где этот модуль пытается разрешить привязку, которая еще не загружена. Это происходит потому, что 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;
    }
}
3 голосов
/ 17 мая 2016

Еще одна вещь, которую вы должны проверить, является ли класс, который расширяет NinjectModule, открытым, иначе он не будет виден в сборке.

0 голосов
/ 11 декабря 2017

Вы можете использовать отражение, чтобы найти и создать экземпляры модулей Ninject:

BuildManager.GetReferencedAssemblies()
    .Cast<Assembly>()
    .SelectMany(a => a.DefinedTypes)
    .Where(t => typeof(INinjectModule).IsAssignableFrom(t))
    .Select(t => (INinjectModule)Activator.CreateInstance(t))
0 голосов
/ 26 октября 2017

Я думаю, что не рекомендуется использовать CurrentDomain.GetAllAssemblies (), потому что не все сборки проекта могут быть загружены при запуске программы (некоторые сборки могут быть загружены, например, при действиях пользователя или других событиях). В этом случае у вас будут исключения с нулевой ссылкой для зависимостей.

...