2
votes

My environment is ASP.NET Core 2.x accessing CosmosDb (aka DocumentDb) with the .NET SDK.

The default consistency level of my collection is set to "Session". For my use-case I need a single authenticated web user to always have consistent data in terms of reads/writes between web requests.

I have some CosmosDB Repository logic that is made available to my controller logic via ASP.NET Core Singleton dependency injection as such:

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 creates a cosmos client like so:

  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();
        }

As far as I understand that means one CosmosDB client per Web App server. I do have multiple web app servers, so a single user might hit the CosmosDB from multiple AppServers and different CosmosDb clients.

Before a user interacts with the ComosDB, I check their session object for a CosmosDb SessionToken, like so:

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

Then, when writing a document for example, the method looks something like so:

 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;
        }

The idea being that if we have a session token, we pass one in and use it. If we don't have one, just create the document and then return the newly created session token back to the caller. This works fine...

Except, I'm unclear as to why when I do pass in a session token, I get a DIFFERENT session token back. In other words, when _Client.CreateDocumentAsync returns, response.SessionToken is always different from parameter sessionTokenIn.

Does that mean I should be using the new session token from that point on for that user? Does it mean I should ignore the new session token and use the initial session token?

How long do one of these "sessions" even last? Are they sessions in the traditional sense?

Ultimately, I just need to make sure that the same user can always read their writes, regardless of which AppServer they connect with or how many other users are currently using the DB.

1
I see this is an old question but I'm wondering if you ever got an answer to this question? - Joshua Hayes
Had upvoted Q and A as both are great, but this is a dup and is well-answered in stackoverflow.com/a/37060289/11635 - Ruben Bartelink

1 Answers

1
votes

I guess the confusion here is on what a session is?

In most scenarios/frameworks treat session as static identifier (correlation), where as with cosmos the sessionToken is dynamic (kind of bookmark/representation of cosmos db state, which changes with writes). Naming it as 'sessionToken' might be root of the confusion.

In this specific scenario, you should use the "returned sessiontoken" from cosmos API's.