使用ASP.NET MVC应用程序中的StructureMap嵌套容器进行NHibernate会话/ Transacion管理

时间:2012-09-26 06:02:25

标签: asp.net-mvc-3 nhibernate structuremap

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

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

另外,我使用以下实现创建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 Application中ActionFilterAttributes的生命周期,以便能够通过Nested Container和NHibernate Session一起处理它。 ActionFilterAttribute应该是完全无状态的,对它来说什么是好的实现。

如果您需要更多信息,请与我们联系。

1 个答案:

答案 0 :(得分: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一样适用