2015-10-19 36 views
0

我正在构建一组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是一个对象,但我想知道是否有另一种解决方案利用并行性

+0

看看使用DI库,[simpleinjector](https://simpleinjector.org/index.html)是一样的好。使用DI容器,您可以将实例的生命周期与作用域绑定在一起,在这种情况下,您希望将“ISession”绑定到Web请求。 SimpleInjector非常适合这一点,并且适用于任务和异步。 –

回答

1

看起来好像你正在处理的问题是由于HttpContext在任务内部为空,因此无法访问存储在上下文变量中的NHibernate会话。

您可以通过在调用任务之前获取ISession来解决此问题。

添加在构造函数中您DataProviderImplGeneric所以你手动传递一个在你从任务中调用此之前

DataProviderImplGeneric(ISession session) { 
     this.session = session; 
} 

只是检索会话。

var session = GetCurrentNHibernateSession(); 

return Task.Factory.StartNew(() => { 
    var dataProvider = DataProviderImplGeneric<UserModel, int>(session); 
    return dataProvider.Save(user); 
}