自定义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导致该问题。
答
确定问题的确切来源后,很容易修复。
添加这个异步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方法。
你可以在'HttpContext.User'为空的地方显示代码吗?很有可能当时没有Http请求,因此你的问题 – trailmax
好了,确定了问题发生的位置后,解决方案显然是bug引发了另一个问题。如果我重写上面的使用HasPassword异步方法,并使用UserManager.FindByIdAsync,则HttpContext.Current始终有一个值。但是为什么在调用UserManager的同步方法时并非如此?闻起来就像一个错误..也许UserManager内部调用异步方法,并不恢复上下文?时间去看看源代码 – user3566056