Unity DI使用PerRequestLifetimeManager注入DbContext [英] Unity DI Inject DbContext with PerRequestLifetimeManager

查看:864
本文介绍了Unity DI使用PerRequestLifetimeManager注入DbContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  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()抛出错误的方法:由于DbContext已被处理,操作无法完成。


没有这一行代码,一切正常,但是没有设置它可能不会处理上下文。


我的 UnitOfWork class:

  public class UnitOfWork:IUnitOfWork,IDisposable 
{
private readonly VotingSystemContext _context;
private bool _disposed;

// GenericRepository属性

private void Dispose(bool disposal)
{
if(!_disposed)
{
if(disposal)
{
_context.Dispose();
}
}
_disposed = true;
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}

我使用最新版本的 Unity 3.5.1404


提前感谢



编辑:



存储库的Get()方法:

  public sealed class GenericRepository< TEntity> ; :IGenericRepository< TEntity>其中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 = = null,int?pageSize = null)
{
IQueryable< TEntity> query = _dbSet;
if(filter!= null)
{
query = query.Where(filter);
}
列表< 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 )。取(pageSize.Value);
}
返回查询;
}
//其他方法,如删除,更新和GetById
}
}

ApiController的 Get()方法:

  public IEnumerable< VotingModel> Get(int page = 1,int size = 10)
{
//获取所有主题
列表<主题> themes = _themeService.GetAll(page,size);
//将主题转换为VotingModel(与主题相同的模型,不会转换系统抛出关于序列化对象的错误,并添加新的UserName)。
列表< VotingModel> model = themes.Select(t =>
{
MembershipUser membershipUser = Membership.GetUser(t.UserId ?? -1);
return t.ToVotingModel(membershipUser!= null?membershipUser .UserName:string.Empty);
})。ToList();
返回模型;
}

服务 GetAll()方法:

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


解决方案

所以我会有依赖结构如下:




  • UnitOfWork - 获取DbContext

  • 存储库 - 获取UnitofWork

  • 服务 - 获取Repository(ies)

  • ApiController - 获取服务


$ b $你会坚持Unity处理每个人的生命周期。但事情是,您希望服务能够提供请求范围,就像其他人(UoW和Repos)一样。你可能有这样的使用寿命设置,但我不知道Unity在我的头顶。我可以看到你的UofW和repos设置了请求生命周期。



最大的区别在于 UnitOfWork 没有依赖于存储库,而是依赖于其他方式。因此,库基础类通过 UnitOfWork 获得其 DbSet< T> ,它具有 DbContext 。您将在 UnitOfWork 上有一些方法将返回一个 IDbSet< T> 就像您在 DbContext上调用一样。 UnitOfWork DbContext的包装器本身就是相当的工作单位。

  public sealed class GenericRepository< T> :IRepository< T>其中T:BaseEntity 
{
private readonly IDbSet< T> _dbSet;
私人只读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 = = null,int?pageSize = null)
{
IQueryable< TEntity> query = _dbSet;
if(filter!= null)
{
query = query.Where(filter);
}
列表< 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 )。取(pageSize.Value);
}
返回查询;
}
//其他方法,如删除,更新和GetById
}

UnitOfWork 将是类似的,但以 DbContext 作为依赖关系(您可能已经有这个但省略了构造函数):

  public class UnitOfWork:IUnitOfWork 
{
private readonly VotingSystemContext _context;
private bool _disposed;

public UnitOfWork(DbContext context)
{
_context = context;
}

public IDbSet< T>设置< T>()
{
return _context.Set< T>();
]
}

该服务将注册存储库:

  public class ThemeService 
{
private IRepository< Theme> ThemeRepository {get;组;

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

//等
}

ApiController 将获得注入的必需服务,在这种情况下, ThemeService

  public class ApiController ThemeController 
{
private ThemeService _themeService;

public ThemeController(ThemeService service)//连同任何其他需要的服务
{
_themeService = service;
}

public IEnumerable< VotingModel> Get(int page = 1,int size = 10)
{
//获取所有主题
列表<主题> themes = _themeService.GetAll(page,size);
//将主题转换为VotingModel(与主题相同的模型,不会转换系统抛出关于序列化对象的错误,并添加新的UserName)。
列表< VotingModel> model = themes.Select(t =>
{
MembershipUser membershipUser = Membership.GetUser(t.UserId ?? -1);
return t.ToVotingModel(membershipUser!= null?membershipUser .UserName:string.Empty);
})。ToList();
返回模型;
}

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

  DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule)); 

将留下,而$ code> DbContext 将被处理通过Unity,您不必自己调用 Dispose()



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:

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

这篇关于Unity DI使用PerRequestLifetimeManager注入DbContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆