Универсальный хостинг с пользовательским DI пытается получить неправильный тип

#c# #dependency-injection #.net-core

#c# #внедрение зависимостей #.net-core

Вопрос:

Я использую общий хостинг в .NET Core, и я создал IHostedService экземпляр на моем общем хосте следующим образом:

 IHostBuilder builder = new HostBuilder()
    .ConfigureServices((hostBuilderContext, services) => {
        services.AddHostedService<MyService>();
     });
  

Где MyService всего лишь простой скелет:

 public class MyService : IHostedService {
    public async Task StartAsync(CancellationToken cancellationToken) { }
    public async Task StopAsync(CancellationToken cancellationToken) { }
}
  

Это работает просто отлично.

Однако, если я попытаюсь использовать пользовательский DI вместо Microsoft.Extensions.DependencyInjection AddHostedService() запроса IHost вместо IHostedService . Я вижу, что это происходит путем отладки пользовательского IServiceProvider :

 public class MyCustomProvider : IServiceProvider {

    SomeContainer _someContainer;

    public MyCustomProvider(SomeContainer someContainer) {
        _container = container;
    }
    public object GetService(Type serviceType) {
        return _container.Get(serviceType);
        // This is only called once, and serviceType is typeof(IHost)
    }
}
  

Где общий хост теперь настроен следующим образом:

 IHostBuilder builder = new HostBuilder()
    .UseServiceProviderFactory(new MyContainerFactory())
    .ConfigureServices((hostBuilderContext, services) => {
        services.AddHostedService<MyService>();
     });
  

С MyContainerFactory настройкой, подобной этой:

 class MyContainerFactory : IServiceProviderFactory<SomeContainer> {
    public SomeContainer CreateBuilder(IServiceCollection services) {
        return SomeContainer.SetupStuff().Create();
    }
    public IServiceProvider CreateServiceProvider(SomeContainer container) {
        return new MyCustomProvider(container);
    }
}
  

Видя, что мой пользовательский DI-контейнер успешно вызывается, я подозреваю, что нет ничего плохого в том, как настроен мой контейнер. Очевидно, что он не может найти ни одного, IHost потому что MyService наследуется от IHostedService , но почему он пытается получить IHost в первую очередь? Что-то должно быть не так, но я просто не могу понять, где!

Почему мой универсальный хост пытается создать IHost вместо IHostedService при вызове AddHostedService()

Комментарии:

1. Какой «пользовательский DI» вы здесь используете? Вы действительно создаете контейнер самостоятельно или используете один из существующих? Это важно, потому что большинство контейнеров DI уже имеют интеграцию, доступную для .NET Core, но значительная часть из них не интегрируется с использованием UseServiceProviderFactory и других конструкций. Этот шаблон называется соответствующим контейнером , и вы можете найти подробное обсуждение того, почему некоторые контейнеры не поддерживают это здесь .

2. Я использую System.Composition

3. Ах… ты используешь MEF. Я не уверен, совместима ли композиционная модель MEF с регистрационным API, неявно определенным IServiceCollection , и определить полностью совместимый адаптер MEF может оказаться непростой задачей. Вместо этого вы могли бы попробовать подход, используемый Castle Windsor, Ninject и Simple Injector, который заключается в использовании MEF в качестве вашего контейнера приложения и сохранении встроенного контейнера на месте для создания компонентов фреймворка.

Ответ №1:

Проблема в том, что HostBuilder добавляет все общие службы, специфичные для хоста, к встроенному, IServiceCollection который передается IServiceProviderFactory , однако на вашем заводе эти службы игнорируются.

Это приводит к тому, что вновь сгенерированный SomeContainer пропускает необходимые базовые службы (например, IHost , IConfiguration ILoggerFactory и т.д.) Для запуска.

IHost То, что «отсутствует» (или, скорее, недоступно в вашем пользовательском DI), — это класс, который запускает все размещенные службы.

Решение состоит в том, чтобы добавить все службы (или, по крайней мере, IHost , но позже это может привести к отсутствию некоторых других служб) в ваш SomeContainer in IServiceProviderFactory.CreateBuilder .