我正在构建一组API。其中之一是一个认证API,它返回JWT令牌。我正在尝试实施“每次操作的会话”方法,其中包含ActionFiltersAttribute
。我的控制器装饰有此属性:带有任务/线程的RESTful API中的NHibernate会话管理
public class NHibernateSessionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var session = NHibernateSessionManager.SessionFactory.OpenSession();
session.BeginTransaction();
CurrentSessionContext.Bind(session);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var session = CurrentSessionContext.Unbind(NHibernateSessionManager.SessionFactory)
if (session != null)
{
if (session.Transaction.IsActive)
{
try
{
session.Transaction.Commit();
}
catch
{
session.Transaction.Rollback();
}
}
session.Close();
}
}
}
问题在哪里?使用NHibernate来管理用户而不是实体框架我已经实现了所有需要的ASP.NET Identity接口,并且它们都返回Task<T>
。例如以下动作:
AccountController.cs
public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword,
model.NewPassword);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
有ChangePasswordAsync
内部调用多种方法至极里面有新的任务,其中SessionFactory.GetCurrentSession()
导致NullException
代码。据我所知,因为那是另一个线程和上下文。 在代码中,第一次保存尝试没有失败,第二次没有失败。重复的代码仅用于说明情况。
UserStore.cs
public System.Threading.Tasks.Task UpdateAsync(UserModel user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
//Here the Session is found
DataProviderI<UserModel, int> prov = new DataProviderImplGeneric<UserModel, int>();
prov.Save(user);
return Task.Factory.StartNew(() =>
{
//Here the Session is NOT found
DataProviderI<UserModel, int> prov2 = new DataProviderImplGeneric<UserModel, int>();
prov.Save(user);
});
}
什么对付这一点,所有的Action
时得到同样ISession
的最佳方式?
据我所知,NHibernate不支持异步调用,我可以在返回类型为Task.FromResult(0)
的虚方案或Task.FromResult<T>(T)
上重构方法,其中T是一个对象,但我想知道是否有另一种解决方案利用并行性
看看使用DI库,[simpleinjector](https://simpleinjector.org/index.html)是一样的好。使用DI容器,您可以将实例的生命周期与作用域绑定在一起,在这种情况下,您希望将“ISession”绑定到Web请求。 SimpleInjector非常适合这一点,并且适用于任务和异步。 –