Search code examples
c#dependency-injectionmefautofac

Inject dependency as method parameter instead of constructor parameter


Can we inject dependency as method parameter instead of constructor parameter either using MEF or Autofac?

Thanks


Solution

  • I don't know about MEF, as I've never used it. You can do it with Unity and with Autofac

    Unity

    From the MSFT documentation.

    Unity instantiates dependent objects defined in parameters of methods that carry the InjectionMethod attribute within the scope of the target object. Then it calls the attributed method of the target object before returning the object to the caller. You must apply the InjectionMethod attribute in the target class to initiate method call injection.

    public class MyObject
    {
       public SomeOtherObject dependentObject;
    
      [InjectionMethod]
      public void Initialize(SomeOtherObject dep) 
      {
        // assign the dependent object to a class-level variable
        dependentObject = dep;
      }
    }
    

    That will mark the class as having a dependency method that must get invoked when the class is instanced, and have its method parameter injected.

    IUnityContainer uContainer = new UnityContainer();
    MyObject myInstance = uContainer.Resolve<MyObject>();
    
    // access the dependent object
    myInstance.dependentObject.SomeProperty = "Some value";
    

    Autofac

    Autofac does it through lambdas or callbacks during the activation of a service. From the Autofac documentation

    While constructor parameter injection is the preferred method of passing values to a component being constructed, you can also use property or method injection to provide values.

    Property injection uses writeable properties rather than constructor parameters to perform injection. Method injection sets dependencies by calling a method.

    // Register the type that you want to resolve with a resolution callback. Within the callback, invoke the method with a resolved dependency.
    builder.Register(c => {
      var result = new MyObjectType();
      var dep = c.Resolve<TheDependency>();
      result.SetTheDependency(dep);
      return result;
    });
    

    An alternative is the registration callback.

    builder
      .Register<MyObjectType>()
      .OnActivating(e => {
          var dep = e.Context.Resolve<TheDependency>();
          e.Instance.SetTheDependency(dep);
      });
    

    Both frameworks can only do the method injection at the time of resolution. However, you can't inject a dependency in to a method after the object has been instanced. In those scenarios, you should use a factory to fetch the dependency you have, having the factory resolve it through your DI container.

    Factory

    // Create the factory. The factory will have a static method that the DI system can register a lambda with, so that the factory can resolve through the DI container without being tightly coupled to it.
    public class BarFactory
    {
        private static Func<IBarDependency> internalFactory;
    
        public static void SetFactory(Func<IBarDependency> factory)
        {
            this.internalFactory = factory;
        }
    
        public IBarDependency CreateBar()
        {
            // Use the DI container lambda assigned in SetFactory to resolve the dependency.
            return internalFactory();
        }
    }
    
    public class DependencyInjectionBootstrap
    {
        IContainer container;
    
        public void SetupDI()
        {
            var builder = new ContainerBuilder();
            builder.RegisterType<BarDependency>().As<IBarDependency>();
            container = builder.Build();
    
            // Tell the factory to resolve all IBarDependencies through our IContainer.
            BarFactory.SetFactory(() => container.Resolve<IBarDependency>());
        }
    }
    
    public class FooViewModel
    {
        public void ExecuteSave()
        {
            var barFactory = new BarFactory();
            IBarDependency bar = barFactory.CreateBar();
        }
    }