DI error on distributed cache (NET SDK 3.0X)

Hi everyone,

I need to use Couchbase as Distributed Cache for a .Net core application.
The ‘how to’ guide is outdated (2017) and does not apply anymore with the .Net 3.05 sdk.
So I used the last version available on Github (nuget package is outdated too), and after my first debugging, an error occures at startup :

Unable to resolve service for type ‘Couchbase.Extensions.Caching.ICouchbaseCacheBucketProvider’ while attempting to activate ‘Couchbase.Extensions.Caching.Internal.DefaultCouchbaseCacheCollectionProvider’

Here is my code int the ConfigureServices(IServiceCollection serviceCollection) method, where I setup things for dependency injection

 serviceCollection.AddCouchbase(opt => {
            opt
            .WithConnectionString("http://192.168.1.xxx:8091")
            .WithCredentials(username: "MyDistributedCache", password: "xxxxxxxxxx")
            .WithBuckets("MyDistributedCache");
            }
        ) ;

 serviceCollection.AddDistributedCouchbaseCache(setup => setup.LifeSpan = TimeSpan.FromMinutes(120));

My user and my bucket have the same name, as it was advised in the ‘how to’ guide.

I checked the .Net SDK extensions source code in the github repo, and I can see this part of code which seems interesting

        services.TryAddSingleton<ICouchbaseCacheCollectionProvider, DefaultCouchbaseCacheCollectionProvider>();

What am I missing ? Maybe I have to specify something for the DefaultCoucheBaseCollectionProvider ?

Thanks for your help.

PS : By the way, if one of the nugget packgae maintainer reads this message, the nugget package is outdated too, and its reference to an old version of ITracing causes a CS0433 issue code using an updated version of ITracing.

@david-77

The work to update the distributed caching provider to be compatible with SDK 3.x is still a work in progress. As such, NuGet packages and updated documentation have not yet been released. So your approach of building from source is correct.

To make it work, please do one of the following:

  1. Use the other overload to AddDistributedCouchbaseCache which accepts a bucket name parameter
  2. Manually register an implementation of ICouchbaseCacheBucketProvider

Please keep us informed of any other issues you have since it will help us when finishing the SDK 3.x work.

Hi @btburnett3,

Thank you for this quick answer ! I used the first option and it works :

 serviceCollection.AddCouchbase(opt => {
            opt
            //.WithConnectionString("http://192.168.1.xxxx:8091")
            .WithConnectionString("couchbase://192.168.1.xxxxx")                
            .WithCredentials(username: "MyDistributedCache", password: "xxxxxxx");
            }
        ) ;
        serviceCollection.AddDistributedCouchbaseCache("MyDistributedCache",setup => setup.LifeSpan = TimeSpan.FromMinutes(120));

I had to change the connectionstring to reach the coucbase server ( the “http” way seems obsolete).

Thanks again !

I still face the same issue while using docker to host 3 containers for each node.
Case Study:

  1. Use docker Couchbase containers instances to create 3 nodes in one cluster on local machine.
    docker run -d --name db3 -p 8091-8096:8091-8096 -p 11210-11211:11210-11211 couchbase
    docker run -d --name db1 couchbase
    docker run -d --name db2 couchbase
  2. Configure all 3 nodes and rebalanced
  3. Created a bucket
  4. Access the cache content

Error:
BucketNotFoundException: Bucket with name Cache-Sample does not exist or cannot be reached.
Couchbase.Core.ClusterContext.GetOrCreateBucketAsync(string name)

Question:
I want to know if I should be adding all 3 node IP adddresses as fetched from Docker container ?
What configuration am I missing?

The startup code is as below:

public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddLogging();
services.AddCouchbase(options =>
options
WithConnectionString(“couchbase://172.17.0.2”) //Node 1 instance
.WithConnectionString(“couchbase://117.17.0.3”) //Node 2 instance
.WithConnectionString(“couchbase://117.17.0.4”) //Node 3 instance
.WithCredentials(“Administrator”, “********”));
.WithBuckets(“Cache-Sample”)) ;
services.AddDistributedCouchbaseCache(“Cache-Sample”, opt => { });
}

And in CacheController, I try to access the distributed cache as below:

var data = await _cache.GetStringAsync(cacheKey);

@Subasish

First, let me say that yes you should (in production) include at least a few of your nodes in the connection string. This isn’t required for connectivity, but it provides redundancy in the event of node outages. The bootstrap process attempts to use the nodes one at a time until it succeeds.

However, your syntax for adding more than one node is incorrect. It should be:

options
    .WithConnectionString(“couchbase://172.17.0.2,117.17.0.3,117.17.0.4”)

However, based on your Docker commands, this is not your problem. The key is the nature of the Couchbase architecture. Couchbase is designed to be highly performant and reliable, so routing all traffic through a single node to reach the other nodes isn’t really an option. Instead, the SDK establishes connections directly to every node in the cluster and speaks directly to the correct node depending on which document you are requesting.

This means that you need access from your application to every node in the cluster across a variety of ports (typically 8091-8096 and 11210-11211 at a minimum, more if you’re using SSL). The way you’re launching in Docker is only giving that access to the first node in the cluster via your localhost IP. Additionally, depending on how your Docker networking is setup, the nodes may not be accessible from your application by their internal Docker IP, which is also a requirement.

There are a few ways to deal with this issue, in my experience:

  1. Configure your IDE to launch your application within Docker instead of your host machine, so that it is running within the Docker network and has access to all of the nodes
  2. For local development run a single node instead of a cluster, using localhost port forwarding (as you already do for the first node in your example)
  3. Configure routing within Docker to ensure that traffic to the internal Docker IPs from your host machine is routed correctly and reaches those machines.

Of course, I could be wrong about all of this. Let me know if this doesn’t help.

@btburnett3 Thanks for the elaborate explanation. Good to know the right way of adding more nodes in the connection string.
As far as connectivity problem is concerned its solved now - application container and couchbase containers were not using the same network bridge.
That was solved following below listed commands:

  1. Create docker network
    docker network create -d bridge couchbase_bridge
    List docker containers
    docker network ls
  2. Connect docker network with container on each node
    docker network connect couchbase_bridge db
    docker network connect couchbase_bridge db1
    docker network connect couchbase_bridge db2
    docker network connect couchbase_bridge CacheApplication
  3. Inspect Docker network for each container
    docker inspect --format=‘{{json .NetworkSettings.Networks}}’ CacheApplication
    => It should show the cache network associated with particular network

The last part of your comment - “3. Configure routing within Docker to ensure that traffic to the internal Docker IPs from your host machine is routed correctly and reaches those machines.” - Could you tell me please how to go about it?

@Subasish

Frankly, I’m not 100% sure how to go about it these days. I haven’t done it in a few years and I know Docker Desktop has changed a lot. This sort of thing is what I used to do: Connecting to containers IP address - Docker Desktop for Windows - Docker Community Forums