How to use Property Injection in MVC Core and AutoFac
Asked Answered
V

2

5

I can use Constructor Parameter Injection easily In MVC Core. But Property Injection is not supported.I try use AutoFac but fail too.
So how to use Property Injection in MVC Core.
Here is the code with 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); 
Voe answered 23/5, 2018 at 4:4 Comment(0)
A
3

In dotnet core, you need to make the following changes to make Autofac work: Add a public Autofac IContainer in your application Startup.cs

public IContainer ApplicationContainer { get; private set; }

Change ConfigureServices in Startup.cs to return IServiceProvider, do all your registrations, populate the framework services in your container by using builder.Populat(services);. Please note that there is no need for you to do builder.RegisterType<HomeController>().PropertiesAutowired();

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

You will also need to make sure you dispose the container on application stopped by doing this in your Configure method.

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

After you do this - your controllers should automatically get the properties autowired.

Administrate answered 23/5, 2018 at 17:43 Comment(3)
Hello, I am attempting to have Autofac property injection working on my custom DataAnnotations (overloads of DisplayName, etc), but properties are never set. I have explicitly defined an OnActivated handler to set properties in Autofac, but apparently Autofac is never called to initialize DataAnnotations. Do you have an idea of is there something special to do for this ? Thank you !Mislike
@Mislike - can you provide an example of what you're trying to do?Administrate
not valid in ASP.NET Core 3.0+ docs.autofac.org/en/latest/integration/…Infringement
V
2

Property injection requires some additional setup. Let's Assume in your case we have this hierarchy of classes:

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

The first things needed to be done are changing the return type to IServiceProvider for ConfigureServices(IServiceCollection services) and building new container using Populate method from 'Autofac.Extensions.DependencyInjection' method in order to return AutofacServiceProvider

New ConfigureServices method:

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

Next step is registration of classes in DI container. Property-injection for 'service classes' requires less action than for 'controllers'. To setup property injection for service classes you just need to:

  1. Register type in the container: builder.RegisterType<Repository>().As<IRepository>();
  2. Register type in which you are going to inject dependencies through properties with PropertiesAutowired(): builder.RegisterType<Test>.As<ITest>().PropertiesAutowired()

To setup property injection for a controllers you need a little more steps:

  1. Execute AddControllersAsServices() on services.AddMvc()
  2. Regiser DI for controllers with call of PropertiesAutowired() for all controllers:

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

As a result here is ConfigureServices() for predetermined hierarchy:

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());
}
Vernellvernen answered 31/12, 2018 at 14:15 Comment(1)
not valid in ASP.NET Core 3.0+ docs.autofac.org/en/latest/integration/…Infringement

© 2022 - 2024 — McMap. All rights reserved.