问题描述
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
所以我按照建议在,并在代码末尾添加新行:
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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!