I have the following code that initialize instances with Unity:
IUnityContainer container = new UnityContainer();
container.RegisterType<DbContext, VotingSystemContext>(new PerRequestLifetimeManager(), new InjectionConstructor());
container.RegisterType(typeof(IGenericRepository<>), typeof(GenericRepository<>));
container.RegisterType<IUnitOfWork, UnitOfWork>(new PerRequestLifetimeManager());
container.RegisterTypes(
AllClasses.FromAssemblies(
Assembly.GetAssembly(typeof(IUserService)),
Assembly.GetAssembly(typeof(UserService))),
WithMappings.FromMatchingInterface,
WithName.Default, WithLifetime.PerResolve);
DependencyResolver.SetResolver(new Unity.Mvc4.UnityDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
I use PerRequestLifetimeManager
so I followed the suggestion on MSDN and added new line at the end of the code above:
DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
But after I placed it. When the page(only static html) is loaded I send ajax request to my WebApi constroller that calls GenericReposirory
Get()
method that throw error: The operation cannot be completed because the DbContext has been disposed.
Without this line of code everything works OK, but without setting it probably the context will not be dispose.
My UnitOfWork
class:
public class UnitOfWork : IUnitOfWork, IDisposable
{
private readonly VotingSystemContext _context;
private bool _disposed;
//GenericRepository properties
private void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_context.Dispose();
}
}
_disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
P.S. I use the latest version of Unity 3.5.1404.
Thanks in advance.
EDIT:
Get() method of Repository:
public sealed class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : BaseEntity
{
public GenericRepository(VotingSystemContext context)
{
_context = context;
_dbSet = context.Set<TEntity>();
}
private readonly DbSet<TEntity> _dbSet;
private readonly VotingSystemContext _context;
public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "", int? page = null, int? pageSize = null)
{
IQueryable<TEntity> query = _dbSet;
if (filter != null)
{
query = query.Where(filter);
}
List<string> properties = includeProperties.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
properties.ForEach(property =>
{
query = query.Include(property);
});
if (orderBy != null)
{
query = orderBy(query);
}
if (page != null && pageSize != null)
{
query = query.Skip((page.Value - 1) * pageSize.Value).Take(pageSize.Value);
}
return query;
}
// other methods like Delete, Update and GetById
}
}
ApiController's Get()
method:
public IEnumerable<VotingModel> Get(int page = 1, int size = 10)
{
//get all themes
List<Theme> themes = _themeService.GetAll(page, size);
//convert themes to VotingModel (same model as Theme just without converting system throw an error about serializing object and also add new filed UserName).
List<VotingModel> model = themes.Select(t =>
{
MembershipUser membershipUser = Membership.GetUser(t.UserId ?? -1);
return t.ToVotingModel(membershipUser != null ? membershipUser.UserName : string.Empty);
}).ToList();
return model;
}
Service GetAll()
method:
public List<Theme> GetAll(int page = 1, int pageSize = 10)
{
return UnitOfWork.ThemeRepository.Get(null, null, "Comments", page, pageSize).ToList();
}
So I would have the dependency structure like so:
and you'd stick with Unity handling the lifetime of each. The thing is though, you'd want the Services to have request scope, just like the others (UoW and Repos). You may have the service lifetime set up that way, but I don't know Unity off the top of my head. I can see that you do have the UofW and repos set with request lifetimes.
The big difference being that the UnitOfWork
doesn't have a dependency on repositories, but rather the other way around. So the repository base class gets its DbSet<T>
via the UnitOfWork
which has the DbContext.
You'd have some method on UnitOfWork
that would return an IDbSet<T>
just as if you were calling that on the DbContext.
The UnitOfWork
being a wrapper for DbContext
which in itself is pretty Unit of Work-like.
public sealed class GenericRepository<T> : IRepository<T> where T : BaseEntity
{
private readonly IDbSet<T> _dbSet;
private readonly IUoW _uoW;
public GenericRepository(IUoW unitOfWork)
{
_uoW = unitOfWork;
_dbSet = _uoW.Set<T>();
}
public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "", int? page = null, int? pageSize = null)
{
IQueryable<TEntity> query = _dbSet;
if (filter != null)
{
query = query.Where(filter);
}
List<string> properties = includeProperties.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
properties.ForEach(property =>
{
query = query.Include(property);
});
if (orderBy != null)
{
query = orderBy(query);
}
if (page != null && pageSize != null)
{
query = query.Skip((page.Value - 1) * pageSize.Value).Take(pageSize.Value);
}
return query;
}
// other methods like Delete, Update and GetById
}
The UnitOfWork
would be similar, but take the DbContext
as the dependency (you may already have this but omitted the constructor):
public class UnitOfWork : IUnitOfWork
{
private readonly VotingSystemContext _context;
private bool _disposed;
public UnitOfWork(DbContext context)
{
_context = context;
}
public IDbSet<T> Set<T>()
{
return _context.Set<T>();
]
}
The service would have the repository injected:
public class ThemeService
{
private IRepository<Theme> ThemeRepository { get; set; }
public ThemeService(IRepository<Theme> themeRepo)
{
ThemeRepository = themeRepo;
}
public List<Theme> GetAll(int page = 1, int pageSize = 10)
{
return ThemeRepository.Get(null, null, "Comments", page, pageSize).ToList();
}
// etc.
}
The ApiController
would get the needed services injected, in this case the ThemeService
:
public class ApiController ThemeController
{
private ThemeService _themeService;
public ThemeController(ThemeService service) // along with any other needed services
{
_themeService = service;
}
public IEnumerable<VotingModel> Get(int page = 1, int size = 10)
{
//get all themes
List<Theme> themes = _themeService.GetAll(page, size);
//convert themes to VotingModel (same model as Theme just without converting system throw an error about serializing object and also add new filed UserName).
List<VotingModel> model = themes.Select(t =>
{
MembershipUser membershipUser = Membership.GetUser(t.UserId ?? -1);
return t.ToVotingModel(membershipUser != null ? membershipUser.UserName : string.Empty);
}).ToList();
return model;
}
The ultimate idea being that the Unity container handles the lifetime of all the dependencies and the UnitOfWork
doesn't have to try to manage repositories. Your line
DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
would stay and the DbContext
would get disposed by Unity, and you don't have to call Dispose()
on it yourself.