Reputation:
Is there a way I can acheieve the following in a shorter way than explicitly register those types one by one:
builder.RegisterType<Repo1>().Keyed<IRepository>(typeof(Repo1));
builder.RegisterType<Repo2>().Keyed<IRepository>(typeof(Repo2));
builder.RegisterType<Repo3>().Keyed<IRepository>(typeof(Repo3));
..
Registering each repository as IRepository interface with it's type as key, so that I can use IIndex<Type, IRepository>
Thanks in advance
Upvotes: 0
Views: 6726
Reputation: 1
Taking a little inspiration from MEF , I have created a similar "Export Attribute" to achieve this in autofac. You can create an Export attribute and use it on each implementation of IRepository as
[Export(typeof(IRepository))]
.
e.g. [Export(typeof(IRepository))]
class Repo1:IRepository
{}
At the time of registration, simply extract the type and using RegisterGeneric(), register your components.
/// <summary>
/// Export attribute to allow registering components using autofac.
/// This attribute must be used for all pluggable components that require to be discovered dynamically.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class ExportAttribute:Attribute
{
private Type type;
public ExportAttribute(Type type)
{
this.type = type;
}
/// <summary>
/// Provides the type (any interface) of Export
/// </summary>
public Type Type { get { return this.type; } }
}
/// <summary>
/// Registers components based on Export attribute containing their type information
/// </summary>
private void BuildContainer()
{
var allAssemblies = AssemblyInitializer.GetLoadedPlugins();
allAssemblies.ForEach(assembly =>
{
var allTypes = assembly.GetTypes().Where(a => a.GetCustomAttribute(typeof(ExportAttribute)) != null).ToList<Type>();
allTypes.ForEach(y =>
{
var classType = ((ExportAttribute)(y.GetCustomAttribute(typeof(ExportAttribute)))).Type;
if (!classType.IsInterface || !classType.IsAbstract || !classType.IsPublic) return;
if (classType.Equals(typeof(IRepository<>)))
{
builder.RegisterGeneric(y.GetTypeInfo()).Named(y.GetTypeInfo().Name, typeof(IRepository<>));
}
// Handle code for any other specific Interfaces
});
});
this.Container = builder.Build();
}
Upvotes: 0
Reputation: 391
You could register a function that will return a repository for a given type, to use in your Unit of Work. Func<Type, IRepository>
can be registered in Autofac and injected into your Unit of Work.
// register your services as per Nico's answer
builder.Register...
// register a factory with Autofac
builder.Register<Func<Type, IRepository>>(x => {
var context = x.Resolve<IComponentContext>();
return y => {
return (IRepository) context.Resolve(y);
};
});
// use the factory in your Unit of Work
class UnitOfWork
{
readonly Func<Type, IRepository> _factory;
public void SomeMethod(object o)
{
var repository = _factory(o.GetType());
repository.DoSomething(o);
}
}
Upvotes: 2
Reputation: 12683
Not really sure if I am following the question correctly howevery typically IRepository points to a data repository with generic functions (insert, update, delete etc). However autofac keyed services are used to register the service with key names (or any key type). If this is the case you will have to come up with a solution that can locate all your Repo
types and register them individually in a loop. This could be achieved using Reflection. However each object Repo1
, Repo2
etc, will need a common derivative.
For example lets say each Repo
object derrives from the interface IRepo
then we can use reflection to find all instances of the IRepo
interface where the type is a class
then loop through each instance registering it to your container. Something like.
var iRepoType = typeof(IRepo);
var repoTypes = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => type.IsClass && iRepoType.IsAssignableFrom(type))
.ToList();
foreach(var repoType in repoTypes)
{
builder.RegisterType(repoType).Keyed<IRepository>(repoType);
}
Now personally this doesn't make any sense as when you look at this keyed service you are saying when I pass in the key typeof(Repo1)
I want Repo1
. Therefore isn't this the same as registering each type of Repository differently without using Keyed services?
I have posted an answer in code review talking about Repository patterns and classes that may also be some interest.
Upvotes: -1