2

I am using MVC with EF and Autofac. I have a concrete class called Helper. Helper is in another DLL and not the main MVC web application.

It has a property of type DBContext called 'Context'.

I want to inject an instance of the DBContext into this property - however its always null.

Here is what I have so far in GLobal:

    var output = new DbContext(connectionString);
    builder.RegisterInstance(output).As<DbContext>().PropertiesAutowired();
             builder.RegisterType<Helper().WithParameter("Context",output).PropertiesAutowired();

        // Set the dependency resolver to be Autofac.
        var container = builder.Build();
        DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

Context is the property on the Helper class which I would like injected with the instance 'output'.

Context is always null.

Chris
  • 365
  • 7
  • 19
  • Could you give the constructor signature of the Helper class? As far as I can tell, either you need WithParameter OR PropertiesAutowired, but not both. And possibly you don't need either, if you have a parameter of type DbContext in your Helper constructor. – Alberto Chiesa Jun 22 '16 at 10:19
  • Thanks for your reply. I just an empty constructor i.e public Helper(){}. – Chris Jun 22 '16 at 10:32
  • Could you share the code of the `Context` property ? Is it public and read/write ? – Cyril Durand Jun 22 '16 at 10:38
  • public DbContext Context { get; set; } – Chris Jun 22 '16 at 10:38

1 Answers1

8

In Autofac, the easiest way to manage dependencies is to leverage constructor injection.

Basically, instead of telling Autofac "wire up the properties for me and do your mojo", you tell him to let YOU in charge of declaring the list of components.

So, instead of wondering why property injection is not working, declare explicitly your dependencies in Helper constructor:

public class Helper
{
    public DbContext Context { get; private set; }

    public Helper(DbContext context /* Autofac is going to fill in this */)
    {
        Context = context;
    }
}

Then, in Global (or in some other class encapsulating your registrations) you just tell Autofac to look at the Helper type and try his best to call the best constructor, which is the simplest thing you can do:

// Either InstancePerDependency, or SingleInstance, or something else depending upon you requirements.
builder.RegisterType<Helper>().AsSelf().InstancePerDependency();

And you should be done: Autofac will search for the constructor with most parameters (and there will be only one with a parameter of type DbContext and will check if he knows how to create parameters for the requested type (which he can).

So, voilà, you get a ready to use Helper!

Edit: I'm keeping the example above, because it's the correct answer to the question, BUT, to reply to the comment, I would use a little more machinery, in the form of an Init method:

public class Helper
{
    public DbContext Context { get; private set; }

    public Init(DbContext context /* Autofac is going to fill in this */)
    {
        Context = context;
    }
}

And you can instruct Autofac to call this method during object initialization:

builder.RegisterType<CustomHelper>()
       .AsSelf()
       .InstancePerDependency()
       .OnActivating(h => {
            var dbContext = h.Context.Resolve<DbContext>();
            ((Helper)h.Instance).Init(dbContext);
        });

OnActivating lets you write the explicit initialization call. Keep in mind you probably want to register all the types in an assembly which derive from Helper, but probably that is for another question.

Ramil Aliyev 007
  • 4,437
  • 2
  • 31
  • 47
Alberto Chiesa
  • 7,022
  • 2
  • 26
  • 53
  • Thanks for your reply. This is an ideal situation however, the Helper is a base class and I dont want any class that inherits Helper to have to also have DbContext in its constructor. Is there a way autofac can force the system to use the overloaded constructor with the DbContext? Thanks Again. – Chris Jun 22 '16 at 10:44
  • Thanks for your answer. This is a good work around. However, I stuck a breakpoint on the Init method and it is never called. Here is my global: var output = new DbContext(connectionString); builder.RegisterType().AsSelf().InstancePerDependency() .OnActivating(h => { ((BaseHelper)h.Instance).Init(output); }); – Chris Jun 22 '16 at 11:14
  • Inheritance is not very DI-friendly. A better approach would be to change the design (if possible) to use a more DI-friendly pattern such as Decorator or Proxy so the `DbContext` dependency won't be directly required by your concrete instance. Have a look at the way [filters](http://stackoverflow.com/a/28365933/181087) work in MVC for inspiration. – NightOwl888 Jun 22 '16 at 11:15
  • Wait. You're telling me you get a HomeHelper object without Init being called on the base type? Are you sure you are not registering HomeHelper twice? When you register something more than once, "the last one wins", so to speak. – Alberto Chiesa Jun 22 '16 at 11:18
  • Thanks for the comments. I am going to change the design to use constructor injection. Seems the best way forward. – Chris Jun 22 '16 at 11:44
  • It is not working for me in ASP.NET Core 3.1 – Ramil Aliyev 007 Apr 24 '21 at 17:03