Nhibernate 带StructureMap的ASP.NET MVC 3 RC2中的操作筛选器依赖项注入

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

我一直在使用ASP.NET MVC RC2中的DI支持

我已经为NHibernate实现了每个请求的会话,需要将
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();
        }
    }
}