C# OWIN Store update、insert或delete语句影响了意外的行数(0)错误

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令牌、令牌类型和

我遇到了一个非常奇怪的问题,刷新令牌在托管我的WEPAPI项目的Azure应用程序服务上几个小时后“消失”。我已经为我的密码流实现了OAuth。AccessToken在1小时后过期,RefreshToken在一周后过期

了解一些背景。这发生在一个Azure应用程序服务上,我正在托管我的Web Api,一个移动前端正在调用它(有多个用户/移动设备正在调用此应用程序服务)

下面是使用
/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)