Managing Connections Using the .NET SDK with Couchbase Server
This section describes how to connect the .NET SDK to a Couchbase cluster and bucket. It contains best practices as well as information on the connection string, SSL and other advanced connection options.
Connecting to a Cluster and Opening a Bucket
Connecting to a bucket is a two-step process: first, a Cluster object needs to be created or the ClusterHelper object needs to be initialized, followed by one or more calls to OpenBucket()
or GetBucket(..)
:
var cluster = Cluster();
var credentials = new PasswordAuthenticator("Administrator", "password");
cluster.Authenticate(credentials);
var bucket = cluster.OpenBucket("default");
//or alternately
ClusterHelper.Initialize(new ClientConfiguration(), credentials);
var bucket = ClusterHelper.GetBucket("default");
The ClusterHelper is a singleton/multiton that makes it easier to manage resources and instances in server runtime environments such as ASP.NET and Owin/Katana.
A ClusterHelper will make a singleton instance of a Cluster object and configuration and store references to opened IBucket objects that can be reused throughout the lifespan of an application.
|
The PasswordAuthenticator is used for connecting to Couchbase Server 5.0 and greater using RBAC (Role Based Access Control).
In this case we are using the administrator account, however, a more secure way to connect is to create a user with minimal privileges and a unique password.
If you are connecting to an older server version that does not use RBAC then you would omit the PasswordAuthenticator and instead pass the bucket password into the OpenBucket method.
|
If no further arguments are applied, this code connects to localhost
and opens the default bucket.
While this is suitable for development, you most probably want to connect to a remote cluster and also a different bucket.
To do this, you create a ClientConfiguration
object with a custom configuration:
//define a configuration object
var config = new ClientConfiguration {
Servers = new List<Uri> {
new Uri("http://192.168.56.101:8091"),
new Uri("http://192.168.56.102:8091")
}
};
//create the cluster and pass in the RBAC user
var cluster = new Cluster(config);
var credentials = new PasswordAuthenticator("Administrator", "password");
cluster.Authenticate(credentials);
//open the new bucket
var bucket = cluster.OpenBucket("mybucket");
//or alternately
ClusterHelper.Initialize(config, credentials);
var bucket = ClusterHelper.GetBucket("mybucket");
The ClientConfiguration object also exposes per bucket configuration settings, for example:
var config = new ClientConfiguration{
Servers = new List<Uri> {
new Uri("http://192.168.56.101:8091"),
new Uri("http://192.168.56.102:8091")
},
BucketConfigs = new Dictionary<string, BucketConfiguration> {{
"mybucket", new BucketConfiguration{
BucketName = "mybucket"
}
}
}
};
//create the authenticator for passing in the user and password for RBAC
var credentials = new PasswordAuthenticator("Administrator", "password");
//create the cluster and open the new bucket
var cluster = new Cluster(config, credentials);
var bucket = cluster.OpenBucket("mybucket");
//or alternately
ClusterHelper.Initialize(config, credentials);
var bucket = ClusterHelper.GetBucket("mybucket");
It is very important in a production setup to pass in at least two or three nodes of the cluster because if the first one in the list fails the other ones can be tried. After initial contact is made, the bootstrap list provided by the user is thrown away and replaced with a list provided by the server (which contains all nodes of the cluster).
As an alternative to programmatic configuration, the SDK also supports configuration via config file and soon will support JSON config files. Here is an example of an App.Config that is equivalent to the configuration above and assumes that you are connecting to Couchbase Server 5.0 or greater using RBAC:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="couchbaseClients">
<section name="couchbase" type="Couchbase.Configuration.Client.Providers.CouchbaseClientSection, Couchbase.NetClient" />
</sectionGroup>
</configSections>
<couchbaseClients>
<couchbase username="Administrator" password="password">
<servers>
<add uri="http://192.168.56.101:8091"></add>
<add uri="http://192.168.56.102:8091"></add>
</servers>
<buckets>
<add name="mybucket" password="mybucketpassword"></add>
</buckets>
</couchbase>
</couchbaseClients>
</configuration>
To open these buckets you would pass the path to the configuration section:
var cluster = new Cluster("couchbaseClients/couchbase");
var bucket = cluster.OpenBucket("mybucket");
//or alternatively
ClusterHelper.Initialize("couchbaseClients/couchbase");
var bucket = cluster.OpenBucket("mybucket");
More buckets can be open at the same time if needed:
var bucket1 = cluster.OpenBucket("bucket1");
var bucket2 = cluster.OpenBucket("bucket2");
If more than one bucket is open at a time, the underlying internals of the client makes sure to utilize the resources as best as possible, that is sharing sockets, thread pools and so on.
Here are some very important things to keep in mind:
-
Always create only one instance of a
Cluster
and share it across threads (same with buckets) or use theClusterHelper
to help you do this. TheClusterHelper
is a singleton for aCluster
instance and a "multi-ton" for bucket instances; the buckets will be cached and reused. -
The SDK is thread-safe, so no additional synchronization is needed when interacting with the SDK.
-
If different clusters need to be accessed, you can do this with multiple
Cluster
instances. -
The
Cluster
instance and theClusterHelper
class should be initialized when the application starts up and closed viaDispose()
when the application shuts down.
Disconnecting from a Bucket
The most common case is to Dispose the whole Cluster
from the server, which has the same effect as closing all buckets manually and in addition close all underlying resources like threads and sockets.
This also means that once Dispose()
has been called, you can’t reopen buckets from the same Cluster
instance.
cluster.Dispose();
After a Dispose() called on a Cluster instance any subsequent attempts to open or use a bucket or cluster will cause a ObjectDisposedException to be thrown. You can also Dispose of a bucket instance:
bucket.Dispose();
This will release only the resources allocated for this bucket and it is possible to reopen it at a later point.
If you do not Dispose of the Cluster or bucket instance that you are using in your application, eventually the AppDomain or process will destroy the objects however, any underlying resources (sockets for example) will be closed by the OS whenever it decides to do so. This can lead to other problems so always Dispose of your Cluster and bucket objects before the hosting application shuts down.
Connecting with SSL
Couchbase Server EE 3.0 and later supports full encryption of client-side traffic. That includes key-value type operations, queries, and configuration communication. Make sure to have a proper Couchbase Server version installed before proceeding with configuring encryption on the client side.
To configure encryption for the .NET SDK:
-
Copy and import the certificate from the cluster into your certificate store
-
Enable encryption on the client by setting ClientConfiguration.UseSsl to true
Depending upon your version of Windows and whether or not you are using OWIN or IIS, how you import into your certificate store may vary.
If you are running on localhost
and just want to enable it for a development machine, just copying and pasting it suffices.
Navigate in the admin UI to and copy the input box of the SSL certificate into a file on your machine (here named cluster.crt).
It looks similar to this:
-----BEGIN CERTIFICATE----- MIICmDCCAYKgAwIBAgIIE4FSjsc3nyIwCwYJKoZIhvcNAQEFMAwxCjAIBgNVBAMT ASowHhcNMTMwMTAxMDAwMDAwWhcNNDkxMjMxMjM1OTU5WjAMMQowCAYDVQQDEwEq MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzz2I3Gi1XcOCNRVYwY5R ................................................................ mgDnQI8nw2arBRoseLpF6WNw22CawxHVOlMceQaGOW9gqKNBN948EvJJ55Dhl7qG BQp8sR0J6BsSc86jItQtK9eQWRg62+/XsgVCmDjrB5owHPz+vZPYhsMWixVhLjPJ mkzeUUj/kschgQ0BWT+N+pyKAFFafjwFYtD0e5NwFUUBfsOyQtYV9xu3fw+T2N8S itfGtmmlEfaplVGzGPaG0Eyr53g5g2BgQbi5l5Tt2awqhd22WOVbCalABd9t2IoI F4+FjEqAEIr1mQepDaNM0gEfVcgd2SzGhC3yhYFBAH//8W4DUot5ciEhoBs= -----END CERTIFICATE-----
Paste this into notepad running with administrative privileges and then save it to disk with a file extension of .crt and a file type of "All Files". Then right click on the file and select "Import Certificate", then select "Local Machine", select the "Trusted Root Certificate Authorities" and finally "Finish". Once you have done this, all traffic between the client and the server will be encrypted.
Using DNS SRV records
As an alternative to specifying multiple hosts in your program, you can get the actual bootstrap node list from a DNS SRV record. The following steps are necessary to make it work:
-
Set up your DNS server to respond properly from a DNS SRV request.
-
Enable it on the SDK and point it towards the DNS SRV entry.
Your DNS server should be set up like this (one row for each bootstrap node):
_couchbase._tcp.example.com. 3600 IN SRV 0 0 0 node1.example.com. _couchbase._tcp.example.com. 3600 IN SRV 0 0 0 node2.example.com. _couchbase._tcp.example.com. 3600 IN SRV 0 0 0 node3.example.com.
The ordering, priorities, ports and weighting are completely ignored and should not be set on the records to avoid ambiguities. |
If you plan to use secure connections, you use _couchbases
instead:
_couchbases._tcp.example.com. 3600 IN SRV 0 0 0 node1.example.com. _couchbases._tcp.example.com. 3600 IN SRV 0 0 0 node2.example.com. _couchbases._tcp.example.com. 3600 IN SRV 0 0 0 node3.example.com.
DNS SRV bootstrapping is available in the .NET SDK from version 2.3.9.
In order to make the SDK use the SRV records, you need to create a custom implemention of IServerResolver
and then use the custom class name in the Couchbase client configuration.
Below is an example web.config that uses a custom resolver implementation.
<couchbase> <buckets> <add name="default" /> </buckets> <serverResolver type="MyApp.MyServerResolver, MyApp" /> </couchbase>
The .NET Framework does not offer DNS-SRV resolution directly but there are some third party packages that can help do that such as DnsClient. Also, if you’re creating an ASP.NET Core web application, there is the Couchbase.Extensions.DnsDiscovery community package that can resolve and setup the configuration for you.