我想分享您在 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 是否应该完全无状态,以及什么是好的实现。
如果您需要更多信息,请告诉我。