首页 > 解决方案 > 在 Web 环境中使用会话令牌管理 CosmosDb 会话一致性级别

问题描述

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

我的收藏的默认一致性级别设置为“会话”。对于我的用例,我需要一个经过身份验证的 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 或当前有多少其他用户正在使用数据库。

标签: asp.net-coreazure-cosmosdb

解决方案


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

在大多数场景/框架中,将 session 视为静态标识符(相关性),而与 cosmos 一样, sessionToken 是动态的(一种书签/cosmos db 状态的表示,随 writes 而变化)。将其命名为“sessionToken”可能是混淆的根源。

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


推荐阅读