How to resolve property injection with Autofac?

Dan picture Dan · Apr 14, 2015 · Viewed 7.9k times · Source

I have an MVC web app which uses Autofac to inject services in controllers.

The problem: I am trying to do property injection on a service and it fails (the property is always null).

What I expect: I expect to have the property initialized properly (not null) by Autofac.

Example:

  • I'm trying to inject the AliasesService as IAliasesService into controllers.
  • The AliasesService depends on MailService.
  • MailService is a property of AliasesService.
  • The AliasesService is properly instantiated and passed to MyController.
  • The MailService is NOT properly instantied and set to the property of AliasesService

Controller:

public class MyController: Controller
{
    private IAliasesService AliasesService { get; set; }

    public MyController(IAliasesService aliasesService)
    {
        AliasesService = aliasessService;
    }

    public ActionResult Index()
    {
        var model = aliasesService.GetUserRoles();

        return View();
    }
}

Global.asax:

var builder = new ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();

builder.RegisterType<MailService>().As<IMailService>();
builder.RegisterType<AliasesService>().As<IAliasesService>().PropertiesAutowired();

var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

AliasesService:

public class AliasesService
{
     public IMailService MailService { get; set; }

     public Dictionary<int,string> GetUserRoles()
     {
          MailService.SendMail("method GetUserRoleshas been called");
          return null;
     }
}

Worth mentioning:

  • if I try to do property injection for controllers it works as expected
  • constructor injection works but I need property injection.

What other things I tried with no success:

1

builder.RegisterType<MailService>()
       .As<IMailService>();
builder.Register(c => new AliasesService() 
       { 
           MailService = c.Resolve<IMailService>() 
        })
       .As<IAliasesService>();

2

builder.RegisterType<MailService>()
       .As<IMailService>();
builder.RegisterType<AliasesService>()
       .WithProperty("MailService", new MailService())
       .As<IAliasesService>();

Minimal example:

using Autofac;

namespace ConsoleApplication1
{
    public interface IBar
    {    
    }

    public class Bar: IBar
    {
        public string Text { get; set; }

        public Bar()
        {
            Text = "Hello world!";
        }
    }

    public interface IFoo
    {
    }

    public class Foo: IFoo
    {
        public IBar Bar { get; set; }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = new ContainerBuilder();

            builder.RegisterType<Bar>().As<IBar>();
            builder.RegisterType<Foo>().As<IFoo>().PropertiesAutowired();

            var container = builder.Build();

            var foo = container.Resolve<IFoo>();
        }
    }
}

Alternative solution:

For the minimal example Autofac works but in the context of controllers I still did not managed to make it work as expected so I gave up on using it as I wasted too much time. I'm using Castle Windsor for now and it does everything I need, thank you for the support.

Answer

Cyril Durand picture Cyril Durand · Apr 15, 2015

On your minimal code sample the property Bar is declared of type Bar which is not registered. The declared property type should be registered in order to let Autofac resolve it. You should change the type of the property to IBar or register Bar as Bar

public class Foo : IFoo
{
    public IBar Bar { get; set; }
}

or

builder.RegisterType<Bar>().As<Bar>();