Autofac не может разрешить ASP. NET Core Controller при попытке передать параметры для регистрации - PullRequest
0 голосов
/ 10 октября 2019

Мы использовали Autofac в качестве контейнера IoC для внедрения зависимостей. Чтобы передать параметры контроллерам Web API во время регистрации, мы надеялись передать их конструктору Controller. Это параметр двойного типа с именем ratio в конструкторе ниже.

Однако Autofac выдает исключение, поскольку не может разрешить последний параметр с типом double (ratio здесь) и не может создатьэкземпляр DataProcessController.

public DataProcessController(ILogger logger, IDataProvider dataProvider, double ratio)
{
  ...
}

с использованием метода WithParameter для указания используемого значения.

builder.RegisterType<DataProcessController>().AsSelf()
            .WithParameter("ratio", 0.4);

Также я вызываю AddControllersAsServices для регистрацииконтроллер как сервис и разрешите его из контейнера.

services.AddMvc()
        .AddControllersAsServices()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

и позвоните Populate() после завершения регистрации.

builder.Populate(services);
return new AutofacServiceProvider(builder.Build());

Все определено в функции ниже:

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddOptions();
        services.AddHttpClient();
        services.AddMvc()
            .AddControllersAsServices()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        //Autofac
        var builder = new ContainerBuilder();
        builder.RegisterInstance(_logger).As<ILogger>().SingleInstance();

        //All other dependencies are defined here....

        builder.RegisterType<DataProcessController>().AsSelf()
            .WithParameter("ratio", 0.4);

        // auto-discover examples from this assembly
        services.AddSwaggerExamplesFromAssemblyOf<Startup>();

        builder.Populate(services);
        return new AutofacServiceProvider(builder.Build());
    }

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

1 Ответ

0 голосов
/ 10 октября 2019

Вам нужно позвонить builder.Populate(services) ДО того, как вы добавите вещи в контейнер для переопределения.

Если вы посмотрите в документах о том, как работает новый материал IServiceProviderFactory, это в основном:

  • Используйте ConfigureServices, чтобы зарегистрировать вещи с IServiceCollection
  • За кулисами на фабрике поставщика услуг создается ContainerBuilder и для вас вызывается builder.Populate(services)
  • Используйте ConfigureContainer для прямой регистрации в Autofac напрямую
  • За кулисами на заводе поставщика услуг создается конечный контейнер и помещается в IServiceProvider

В более старой интеграции, где вы строите AutofacServiceProvider самостоятельно, вы должны быть осторожны с порядком. Это все еще Autofac - последний в победах.

Когда вы делаете services.AddControllersAsServices(), это все равно, что сказать builder.RegisterType<DataProcessController>().AsSelf() ... но на самом деле он еще не разговаривает со строителем. Это похоже на «сохраненную регистрацию», которая не будет «воспроизводиться» до тех пор, пока вы не позвоните Populate.

Таким образом, если вы упростите свои регистрации и поместите вещи в порядок , они фактически выполнятся :

// These will NOT be executed until builder.Populate()
// services.AddOptions();
// services.AddHttpClient();
// services.AddMvc()
//    .AddControllersAsServices()
//    .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

var builder = new ContainerBuilder();
builder.RegisterInstance(_logger).As<ILogger>().SingleInstance();
builder.RegisterType<DataProcessController>().AsSelf()
    .WithParameter("ratio", 0.4);

// Still not executed until builder.Populate()
services.AddSwaggerExamplesFromAssemblyOf<Startup>();

// Here goes everything!
// - AddOptions => ContainerBuilder
// - AddHttpClient => ContainerBuilder
// - AddMvc => ContainerBuilder
// - AddControllersAsServices => ContainerBuilder
// ---- OH NO! JUST OVERWROTE THE WITHPARAMETER REGISTRATION!
// - AddSwaggerExamplesFromAssemblyOf => ContainerBuilder
builder.Populate(services);

return new AutofacServiceProvider(builder.Build());

Вот что я бы порекомендовал:

НАИЛУЧШИЙ ПРИМЕР: ПЕРЕМЕСТИТЬ ПОДДЕРЖКУ ФАБРИКИ ПРОВАЙДЕРА СЕРВИСА

В документации это тот, где в ASP.NET 1.1-2.2 вы сами не собираете AutofacServiceProvider и вместо этого регистрируете Autofac на уровне веб-хоста . Это лучший вариант, потому что он готовит вас к обновлению до ASP.NET Core 3.0, когда вы будете готовы. После того, как вы нажмете 3.0, вам все равно придется это сделать.

ПАРАМЕТР ОТДЫХА: ОРГАНИЗОВАТЬ РЕГИСТРАЦИИ

Если вы не можете переключить интеграцию, чтобы заставить вас использоватьразделите методы ConfigureServices и ConfigureContainer, хотя бы организуйте код в ConfigureServices, чтобы вы были готовы. Это также гарантирует, что все будет вызвано в правильном порядке, чтобы избежать этой проблемы сейчас и в будущем.

  • Сгруппируйте все services.AddWhatever() регистрации для IServiceCollection вверху. Например, не позволяйте services.AddSwaggerExamplesFromAssembly задерживаться среди регистраций Autofac.
  • Создайте ContainerBuilder и немедленно позвоните Populate. Не помещайте никакие регистрации между этими двумя вещами.
  • Сгруппируйте все builder.Register<T>() регистрации с ContainerBuilder после вызова builder.Populate.
  • Оставьте создание поставщика услуг какАбсолютно последняя вещь в методе, как у вас сейчас.
...