This is more of an async/await question than ASP.NET Identity. I am using Asp.Net Identity, and have a custom UserStore, with a customized GetRolesAsync method. The UserManager is called from a WebApi controller.
public class MyWebApiController {
private MyUserManager manager = new MyUserManager(new MyUserStore());
[HttpGet]
public async Task<bool> MyWebApiMethod(int x) {
IList<string> roles = await manager.GetRolesAsync(x);
return true;
}
}
public class MyUserManager : UserManager<MyUser, int> {
// I do not implement a custom GetRolesAsync in the UserManager, but
// from looking at the identity source, this is what the base class is doing:
// public virtual async Task<IList<string>> GetRolesAsync(TKey userId)
// {
// ThrowIfDisposed();
// var userRoleStore = GetUserRoleStore();
// var user = await FindByIdAsync(userId).WithCurrentCulture();
// if (user == null)
// {
// throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.UserIdNotFound,userId));
// }
// return await userRoleStore.GetRolesAsync(user).WithCurrentCulture();
// }
}
public class MyUserStore {
public async Task<IList<string>> GetRolesAsync(TUser user) {
// I need HttpContext here and it is NULL. WHY??
var currentContext = System.Web.HttpContext.Current; // NULL!
var query = from userRole in _userRoles
where userRole.UserId.Equals(userId)
join role in _roleStore.DbEntitySet on userRole.RoleId equals role.Id
select role.Name;
return await query.ToListAsync();
}
}
Why is context null in MyUserStore.GetRolesAsync? I thought await passed the context down? I've stepped through other async methods in MyUserStore and they all have the correct context, and the code seems virtually identical.
This turns out to be a property of
TaskExtensions.WithCurrentCulture
. These are the docs for EF, but they apply for ASP.NET Identity as well:This causes the synchronization context not to marshal, which causes
HttpContext
to benull
.Here is the relevant part from the source: