C# OWIN Store update、insert或delete语句影响了意外的行数(0)错误
我遇到了一个非常奇怪的问题,刷新令牌在托管我的WEPAPI项目的Azure应用程序服务上几个小时后“消失”。我已经为我的密码流实现了OAuth。AccessToken在1小时后过期,RefreshToken在一周后过期 了解一些背景。这发生在一个Azure应用程序服务上,我正在托管我的Web Api,一个移动前端正在调用它(有多个用户/移动设备正在调用此应用程序服务) 下面是使用C# OWIN Store update、insert或delete语句影响了意外的行数(0)错误,c#,.net,entity-framework-6,owin,castle-windsor,C#,.net,Entity Framework 6,Owin,Castle Windsor,我遇到了一个非常奇怪的问题,刷新令牌在托管我的WEPAPI项目的Azure应用程序服务上几个小时后“消失”。我已经为我的密码流实现了OAuth。AccessToken在1小时后过期,RefreshToken在一周后过期 了解一些背景。这发生在一个Azure应用程序服务上,我正在托管我的Web Api,一个移动前端正在调用它(有多个用户/移动设备正在调用此应用程序服务) 下面是使用/token调用的初始调用示例: 我的授权类型是密码。通常,我会返回一个刷新\u令牌字段以及访问\u令牌、令牌类型和
/token
调用的初始调用示例:
我的授权类型是密码。通常,我会返回一个刷新\u令牌
字段以及访问\u令牌
、令牌类型
和到期
在我推送应用服务后的最初几个小时内工作正常,然后刷新令牌消失。我真的被这个问题难住了
这是我的CreateAsync
代码:
public async Task CreateAsync(AuthenticationTokenCreateContext context)
{
var clientid = context.Ticket.Properties.Dictionary["as:client_id"];
if (string.IsNullOrEmpty(clientid))
{
return;
}
string refreshTokenId = await CreateRefreshTokenId(clientid, context);
if (refreshTokenId != null)
{
context.SetToken(refreshTokenId);
}
else
{
throw new Exception("refresh token could not be created");
}
}
private async Task<string> CreateRefreshTokenId(string clientId, AuthenticationTokenCreateContext context)
{
var ticket = context.Ticket;
var refreshTokenId = Guid.NewGuid().ToString("n");
var refreshTokenLifeTime = ConfigurationManager.AppSettings["as:clientRefreshTokenLifeTime"];
var token = new CreateRefreshTokenDTO
{
RefreshTokenId = refreshTokenId,
ClientId = clientId,
Subject = ticket.Identity.Name,
IssuedUtc = DateTime.UtcNow,
ExpiresUtc = DateTime.UtcNow.AddMinutes(Convert.ToDouble(refreshTokenLifeTime))
};
ticket.Properties.IssuedUtc = token.IssuedUtc;
ticket.Properties.ExpiresUtc = token.ExpiresUtc;
token.ProtectedTicket = context.SerializeTicket();
var result = await createRefreshTokenManager.ManagerRequest(new CreateRefreshTokenRequest
{
RefreshToken = token
});
return result.IsError ? null : refreshTokenId;
}
这个错误是我无法将任何日志保存到数据库的原因
我使用温莎城堡作为我的IoC和EF6。
我的通话顺序如下:
1] 尝试验证上下文。在这里,我向一个LoginUserManager
调用另一个wait
,在那里我基本上获取并验证了用户信息
// This is used for validating the context
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
2] CreateAsync用于从上下文创建访问和刷新令牌
public async Task CreateAsync(AuthenticationTokenCreateContext context)
在CreateAsync内部,我进行一个wait
调用CreateOrUpdateRefreshTokenManager
,如果条目存在,则执行更新或创建。并最终进行SaveChanges()
如果我不调用SaveChanges()
则该SaveChanges()
就是导致错误的原因。这很奇怪,因为在我的代码的其他部分中,在web请求生命周期结束时,我根本不调用SaveChanges()
,而是进行了更新/创建/删除。我想EF/Windsor会帮我处理储蓄
我的想法是,因为这个流不同于我所有的其他端点,它处理两个异步调用,在这两个调用之间的某个地方,我正在处理DbContext,这可能就是为什么我看到它在第二个(CreateAsync
)调用失败的原因。不确定,只是我的想法
不管怎么说,很抱歉这里的帖子太冗长了。我想发布尽可能多的信息,我希望这也能帮助其他人面对这个或类似的问题
谢谢
更新2
我注意到,在/token
调用中出现此错误后,我进行的任何其他(AllowAnonymous)调用都可以工作,即使是那些涉及数据库的调用。但是,/token
调用不再有效。我唯一的解决方法是重新启动服务器
更新3
我只能在移动测试(链接到Azure服务器)上复制此问题,但无法在本地复制。我用来复制的步骤:
使用一个帐户登录
注销
使用其他帐户登录
注销
使用我尝试的第一个帐户登录)-此操作失败
好吧,你会的,我能找出这个问题,我会尽我所能描述这里发生了什么
对于那些学习过一个或任何其他类似教程的人,您会看到基本上已经设置了一些存储库结构,可能还有您自己的上下文,您继承了基本上下文,对吗
在我的例子中,我在请求结束时通过重写ApiController
类中的Dispose(bool disposing)方法来处理上下文的Dispose。如果你正在构建一个WebApi,你就会知道我在说什么,因为你编写的任何控制器都会继承这个。如果您已经设置了一些IoC,并且将生存时间设置为请求的结尾,那么它将在那里进行处理:)
然而,在这个/token
调用的例子中,我注意到我们从未点击任何控制器……或者至少没有使用ApicController的控制器,所以我甚至无法点击Dispose方法。这意味着环境保持“活跃”。在我对/token
端点的第二次、第三次、第四次etc调用中,我在watcher中注意到上下文调用正在生成(这意味着它正在保存我以前从/token
调用中对上下文所做的编辑-它们从未被处理过!从而使上下文过时)
不幸的是,针对我的情况,解决这个问题的方法是将/token
请求中的任何上下文调用包装在using
语句中,这样我就知道using
完成后,它会正确地处理。这似乎奏效了:)
因此,如果您有一个类似于我的项目或类似于我分享的教程,您可能会遇到这个问题。我有过几次这个错误,最初不知道是什么导致了它。这通常与未正确加载导航属性或将子实体附加到父实体,然后尝试保存有关。感谢@aligray此表-RefreshTokens表-没有外键或子实体。它只是用来保存刷新令牌数据(当然是散列的)。
public async Task CreateAsync(AuthenticationTokenCreateContext context)