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. Мы сделали это в качестве концепции проекта, и она работала без проблем. В нашем новом проекте у нас есть следующие проблемы:
- Если вы попытаетесь разрешить службу в конструкторе контроллера, она выдаст ошибку, указывающую, что внедрение зависимости Microsoft не может разрешить службу. Не уверен, почему он не использует провайдера Autofac здесь.
- Если мы вручную разрешим один тип при запуске вместе со сканированием сборки, мы получим ошибку в конструкции контроллера, указывающую на то, что Autofac не может разрешить службу (здесь используется поставщик Autofac, но все еще не находит наши типы).
- Если я проверяю конструктор и контейнер перед его возвратом в ConfigureServices, кажется, что все наши типы зарегистрированы. Тем не менее, если я изменяю контроллер для внедрения IServiceProvider, а затем пытаюсь разрешить службу из него, он точно использует поставщика Autofac, но я всегда получаю нулевое значение (служба не найдена).
Попробовав много вещей, я взял наше доказательство концепции проекта и скопировал его в наше новое решение (в случае, если мы пропустили какие-то небольшие настройки или что-то еще при настройке нашего нового проекта), и плохое поведение продолжилось. Я начинаю думать, что наши сборки вносят некоторую ошибку (так как это единственные вещи, которые изменились после копирования), но Autofac не выдает ошибку во время сканирования, а вместо этого просто не использует типы, которые он сканировал правильно,
Редактировать 1
Я создал и опубликовал очень упрощенный пример, который воспроизводит проблему, с которой я сталкиваюсь. Вы должны быть в состоянии снять это и запустить это, чтобы воспроизвести ошибку. Вы должны получить ошибку в конструкторе контроллера дома, указывающую, что разрешение службы не удалось.
Примечание: при запуске этого примера он запускает файл.bat, который помещает выходные dll из проекта домена в папку.nuget вашего профиля пользователя.
Редактировать 2
Разделить интерфейс на папку абстракций на основе рекомендаций Travis Illig. Как только я это сделал, решение начало работать. Мы разделили его на наш "настоящий" проект, но он не работает. Все еще экспериментирую, чтобы понять почему.
Редактировать 3
В итоге наш проект снова заработал. Проблема закончилась несколькими вещами:
- У нас была зависимость проекта абстракции, перечисленная в нашем веб-проекте, и мы также загружали и сканировали dll из этой сборки (двойная загрузка). (Я думаю, что это была большая проблема.)
- Наши версии NuGet были плохими, поэтому я не думаю, что они загружались правильно. Мы использовали 1.0.0-1, который является недопустимым предварительным форматом. Обновил его до 1.0.0-b1, и, похоже, все стало работать лучше.
Мне потребовалось гораздо больше времени, чтобы понять, и моя самая большая проблема на данный момент заключается в том, что Autofac потерпит неудачу молча. Я действительно хотел бы, чтобы это взорвалось и дало бы мне некоторый вывод отладки или что-то, указывающее, что была проблема. Вместо этого все, казалось, сканировало и загружалось нормально, но потом, когда вы перешли на использование контейнера, ничего не решало.
1 ответ
Скорее всего, сборки загружаются в таком порядке, что некоторые типы не могут быть загружены из-за того, что не загружаются необходимые сборки.
Например, скажем, у вас есть сборка А, которая содержит интерфейс IComponent
, Также скажем, у вас есть сборка B, которая содержит класс Component
который реализует IComponent
, Если вы сначала загрузите сборку B, введите Component
не будет загружаться, потому что реализуемый интерфейс не определен.
При сканировании типов Autofac старается быть максимально безопасным и не взорвется, если из-за столкновения попадут типы, которые не могут быть загружены. Вы можете увидеть в источнике регистрации сканирования, где он использует специальный безопасный метод для загрузки.
В вашем спайк-коде я держу пари, что сборок было загружено гораздо меньше, поэтому вы загрузили все в правильном порядке. Счастливая случайность Когда вы попадаете в более крупные проекты, гораздо проще упасть, чтобы контролировать порядок загрузки и вызывать подобные проблемы.