6

I have a repository factory NhRepositoryFactory

public interface IRepositoryFactory  
{  
  IRepository<T> Create<T>() where T: Entity;  
} 

public class NhRepositoryFactory: IRepositoryFactory  
{  
  public IRepository<T> Create<T>() where T : Entity  
  {  
    return new NhRepository<T>();  
  }  
}

In order to resolve some repositories dependencies I want to get them from the Autofac container. So I should somehow inject Func<IRepository<T>> factory into my class. How can I accomplish this?
Thanks in advance.

Dmitriy Melnik
  • 530
  • 2
  • 5
  • 12
  • Why won't you store the Autofac container inside the `NhRepositoryFactory`? – Steven Mar 12 '12 at 08:45
  • 2
    I want my factory be Autofac-agnostic. – Dmitriy Melnik Mar 12 '12 at 08:46
  • It contains just one single line of code. You can place it inside your composition root. It doesn't have to be container-agnostic. – Steven Mar 12 '12 at 08:49
  • I haven't got the point. `IRepositoryFactory` is also resolved with Autofac. Could you write what the `Create` method will look like? – Dmitriy Melnik Mar 12 '12 at 09:01
  • 1
    Your question is similar to http://stackoverflow.com/questions/8579128/autofac-generic-service-resolution-at-runtime/8597212#8597212, so is the answer. – rcaval Mar 12 '12 at 12:02

2 Answers2

9

The NhRepositoryFactory contains no business logic and can be part of your composition root. This allows you to let it have a reference to the container. This is just mechanics and is not considered to be the Service Locator anti-pattern. The NhRepositoryFactory will look like this:

// This class is part of your composition root
public class NhRepositoryFactory : IRepositoryFactory  
{
    private readonly Container container;

    public NhRepositoryFactory(Container container)
    {
        this.container = container;
    }

    public IRepository<T> Create<T>() where T : Entity  
    {  
        return this.container.Resolve<NhRepository<T>>();
    }  
}

And you can register it like this:

builder.Register<IService>(c => new NhRepositoryFactory(c))
    .SingleInstance();
Steven
  • 166,672
  • 24
  • 332
  • 435
  • I agree it seems inevitable to couple with Autofac one way or another. I've done it the way you suggested. The difference is that I passed `ILifetimeScope` instead of `Container`. – Dmitriy Melnik Mar 12 '12 at 14:00
  • 1
    I've changed the implementation. I've created `IObjectFactory` interface with `T Create()` method that uses `ILifetimeScope` to create objects. It is implemented by `AutofacObjectFactory` class which is injected into `NhRepositoryFactory`. So now there is no Autofac-coupling. – Dmitriy Melnik Mar 13 '12 at 04:56
  • After the refactoring `IRepositoryFactory` has been eliminated. Its place has taken `IObjectFactory`. – Dmitriy Melnik Mar 13 '12 at 05:09
  • I think this is just bad practice. Why are you returning NhRepository from factory as oppossed to feeding it in through constructor injection? Factory pattern makes no sense here. – Sergey Akopov Nov 29 '12 at 16:54
  • @DmitriyMelnik May I ask the final example? – Akim Khalilov Dec 28 '12 at 12:20
5

Autofac is also able to handle the generic creation natively without the factory.

builder.RegisterGeneric(typeof(NhRepository<>))
    .As(typeof(IRepository<>))
    .InstancePerLifetimeScope();

Using this pattern you can simply take a dependency on IRepository and autofac will fill out the dependencies.

Danielg
  • 2,669
  • 1
  • 22
  • 17
  • 2
    I've tried it this way. But when some class needed several repositories I had to add them as constructor parameters. A field for each of them was to be created also. It seemed clumsy so I created a factory. – Dmitriy Melnik Mar 13 '12 at 03:12