Nhibernate 带StructureMap的ASP.NET MVC 3 RC2中的操作筛选器依赖项注入
我一直在使用ASP.NET MVC RC2中的DI支持 我已经为NHibernate实现了每个请求的会话,需要将Nhibernate 带StructureMap的ASP.NET MVC 3 RC2中的操作筛选器依赖项注入,nhibernate,asp.net-mvc-3,structuremap,Nhibernate,Asp.net Mvc 3,Structuremap,我一直在使用ASP.NET MVC RC2中的DI支持 我已经为NHibernate实现了每个请求的会话,需要将ISession注入我的“工作单元”操作过滤器 如果我直接引用StructureMap容器(ObjectFactory.GetInstance)或使用DependencyResolver获取会话实例,则一切正常: ISession Session { get { return DependencyResolver.Current.GetService<IS
ISession
注入我的“工作单元”操作过滤器
如果我直接引用StructureMap容器(ObjectFactory.GetInstance)或使用DependencyResolver获取会话实例,则一切正常:
ISession Session {
get { return DependencyResolver.Current.GetService<ISession>(); }
}
SessionTest是使用StructureMap筛选器提供程序注入的
我发现在一个有20张图片的页面上,有2-3个请求的“sessionsMatch”是错误的
我的会话管理的StructureMap配置如下:
For<ISessionFactory>().Singleton().Use(new NHibernateSessionFactory().GetSessionFactory());
For<ISession>().HttpContextScoped().Use(ctx => ctx.GetInstance<ISessionFactory>().OpenSession());
这个配置是线程安全的吗?以前,我使用自定义的iactionvoker
将依赖项注入到同一个过滤器中。在MVC3RC2出现上述问题之前,这一切都很好,这就是为什么我想改用过滤器提供程序的原因
任何帮助都将不胜感激
我正在使用NHibernate 3 RC和最新版本的StructureMap
更新:
下面是我对依赖解析程序
和过滤器属性过滤器提供程序
的实现:
public class StructureMapDependencyResolver : IDependencyResolver {
private readonly IContainer container;
public StructureMapDependencyResolver(IContainer container) {
this.container = container;
}
public object GetService(Type serviceType) {
var instance = container.TryGetInstance(serviceType);
if (instance==null && !serviceType.IsAbstract){
instance = AddTypeAndTryGetInstance(serviceType);
}
return instance;
}
private object AddTypeAndTryGetInstance(Type serviceType) {
container.Configure(c=>c.AddType(serviceType,serviceType));
return container.TryGetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType) {
return container.GetAllInstances(serviceType).Cast<object>();
}
}
public class StructureMapFilterAttributeFilterProvider : FilterAttributeFilterProvider
{
private readonly IContainer container;
public StructureMapFilterAttributeFilterProvider(IContainer container) {
this.container = container;
}
protected override IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
return BuildUp(base.GetControllerAttributes(controllerContext, actionDescriptor));
}
protected override IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
return BuildUp(base.GetActionAttributes(controllerContext, actionDescriptor));
}
private IEnumerable<FilterAttribute> BuildUp(IEnumerable<FilterAttribute> attributes) {
foreach (var attr in attributes)
container.BuildUp(attr);
return attributes;
}
}
公共类结构MapDependencyResolver:IDependencyResolver{
专用只读IContainer容器;
公共结构MapDependencyResolver(IContainer容器){
this.container=容器;
}
公共对象GetService(类型serviceType){
var实例=container.TryGetInstance(serviceType);
if(instance==null&!serviceType.IsAbstract){
实例=AddTypeAndTryGetInstance(serviceType);
}
返回实例;
}
私有对象AddTypeAndTryGetInstance(类型serviceType){
Configure(c=>c.AddType(serviceType,serviceType));
返回容器.TryGetInstance(服务类型);
}
公共IEnumerable GetServices(类型serviceType){
return container.GetAllInstances(serviceType.Cast();
}
}
公共类结构MapFilterAttributeFilterProvider:FilterAttributeFilterProvider
{
专用只读IContainer容器;
公共结构映射筛选器属性筛选器提供程序(IContainer容器){
this.container=容器;
}
受保护的重写IEnumerable GetControllerAttributes(ControllerContext ControllerContext,ActionDescriptor ActionDescriptor){
返回构建(base.GetControllerAttributes(controllerContext,actionDescriptor));
}
受保护的覆盖IEnumerable GetActionAttributes(ControllerContext ControllerContext,ActionDescriptor ActionDescriptor){
返回构建(base.GetActionAttributes(controllerContext,actionDescriptor));
}
私有IEnumerable组合(IEnumerable属性){
foreach(属性中的var attr)
容器堆积(attr);
返回属性;
}
}
您是否实现了自己的使用StructureMap的IDependencyResolver?似乎您不能这样做,因为您将会话设置为HttpContext作用域,但在同一请求中看到的是不同的会话。我不知道这是否有帮助,但对于MVC 3,操作筛选器现在被缓存,而不是在每个请求开始时被新实例化。因此,如果在构造函数中注入依赖项,它将无法正常工作。你能发布你的FilterAttributeFilterProvider的实现吗?我想我会回来提供解决方案
正如@Thomas在上面指出的,动作过滤器现在缓存在MVC3中。这意味着,如果您使用预期的较短生命周期(例如http请求)注入对象,它将被缓存
为了解决这个问题,我们没有注入一个ISession
,而是注入一个Func
。然后,每次需要访问ISession时,我们都会调用该函数。这确保即使缓存了ActionFilter,ISession的作用域也正确
我必须像这样配置StructureMap来注入“lazy”实例(不幸的是,它不会像使用Ctor注入那样自动注入一个lazy实例):
x.SetAllProperties(p=>{
p、 of type();
});
我更新的ActionFilter如下:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class UnitOfWorkAttribute : ActionFilterAttribute {
public Func<ISession> SessionFinder { get; set; }
public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext) {
var session = SessionFinder();
session.BeginTransaction();
}
public override void OnResultExecuted(System.Web.Mvc.ResultExecutedContext filterContext) {
var session = SessionFinder();
var txn = session.Transaction;
if (txn == null || !txn.IsActive) return;
if (filterContext.Exception == null || filterContext.ExceptionHandled)
{
session.Transaction.Commit();
}
else
{
session.Transaction.Rollback();
session.Clear();
}
}
}
[AttributeUsage(AttributeTargets.Method,AllowMultiple=true)]
公共类UnitOfWorkAttribute:ActionFilterAttribute{
public Func SessionFinder{get;set;}
公共覆盖无效OnActionExecuting(System.Web.Mvc.ActionExecutingContext筛选器上下文){
var session=SessionFinder();
session.BeginTransaction();
}
public override void OnResultExecuted(System.Web.Mvc.ResultExecutedContext filterContext){
var session=SessionFinder();
var txn=会话事务;
if(txn==null | | |!txn.IsActive)返回;
if(filterContext.Exception==null | | filterContext.ExceptionHandled)
{
Commit();
}
其他的
{
session.Transaction.Rollback();
session.Clear();
}
}
}
我发现了一个类似的问题。听起来不错。那么,会话是如何设置的呢?设置要注入的操作的属性。但是注入了哪个函数?这将取决于您如何使用StructureMap配置依赖项。通常我们会执行类似于For().HttpContextScoped().Use(ctx=>ctx.GetInstance().OpenSession())的操作。
public class StructureMapDependencyResolver : IDependencyResolver {
private readonly IContainer container;
public StructureMapDependencyResolver(IContainer container) {
this.container = container;
}
public object GetService(Type serviceType) {
var instance = container.TryGetInstance(serviceType);
if (instance==null && !serviceType.IsAbstract){
instance = AddTypeAndTryGetInstance(serviceType);
}
return instance;
}
private object AddTypeAndTryGetInstance(Type serviceType) {
container.Configure(c=>c.AddType(serviceType,serviceType));
return container.TryGetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType) {
return container.GetAllInstances(serviceType).Cast<object>();
}
}
public class StructureMapFilterAttributeFilterProvider : FilterAttributeFilterProvider
{
private readonly IContainer container;
public StructureMapFilterAttributeFilterProvider(IContainer container) {
this.container = container;
}
protected override IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
return BuildUp(base.GetControllerAttributes(controllerContext, actionDescriptor));
}
protected override IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
return BuildUp(base.GetActionAttributes(controllerContext, actionDescriptor));
}
private IEnumerable<FilterAttribute> BuildUp(IEnumerable<FilterAttribute> attributes) {
foreach (var attr in attributes)
container.BuildUp(attr);
return attributes;
}
}
x.SetAllProperties(p => {
p.OfType<Func<ISession>>();
});
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class UnitOfWorkAttribute : ActionFilterAttribute {
public Func<ISession> SessionFinder { get; set; }
public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext) {
var session = SessionFinder();
session.BeginTransaction();
}
public override void OnResultExecuted(System.Web.Mvc.ResultExecutedContext filterContext) {
var session = SessionFinder();
var txn = session.Transaction;
if (txn == null || !txn.IsActive) return;
if (filterContext.Exception == null || filterContext.ExceptionHandled)
{
session.Transaction.Commit();
}
else
{
session.Transaction.Rollback();
session.Clear();
}
}
}