Bucket.Scope comes up missing

In my Data Access class I’ve “created” a cluster connection in by class constructor thus:
public class DAL_CMDB
{
private ICluster _cluster;

    public DAL_CMDB(IAsyncLoggerClient logger, IConfiguration iConfig)
    {
        //_CMDB = cmdb;
        log = logger;
        _config = iConfig;
        IConfigurationSection CouchbaseSection = _config.GetSection("couchbase");
        _cluster = (ICluster)Cluster.ConnectAsync(
            CouchbaseSection.GetValue<string>("ConnectionString")
            , CouchbaseSection.GetValue<string>("Username")
            , CouchbaseSection.GetValue<string>("Password")
            );

    }

then in my task

{
            IGetResult getResult = null;
            string documentPath = CachedDocumentKey(documentName);
            if (documentPath != String.Empty)
            { // Apply the mapping key to retrieve data from the correct location in couchbase
                string[] CBSchema = documentPath.Split('.');
                var buket = _cluster.BucketAsync(CBSchema[0]);
                var scoap = buket.Scope(CBSchema[1]);
                var collekshun = scoap.Collection(CBSchema[2]);
                if (CBSchema.Length > 3)
                {
                    getResult = collekshun.GetAsync(CBSchema[3]);
                }
            }
            else

However on building I get the error:
Severity Code Description
Error CS1061 ‘ValueTask’ does not contain a definition for ‘Scope’ and no accessible extension method ‘Scope’ accepting a first argument of type ‘ValueTask’ could be found (are you missing a using directive or an assembly reference?)

This is following the example given here in the couchbase docs: Managing Connections using the .NET SDK with Couchbase Server | Couchbase Docs

My goal is to be able to dynamically manage the source of my documents how I need to set the scope doesn’t look like the docs are correct, and is missing something.

@elbilo -

You need to await your async methods.

Jeff

Thanks for you input that did help some but I’m still having problems with creating the cluster connection. The example in the couchbase docs only shows using DI for a bucket connection not for a cluster. It’s unclear to me how I could do that. I also had to roll back to 3.0.5 version of the couchbaseNetClient as the newer versions do not seem to be downward compatible.
AS you can see above I tried to create the cluster connection in my class’s constructor but here again I run into a blocker with the following error message:
Unable to cast object of type ‘AsyncStateMachineBox`1[Couchbase.ICluster,Couchbase.Cluster+d__25]’ to type ‘Couchbase.ICluster’.

When this statement is executed:
_cluster = (ICluster)Cluster.ConnectAsync(
CouchbaseSection.GetValue(“ConnectionString”)
, CouchbaseSection.GetValue(“Username”)
, CouchbaseSection.GetValue(“Password”)
);

Apparently ICuster is not the right type for a cluster connection, so What is the right type as using a “var” type is not feasible at this point (and IMHO poor coding practice and we should be able to use strongly typed variables).

Your not awaiting the Task<ICluster> object returned by ConnectAsync:

_cluster = await Cluster.ConnectAsync(...);

I think reading up on async/await might be beneficial for you, but as generall rule, whenever you see a method with an “Async” postfix that returns a Task or a Task<T> you’ll have to await the method or use the blocking API (which is not suggested).

It should be backward compatible, I’ll look into this.

Jeff

Yes I understand that but I don’t believe I can have a class constructor be a Task, and I can only use await statements inside a task.

My task here is to have the various methods dynamically pull data from different buckets, scopes, containers, documents, dynamically from the same cluster. I would prefer to use Key Value and sub document operations.

If you have suggestions of other postings I should consider please let me know. This service is built on using DI so I’d like to stay in that paradigm.

@elbilo -

There is an updated version 3.1.5 of DI to NuGet, so that should help you on the DI side.

I am just answering the question that was asked ( “What is the right type”) :slight_smile: yeah, you cannot await in a CTOR - what you could do is ConnectionAsync(...).GetWaiter().GetResult() - but I wouldn’t suggest it. Anything IO bound should be in a method call.

Anyways, the new package should work for you and get you unblocked. Let me know how it goes!

Jeff

@elbilo The DI package is built to be used where IBucketProvider or IClusterProvider is injected in the constructor, but getting actual IBucket or ICluster is done asynchronously in your method when it is needed. This alleviates problems with async calls in the constructor.

If you don’t want to use the DI package, you can get a similar pattern yourself by initializing an AsyncLazy in the constructor and access it in an async method. You can get AsyncLazy in this NuGet package: NuGet Gallery | Nito.AsyncEx 5.1.0

1 Like

Thank you for that answer.
Concerning the IClusterProvider; is there an equivalent service interface for INamedBucketProvider? and is there a method AddCouchbaseCluster for the start-up? Do I create this interface in the same way as I would for the IBucketProvider?

One more question, When I attach to individual buckets in my DAL layer do I can I, or do I, need to dispose of those bucket objects and release any connection to the buckets?

@elbilo

If you’re asking about multi-cluster support, the current DI system doesn’t have support for multi-cluster, only a single cluster. I have been playing around with the concept, though: http://review.couchbase.org/c/couchbase-net-client/+/150914

As far as dispose, you should specifically NOT dispose the buckets. They are intended to be long-lived, reused objects and not disposed. You control shutdown using the ICouchbaseLifetimeService.

As Spock would say “Fascinating”, and we will be moving to multiple clusters in the near future as we will need to support multiple regions. For the moment we are working with a single cluster.
I’m still not quite clear as to what I need in my startup.cs file for the configure services method, Is there a services.AddCouchbaseCluster(cluster) method I need add? Where cluster is the singleton I created earlier in my startup?

@elbilo,

When you call .AddCouchbase(options => { /* config here */ }) this is registering the cluster with all configuration. The singleton is then accessible by getting IClusterProvider from DI and calling await clusterProvider.GetClusterAsync(). This will bootstrap the cluster on the first call, after which it returns the same singleton for the remainder of the application’s lifetime.

1 Like