Unity DI使用PerRequestLifetimeManager注入DbContext

时间:2014-05-02 14:20:40

标签: c# .net entity-framework unity-container


我有以下代码用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);

我使用PerRequestLifetimeManager,因此我按照MSDN上的建议操作,并在上面的代码末尾添加了新行:

DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));

但是在我放好之后。当加载页面(仅静态html)时,我向我的WebApi控制器发送ajax请求,该控制器调用抛出错误的GenericReposirory Get()方法:The operation cannot be completed because the DbContext has been disposed.
没有这行代码,一切正常,但没有设置它可能不会处置上下文。
我的UnitOfWork课程:

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。我使用最新版本的 Unity 3.5.1404
提前谢谢。

修改

存储库的Get()方法:

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的Get()方法:

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;
}

服务GetAll()方法:

public List<Theme> GetAll(int page = 1, int pageSize = 10)
{
    return UnitOfWork.ThemeRepository.Get(null, null, "Comments", page, pageSize).ToList();
}

2 个答案:

答案 0 :(得分:4)

所以我会有这样的依赖结构:

  • UnitOfWork - 获取DbContext
  • 存储库 - 获取UnitofWork
  • 服务 - 获取存储库(ies)
  • ApiController - 获取服务

并且你坚持使用Unity来处理每个人的生命。但事情是,您希望服务具有请求范围,就像其他服务(UoW和Repos)一样。您可以按照这种方式设置服务生命周期,但我并不了解Unity。我可以看到你确实拥有UofW和repos设置请求生命周期。

最大的区别在于UnitOfWork并不依赖于存储库,而是相反。因此,存储库基类通过DbSet<T>通过UnitOfWork得到DbContext.UnitOfWork上有一些方法可以返回IDbSet<T>就像你在DbContext. UnitOfWork上调用DbContext作为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 } 的包装一样,它本身就像工作单位一样。

UnitOfWork

DbContext类似,但是以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>(); ] } 作为依赖项(您可能已经有了这个但省略了构造函数):

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.
}

该服务将注入存储库:

ApiController

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; }

UnitOfWork

最终的想法是Unity容器处理所有依赖项的生命周期,DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule)); 不必尝试管理存储库。你的行

DbContext

将留下并且Dispose()将被Unity处理掉,而您不必自己致电{{1}}。

答案 1 :(得分:2)

尝试使用Microsoft.Practices.Unity.HierarchicalLifetimeManager,这样:

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

Microsoft.Practices.Unity.HierarchicalLifetimeManager提供:

     
      
  1. 每次请求后的Dispose()调用
  2.   
  3. 每个请求使用相同的DbContext实例
  4.   

喜欢文章:https://jasenhk.wordpress.com/2013/06/11/unit-of-work-and-repository-pattern-with-unity-dependency-injection/