Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 592
Satyajit Avatar asked Jul 12 '15 18:07

Satyajit


1 Answers

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();
    }
}
like image 139
Johnathon Sullinger Avatar answered Nov 15 '22 00:11

Johnathon Sullinger