1

我想分享您在 ASP.NET MVC 应用程序中使用 StructureMap 嵌套容器管理 NHibernate 会话和事务的经验。有没有人尝试创建一个ActionFilterAttribute将使用事务隔离级别参数化并覆盖OnActionExecuting, OnActionExecuted,OnResultExecuted来开始和提交\回滚 NHibernate 事务。我非常感谢您的专业知识。

我使用Building a Better MVC Dependency Resolver来构建 DependencyResolver,并在 ASP.NET MVC: Filters 中将 ISession 注入 TransactionAttribute Dependency Injection

另外,我使用以下实现创建 TransactionAttribute 类:

public class TransactionAttribute : ActionFilterAttribute
{
    public ISession Session { get; set; }
    public bool Distributed { get; set; }

    public IsolationLevel IsolationLevel
    {
        get { return _isolationLevel; }
        set { _isolationLevel = value; }
    }

    private ITransaction _sessionTransaction;
    private TransactionScope _transactionScope;
    private IsolationLevel _isolationLevel = IsolationLevel.ReadCommitted;

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.IsChildAction)
            return;

        if (Session.Transaction == null || !Session.Transaction.IsActive)
        {
            if (Distributed)
                _transactionScope = new TransactionScope(TransactionScopeOption.Required);

            _sessionTransaction = Session.BeginTransaction(IsolationLevel);
        }
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.IsChildAction)
            return;

        if (_sessionTransaction != null)
        {
            if (filterContext.Exception != null && !filterContext.ExceptionHandled)
            {
                try
                {
                    _sessionTransaction.Rollback();
                }
                finally
                {
                    if (_transactionScope != null)
                        _transactionScope.Dispose();
                }
            }
        }
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        if (filterContext.IsChildAction)
            return;

        if (_sessionTransaction != null)
        {
            try
            {
                if (filterContext.Exception == null || filterContext.ExceptionHandled)
                {
                    _sessionTransaction.Commit();

                    if (_transactionScope != null)
                        _transactionScope.Complete();
                }
                else
                {
                    _sessionTransaction.Rollback();
                }
            }
            finally
            {
                if (_transactionScope != null)
                    _transactionScope.Dispose();
            }
        }
    }
}

使用约定来确保我们为控制器创建 unqiue 实例:

public class ControllerConvention : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
        if (type.IsClass && !type.IsAbstract && typeof(IController).IsAssignableFrom(type))
        {
            registry.For(type).LifecycleIs(InstanceScope.Unique).Add(type);
        }
    }
}

我遇到的问题是它适用于简单的情况。但是,有时在更复杂的情况下,我会收到有关访问已处置对象的错误消息。此外,我添加了日志记录并注意到 TransactionAttribute 对象实例经常被重用,因为 Session 属性已经分配了一个旧对象。

我还想知道是否可以控制 ASP.NET MVC 应用程序中 ActionFilterAttributes 的生命周期,以便能够通过嵌套容器和 NHibernate Session 一起处理它。ActionFilterAttribute 是否应该完全无状态,以及什么是好的实现。

如果您需要更多信息,请告诉我。

4

1 回答 1

0

我认为您遇到了这个问题,因为 ActionFilters 不是瞬态的。您在整个应用程序中重复使用它的相同实例。

你可以通过在你的 nhibernate 配置中添加一个属性来管理你的会话:

<property name="current_session_context_class">web</property>

然后你可以像这样在你的属性中绑定会话:

public override void OnActionExecuting(HttpActionContext actionContext)
{
    var session = SessionFactory.OpenSession();
    CurrentSessionContext.Bind(session);
    session.BeginTransaction();
}

然后释放它你可以这样做:

public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
    var session = SessionFactory.GetCurrentSession();
    var transaction = session.Transaction;
    if (transaction != null && transaction.IsActive)
    {
        transaction.Commit();
    }
    session = CurrentSessionContext.Unbind(SessionFactory);
    session.Close();
}

这里有一个很棒的帖子:http ://www.piotrwalat.net/nhibernate-session-management-in-asp-net-web-api/

它适用于 MVC 就像它适用于 WebAPI

于 2013-02-10T14:41:01.200 回答