How to return an instance of ICouchbaseCollection

Hi,

I’m trying to retrieve and instance of ICouchbaseCollection (bucket.DefaultCollection()) to assign to a static property for reuse. I’m using Couchbase version 6.5 server, Net SDK 3.0.2, SharePoint 2019, VS 2019, .Net framework 4.6.1, Windows Server 2016 Standard.

I would greatly appreciate it if you could provide code of a full function to achieve this.

Cheers,
Ray

Hi @raymond.vanleeuwen,

Could you provide some more details? It sounds like you already know how to get a collection object (bucket.DefaultCollection). Could you provide an example of what you’ve already tried and maybe we can help fill in the gaps?

Hi Matthew,

Due to the async operations, function calls have to use the keyword async and return a certain type.
In a SharePoint 2013 environment, windows server 2012, VS 2017, .Net SDK 3.0.2,.net framework 4.6.1 the code pasted below works. The static property Instance (CouchbaseCollection) of the singleton class can be accessed when called.

In the SharePoint 2019 environment, Cluster.ConnectAsync() returns this:
Id = 13150, Status = WaitingForActivation, Method = “{null}”, Result = “{Not yet computed}”

The above is returned for a local Couchbase server as well as a remote one.

Here’s the POC code:

    private static readonly object Mutex = new object();

    private static ICouchbaseCollection Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (Mutex)
                {
                    if (_instance == null)
                    {
                        var bucketName = GetBucketName();
                        var couchbaseUrl = GetCouchbaseURLs();  
                        var password = GetPassword();
                        var userName = GetUserName();
                        _instance = GetCouchbaseBucketCollectionInstance(couchbaseUrl, userName, password, bucketName);
                    }
                }
            }
            return _instance;
        }
    }


    private static ICouchbaseCollection GetCouchbaseBucketCollectionInstance(string url, string userName, string passWord, string bucketName)
    {
        var bucket = GetCluster(url, userName, passWord, bucketName);
        return bucket.Result.DefaultCollection();
    }

    private static async ValueTask<IBucket> GetCluster(string url, string userName, string passWord, string bucketName)
    {
        var cluster = await Cluster.ConnectAsync(url, userName, passWord);

        return await cluster.BucketAsync(bucketName);
    }

Cheers,
Ray

Hey Ray,

Thanks for the code sample. I don’t have a SharePoint environment, but I tried your code in a console app, and it seemed to work okay. I can’t think of a reason why the Couchbase .NET SDK would work differently in SharePoint 2013 vs SharePoint 2019.

There are a couple of pitfalls that may cause you problems (now or in the future). I don’t know if these are related to the problem you are having or not.

  • A Cluster object is created in GetCluster method. Getting a Cluster is a relatively expensive operation. It seems like its being used only by your Instance singleton, but if it’s used elsewhere/multiple times, that could be a lot of unnecessary extra work and connections.
  • It doesn’t look like the Cluster object being created is disposed at any point. I’m not a SharePoint dev, so I’m not familiar with the lifecycle, but that Cluster object needs to be Dispose()d when its no longer being used.
  • Your code is using .Result to turn async code into blocking code. This isn’t really related to Couchbase, but it’s something that could cause problems down the road. I’d refer to some of the great writing from Stephen Cleary about async/await and blocking. You may want to use ConfigureAwait(false) and/or move all of your code to async (again, I’m not a SharePoint dev, so I don’t know if that’s practical or not)

Ray,

I have a semi-educated guess. The use of .Result (or .GetAwaiter().GetResult) in a synchronous method to get an asynchronous result is problematic. Depending on the nature of the code calling your method, this can cause deadlocks, thread pool depletion, or other problems. Since your code is being called by SharePoint, I’d assume that some underlying change in SharePoint is incompatible.

Ideally, you should implement the Instance property instead as a function returning ValueTask and then have everything async up and down the call stack. There are patterns you can use for an asynchronously initialized lazy property, such as this one: https://gist.github.com/StephenCleary/3773234.

1 Like

Hi Matt,

@btburnett3

I’ve applied ConfigureAwait(false) and works fine now in the SharePoint 2019 environment. Confirmed for SharePoint 2013 as well.

Thanks for the tip.

Cheers,
Ray

2 Likes