Как использовать расширение Ninject Conventions без ссылки на сборку (или типы внутри нее) - PullRequest
18 голосов
/ 26 октября 2010

Извините за длинный вопрос, это долго, потому что я копаю в этом весь день.

Общая проблема:

У меня есть приложение ASP.Net MVC2 со следующими проектами: MyApp.Web, MyApp.Services, MyApp.Data.

Мы кодируем интерфейсы и используем Ninject 2 для DI / IoC.

Однако, я ужасно устал набирать текст (и забыл набрать):

Bind<ISomeService>.To<SomeService>;

Итак, зная о Ninject.Extensions.Convensions, я попытался использовать его для автоматического сканирования и регистрации модулей и простых зависимостей типа IXxxx => Xxxx.

То, что я пробовал, работает (но не совсем достаточно):

Я могу использовать следующий код для настройки Ninject, и кажется, что все настроено правильно.

    public static IKernel Initialize()
    {
        var kernel = new StandardKernel();

        kernel.Scan(a => {
                        a.FromAssemblyContaining<MyApp.Data.SomeDataClass>();
                        a.FromAssemblyContaining<MyApp.Services.SomeServiceClass>();
                        a.AutoLoadModules();
                        a.BindWithDefaultConventions();
                        a.InTransientScope();
                    });

        return kernel;
    }

Чего я хочу достичь вместо этого:

Однако ... Я хотел бы пойти немного дальше, я думаю, что поддерживается, но я не могу заставить его работать.

Поскольку наш проект MyApp.Web вообще ничего не использует (напрямую) из MyApp.Data, я стараюсь избегать ссылки на MyApp.Data. С помощью приведенного выше кода я должен ссылаться на MyApp.Data из MyApp.Web из-за ссылки времени компиляции на SomeDataClass.

Я бы предпочел указать имя сборки для сканирования и регистрации Ninject. Кажется, расширение Conventions поддерживает это с помощью перегрузок From, которые принимают строку (или перечисление строк).

Что я пробовал и как ломается:

Итак, я попробовал несколько вариантов перегрузок From:

    public static IKernel Initialize()
    {
        var kernel = new StandardKernel();

        kernel.Scan(a => {
                        a.From("MyApp.Data");
                        a.From("MyApp.Services.dll");
                        a.From("AnotherDependency, Version=1.0.0.0, PublicKeyToken=null"); //etc., etc. with the From(...)'s
                        a.AutoLoadModules();
                        a.BindWithDefaultConventions();
                        a.InTransientScope();
                    });

        return kernel;
    }

Но я получаю FileNotFoundExceptions с таким сообщением, как:

Не удалось загрузить файл или сборку 'file: /// C: \ Program Files (x86) \ Общие файлы \ Microsoft Общий \ DevServer \ 10.0 \ MyApp.Data» или одна из его зависимостей. Система не могу найти файл указано. ":" файл: /// C: \ Program Files (x86) \ Общие файлы \ Microsoft Общий \ DevServer \ 10,0 \

Что я нашел, пытаясь решить это сам:

Я проверил источник для Ninject.Extensions.Conventions, и я признаю, что совершенно заблудился относительно того, как это должно работать, но я могу видеть, что он делает.

Сканер сборок создает список сборок для сканирования при вызове различных методов FromXXX.

Когда я вызываю метод From ("assemblyName"), он сначала проверяет, содержит ли список уже какие-либо сборки, где assembly.AssemblyName.Name соответствует имени, которое я передал (а AssemblyName.Name - simple name, т.е. MyApp.Data, согласно MSDN).

Поток проходит через пару неважных методов, приземляясь в методе FindAssemblies. Этот метод принимает имя, которое я передал (которое мы уже видели, должно быть простым именем сборки). Затем он создает новое AssemblyName, с нашим переданным именем, используемым как AssemblyName.CodeBase.

Затем он пытается загрузить сборку во временный домен приложений. Это шаг, который завершается неудачей с вышеуказанным исключением.

Очевидно, что путь, который он ищет, неверен, но я не могу указать путь через метод From (). Это тоже не работает.

Я пробовал некоторые другие методы FromXXX, но я ни к чему не привел и уже потратил слишком много времени на это. Сопоставление FromAssembliesInPath и FromAssemblies также не работает, поскольку, опять же, он выполняет поиск в совершенно неправильном каталоге.

Э-э ... что за вопрос был снова:

Может кто-нибудь объяснить, как заставить Ninject Conventions загружать сборки по имени, не создавая ссылку на сборку и загружая ее, указав содержащийся тип? Пожалуйста.

Я уже просмотрел страницы и страницы группы Ninject google и прочитал только (как мне кажется) соответствующую документацию и не смог решить это .. пока.

Ответы [ 2 ]

4 голосов
/ 31 октября 2010

На этот вопрос ответили в списке рассылки.http://groups.google.com/group/ninject/browse_thread/thread/a7f2163e060a6d64

Короче говоря:

  1. Форма (путь) принимает путь либо относительно рабочего каталога, либо абсолютного
  2. Сборка должна находиться в пути поискапоскольку он загружается в контекст загрузки, чтобы избежать других проблем с переключением контекста загрузки.
  3. Сервер разработки усложняет все, поскольку он копирует все сборки в их собственный каталог, что делает невозможным использование вызывающей сборки длясоздать путь.Это означает единственный способ для веб-приложений, использующих сервер разработки.
  4. Мы добавим поддержку полных имен сборок в будущей версии, чтобы упростить эту задачу.
1 голос
/ 27 октября 2010

Я не уверен, что это опечатка в вашем примере, но я заметил, что вы написали

kernel.Scan(a => {
    a.From("MyApp.Data");
    // etc.
}

Но не должно ли это быть

kernel.Scan(a => {
    a.From("MyApp.Data.dll")
    // etc.
});

Потому что, если я включаю часть .dll в мой пример проекта, она работает, но если я ее опускаю, я получаю исключение FileNotFoundException.

...