我想请求在ASP.NET MVC应用程序中与StructureMap嵌套容器分享您对NHibernate会话和事务管理的经验。有没有人尝试创建一个ActionFilterAttribute
,它将使用事务隔离级别进行参数化,并覆盖OnActionExecuting
,OnActionExecuted
,OnResultExecuted
以开始并提交\ 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应该是完全无状态的,对它来说什么是好的实现。
如果您需要更多信息,请与我们联系。
答案 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一样适用