Unity DI Inject DbContext with PerRequestLifetimeManager

荒凉一梦 提交于 2019-11-30 15:47:48
bcr

So I would have the dependency structure like so:

  • UnitOfWork - gets DbContext
  • Repository - gets UnitofWork
  • Service - gets Repository(ies)
  • ApiController - gets Service(s)

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.

Gabriel Simas

Try to use Microsoft.Practices.Unity.HierarchicalLifetimeManager instead, that´s way:

container.RegisterType<DbContext, VotingSystemContext>(new HierarchialLifetimeManager(), new InjectionConstructor());

The Microsoft.Practices.Unity.HierarchicalLifetimeManager provides:

  1. A Dispose() call after each request
  2. The same DbContext instance per request

Like article: https://jasenhk.wordpress.com/2013/06/11/unit-of-work-and-repository-pattern-with-unity-dependency-injection/

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!