使用Web环境中的会话令牌管理CosmosDb会话一致性级别

时间:2018-05-24 03:26:30

标签: asp.net-core azure-cosmosdb

我的环境是ASP.NET Core 2.x使用.NET SDK访问CosmosDb(也就是DocumentDb)。

我的集合的默认一致性级别设置为“Session”。对于我的用例,我需要一个经过身份验证的Web用户,以便在Web请求之间的读/写方面始终保持一致的数据。

我有一些CosmosDB存储库逻辑,可以通过ASP.NET Core Singleton依赖注入使我的控制器逻辑可用:

services.AddSingleton<DocumentDBRepository, DocumentDBRepository>(x =>
                 new DocumentDBRepository(
                     WebUtil.GetMachineConfig("DOCDB_ENDPOINT", Configuration),
                     WebUtil.GetMachineConfig("DOCDB_KEY", Configuration),
                     WebUtil.GetMachineConfig("DOCDB_DB", Configuration),
                     "MyCollection",
                     maxDocDbCons));

DocumentDBRespository创建一个cosmos客户端,如下所示:

  public DocumentDBRepository(string endpoint, string authkey, string database, string collection, int maxConnections)
        {
            _Collection = collection;
            _DatabaseId = database;
            _Client = new DocumentClient(new Uri(endpoint), authkey,
                new ConnectionPolicy()
                {
                    MaxConnectionLimit = maxConnections,
                    ConnectionMode = ConnectionMode.Direct,
                    ConnectionProtocol = Protocol.Tcp,
                    RetryOptions = new RetryOptions()
                    {
                        MaxRetryAttemptsOnThrottledRequests = 10
                    }
                });

            _Client.OpenAsync().Wait();
            CreateDatabaseIfNotExistsAsync().Wait();
            CreateCollectionIfNotExistsAsync().Wait();
        }

据我所知,这意味着每个Web App服务器有一个CosmosDB客户端。我有多个Web应用服务器,因此单个用户可能会从多个AppServer和不同的CosmosDb客户端访问CosmosDB。

在用户与ComosDb交互之前,我检查他们的会话对象是否有CosmosDb SessionToken,如下所示:

string docDbSessionToken = HttpContext.Session.GetString("StorageSessionToken");

然后,在编写文档时,该方法看起来像这样:

 public async Task<Document> CreateItemAsync<T>(T item, Ref<string> sessionTokenOut, string sessionTokenIn = null)
        {
            ResourceResponse<Document> response = null;
            if (string.IsNullOrEmpty(sessionTokenIn))
            {
                response = await _Client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(_DatabaseId, _Collection), item);
            }
            else
            {
                response = await _Client.CreateDocumentAsync(UriFactory.CreateDocumentCollectionUri(_DatabaseId, _Collection), item, new RequestOptions() { SessionToken = sessionTokenIn });
            }

            sessionTokenOut.Value = response.SessionToken;
            Document created = response.Resource;
            return created;
        }

我们的想法是,如果我们有一个会话令牌,我们会传入一个并使用它。如果我们没有,只需创建文档,然后将新创建的会话令牌返回给调用者。这很好用......

除此之外,我不清楚为什么当我传入会话令牌时,我会收到一个不同的会话令牌。换句话说,当_Client.CreateDocumentAsync返回时,response.SessionToken始终与参数sessionTokenIn不同。

这是否意味着我应该为该用户使用新的会话令牌?这是否意味着我应该忽略新的会话令牌并使用初始会话令牌?

这些“会话”中的一个会持续多长时间?他们是传统意义上的会议吗?

最终,我只需要确保同一个用户始终可以读取他们的写入,无论他们连接哪个AppServer或当前有多少其他用户使用该数据库。

提前致谢!

1 个答案:

答案 0 :(得分:0)

我想这里的困惑在于会话是什么?

在大多数情况下/框架将会话视为静态标识符(相关性),其中,与cosmos一样,sessionToken是动态的(cosmos db状态的书签/表示形式,随写入而变化)。将其命名为“sessionToken”可能是混乱的根源。

在这种特定情况下,您应该使用cosmos API中的“返回的会话结构”。