NHibernate会话关闭时,页面
这是我今天遇到的另一个奇怪的问题!我创建了使用nhibernate的MVC 4应用程序。并在我的HomeController上添加了名为[LoggingNHibernateSessionAttribute]的过滤器属性,该属性管理每个操作的会话。我遵循'ASP.NET MVC4和Apress发布的Web API'。NHibernate会话关闭时,页面
public class LoggingNHibernateSessionAttribute : ActionFilterAttribute
{
private readonly IActionLogHelper _actionLogHelper;
private readonly IActionExceptionHandler _actionExceptionHandler;
private readonly IActionTransactionHelper _actionTransactionHelper;
public LoggingNHibernateSessionAttribute()
: this(WebContainerManager.Get<IActionLogHelper>(),
WebContainerManager.Get<IActionExceptionHandler>(),
WebContainerManager.Get<IActionTransactionHelper>())
{
}
public LoggingNHibernateSessionAttribute(
IActionLogHelper actionLogHelper,
IActionExceptionHandler actionExceptionHandler,
IActionTransactionHelper actionTransactionHelper)
{
_actionLogHelper = actionLogHelper;
_actionExceptionHandler = actionExceptionHandler;
_actionTransactionHelper = actionTransactionHelper;
}
public override void OnActionExecuting(ActionExecutingContext actionExectingContext)
{
_actionLogHelper.LogEntry(actionExectingContext.ActionDescriptor);
_actionTransactionHelper.BeginTransaction();
}
public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
{
_actionTransactionHelper.EndTransaction(actionExecutedContext);
_actionTransactionHelper.CloseSession();
_actionExceptionHandler.HandleException(actionExecutedContext);
_actionLogHelper.LogExit(actionExecutedContext.ActionDescriptor);
}
}
ActionTransactionHelper
public class ActionTransactionHelper : IActionTransactionHelper
{
private readonly ISessionFactory _sessionFactory;
private readonly ICurrentSessionContextAdapter _currentSessionContextAdapter;
public ActionTransactionHelper(
ISessionFactory sessionFactory,
ICurrentSessionContextAdapter currentSessionContextAdapter)
{
_sessionFactory = sessionFactory;
_currentSessionContextAdapter = currentSessionContextAdapter;
}
public void BeginTransaction()
{
var session = _sessionFactory.GetCurrentSession();
if (session != null)
{
session.BeginTransaction();
}
}
public bool TransactionHandled { get; private set; }
public void EndTransaction(ActionExecutedContext filterContext)
{
var session = _sessionFactory.GetCurrentSession();
if (session == null) return;
if (!session.Transaction.IsActive) return;
if (filterContext.Exception == null)
{
session.Flush();
session.Transaction.Commit();
}
else
{
session.Transaction.Rollback();
}
TransactionHandled = true;
}
public bool SessionClosed { get; private set; }
public void CloseSession()
{
if (_currentSessionContextAdapter.HasBind(_sessionFactory))
{
var session = _sessionFactory.GetCurrentSession();
session.Close();
session.Dispose();
_currentSessionContextAdapter.Unbind(_sessionFactory);
SessionClosed = true;
}
}
}
运行应用程序时,我可以在数据库中保存的实体。但是当我点击刷新按钮和异常抛出指示会话关闭。
我不知道为什么会发生这种情况。 (我搜索并找到这个NHibernate throwing Session is closed,但无法解决我的问题)。
在我的NinjectConfigurator中,我将inRequestScope()添加到所有注入但没有答案。我检查了什么时候刷新页面会话将被打开。但我不知道它为什么说会议闭幕?!
UPDATE:
当我第一次运行该应用程序。我可以创建一个新成员。但是当我点击刷新按钮时,会话将意外关闭! 第一次运行:
- 一切击中刷新按钮后,效果很好
:
- 一个新的会话绑定到当前上下文。
- 新的会话将被注入该库(会话是打开的)
- 的ActionTransactionHelper调用的BeginTransaction() 4- customMembership的createUser(....)称为 5但当_userRepositoy.save(用户)称为在存储库会话关闭!!!!
注意:但是当仍然没有调用endTransaction和closeSession时。但会议如何关闭?如果我在onActionExecute()中注释closeSession(),则返回 。会话一直开放,如果刷新页面,一切都会很好。 我查了很多,并尝试了我认识的不同方式。它只发生在我第二次想用我的customMembership进行CRUD操作时。
对于其他实体,它的作用就像一个魅力! 我已经上传了我的示例代码。用于测试只需创建并清空数据库并更改连接字符串。然后去到localhost:*****/API /类别(用户,并通过不要求)
下载示例项目: 大小:47 MB https://www.dropbox.com/s/o63wjng5f799fii/Hashem-MVC4ServicesBook.rar
大小:54 MB Zip格式: https://www.dropbox.com/s/smrsbz4cbtznx1y/Hashem-MVC4ServicesBook2.zip
这里非常重要的一点,可能是NHibernate的本质。 NHibernate和它的Session
在ASP.NET MVC中活得更长,然后可以预料。我指的不仅是内部的
- ActionExecuting的(控制器操作开始)
- ActionExecuted(查看或重定向的叫法),其实
会议还必须度过渲染的阶段。因为我们可以在“Action()”中加载一些代理,但是它的集合只能在View
渲染期间加载lazily
。因此,即使在这些阶段Session
必须(从请求begining同一个Session)打开
- ResultExecuting(代理可能一开始就被这里只加载)
- ResultExecuted(几乎全部完成,让我们紧密会话)
其他的话...... 保持会话打开throught完整的请求。从授权直到呈现内容。
注:Anohter提示,只是为了确保一切正常,我使用的这个场景(也许你做的一样好):
- 客户端形式是约将数据发送到服务器。该方法是POST,该行动是更新()
- 发送FORM即将服务器,操作更新()是triggerred - 所有交易的东西到位(如上所述)
- 一旦NHibernate的持续数据到数据库,更新()动作结束,被重定向到行动
-
Detail()
如果一切正常或 -
Edit()
,如果出现错误
-
- 用户的浏览器重定向到操作细节或编辑。因此,如果用户进行刷新,则刷新细节或编辑。该
Update()
根本没有被调用(这是一个POST方法)
事实上,步骤1.是操作Detail
或Edit
之一。在这种情况下,我们将面临这个问题...
你有这个错误,因为Asp.Net MVC不会创建LoggingNHibernateSessionAttribute
每个请求的新实例。它首次请求操作并在将来使用此实例时会创建一个新实例。
行为如下:
- 的
Post
首先调用 - 创建>一个又一个的 'LoggingNHibernateSession' 实例 - 创建
-
Put
首先调用 'LoggingNHibernateSession'>新实例 - 第二次调用
Put
- >使用上一步中的“LoggingNHibernateSession”实例 -
第一次调用
Delete
- >另一个 'LoggingNHibernateSession' 的实例使用Func<IActionLogHelper>
代替在构造IActionLogHelper
创建[LoggingNHibernateSession] public JsonResult Post(Dto data) { /* ... */ } [LoggingNHibernateSession] public JsonResult Put(int id, Dto data) { /* ... */ } [LoggingNHibernateSession] public JsonResult Delete(int id) { /* ... */ }
它可以解决。IActionLogHelper
的实例可以在OnActionExecuting
方法中初始化。
public class LoggingNHibernateSessionAttribute : ActionFilterAttribute
{
/* your code */
private readonly Func<IActionTransactionHelper> _getActionTransactionHelper;
private IActionTransactionHelper _actionTransactionHelper;
public LoggingNHibernateSessionAttribute()
: this(WebContainerManager.Get<IActionLogHelper>(),
WebContainerManager.Get<IActionExceptionHandler>(),
() => WebContainerManager.Get<IActionTransactionHelper>())
{
}
public LoggingNHibernateSessionAttribute(
IActionLogHelper actionLogHelper,
IActionExceptionHandler actionExceptionHandler,
Func<IActionTransactionHelper> getActionTransactionHelper)
{
_actionLogHelper = actionLogHelper;
_actionExceptionHandler = actionExceptionHandler;
_getActionTransactionHelper = getActionTransactionHelper;
_actionTransactionHelper = null;
}
public override void OnActionExecuting(ActionExecutingContext actionExectingContext)
{
_actionTransactionHelper = _getActionTransactionHelper();
_actionLogHelper.LogEntry(actionExectingContext.ActionDescriptor);
_actionTransactionHelper.BeginTransaction();
}
/* your code */
}
我想可能是因为这个。你会解释更多关于你的解决方案吗? –
通常IoC容器的实例是在'Application_Start'中创建的,并放置在'Application_End'中。所以,你可以创建一个函数来解析每次调用时的依赖(它类似于延迟加载),并且每次请求(OnActionExecuting)都会返回一个新的IActionTransactionHelper实例。上传的示例代码为 –
。请检查。 –
上传的示例代码。请检查。 –