2017-08-04 40 views
1

我已經通過以下示例集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

回答

0

確定問題的確切來源後,很容易修復。

添加這個異步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方法。