Autofac не разрешает типы из сканирования сборки в asp.net 5

У нас есть веб-проект dnx46, который использует автоматическое сканирование сборок во время запуска для регистрации типов. Наши зависимости project.json включают в себя:

"Autofac.Configuration": "4.0.0-rc1-268",
"Autofac.Extensions.DependencyInjection": "4.0.0-rc1-177",
"Autofac.Extras.CommonServiceLocator": "3.2.0",
"Microsoft.AspNet.Hosting": "1.0.0-rc1-final",
"Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
"Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
"Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-rc1-final",
"Microsoft.AspNet.Mvc.ViewFeatures": "6.0.0-rc1-final",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
"Microsoft.AspNet.Session": "1.0.0-rc1-final",
"Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final",
"Microsoft.AspNet.Tooling.Razor": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc1-final",
"Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final",
"Microsoft.Extensions.Logging": "1.0.0-rc1-final",
"Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final",
"Microsoft.Extensions.Logging.Debug": "1.0.0-rc1-final",
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0-rc1-final",
"Newtonsoft.Json": "8.0.3"

Наш метод startup.cs ConfigureServices выглядит следующим образом:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(serviceType => Configuration);
    services.AddInstance<Microsoft.Extensions.Configuration.IConfiguration>(Configuration);

    services.AddCaching();
    services.AddSession();
    services.AddMvc();

    var builder = new ContainerBuilder();

    var assemblies = Directory.GetFiles(<ourBinDirectoryPath>, "*.dll", SearchOption.TopDirectoryOnly).Select(Assembly.LoadFrom);

    foreach (var assembly in assemblies)
    {
        builder.RegisterAssemblyTypes(assembly).Where(t => t.Name.EndsWith("Service") || t.Name.EndsWith("Repository") || t.Name.EndsWith("DataContext")).AsSelf().AsImplementedInterfaces();
        builder.RegisterAssemblyTypes(assembly).Where(t => !t.Name.EndsWith("Service") && !t.Name.EndsWith("Repository") && !t.Name.EndsWith("DataContext")).AsSelf().AsImplementedInterfaces().InstancePerDependency();
    }

    builder.Populate(services);
    var container = builder.Build();

    return container.Resolve<IServiceProvider>();
}

Наш процесс состоит в том, что у нас есть несколько проектов, которые мы создаем, которые помещают дроп-файлы, которые понадобятся этому проекту в пользовательскую папку bin. При запуске мы сканируем эти сборки для регистрации типов в Autofac. Мы сделали это в качестве концепции проекта, и она работала без проблем. В нашем новом проекте у нас есть следующие проблемы:

  1. Если вы попытаетесь разрешить службу в конструкторе контроллера, она выдаст ошибку, указывающую, что внедрение зависимости Microsoft не может разрешить службу. Не уверен, почему он не использует провайдера Autofac здесь.
  2. Если мы вручную разрешим один тип при запуске вместе со сканированием сборки, мы получим ошибку в конструкции контроллера, указывающую на то, что Autofac не может разрешить службу (здесь используется поставщик Autofac, но все еще не находит наши типы).
  3. Если я проверяю конструктор и контейнер перед его возвратом в ConfigureServices, кажется, что все наши типы зарегистрированы. Тем не менее, если я изменяю контроллер для внедрения IServiceProvider, а затем пытаюсь разрешить службу из него, он точно использует поставщика Autofac, но я всегда получаю нулевое значение (служба не найдена).

Попробовав много вещей, я взял наше доказательство концепции проекта и скопировал его в наше новое решение (в случае, если мы пропустили какие-то небольшие настройки или что-то еще при настройке нашего нового проекта), и плохое поведение продолжилось. Я начинаю думать, что наши сборки вносят некоторую ошибку (так как это единственные вещи, которые изменились после копирования), но Autofac не выдает ошибку во время сканирования, а вместо этого просто не использует типы, которые он сканировал правильно,

Редактировать 1

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

Примечание: при запуске этого примера он запускает файл.bat, который помещает выходные dll из проекта домена в папку.nuget вашего профиля пользователя.

Редактировать 2

Разделить интерфейс на папку абстракций на основе рекомендаций Travis Illig. Как только я это сделал, решение начало работать. Мы разделили его на наш "настоящий" проект, но он не работает. Все еще экспериментирую, чтобы понять почему.

Редактировать 3

В итоге наш проект снова заработал. Проблема закончилась несколькими вещами:

  1. У нас была зависимость проекта абстракции, перечисленная в нашем веб-проекте, и мы также загружали и сканировали dll из этой сборки (двойная загрузка). (Я думаю, что это была большая проблема.)
  2. Наши версии NuGet были плохими, поэтому я не думаю, что они загружались правильно. Мы использовали 1.0.0-1, который является недопустимым предварительным форматом. Обновил его до 1.0.0-b1, и, похоже, все стало работать лучше.

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

1 ответ

Решение

Скорее всего, сборки загружаются в таком порядке, что некоторые типы не могут быть загружены из-за того, что не загружаются необходимые сборки.

Например, скажем, у вас есть сборка А, которая содержит интерфейс IComponent, Также скажем, у вас есть сборка B, которая содержит класс Component который реализует IComponent, Если вы сначала загрузите сборку B, введите Component не будет загружаться, потому что реализуемый интерфейс не определен.

При сканировании типов Autofac старается быть максимально безопасным и не взорвется, если из-за столкновения попадут типы, которые не могут быть загружены. Вы можете увидеть в источнике регистрации сканирования, где он использует специальный безопасный метод для загрузки.

В вашем спайк-коде я держу пари, что сборок было загружено гораздо меньше, поэтому вы загрузили все в правильном порядке. Счастливая случайность Когда вы попадаете в более крупные проекты, гораздо проще упасть, чтобы контролировать порядок загрузки и вызывать подобные проблемы.

Другие вопросы по тегам