I have an generic implementation of my entity reader and writer. I want to create an registration of these to the same instance. But this fails with the following exception:
An exception of type 'System.InvalidOperationException' occurred in mscorlib.dll but was not handled in user code
var registration = Lifestyle.Scoped.CreateRegistration(typeof (EntityFrameworkRepository<>), container);
container.AddRegistration(typeof (IUnitOfWork), registration);
container.AddRegistration(typeof (IEntityWriter<>), registration);
container.AddRegistration(typeof (IEntityReader<>), registration);
My implementation type signature is as follows:
internal sealed class EntityFrameworkRepository<TEntity> : IEntityWriter<TEntity>, IEntityReader<TEntity>, IUnitOfWork where TEntity : Entity
{
// ...
}
Is generics not supported in the CreateRegistation(..)
or should I just wire them up like (probably will throw an lifestyle warning)?
container.Register(typeof (IUnitOfWork), typeof (EntityFrameworkRepository<>), Lifestyle.Scoped);
container.Register(typeof (IEntityWriter<>), typeof (EntityFrameworkRepository<>), Lifestyle.Scoped);
container.Register(typeof (IEntityReader<>), typeof (EntityFrameworkRepository<>), Lifestyle.Scoped);
I think we're missing a few pre condition checks here, because you can't create Registration
objects for open-generic types. A Registration
instance is specific for a closed-generic or non-generic type. This means that both CreateRegistration(typeof(EntityFrameworkRepository<>), ...
and AddRegistration(typeof(IUnitOfWork), ...
are not valid calls.
I understand what you are trying to do, you want to have the same repository instance during a request, independently whether someone uses it as a writer or a reader. That is obvious, because Simple Injector will throw an exception telling you that you have a Torn Lifestyle.
To apply this design, you will have to define two generic adapters, from each generic abstraction to the generic repository as follows:
public class EnityWriterAdapter<T> : IEntityWriter<T>
{
public EntityWriterAdapter(EntityFrameworkRepository<T> repository) { ... }
}
public class EnityReaderAdapter<T> : IEntityReader<T>
{
public EnityReaderAdapter(EntityFrameworkRepository<T> repository) { ... }
}
Now the registration can become the following:
container.Register(typeof(EntityFrameworkRepository<>),
typeof(EntityFrameworkRepository<>), Lifestyle.Scoped);
container.Register(typeof(IEntityWriter<>), typeof(EntityWriterAdapter<>));
container.Register(typeof(IEntityReader<>), typeof(EntityReaderAdapter<>));
Note that I'm unsure what to do with the IUnitOfWork
registration, because it's unclear to me which closed EntityFrameworkRepository<T>
should get injected into consumers that expect IUnitOfWork
. There seems to be some ambiguity in this.