Reputation: 4363
I'm having difficulties in understanding how Unity resolves references for objects further down the hierarchy tree and how to inject the relevant constructors.
Currently I have my container configured thus:
container
.RegisterType<IDataContextAsync, Zeus>("ZeusLive", new PerRequestLifetimeManager(), new InjectionConstructor("ZeusLive"))
.RegisterType<IDataContextAsync, Zeus>("Zeus", new PerRequestLifetimeManager(), new InjectionConstructor("Zeus"))
.RegisterType<IUnitOfWorkAsync, UnitOfWork>("ZeusUnitOfWork", new InjectionConstructor(new ResolvedParameter<IDataContextAsync>("Zeus")))
.RegisterType<IRepositoryAsync<cd_Job>, Repository<cd_Job>>(new InjectionConstructor(new ResolvedParameter<IUnitOfWorkAsync>("ZeusUnitOfWork"), new ResolvedParameter<IDataContextAsync>("Zeus")));
(I'm using a generic Unit of work and Repository pattern (https://genericunitofworkandrepositories.codeplex.com/))
The issue is with this line:
.RegisterType<IRepositoryAsync<cd_Job>, Repository<cd_Job>>(new InjectionConstructor(new ResolvedParameter<IUnitOfWorkAsync>("ZeusUnitOfWork"), new ResolvedParameter<IDataContextAsync>("Zeus")))
I get the following error:
The type Repository.Pattern.Ef6.Repository`1[[DataRepository.Models.cd_Job, DataRepository, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] does not have a constructor that takes the parameters (IUnitOfWorkAsync, IDataContextAsync)
Where the constructor for the Repository class is as follows:
public Repository(IDataContextAsync context, IUnitOfWorkAsync unitOfWork)
{
_context = context;
_unitOfWork = unitOfWork;
// Temporarily for FakeDbContext, Unit Test and Fakes
var dbContext = context as DbContext;
if (dbContext != null)
{
_dbSet = dbContext.Set<TEntity>();
}
else
{
var fakeContext = context as FakeDbContext;
if (fakeContext != null)
{
_dbSet = fakeContext.Set<TEntity>();
}
}
}
I suspect my issue is that I don't fully understand how the hierarchical references are resolved and my mistake is obvious, but I'm still learning so would appreciate some pointers
Upvotes: 2
Views: 525
Reputation: 34992
You need to provider the parameters for the InjectionConstructor
in the same order they are defined in your constructor.
Your constructor is defined like this:
public Repository(IDataContextAsync context, IUnitOfWorkAsync unitOfWork)
{
}
So you need to register it like this:
.RegisterType<IRepositoryAsync<cd_Job>, Repository<cd_Job>>(
new InjectionConstructor(
new ResolvedParameter<IDataContextAsync>("Zeus"),
new ResolvedParameter<IUnitOfWorkAsync>("ZeusUnitOfWork")))
As you can notice, I have changed the order in which you were supplying the IDataContextAsync
and IUnitOfWorkAsync
. Basically the way you had it, you were providing the parameters in the wrong order.
As a side note, you don't need to provide a name for every single registration. You only need to provide a name when you want to registering multiple times the same interface, and even in that case you can still have a default unnamed registration.
Also, you don't need to manually tell Unity how to resolve every constructor parameter as by default he is smart enough to resolve it (if it knows how to resolve it).
So your example could be simplified as this:
container
.RegisterType<IDataContextAsync, Zeus>("ZeusLive", new PerRequestLifetimeManager(), new InjectionConstructor("ZeusLive"))
.RegisterType<IDataContextAsync, Zeus>(new PerRequestLifetimeManager(), new InjectionConstructor("Zeus"))
.RegisterType<IUnitOfWorkAsync, UnitOfWork>()
.RegisterType<IRepositoryAsync<cd_Job>, Repository<cd_Job>>();
Unity is smart enough to realize Repository
has a constructor that takes IDataContextAsync
and IUnitOfWorkAsync
, and provide instances for them as he knows how to resolve them. The default registrations for those interfaces will be resolved as instances of the classes Zeus
(with constructor parameter Zeus, probably the connection string?) and UnitOfWork
respectively.
Hope that helps!
Upvotes: 3