.ConfigureAwait(false)
..
所讨论的代码看起来很像这样:“testx=…..”行是调试问题以暴露行为的一部分
public async Task<ActionResult> Index()
{
ValidateRoleAccess(Roles.Admin, Roles.AuthorizedUser, Roles.AuditReadOnly);
var test1 = System.Web.HttpContext.Current != null
var decisions = await _lookupService.GetAllDecisions();
var test2 = System.Web.HttpContext.Current != null
var statuses = await _lookupService.GetAllEnquiryStatuses();
var test3 = System.Web.HttpContext.Current != null
var eeoGroups = await _lookupService.GetEEOGroups();
var test4 = System.Web.HttpContext.Current != null
var subCategories = await _lookupService.GetEnquiryTypeSubCategories();
var test5 = System.Web.HttpContext.Current != null
var paystreams = await _lookupService.GetPaystreams();
var test6 = System.Web.HttpContext.Current != null
var hhses = await _lookupService.GetAllHHS();
var test7 = System.Web.HttpContext.Current != null
// ...
调用本身是通过相同的查找服务对EF的简单查询。如果它们是EF并且使用相同的UoW/DbContext,则不能将它们更改为使用
Task.WhenAll()
.
测试1为真->测试7
实际结果:
当我在等待的查找调用之后针对特定角色添加验证时,发现了这个问题。检查触发了验证方法使用的HttpContext.Current上的空引用异常。因此,它在异步之前的ValidateRoleAccess调用中使用时通过,但在所有等待的方法之后调用时失败。
我改变了方法的顺序,在等待2或3次之后失败了,没有特定的罪魁祸首方法。该应用程序的目标是.Net 4.6.1。这是一个非阻塞问题,因为我能够在等待之前执行角色检查,将结果放入变量,并在等待之后引用变量,但是在1-2次等待之后工作是一个非常意外的“gotcha”,但不是更多。代码将被重新分解,因为这些查找不需要异步调用,也不返回整个实体,但我仍然非常好奇,是否有一个解释,为什么在使用.ConfigureAwait(false)的两个等待任务之后,HttpContext会“丢失”。
更新一:情节越来越浓。。
例如:
var decisions = await _lookupService.GetAllDecisions();
results.Add(System.Web.HttpContext.Current != null);
decisions = await _lookupService.GetAllDecisions();
results.Add(System.Web.HttpContext.Current != null);
decisions = await _lookupService.GetAllDecisions();
results.Add(System.Web.HttpContext.Current != null);
返回True,True,True,但将其更改为:
var eeoGroups = _lookupService.GetEEOGroups();
results.Add(System.Web.HttpContext.Current != null);
eeoGroups = _lookupService.GetEEOGroups();
results.Add(System.Web.HttpContext.Current != null);
eeoGroups = _lookupService.GetEEOGroups();
results.Add(System.Web.HttpContext.Current != null);
再深入一点,我注意到这些方法是EntityFramework和旧的基于NHibernate的存储库代码的混合。是EntityFramework异步方法在await上绊倒了上下文。
在等待之后触发上下文的方法之一:
public async Task<List<string>> GetEEOGroups()
{
return await _dbContext.EmployeeEEOGroup.GroupBy(e => e.EEOGroup).Select(g => g.FirstOrDefault().EEOGroup).ToListAsync();
}
同样:*编辑-复制/粘贴的whups:)
public async Task<IEnumerable<SapHHS>> GetAllHHS()
{
return await _dbContext.HHS.Where(x => x.IsActive).ToListAsync();
}
但这很好:
public async Task<IEnumerable<Decision>> GetAllDecisions()
{
return await Task.FromResult(_repository.Session.QueryOver<Lookup>().Where(l => l.Type == "Decision" && l.IsActive).List().Select(l => new Decision { DecisionId = l.Id, Description = l.Name }).ToList());
}
<httpRuntime targetFramework="4.5" />
,EF似乎把这个假设弄错了。