Как использовать Property Injection в MVC Core и AutoFac

Я могу легко использовать Constructor Parameter Injection в MVC Core. Но свойство Injection не поддерживается. Я пытаюсь использовать AutoFac, но тоже не получается.
Итак, как использовать Property Injection в MVC Core.
Вот код с автофаком

services.AddMvc();
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Test2>().As<ITest>();
builder.RegisterType<HomeController>().PropertiesAutowired();
builder.Populate(services);
var container = builder.Build();
//The following code works
HomeController test2 = container.Resolve<HomeController>();
return new AutofacServiceProvider(container); 

1 ответ

В ядре dotnet для работы Autofac необходимо внести следующие изменения: Добавить общедоступный Autofac IContainer в вашем приложении Startup.cs

public IContainer ApplicationContainer { get; private set; }

+ Изменить ConfigureServices в Startup.cs возвращать IServiceProvider, сделайте все свои регистрации, заполните сервисы фреймворка в вашем контейнере, используя builder.Populat(services);, Обратите внимание, что вам не нужно делать builder.RegisterType<HomeController>().PropertiesAutowired();

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    builder.Populate(services);
    ApplicationContainer = container;
    return new AutofacServiceProvider(ApplicationContainer);
}

Вам также необходимо убедиться, что вы удалили контейнер для приложения, остановленного, выполнив это в своем Configure метод.

public void Configure(IApplicationBuilder app, IApplicationLifetime appLifetime)
{
    app.UseMvc();           
    appLifetime.ApplicationStopped.Register(() => ApplicationContainer.Dispose());
}

После того как вы это сделаете - ваши контроллеры должны автоматически получить свойства автоматически подключенными.

Внедрение свойства требует дополнительной настройки. Предположим, в вашем случае у нас есть эта иерархия классов:

    public class HomeController 
    {
        public ITest Test {get; set;}            
    }    
    public class Test : ITest
    {
        public IRepository Repository {get;set;}    
    }
    public class Repository: IRepository
    {
    }

Прежде всего нужно изменить тип возвращаемого значения на IServiceProvider для ConfigureServices(IServiceCollection services) и создание нового контейнера с использованием Populate метод из метода 'Autofac.Extensions.DependencyInjection' для возврата AutofacServiceProvider

Новый метод ConfigureServices:

public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().AddControllersAsServices();
        ContainerBuilder builder = new ContainerBuilder();

        builder.Populate(services);//Autofac.Extensions.DependencyInjection

        /*Here we are going to register services for DI*/

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

Следующим шагом является регистрация классов в DI-контейнере. Внедрение свойств для "классов обслуживания" требует меньше действий, чем для "контроллеров". Чтобы настроить внедрение свойств для классов обслуживания, вам просто необходимо:

  1. Тип регистрации в контейнере:builder.RegisterType<Repository>().As<IRepository>();
  2. Зарегистрируйте тип, в который вы собираетесь внедрить зависимости через свойства с помощью PropertiesAutowired ():builder.RegisterType<Test>.As<ITest>().PropertiesAutowired()

Чтобы настроить внедрение свойства для контроллеров, вам нужно сделать еще несколько шагов:

  1. казнить AddControllersAsServices() на services.AddMvc()
  2. Regiser DI для контроллеров с вызовом PropertiesAutowired() для всех контроллеров:

    //in case you just need to allow registration for several specific controllers change this line
    var controllersTypesInAssembly = typeof(Startup).Assembly
            .GetExportedTypes()
            .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();
    
    builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired(); 
    

В результате вот ConfigureServices() для предопределенной иерархии:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1).AddControllersAsServices();
    ContainerBuilder builder = new ContainerBuilder();

    builder.Populate(services);//Autofac.Extensions.DependencyInjection

    builder.RegisterType<Repository>().As<IRepository>()
        .InstancePerLifetimeScope();
    var controllersTypesInAssembly = typeof(Startup).Assembly.GetExportedTypes()
        .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray();

    builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired();
    builder.RegisterType<Test>().As<ITest>().PropertiesAutowired();
    return new AutofacServiceProvider(builder.Build());
}
Другие вопросы по тегам