Как использовать внедрение свойств в MVC Core и AutoFac

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

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); 

person Siying Wang    schedule 23.05.2018    source источник


Ответы (2)


В dotnet core вам необходимо внести следующие изменения, чтобы 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());
}

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

person Hiral Desai    schedule 23.05.2018
comment
Здравствуйте, я пытаюсь использовать внедрение свойств Autofac для моих пользовательских аннотаций данных (перегрузки DisplayName и т. д.), но свойства никогда не устанавливаются. Я явно определил обработчик OnActivated для установки свойств в Autofac, но, по-видимому, Autofac никогда не вызывается для инициализации DataAnnotations. У вас есть идея, есть ли что-то особенное для этого? Благодарю вас ! - person AFract; 13.09.2018
comment
@AFract - можете ли вы привести пример того, что вы пытаетесь сделать? - person Hiral Desai; 20.12.2018

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

    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. Регистрировать 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());
}
person svoychik    schedule 31.12.2018