繁体   English   中英

Unity DI使用PerRequestLifetimeManager注入DbContext

[英]Unity DI Inject DbContext with PerRequestLifetimeManager


我有以下代码可使用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 constroller发送ajax请求,该WebApi constroller调用该类的GenericReposirory Get()方法, The operation cannot be completed because the DbContext has been disposed.方法抛出错误: 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);
   }
}

PS我使用最新版本的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();
}

因此,我将具有如下所示的依赖结构:

  • UnitOfWork-获取DbContext
  • 存储库-获取工作单位
  • 服务-获取存储库
  • ApiController-获取服务

并且您会坚持使用Unity来处理每个生命周期。 事实是,您希望服务具有请求范围,就像其他服务(UoW和Repos)一样。 您可能以这种方式设置了服务寿命,但我不知道Unity是我的头等大事。 我可以看到您确实为UofW和repos设置了请求生存期。

最大的区别在于, UnitOfWork不依赖于存储库,而是相反。 因此,存储库基类通过具有DbContext.UnitOfWork获取其DbSet<T> DbContext. 您在UnitOfWork上有一些方法可以返回IDbSet<T>就像在DbContext.上调用它DbContext. UnitOfWorkDbContext的包装, DbContext本身就是类似Work of Unit的包装。

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

最终的想法是,Unity容器可以处理所有依赖项的生命周期,而UnitOfWork不必尝试管理存储库。 你的线

DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));

会保留,而DbContext会被Unity处理,而您不必自己对其调用Dispose()

尝试改为使用Microsoft.Practices.Unity.HierarchicalLifetimeManager,方法是:

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

Microsoft.Practices.Unity.HierarchicalLifetimeManager提供:

  1. 在每个请求之后进行Dispose()调用
  2. 每个请求相同的DbContext实例

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM