.NET Client Library

Communicate with Couchbase Server using .NET

Note: Version 1.2 is the most recent release of this SDK.  It is recommended for all deployments.

This Couchbase Client Library for .NET provides a complete interface to the functionality of Couchbase using the .NET framework. For more on Couchbase Server and .NET read our Getting Started guide followed by our in-depth Couchbase and .NET tutorial.

Getting Started

Here is a video that demonstrates how to use the Couchbase .NET Client Library:

Couchbase .NET Client on Vimeo.

Download and Installation

The easiest way to add the Couchbase .NET Client to your application is to use the Nuget package manager.

PM> Install-Package CouchbaseNetClient

You can also download the latest release from the link at at the upper right of this page.

If you prefer to work with the source, you can find that on Github. 

git clone https://github.com/couchbase/couchbase-net-client.git
cd couchbase-net-client
git init submodule
git submodule update


Hello, Couchbase!

Project Setup

Create a new console project in Visual Studio.  Either use Nuget to add the CouchbaseNetClient package or add a reference to the Couchbase.dll and Enyim.Memcached.dll assemblies. 

Visual Studio console applications target the .NET Framework Client Profile by default, so you'll need to update the project properties to instead target the full .NET Framework.  If you skip this step, you'll get compilation errors.

Adding Configuration

You can configure your Couchbase client either programmatically or using the app.config file with the appropriate Couchbase config section.  Using app.config is more flexible and is the preferred approach.  Modify your app.config file as follows:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="couchbase" type="Couchbase.Configuration.CouchbaseClientSection, Couchbase"/>
  </configSections>
  <couchbase>
    <servers bucket="default" bucketPassword="">
      <add uri="http://192.168.0.2:8091/pools"/>
      <add uri="http://192.168.0.3:8091/pools"/>
    </servers>
  </couchbase>
</configuration>

The URIs in the servers list are used by the client to obtain information about the cluster configuration.  If you're running on your local dev machine, include only a single URI using 127.0.0.1 as the address. 

The default Couchbase Server installation creates a bucket named default without a password.  Modify this configuration section to match your particular setup.

Getting Started

Add the following using statements to Program.cs:

using Couchbase;
using Enyim.Caching.Memcached;

Couchbase is the namespace containing the client and configuration classes you'll work with.  Enyim.Caching.Memcached contains supporting infrastructure.  Couchbase protocol compatible with Memcached.

Next create an instance of the client in the Main method.  Use the default constructor, which relies on the configuration from app.config.

var client = new CouchbaseClient();

To store data on the server, use the client's Store method.

client.Store(StoreMode.Add, "somekey", "somevalue");

To retrieve the data, use the Get method.

var someValue = client.Get("somekey") as string;

To retrieve the data without needing an explicit cast, use the generic form of Get.

var someValue = client.Get<string>("somekey")


Complex Types

You can persist your own classes in Couchbase.  You need only mark your classes as Serializable.

[Serializable]
public class Beer {
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Brewery { get; set; }
}

Persist an instance of your type just as you would a primitive type.

var key = Guid.NewGuid();
var beer = new Beer {
    Id = key,
    Name = "Old Yankee Ale",
    Brewery = "Cottrell Brewing Company"
};
client.Store(StoreMode.Add, "beer_" + key, beer);

And retrieve the Beer instance as you would a primitive type.

var beer = client.Get<Beer>("beer_" + key);


Storing JSON Documents

When Couchbase Server 2.0 is released, you'll no doubt want to take advantage of its powerful new View functionality.  Working with views means storing your data as JSON documents.  By the time Couchbase Server 2.0 is released, you should expect that the .NET Client will contain support for JSON transcoding either via explicit configuration or additional API calls.  In the meantime, if you want to plan for 2.0 or simply work with JSON now, here is one approach.

CouchbaseClient Extension Methods

If you want an easy way to read and write JSON, you could add extension methods that serialize and deserialize your objects to and from JSON.  This example uses the DataContractJsonSerializer found in the  System.Runtime.Serialization assembly in .NET 4.0 (for 3.5, this class is found in the System.ServiceModel.Web assembly).  You could just as easily implement these methods with another JSON serializer, such as the popular open source JSON.NET library.

Create a static class named CouchbaseClientExtensions:

public static class CouchbaseClientExtensions {
    ...
}

To write JSON data, add the following method:

public static bool StoreJson<T>(this CouchbaseClient client, StoreMode storeMode, string key, T value) where T : class {
    var ms = new MemoryStream();
    var serializer = new DataContractJsonSerializer(typeof(T));
    serializer.WriteObject(ms, value);
    var json = Encoding.Default.GetString(ms.ToArray());
    ms.Dispose();
    return client.Store(storeMode, key, json);            
}
This method creates a MemoryStream, into which the object is serialized.  GetString then takes the bytes from the stream and converts them to a string, which will be JSON formatted.  Note that this example uses the Default encoding.  Depending on your needs, you may wish to use a specific encoding such as ASCII or UTF8.  The resulting JSON is then passed to the CouchbaseClient's Store method, where it will be persisted as a string (JSON document). 
 

To read JSON data:

public static T GetJson<T>(this CouchbaseClient client, string key) where T : class {    
    var json = client.Get<string>(key);    
    var ms = new MemoryStream(Encoding.Default.GetBytes(json));
    var serializer = new DataContractJsonSerializer(typeof(T));                            
    var obj = serializer.ReadObject(ms) as T;
    ms.Dispose();
    return obj;                        
}

This method reads a string (JSON document) by using the CouchbaseClient's generic Get method.  That string is then written to a MemoryStream, which is then used by the JSON serializer to hydrate an instance of T. 

Using the JSON Extension Methods

The DataContractJsonSerializer will add metadata to the serialized JSON if you don't decorate your class with attributes from the System.Runtime.Serialization namespace.  The new Beer class is below.  The addition of the Type property is to give Beer documents a taxonomy.  This convention will be useful when creating views with Couchbase Server 2.0.

[DataContract]
public class Beer {  

    [DataMember(name="id")]
    public Guid Id { get; set; }

    [DataMember(name="name")]
    public string Name { get; set; }

    [DataMember(name="brewery")]
    public string Brewery { get; set; }

    [DataMember(name="type")]
    public string Type { get; set; }

}

Persisting an instance as JSON is similar to how you persisted it above, except that the generic type is required. 

var key = Guid.NewGuid();
var beer = new Beer {
    Id = key,
    Name = "American Ale",
    Brewery = "Thomas Hooker Brewing Company",
    Type = "beer"
};
client.StoreJson<Beer>(StoreMode.Add, "beer_" + key, beer);

And retrieving the Beer instance is also similar to retrieving as shown above.

var beer = client.GetJson<Beer>("beer_" + key);

Operation Results

There are three variants of CouchbaseClient API methods that return increasing levels of detail as to the success or failure of an operation.  Depending on the level of information you require at runtime, you could choose from any of the approaches outlined below. 

Single Value Results

If the success of an operation doesn't need to be determined at runtime (often the case with caching) you might find it sufficient to use the API methods that return single or scalar values. 

var bar = client.Get("foo") as string;
bar = "bar";
var result = client.Store(StoreMode.Set, "foo", bar);
if (result) {
   Console.WriteLine("Store operation was successful");
}

These API methods return either Booleans indicating the success of an operation (Store, Prepend, Append, Remove), ulong values (Increment, Decrement) or the item at a key (Get).  Most exceptions will not bubble up to these methods and will require logging (see below) to get detailed information about failures. 

CAS Results

For check and set operations, the return values are wrapped in a CasResult instance.  The success of the operation is still determined by a Boolean and detailed failures still require logging. 

var result = client.GetWithCas("foo");
var bar = "bar";
var result = client.Cas(StoreMode.Set, "foo", bar, result.Cas);
if (result.Result) {
   Console.WriteLine("CAS operation was successful");
}

These CasResult API methods return the Result property as a Boolean (Cas, Prepend, Append), as ulong (Increment, Decrement) or the item at a key or an object (Get).  As with the single value results, most exceptions will not bubble up to these methods and will require logging (see below) to get detailed information about failures.

Detailed Operation Results

When you need to react at runtime to detailed information about an operation, you can use the IOperationResult API methods.  These methods all return instances of a class that implements and possibly extends IOperationResult.  The table below summarizes these interface properties.

Each of these methods shares its name with a method from the single-value return API, but prefixed with "Execute."  For example, Get() becomes ExecuteGet() and Store() becomes ExecuteStore().

Property Interface Description
Success IOperationResult Whether the operation succeeded
Message IOperationResult Error, warning or informational message
StatusCode IOperationResult Nullable status code from server
InnerResult IOperationResult Nested result.  Populated by low-level I/O failures.
Value INullableOperationResult Extended by IGetOperationResult, where Value is item for given key. 
HasValue INullableOperationResult Shortcut for null Value check. 
Cas ICasOperationResult

Extended by IGetOperationResult, IMutateOperationResult, IConcatOperationResult and IStoreOperationResult.  Contains possible CAS value for operations.

var getResult = client.ExecuteGet<Beer>("beer_heady_topper");
if (getResult.Success && getResult.HasValue) {  
   
   var beer = getResult.Value;
   beer.Brewery = "The Alchemist";
   var casResult = client.ExecuteCas(StoreMode.Set, "beer_heady_topper", beer, getResult.Cas);

   if (casResult.Success) {
       Console.WriteLine("CAS operation was successful");
   }
} else {
   Console.WriteLine("Get operation failed with message {0} and exception {1} ",
                          getResult.Message, getResult.Exception);
}

It's a good idea with the IOperationResult API to check the InnerResult or StatusCode properties on failures.  When socket I/O failures occur, the client library will gracefully handle them.  Therefore, errors are wrapped up and passed through the layers.  Generally, these errors are bubbled up via the InnerResult properties. 

Configuring Logging

To enable logging, you can tap into the logging capabilities provided by the Enyim.Caching  dependency.  Enyim logging currently supports either log4net or NLog. 

Start by adding a reference to either Enyim.Caching.Log4NetAdapter or Enyim.Caching.NLogAdapter.  Both are available as nuget packages.

http://nuget.org/packages/EnyimMemcached-log4net
http://nuget.org/packages/EnyimMemcached-nlog

You could also get the projects from https://github.com/enyim/EnyimMemcached.  If you use these Visual Studio projects, you'll also need to add a reference to log4net or NLog (depending on which adapter you choose).  Each of these dependencies is located in a "binaries" directory under the root "EnyimMemcached" directory.

For log4net, your configuration should include an enyim.com section that defines which log factory to use along with standard log4net configuration. 

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <sectionGroup name="enyim.com">
      <section name="log" type="Enyim.Caching.Configuration.LoggerSection, Enyim.Caching" />
    </sectionGroup>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <enyim.com>
    <log factory="Enyim.Caching.Log4NetFactory, Enyim.Caching.Log4NetAdapter" />
  </enyim.com>
  <log4net debug="false">
    <appender name="LogFileAppender" type="log4net.Appender.FileAppender,log4net">
      <param name="File" value="c:\\temp\\error-log.txt" />
      <param name="AppendToFile" value="true" />
      <layout type="log4net.Layout.PatternLayout,log4net">
        <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &lt;%X{auth}&gt; - %m%n" />
      </layout>
    </appender>
    <root>
      <priority value="ALL" />
      <level value="DEBUG" />
      <appender-ref ref="LogFileAppender" />
    </root>
  </log4net>  
</configuration>

The log4net configuration will vary by the type of appender you are using.  For more information on log4net configuration, see http://logging.apache.org/log4net/release/manual/configuration.html

You'll also need to initialize (only once in your app) log4net in your code with the standard log4net initializer.

log4net.Config.XmlConfigurator.Configure();
 
NLog configuration requires setting the log factory to NLogAdapter and including the appropriate NLog configuration section. 
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <sectionGroup name="enyim.com">
      <section name="log" type="Enyim.Caching.Configuration.LoggerSection, Enyim.Caching" />
    </sectionGroup>
    <section name="nlog" type="NLog.Config.ConfigSectionHandler, NLog" />
  </configSections>
  <enyim.com>
    <log factory="Enyim.Caching.NLogFactory, Enyim.Caching.NLogAdapter" />
  </enyim.com>
  <nlog>
    <targets>
      <target name="logfile" type="File" fileName="c:\temp\error-log.txt" />
    </targets>
    <rules>
      <logger name="*" minlevel="Info" writeTo="logfile" />
    </rules>
  </nlog>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
  </startup>
</configuration>
See http://nlog-project.org/wiki/Configuration_file for more NLog configuration details. 
 
Once you've enabled logging, you'll be able to more easily debug problems related to network problems, configuration and other errors.