How do I inject my dbContext class using Unity? I can\'t just create a Interface like for my other \"normal\" classes? What should I do with my RequestContext class and what
I'm solving this problem with DbContext.SetDbContext
wrapper class and generics.
I have IRepositoryContext
interface and RepositoryContext
to wrap my DbContext:
public interface IRepositoryContext
{
DbContext DbContext { get; }
///
/// Commit data.
///
void Save();
}
public class RepositoryContext : IRepositoryContext
{
private readonly DbContext _dbContext;
public RepositoryContext(DbContext dbContext)
{
_dbContext = dbContext;
}
public DbContext DbContext { get { return _dbContext; } }
public void Save()
{
_dbContext.SaveChanges();
}
}
Ok, then I write bas implementation of generic repository:
public abstract class RepositoryBase : IRepository
where TEntity : class , IEntity, IRetrievableEntity
where TId : struct
{
protected readonly IRepositoryContext RepositoryContext;
protected readonly DbContext Context;
protected RepositoryBase(IRepositoryContext repositoryContext)
{
RepositoryContext = repositoryContext;
}
public DbSet Data { get { return RepositoryContext.DbContext.Set(); }
public TEntity Get(TId id)
{
return Data.Find(id);
}
public virtual IList GetAll()
{
return Data.ToList();
}
public virtual TEntity Save(TEntity entity)
{
try
{
var state = entity.Id.Equals(default(TId)) ? EntityState.Added : EntityState.Modified;
RepositoryContext.DbContext.Entry(entity).State = state;
RepositoryContext.Save();
return entity;
}
catch (DbEntityValidationException e)
{
throw ValidationExceptionFactory.GetException(e);
}
}
public virtual void Delete(TEntity entity)
{
if (entity == null) return;
Data.Remove(entity);
Context.SaveChanges();
}
public void Commit()
{
RepositoryContext.Save();
}
public IList Get(Expression> criteria)
{
return Data.Where(criteria).ToList();
}
// some other base stuff here
}
Ok, now I can register my DbContext with next extension methods:
public static class RikropCoreDataUnityExtensions
{
#region Const
private readonly static Type _repositoryInterfaceType = typeof(IRepository<,>);
private readonly static Type _deactivatableRepositoryInterfaceType = typeof(IDeactivatableRepository<,>);
private readonly static Type _deactivatableEntityType = typeof(DeactivatableEntity<>);
private readonly static Type _retrievableEntityType = typeof(IRetrievableEntity<,>);
#endregion Const
#region public methods
///
/// Register wrapper class.
///
/// DbContext type.
/// Unity-container.
public static void RegisterRepositoryContext(this IUnityContainer container)
where TContext : DbContext, new()
{
container.RegisterType(new InjectionFactory(c => new RepositoryContext(new TContext())));
}
///
/// Register wrapper class.
///
/// DbContext type.
/// Unity-container.
/// DbContext constructor.
/// Connection string name.
public static void RegisterRepositoryContext(this IUnityContainer container,
Func contextConstructor, string connectionString)
where TContext : DbContext
{
container.RegisterType(
new InjectionFactory(c => new RepositoryContext(contextConstructor(connectionString))));
}
///
/// Automatically generation and registration for generic repository marked by attribute.
///
/// Unity-container.
/// Assembly with repositories marked with RepositoryAttribute.
public static void RegisterCustomRepositories(this IUnityContainer container, Assembly assembly)
{
foreach (var repositoryType in assembly.GetTypes().Where(type => type.IsClass))
{
var repositoryAttribute = repositoryType.GetCustomAttribute();
if (repositoryAttribute != null)
{
container.RegisterType(
repositoryAttribute.RepositoryInterfaceType,
repositoryType,
new TransientLifetimeManager());
}
}
}
///
/// Automatically generation and registration for generic repository for all entities.
///
/// Unity-container.
/// Assembly with Entities which implements IRetrievableEntity.
public static void RegisterRepositories(this IUnityContainer container, Assembly assembly)
{
foreach (var entityType in assembly.GetTypes().Where(type => type.IsClass))
{
if (!entityType.InheritsFromGeneric(_retrievableEntityType))
continue;
Type[] typeArgs = entityType.GetGenericTypeArguments(_retrievableEntityType);
Type constructedRepositoryInterfaceType = _repositoryInterfaceType.MakeGenericType(typeArgs);
container.RegisterRepository(constructedRepositoryInterfaceType);
if (entityType.InheritsFrom(_deactivatableEntityType.MakeGenericType(new[] { typeArgs[1] })))
{
var constructedDeactivatableRepositoryInterfaceType =
_deactivatableRepositoryInterfaceType.MakeGenericType(typeArgs);
container.RegisterRepository(constructedDeactivatableRepositoryInterfaceType);
}
}
}
#endregion public methods
#region private methods
///
/// Generate and register repository.
///
/// Unity-container.
/// Repository interface type.
private static void RegisterRepository(this IUnityContainer container, Type repositoryInterfaceType)
{
var factoryGenerator = new RepositoryGenerator();
var concreteFactoryType = factoryGenerator.Generate(repositoryInterfaceType);
container.RegisterType(
repositoryInterfaceType,
new TransientLifetimeManager(),
new InjectionFactory(
c =>
{
var activator = new RepositoryActivator();
return activator.CreateInstance(c, concreteFactoryType);
}));
}
#endregion private methods
}
Finally you can just resolve IRepository
on your classes. You just need to register your RepositoryContext
:
container.RegisterRepositoryContext();
//container.RegisterRepositoryContext(s => new MyDbContext(s), "myConStr");
And your repository will resolve IRepositoryContext and you can have access to DbSet
and other DbContext members via IRepositoryContext
property.
You can use full source code for repositories, Unity-helpers on Github.