自定义asp.net身份存储 - 为什么HttpContext.Current时常空

问题描述:

我已经通过以下示例集here实现了ASP.NET身份的自定义用户存储。这一切工作正常,除了这个:自定义asp.net身份存储 - 为什么HttpContext.Current时常空

我需要访问有关当前登录用户在我的用户存储中的数据。通常情况下,你会获得通过访问

HttpContext.Current.User 

现在,一旦auser已登录,如果他的用户,然后转到管理控制器(例如,试图改变他/她的密码),当ASP.NET身份通过呼叫再次查找用户

CustomUserManager.FindByIdAsync(string userId) 

HttpContext.Current完全是空的(即在呈现页面之前)。那么,在这种情况下如何获得有关HttpContext的信息呢?用户已正确登录,那么如何确定哪个用户已经登录?

@edit ..这个问题是在CustomUserStore ..这里是一个有点它

public class CustomUserStore<TUser> : IUserStore<TUser>, IUserLoginStore<TUser>, IUserClaimStore<TUser>, IUserPasswordStore<TUser>, IUserSecurityStampStore<TUser>, IUserEmailStore<TUser>, IUserPhoneNumberStore<TUser>, 
    IUserLockoutStore<TUser, string>, IUserTwoFactorStore<TUser, string>//, IQueryableUserStore<TUser> 
    where TUser: CustomUser<string>, IUser<string> 
{ 

    string storageFile = @"c:\temp\aspnetusers.json"; 
    List<TUser> users; 

    public CustomUserStore() 
    { 
     if (File.Exists(storageFile)) 
     { 
      string contents = File.ReadAllText(storageFile); 
      users = JsonConvert.DeserializeObject<List<TUser>>(contents); 
      if (users == null) 
       users = new List<TUser>(); 
     } 
     else 
      users = new List<TUser>(); 
    } 

    #region IUserStore implementation 

    public Task<TUser> FindByIdAsync(string userId) 
    { 
     string sessionId = HttpContext.Current?.Session?.SessionID; 
     return Task.FromResult<TUser>(users.FirstOrDefault(u => u.Id == userId)); 
    } 

    public Task<TUser> FindByNameAsync(string userName) 
    { 
     string sessionId = HttpContext.Current?.Session?.SessionID; 
     return Task.FromResult<TUser>(users.FirstOrDefault(u => string.Compare(u.UserName, userName, true) == 0)); 
    } 

    #endregion 
} 

,它是在FindByAsync方法,其中HttpContext.Current可以为空。

创建

var model = new IndexViewModel 
     { 
      HasPassword = HasPassword(), 
      PhoneNumber = await UserManager.GetPhoneNumberAsync(userId), 
      TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId), 
      Logins = await UserManager.GetLoginsAsync(userId), 
      BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId) 
     }; 

当模型和它在HasPassword方法FindById请求引起该问题

private bool HasPassword() 
    { 
     var user = UserManager.FindById(User.Identity.GetUserId()); 
     if (user != null) 
     { 
      return user.PasswordHash != null; 
     } 
     return false; 
    } 

其他4个请求它发生在的AccountController的指数方法用户管理器都有一个填写好的HttpContext.Current。所以看起来它是调用UserManager导致该问题。

+1

你可以在'HttpContext.User'为空的地方显示代码吗?很有可能当时没有Http请求,因此你的问题 – trailmax

+0

好了,确定了问题发生的位置后,解决方案显然是bug引发了另一个问题。如果我重写上面的使用HasPassword异步方法,并使用UserManager.FindByIdAsync,则HttpContext.Current始终有一个值。但是为什么在调用UserManager的同步方法时并非如此?闻起来就像一个错误..也许UserManager内部调用异步方法,并不恢复上下文?时间去看看源代码 – user3566056

确定问题的确切来源后,很容易修复。

添加这个异步emthod检查,如果用户有一个密码:

private async Task<bool> HasPasswordAsync() 
    { 
     var user = await UserManager.FindByIdAsync(User.Identity.GetUserId()); 
     if (user != null) 
     { 
      return user.PasswordHash != null; 
     } 
     return false; 
    } 

和索引方法,使用新的异步梅索德

var model = new IndexViewModel 
    { 
     HasPassword = await HasPasswordAsync(), 
     PhoneNumber = await UserManager.GetPhoneNumberAsync(userId), 
     TwoFactor = await UserManager.GetTwoFactorEnabledAsync(userId), 
     Logins = await UserManager.GetLoginsAsync(userId), 
     BrowserRemembered = await AuthenticationManager.TwoFactorBrowserRememberedAsync(userId) 
    }; 

但是,为什么不同步的方法调用打破东西?你可以想象,同步调用会运行到HttpContext.Current应该可用的标准上下文中。

我在我的真实项目中有一个更加自定义的用户存储,我经常遇到这个问题更多..猜我需要检查是否包含更多同步访问UserManager方法。