views:

43

answers:

2

I got the following service:

IRepository<TEntity, TPrimaryKey>

..for which I've created an implementation defined as:

Repository<TEntity, TPrimaryKey>.

How do I register it in autofac so that I can resolve it as:

IRepository<User, int>
+3  A: 
builder.RegisterGeneric(typeof (Repository<,>)).As(typeof (IRepository<,>));

I love autofac.

jgauffin
A: 

As an alternative to your own solution, you might try defining a factory for creating new repository instances:

public interface IRepositoryFactory
{
    IRepository<TEntity, TPrimaryKey> 
        CreateRepository<TEntity, TPrimaryKey>();

    // Perhaps other overloads here
}

internal class RepositoryFactory : IRepositoryFactory
{
    public IContainer Container { get; set; }

    public IRepository<TEntity, TPrimaryKey> 
        CreateRepository<TEntity, TPrimaryKey>()
    {
        return container.Resolve<Repository<TEntity, TPrimaryKey>>();
    }
}

You can register the RepositoryFactory as follows:

builder.Register(c => new RepositoryFactory() { Container = c })
    .As<IRepositoryFactory>()
    .SingleInstance();

Now you can declare IRepositoryFactory as constructor argument and create new instances. Look for instance at this ProcessUserAccountUpgradeCommand class that uses dependency injection for its dependencies:

public ProcessUserAccountUpgradeCommand : ServiceCommand
{
    private readonly IRepositoryFactory factory;

    ProcessUserAccountUpgradeCommand(IRepositoryFactory factory)
    {
        this.factory = factory;
    }

    protected override void ExecuteInternal()
    {
        // Just call the factory to get a repository.
        var repository = this.factory.CreateRepository<User, int>();

        User user = repository.GetByKey(5);
    }
}

While this might seem a bit cumbersome to use a factory instead of getting a repository directly, your design will communicate clearly that a new instance is retrieved (because you call the CreateRepository method). Instances returned from a IoC container are normally expected to have a long life.

Another tip: You might want to refactor the use of the primary key type away. It would be cumbersome to always ask for repositories of <User, int> instead of just <User> repositories. Perhaps you find a way to abstract the primary key away inside the factory.

I hope this helps.

Steven
I don't agree. Services do not have to live long. And the code fetching a service should not care about the lifetime, it's an implementation detail. Using a factory means that the lifetime could never change (since it implies that a new instance should be returned every time). For instance, one might start with returning a new instance each time from the container, but switch to a singleton later to be able to cache objects in the repository.
jgauffin
I like to quote Mark Seeman: "Dependencies injected with Constructor Injection tend to be long-lived, but sometimes you need a short-lived object, or to construct the dependency based on a value known only at run-time." "Use Abstract Factory if you need a short-lived object". See: http://stackoverflow.com/questions/2045904/dependency-inject-di-friendly-library/2047657#2047657
Steven
imho it's still not a valid argument since it's a implementation detail. sure. If i want to get an User it should not be created by a DI. But a repository is a service and should be treated as one. Most repositories uses a UnitOfWork which has a longer lifetime (for instance during a HTTP request)
jgauffin
Note that it is the container that is still creating them in the end (as you can see in my example). I find a factory much clearer, but that is of course just one way of doing things ;-)
Steven