下面是Azure Application Insights的一些分析图片。它来自执行该简单请求:
public HttpResponseMessage Login(LoginRequest loginRequest)
{
var t = new DependencyTracker();
using (var context = t.TrackDependency(() => new SocialDbContext(), "NewContext"))
{
var user = t.TrackDependency(() => context.Users.AsNoTracking().SingleOrDefault(x => x.Email == loginRequest.Id || x.Name == loginRequest.Id), "GetUser");
if (user == null) return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.WrongCredentials), "WrongCredentialsUser");
var sid = t.TrackDependency(() => context.IdMappers.AsNoTracking().SingleOrDefault(x => x.Provider == "custom" && x.UserId == user.Id)?.Sid, "GettingSid");
var account = t.TrackDependency(() => context.Accounts.AsNoTracking().SingleOrDefault(a => a.Id == sid), "GettingAccount");
if (account == null) return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.WrongCredentials), "WrongCredentialsAccount");
var incoming = t.TrackDependency(() => Hash(loginRequest.Password, account.Salt), "Hash");
var isLoginOk = t.TrackDependency(() => SlowEquals(incoming, account.SaltedAndHashedPassword), "SlowEquals");
if (isLoginOk && account.TempPasswordExpiry != null)
{
if (DateTimeOffset.Now.CompareTo(account.TempPasswordExpiry.Value) > 0)
return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.WrongCredentials), "WrongCredentialsPassword");
return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.TemporaryPassword), "WrongCredentialsExpiredTempPassword");
}
return isLoginOk
? t.TrackDependency(() => SendToken(user.Id, sid), "SendToken")
: t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.Unauthorized, ApiError.WrongCredentials), "WrongCredentialsPassword");
}
}
有3个SingleOrDefault
来电。在分析器结果中,我看到了这三个电话。
连接这些令人难以置信的等待时间是多少?
是什么原因导致他们以及如何驾驭它?
更新的
我可能错了,但我想我知道that line中解释的this documentation中的延迟加载和锁定Metdata会发生什么。
帐户将需要sid但它锁定了元数据。所以,等待。然后sid需要用户,但它锁定了元数据。所以用户等待。然后用户执行然后sid然后帐户
虽然我会认为user == null
和.Sid
会迫使执行。
有没有办法把延迟加载来测试我说的是什么?
更新2
我刚刚在我的上下文中尝试了this.Configuration.LazyLoadingEnabled = false;
,但问题仍然存在:-(
请注意,我每5分钟左右才能重现一次。在它们之间似乎有一些缓存,因为查询会立即执行。
更新3
我用一个查询而不是三个查询替换了代码:
public HttpResponseMessage Login(LoginRequest loginRequest)
{
var t = new DependencyTracker();
using (var context = t.TrackDependency(() => new SocialDbContext(), "NewContext"))
{
var query = from a in context.Users
join b in context.IdMappers on a.Id equals b.UserId
join c in context.Accounts on b.Sid equals c.Id
where b.Provider == "custom" && (a.Email == loginRequest.Id || a.Name == loginRequest.Id)
select new { Sid = c.Id, c.Salt, c.SaltedAndHashedPassword, c.TempPasswordExpiry, UserId = a.Id };
var account = t.TrackDependency(() => query.SingleOrDefault(), "GettingAccount");
if (account == null) return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.WrongCredentials), "WrongCredentialsAccount");
var incoming = t.TrackDependency(() => Hash(loginRequest.Password, account.Salt), "Hash");
var isLoginOk = t.TrackDependency(() => SlowEquals(incoming, account.SaltedAndHashedPassword), "SlowEquals");
if (isLoginOk && account.TempPasswordExpiry != null)
{
if (DateTimeOffset.Now.CompareTo(account.TempPasswordExpiry.Value) > 0)
return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.WrongCredentials), "WrongCredentialsPassword");
return t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.BadRequest, ApiError.TemporaryPassword), "WrongCredentialsExpiredTempPassword");
}
return isLoginOk
? t.TrackDependency(() => SendToken(account.UserId, account.Sid), "SendToken")
: t.TrackDependency(() => Request.CreateResponse(HttpStatusCode.Unauthorized, ApiError.WrongCredentials), "WrongCredentialsPassword");
}
}
但问题仍然存在,即使现在只有一次等待 但同样,它每5分钟才会发生一次 注意:我无法在本地重现它,它只发生在Azure上。
更新4
即使在通过上下文调用存储过程时,问题仍然存在。所以我猜这与查询计划无关
我不明白的是,即使我用SqlCommand
调用存储过程因此没有实体框架,问题仍然存在......
更新5
这不是实体框架问题。问题是等待sql连接。无论是使用EF还是使用SqlCommand
,每5分钟都会出现相同的慢速等待时间。我将结束这个问题并用适当的问题打开一个新问题。