Skip to content

Instantly share code, notes, and snippets.

@benpriebe
Last active December 15, 2015 11:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benpriebe/5251972 to your computer and use it in GitHub Desktop.
Save benpriebe/5251972 to your computer and use it in GitHub Desktop.

This gist highlights a more complex example on how to implement autofac delegating factories to create container driven dependencies with runtime paramaters.

Please see this article for a primer before delving into the code here:

http://www.codebullets.com/my-favorite-dependency-injection-container-1141

###The Example:###

Suppose you have a DocumentService whose responsiblity is to retrieve documents from a document repository. In this example we support two different document repositories - Azure and Unc (ie. file system).

The DocumentService determines which repository to pull documents from at runtime. However, we don't want to new up instances directly, we want AutoFac to pass those dependencies in the constructor.

Being good citizens, the repo dependencies are based off the interface type - IDocumentRepo.

e.g.

public class DocumentService
{
  private readonly Func<string, IDocumentRepo> _azureRepo;
  private readonly Func<IDocumentRepo> _uncRepo;

  public DocumentService(IDocumentRepo azureRepo, IDocumentRepo uncRepo) {}
  
  ...
}

We have a problem however in that each type of repo has different constructor dependencies and we want to resolve those dependencies at runtime.

This is where we must use AutoFac delegating factories - http://code.google.com/p/autofac/wiki/DelegateFactories

###The Solution###

public interface IDocumentRepo
{
  byte[] GetDocument();
}
 public class UncDocumentRepo : IDocumentRepo
{
  public byte[] GetDocument()
  {
    // e.g. get's the path information from a configuration store and then loads the document and returns it.
    return null;
  }
}
public class AzureDocumentRepo : IDocumentRepo
{
  private readonly string _configurationString;

  public AzureDocumentRepo(string configurationString)
  {
    _configurationString = configurationString;
  }

  public byte[] GetDocument()
  {
    // e.g. create a http client based off configuration string and go pull down document.
    return null;
  }
}
public class DocumentService
{
  private readonly Func<string, IDocumentRepo> _azureRepo;
  private readonly Func<IDocumentRepo> _uncRepo;

  public DocumentService(Func<string, IDocumentRepo> azureRepo, Func<IDocumentRepo> uncRepo)
  {
    _uncRepo = uncRepo;
    _azureRepo = azureRepo;
  }

  public byte[] GetDocument()
  {
    IDocumentRepo repo;
    if (someCondition) // demo purposes only.
      repo = _uncRepo();
    else 
      repo = _azureRepo("instanceId:XX123;uri:http://someaddress.com;userid:3");

    return repo.GetDocument();
  }
}
builder.RegisterType<AzureDocumentRepo>().Named<IDocumentRepo>("Azure");
builder.RegisterType<UncDocumentRepo>().Named<IDocumentRepo>("Unc");

builder.RegisterType<DocumentService>().WithParameters(new[] {
  new ResolvedParameter(
    (p,c) => p.Name == "azureRepo", 
    (p,c) => c.ResolveNamed<Func<string, IDocumentRepo>>("Azure")),
  new ResolvedParameter(
    (p,c) => p.Name == "uncRepo",
    (p,c) => c.ResolveNamed<Func<IDocumentRepo>>("Unc"))
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment