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:

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, therefore the bucket and bucketPassword attributes are
optional. If you created an authenticated bucket, you should specify those
values in place of the default settings above.

The TCP/IP port allocation on Windows by default includes a restricted number of
ports available for client communication. For more information on this issue,
including information on how to adjust the configuration and increase the
available ports, see MSDN: Avoiding TCP/IP Port Exhaustion.

using Couchbase;
using Enyim.Caching.Memcached;
using Newtonsoft.Json;

Couchbase is the namespace containing the client and configuration classes with
which you’ll work. Enyim.Caching.Memcached contains supporting infrastructure.
Recall that Couchbase supports the Memcached protocol and is therefore able to
make use of the popular Enyim Memcached client for many of its core key/value
operations.

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

var client = new CouchbaseClient();

In practice, it’s expensive to create clients. The client incurs overhead as it
creates connection pools and sets up the thread to get cluster configuration.
Therefore, the best practice is to create a single client instance, per bucket,
per AppDomain. Creating a static property on a class works well for this
purpose. For example:

The primary CRUD API used by the.NET Client is that of a standard key/value
store. You create and update documents by supplying a key and value. You
retrieve or remove documents by supplying a value. For example, consider the
JSON document that you’ll find in the “beer-sample” bucket that’s available when
you install Couchbase Server and setup your cluster. The key for this document
is “new_holland_brewing_company-sundog.”

For a key, we’ll simply take the name of the beer and prefix it with the name of
the brewery, separated with a dash and with spaces replaced by underscores. The
exact mechanism by which you create your keys need only be consistent. If you
are going to query documents by key (not just through views) you should choose
predictable keys (e.g., cottrell_brewing-old_yankee_ale).

There are three arguments to Store. The first is the store mode. Use
StoreMode.Add for new keys, StoreMode.Replace to update existing keys and
StoreMode.Set to add when a key doesn’t exist or to replace it when it does.
Store will fail if Add is used with an existing key or Replace is used with a
non-existent key. The second and third arguments are the key and value,
respectively. The return value, assigned to the result variable, is a Boolean
indicating whether the operation succeeded.

Removing a document simply entails calling the Remove method with the key to be
removed. Like the other methods we’ve seen so far, Remove returns a Boolean
indicating operation success.

While storing and retreiving JSON strings is a straightforward process,
documents in a typical application are likely at some point to be represented by
domain objects (i.e., POCOs). More mileage will come from storing some
representation of these data objects. For example, the beer documents could be
represented by an instance of a Beer class in memory. The.NET Client Library
will allow for serializable objects to be persisted using.NET’s standard
over-the-wire serialization. However, on the server, these objects will be
stored as binary attachments to a JSON document. The impact of being an
attachment is that it will not be indexed in a view. A better solution then, is
to serialize data objects to JSON strings before storing them and deserializing
JSON document strings to objects when retreiving them.

If you want an easy way to read and write JSON, the CouchbaseClientExtensions
class under the Couchbase.Extensions namespace provides two very basic methods,
StoreJson and GetJson. Both methods depend on the open source Newtonsoft.Json
library, which is already a dependency of the Couchbase.NET Library. Both
methods wrap only the most basic Get and Store overloads and don’t currently
support CAS or TTL operations. They are included with the library for
convenience and will likely be augmented in the future by a Couchbase Labs
extension library.

To improve the way beer data is managed in this getting started project, add a
new file Beer.cs to the project. It will contain a plain-old-CLR-object (POCO)
with mappings from class properties to JSON properties. For brevity, some
document properties have been omitted. Notice also that the Type property has
been made read-only and forces all beer instances to be marked with the type
“beer.” This type information will be useful when creating views and wanting to
find all “beer” documents.

By default, Json.NET will serialize the properties of your class in the case you
created them. Because we want our properties to match the casing of the
documents in the beer-sample bucket, we’re going to set JSON property names in
JsonProperty attributes (in the Newtonsoft.Json namespace). Again, we could
store instances of this Beer class without converting them first to JSON
(requires marking the class with a Serializable attribute), but that would
prevent those documents from being indexed in views.

Persisting an instance as JSON is similar to how we persisted the JSON document
string above. Replace the code where a JSON string was created with the code
below.

Map/Reduce Views are used to create queryable, secondary indexes in Couchbase
Server. The primary index for documents is the key you use when performing the
standard CRUD methods described above. See the view documentation for more
information on writing views.

For this example, the by_name view in the beer design document will be queried.
This view simply checks whether a document is a beer and has a name. If it does,
it emits the beer’s name into the index. This view will allow for beers to be
queried for by name. For example, it’s now possible to ask the question “What
beers start with A?”

Querying a view through the.NET Client Library requires calling the GetView
method and providing the name of the design document and the name of the view.

var view = client.GetView("beer", "by_name");

The return type of GetView is an enumerable IView, where each enumerated value
is an IViewRow. The actual view query isn’t run until you enumerate over the
view. For example, if you wanted to print out each of the keys that have been
indexed, you could use the IViewRow instance’s Info dictionary. This particular
view emits null as the value, so that will be empty when this snippet runs.

The code above should give you a list of beer names for all beer documents that
exist in the beer-sample bucket. If you want to filter that list, there are
fluent methods that may be chained off of the IView instance before iterating
over it. Modifying the GetView call above as follows will find all beers whose
names start with “A” and limits the results to 50 rows. See the API reference
for other fluent methods. Please note that these methods return an IView
instance, which is an IEnumerable, but is not an IQueryable. Therefore, using
LINQ extension methods on the IView will not reduce the results in the query.
Only the IView fluent methods will affect the query before it is run.

Also included in the IViewRow instance, is the original ID (the key from the k/v
pair) of the document. It is accessible by way of the IViewRow’s ItemId
property. Taking that ID, it is possible to retrieve the original document.
Using the JSON extension methods, it’s also possible to get a Beer instance for
each row. If it seems expensive to perform these lookups, recall that Couchbase
Server has a Memcached layer built in and these queries are unlikely to be
pulling data from disk. The documents are likely to be found in memory.

Finally, there is a generic version of GetView which encapsulates the details of
the view row data structures. To retrieve Beer instances automatically by ID as
you iterate over the view, you need to add the generic parameter to GetView
along with the third Boolean argument to tell the client to perform the by ID
lookup. If you omit the third parameter, the client will attempt to deserialize
the value emitted by the index into an instance of the specified generic type.
Again, in this example the value was null. Therefore, deserialization must be
done by way of ID lookup.

This tutorial assumes that you have Visual Studio 2010 installed, along with
ASP.NET MVC 4. You may use any edition of Visual
Studio or you may use Visual Web Developer. Visual Studio 2012 will also work
for this tutorial, but the screenshots included will be from Visual Studio 2012
Professional.

You will also need to have an installation of Couchbase Server 2.0 and have
obtained the latest Couchbase.NET Client Library, version 1.2 or higher. See
“Getting Started” for more information on client installation.

You also may use an older version of ASP.NET MVC if you do not have MVC 4
installed, but as with using Visual Web Developer or Visual Studio 2012, the
templates shown in the screenshots will vary from what you see.

You should also have installed the beer-sample database on your Couchbase
Server. If you haven’t, simply open the web console and navigate to the
“Settings” tab. There, you’ll find an option to add a sample bucket to your
cluster.

This project will be based on an ASP.NET MVC 4 application template. After
opening Visual Studio, select File -> New Project and then select Web -> ASP.NET
MVC 4 Application under the Visual C# project templates. Name the project
“CouchbaseBeersWeb” and click “OK” to create the solution.

Start with an “Empty” application using the Razor view engine for the MVC
template.

Next you’ll need to add a reference to the Couchbase.NET Client Library. You
could either download the assemblies from the getting started
page or obtain them using the
NuGet package manager. When you install via Nuget, your project will
automatically get references to Couchbase.dll, Enyim.Caching.dll and the
dependencies Newtonsoft.Json.dll and Hammock.dll. These assemblies are also
found in the zip file and should be referenced in your project if not using
Nuget.

The first task to solve is displaying a list of breweries in from our
beer-sample bucket. To add this functionality, there is some plumbing to setup
in our application. These tasks are enumerated below.

Create a Brewery model class to represent beer documents

Create a BreweryRepository to encapsulate data access for Brewery instances

Create a BreweriesController with an Index action used to show a Brewery list

Create a Razor view to display our list of breweries

As a JSON document database, Couchbase supports a natural mapping of domain
objects to data items. In other words, there’s very little difference between
the representation of your data as a class in C# and the representation of your
data as a document in Couchbase. Your object becomes the schema defined in the
JSON document.

When working with domain objects that will map to documents in Couchbase, it’s
useful, but not required, to define a base class from which your model classes
will derive. This base class will be abstract and contain two properties, “Id”
and “Type.”

Right click on the “Models” directory and add a new class named “ModelBase” and
include the following code.

Note that the Type method is abstract and readonly. It will be implemented by
subclasses simply by returning a hard-coded string, typically matching the class
name, lower-cased. The purpose of the Type property is to provide taxonomy to
the JSON documents stored in your Couchbase bucket. The utility will be more
obvious when creating views.

Next, create a new class namedin the “Models” directory of your project. This
class will be a plain old CLR object (POCO) that simply has properties mapping
to the properties of brewery documents in the beer-sample bucket. It will also
extend ModelBase.

After creating the Brewery class, the next step is to create the data access
classes that will encapsulate our Couchbase CRUD and View operations. Create a
new file in “Models” named “RepositoryBase`1.cs” with a class name of
“RepositoryBase.” This will be an abstract class, generically constrained to
work with ModelBase instances. The `1 suffix on the file name is a
convention used for generic classes in C# projects.

The process of creating an instance of a CouchbaseClient is expensive. There
is a fair amount of overhead as the client establishes connections to the
cluster. It is therefore recommended to minimize the number of times that a
client instance is created in your application. The simplest approach is to
create a static property or singleton that may be accessed from data access
code. Using the RepositoryBase, setting up a protected static property will
provide access for subclasses.

To display a list of all breweries, a view will be necessary. This map function
for this view will simply emit null keys and values for each of the brewery
documents in the database. This view will live in a “breweries” design document
and be named “all.”

For more information on working with views in the admin console, see the
documentation.

A null-key index still provides access to each of the document’s keys when the
view is queried. Note however that range queries on keys would not be supported
with this view.

You could create the “all” view above by creating a new design document in the
Couchbase web console or you could use the CouchbaseCluster API ( see
docs
) found in Couchbase.dll to create and to save a design document. However, an
easier approach is to use the CouchbaseLabs
project Couchbase Model Views.

The Couchbase Model Views project is not part of the Client Library, but makes
use of its design doc management API to create views from attributes placed on
model classes. Using NuGet, add a reference to the CouchbaseModelViews package.

Once installed, modify the Brewery class definition to have two class level
attributes, CouchbaseDesignDoc and CouchbaseAllView.

The CouchbaseDesignDoc attribute instructs the Model Views framework to create
a design document with the given name. The CouchbaseAllView will create the
“all” view as shown previously.

To get the Model Views framework to create the design doc and view, you’ll need
to register the assembly containing the models with the framework. In
Global.asax, create a static RegisterModelViews method for this purpose.

Note that the Model Views framework will create the design doc only if it has
changed, so you don’t have to worry about your indexes being recreated each time
your app starts.

To test that the Model Views framework is working, simply run the application
(Ctrl + F5). If all went well, you should be able to navigate to the “Views” tab
in the Couchbase web console and see the new design doc and view in the
“Production Views” tab (as shown below).

If you click the link next to the “Filter Results” button, you will see the JSON
that is returned to the CouchbaseClient when querying a view. Notice the “id”
property found in each row. That is the key that was used to store the document.

With the view created, the next step is to modify the RepositoryBase to have a
GetAll method. This method will use some conventions to allow for reuse across
subclasses. One of those conventions is that queries will be made to design docs
with camel-cased and pluralized names (e.g., Brewery to breweries). To aid in
the pluralization process, create a reference to inflector_extension using
NuGet. Note that in.NET 4.5, there is a PluralizationService class that will
provide some of the same support.

To the RepositoryBase class, add a readonly private field and initialize it to
the inflected and pluralized name of the type of T. The inflector extension
methods will require an additional using statement.

The initial implementation of GetAll will simply return all breweries using
the generic GetView<T> method of CouchbaseClient. The third parameter
instructs CouchbaseClient to retrieve the original document rather than
deserialize the value of the view row.

RepositoryBase is a generic and abstract class, so obviously it cannot be used
directly. Create a new class in “Models” named “BreweryRepository.” The code for
this class is very minimal, as it will rely on its base class for most
functionality.

With the models and repository coded, the next step is to create the controller.
Right click on the “Controllers” directory in the project and select Add ->
Controller. Name the controller “BreweriesController” and select the template
“Controller with empty read/write actions,” which will create actions for
creating, updating, deleting, showing and listing breweries.

The Index method of the BreweriesController will be used to display the list
of breweries. To allow the new controller to access brewery data, it will need
an instance of a BreweryRepository. Create a public property of type
BreweryRepository and instantiate it in the default constructor.

The last step to displaying the list of breweries is to create the Razor view
(as in MVC views, not Couchbase views). In the “Views” directory, create a new
directory named “Breweries.” Right click on that new directory and select “Add”
-> “View.” Name the view “Index” and create it as a strongly typed (to the
Brewery class) view with List scaffolding. This template will create a Razor
view that loops over the brewery results, displaying each as a row in an HTML
table.

At this point, you should build your application and navigate to the Breweries
path (e.g., http://localhost:52962/breweries
). If all went well, you should see a list of breweries.

There are quite a few breweries being displayed in this list. Paging will be an
eventual improvement, but for now limiting the results by modifying the defaults
of the GetAll method will be sufficient.

The MVC scaffolding that created the Razor template to list breweries also
included links to create, show, edit and delete breweries. Using more
scaffolding, these CRUD features are easily implemented.

Create and Update methods require a bit of effort to encapsulate. One decision
to make is whether to use the detailed result ExecuteStore method or the
Boolean> Store method of the Client. ExecuteStore returns an instance of an
IStoreOperationResult, which contains a success status and error message
properties, among others.

Since it is likely important to know whether operations succeeded,
ExecuteStore will be used in our RepositoryBase. However, that interface
will be hidden from the application and instead an int will be returned by each
method. The int will be the status code returned by Couchbase Server for each
operation.

There are other implementation details that need to be considered when
implementing these methods, namely key creation and JSON serialization.

CRUD operations in Couchbase are performed using a key/value API. The key that
is used for these operations may be either meaningful (i.e., human readable) or
arbitrary (e.g., a GUID). When made human readable, your application may be able
to make use of predictable keys to perform key/value get operations (as opposed
to secondary indexes by way of view operations).

A common pattern for creating readable keys is to take a unique property, such
as Brewery.Name, and replace its spaces, possibly normalizing to lowercase. So
“Thomas Hooker Brewery” becomes “thomas_hooker_brewery.”

Add the following BuildKey method to the RepositoryBase to allow for default
key creation based on the Id property.

BuildKey will default to a GUID string when no Id is provided. It’s also
virtual so that subclasses are able to override the default behavior. The
BreweryRepository needs to override the default behavior to provide a key
based on brewery name.

When storing a Brewery instance in Couchbase Server, it first has to be
serialized into a JSON string. An important consideration is how to map the
properties of the Brewery to properties of the JSON document.

JSON.NET (from Newtonsoft.Json) will by default serialize all properties.
However, ModelBase objects all have an Id property that shouldn’t be
serialized into the stored JSON. That Id is already being used as the document’s
key (in the key/value operations), so it would be redundant to store it in the
JSON.

JSON.NET supports various serialization settings, including which properties
should be included in serialization. In RepositoryBase, create a
serializAndIgnoreId method and a private DocumentIdContractResolver class as
shown below.

The DocumentIdContractResolver will prevent the Id property from being saved
into the JSON. It also extends CamelCasePropertyNamesContractResolver to
provide camel-cased properties in the JSON output.

Note that there is a JsonIgnore attribute that could be added to properties
that should be omitted from the serialized JSON, however it is less global in
its application. For example, if a class overrides the Id property of
ModelBase, it would have to add the attribute.

With this new plumbing in place, it’s now possible to complete the Create,
Update and Save methods. Exceptions are caught and wrapped in the
IStoreOperationResult’s Exception property. If an exception is detected, it will
be thrown up to the caller. These new methods also have an optional durability
argument, which will block until a document has been written to disk, or the
operation times out. By default, there is no durability requirement imposed.

The Get method of RepositoryBase requires similar considerations.
CouchbaseClient.ExecuteGet returns an IGetOperationResult. To be consistent
with the goal of not exposing Couchbase SDK plumbing to the app, Get will
return the object or null if not found, while throwing a swallowed exception.
Notice also that the Id property of the model is set to the value of the key,
since it’s not being stored in the JSON.

Completing the CRUD operations is the Delete method. Delete will also hide
its SDK result data structure ( IRemoveOperationResult ) and return a status
code, while throwing swallowed exceptions. Delete also supports the durability
requirement overload.

With the new methods implemented, it’s time to create the scaffolding for the
CRUD forms. The first task will be to create an edit form. Open the
BreweriesController and locate the Edit methods that were generated by the
Add Controller wizard.

In the HTTP GET override of Edit, modify it as shown below. This action will
retrieve the Brewery and pass it to the view as the model. Note the change
from an int id parameter to a string id parameter.

The edit form will be created using scaffolding, as was the case with the
listing page. Right click on the “Breweries” folder in the “Views” directory and
click Add -> View. Name the view “Edit” and strongly type it to a Brewery with
Edit scaffolding.

Rebuild the application and return to the brewery listing page. Click on an
“Edit” link and you should see the edit form loaded with the details for that
brewery. Edit some values on the form and click save. You should see your
changes persisted on the listing page.

The Details action looks very much like Edit. Get the Brewery and provide
it as the model for the view.

Create a scaffolding form for Details using the same process as was used with
Edit.

Rebuild and return to the list page. Click on a “Details” link. You should see a
page listing the data for that brewery.

The Create and Edit actions of the BreweriesController are quite similar,
save for the fact that Create’s GET method doesn’t provide a model to the view.
Again, error handling and validation are being omitted for brevity’s sake.

Go through the scaffolding process again to add a create view for the Create
action. Rebuild and click the “Create New” link on the list page to test the
new form. Breweries (for now) are sorted by key and limited to 50, so you might
not see yours in the list. If you want to verify your create action worked, use
brewery name that starts with a numeric value (e.g., 123 Brewery).

Another reason you wouldn’t see your new brewery appear in the list of breweries
is that the view is set to allow stale (eventually consistent) results. In
other words, the incremental update to the “all” index would be performed after
the query. If you refresh, you should see your brewery in the list.

Allowing the breweries to be sorted by key is convenient, since the key is based
on the breweries name. However, if case-sensitivity is important in sorting or
the key creation strategy changes, then explicitly sorting on the brewery’s name
is a better idea. To that end, creating a new view indexed on the Brewery name
is the right approach.

The new map function will look similar to the “all” map function, but will add
tests on “doc.name” and will emit the doc.name as the key.

If you are using the web console to manage your design documents, save the map
function above as “by_name” in the “breweries” design document. If you are
using the Model Views framework, add an attribute to the Name property of
Brewery>. Then compile and run your application.

Adding the CouchbaseViewKey attribute will create the view above. The first
argument is the name of the view. The second is the name of the JSON document
property to emit as key.

The next step is to replace the GetAll call with a call to the new view. First,
add a protected method in RepositoryBase that returns a typed view instance, set
with the design doc for that model type. The isProjection flag is set when the
type of T does not properties of the JSON to properties of the class. It must
be used with explicit JSON.NET mappings.

Compile and run your application. The list page might be ordered a little
differently as the sample database did scrub some keys of punctuation and other
non-word or non-digit characters. Also now (because of the stale setting), if
you create a new Brewery, it should appear after a redirect and should not
require a refresh.

Note that it is still possible that the view didn’t consider the new Brewery
when it was executed with state set to false. If the document hadn’t persisted
to disk before the index was updated, it wouldn’t have been included.

If that level of consistency is important to your application, you should use an
overload of ExecuteStore that includes durability requirements. See the
documentation on ExecuteStore for more information.

The last piece required to complete the CRUD functionality for breweries is to
implement the delete form. Update the Delete actions in
BreweriesController as shown below.

At this point, you’ve written a full CRUD app for breweries in the beer-sample
database. Another optimization we might want to include is to show the names of
beers that belong to a particular brewery. In the relational world, this is
typically accomplished using a join between two tables. In Couchbase, the
solution is to use a collated view.

Before looking at the map function for this view, it’s useful to inspect a beer
document.

Note the “brewery_id” property. This is the key of a brewery document and can
be thought of as a “foreign key.” Note that this type of document foreign key
relationship is not enforced by Couchbase.

The basic idea behind a collated view is to produce an index in which the keys
are ordered so that a parent id appears first, followed by its children. In the
beer-sample case that means a brewery appears in a row followed by rows of
beers.

The basic algorithm for the map function is to check the doc.type. If a brewery
is found, emit its key (meta.id). If a child is found, emit its parent id
(brewery_id). The map function for the view “all_with_beers” is shown below.

The trick to ordering properly the parent/child keys is to use a composite key
in the index. Parent ids are paired with a 0 and children with a 1. The
collated order of the view results is shown conceptually below.

A Brewery, 0
A Brewery, 1
A Brewery, 1
B Brewery, 0
B Brewery, 1

To use Model Views to create this view, simply add an attribute to an overridden
Id property on the Brewery class.

Since the collated view has a mix of beers and breweries, the generic
GetView<T> method won’t work well for deserializing rows. Instead, we’ll use
the GetView method that returns IViewRow instances. First add a new
GetViewRaw method to RepositoryBase.

Then in BreweryRepository, add a GetWithBeers method to build the object
graph. This new method performs a range query on the view, starting with the
brewery id and including all possible beer names for that brewery.

The final feature to implement on the brewery CRUD forms is paging. It’s
important to state up front that paging in Couchbase does not work like paging
in a typical RDBMS. Though views have skip and limit filters that could be used
create the standard paging experience, it’s not advisable to take this
approach.

The skip filter still results in a read of index data starting with the first
row of the index. For example, if an index has 5000 rows and skip is set to 500
and limit is set to 50, 500 records are read and 50 returned. Instead,
linked-list style pagination is the recommended approach. Paging should also
consider the document ids because keys may collide. However, in the breweries
example, paging on name is safe because name is the source of the unique key.

First add an HTML footer to the list table in the Index view, right before the
final closing table tag. There is a link back to the first page and links to
the previous and next pages. A default page size of 10 is also used. Each time
the page is rendered, it sets the previous key to the start key of the previous
page. The next key will be explained shortly.

For the actual paging, modify the BreweryController ’s Index method to keep
track of pages. The trick is to select page size + 1 from the view. The last
element is not rendered, but its key is used as the start key of the next page.
In simpler terms, the start key of the current page is the next page’s previous
key. The last element’s key is not displayed, but is used as the next page’s
start key.

At this point, breweries may be created, detailed (with Children), listed,
updated and deleted. The next step is to look at the brewery data from a
different perspective, namely location.

Brewery documents have multiple properties related to their location. There are
state and city properties, as well as detailed geospatial data. The first
question to ask of the data is how many breweries exist for a given country.
Then within each country, the counts can be refined to see how many breweries
are in a given state, then city and finally zip code. All of these questions
will be answered by the same view.

Create a view named “by_country” with the code below. This view will not
consider documents that don’t have all location properties. The reason for this
restriction is so that counts are accurate as you drill into the data.

For this view, you’ll also want a reduce function, which will count the number
of rows for a particular grouping by counting how many rows appear for that
grouping. So for example, when the group_level parameter is set to 2 brewery
counts will be returned by city and state. For an analogy, think of a SQL
statement selecting a COUNT(*) and having a GROUP BY clause with city and state
columns.

Couchbase has three built in reduce functions - _count, _sum and _stats. For
this view, _count and _sum will perform the same duties. Emitting a 1 as a
value means that _sum would sum the 1s for a grouping. _count would simply
count 1 for each row, even with a null value.

If you are using Model Views, then simply add CouchbaseViewKeyCount attributes
to each of the properties that should be produced in the view.

This view demonstrates how to create ordered, composite keys from domain object
properties using the Model Views framework.

The next step is to modify the BreweryRepository to include methods that will
return aggregated results grouped at the appropriate levels. This new method
will return key value pairs where the key is the lowest grouped part of the key
and the value is the count. Also add an enum for group levels.

Next, add the Provinces action to the CountriesController. This action will
reuse the repository method, but will change the group level to Province (2) and
pass the selected country to be used as a key to limit the query results.

Compile and run the app. Navigate through the country and province listings to
the cities listing. You should see the page below.

Click through to the codes page and you should see the page below.

The last step for this feature is to display the list of breweries for a given
zip code. To implement this page, you need to add a new method to
BreweryRepository named GetByLocation. This method will use the same view
that we’ve been using, except it won’t execute the reduce step. Not executing
the reduce step means that the results come back ungrouped and individual items
are returned.

Compile and run the app. Click through country, province and state on to the
Codes view. The code above already has a link to this new Details page. When you
click on a postal code, you should see a list of breweries as below.

The last feature to add to the brewery app is the ability to search for
breweries using its longitude and latitude. The experimental spatial indexes in
Couchbase allow for bounding box searches. Spatial indexes are created by
emitting a GeoJSON document as the key. This document must contain a
coordinates property to be indexed.

Using the web console, create a new spatial view (click “Add Spatial View”) in
the breweries design document named “points” using the spatial function below.
Note that spatial views do not use the same map/reduce process as standard
views.

If you are using Model Views, then you’ll need to modify the Brewery class.
Currently, the Model Views framework doesn’t support object graph navigation, so
you’ll need to flatten the “geo” property of the JSON document into the
Brewery as shown below. These flattened properties provide Model Views with a
way to build the spatial index.

Then update BreweryRepository with a method to call the new “points” view.
Spatial views expect a bounding box with lower left and upper right coordinates,
ordered longitude then latitude. The UI will work with a delimited string, so
those points must be parsed and parsed as floats.

Most of the code above is boilerplate. A BreweryRepository is declared and
initialized in the default constructor. The Details action that handles GET
requests simply returns the view. The Details request that handles POST requests
calls the new BreweryRepository method and renders a JSON array of brewery
projections that will be used in the view.

Next create a new Views folder called “Locations” and add a new view named
“Details” to it. This new view will make use of Nokia’s HERE location services
API. You can register for free at http://here.com. Add the
Razor and JavaScript code below to your view.

The details of the HERE API are beyond the scope of this tutorial. The basic
idea though is that when the map is rendered, the bounding box coordinates are
obtained and passed (via AJAX) to the Details POST method on the
LocationsController. The coordinates that come back are used to render points
on the map via a standard marker.

Compile and run these last changes. Navigate to /locations/details and you
should see a map such as the one shown below.

At this point, the brewery features are complete. Creating a set of pages for
the beer documents is a similar exercise that is left to the reader. Using
scaffolding and reusing the patterns from working with breweries, it shouldn’t
take much effort to build those features.

The code for this sample app is on GitHub at
https://github.com/couchbaselabs/beer-sample-net.
It contains all the code from this tutorial, plus the beer pages. It also
contains some very minor style and navigation improvements (such as a home
page).

Finally, a single tutorial can address only so many concerns. Clearly some
shortcuts were taken with validation, exception handling and the like. Certain
architectural patterns, such as dependency injection and MVVM were also omitted
for the sake of brevity. The intent of this tutorial was to provide an
intermediate introduction to Couchbase development with.NET. Your app should be
able to make use of some or all of the patterns described.

Create a connection to Couchbase Server with given parameters, such as node URL. The connection obtains the cluster configuration from the first host to which it has connected. Further communication operates directly with each node in the cluster as required.

Returns

(none)

Arguments

string url

URL for Couchbase Server Instance, or node.

string username

Username for Couchbase bucket.

string password

Password for Couchbase bucket.

The easiest way to specify a connection, or a pool of connections is to provide
it in the App.config file of your.Net project. By doing so, you can change the
connection information without having to recompile. You can update App.config
in Visual Studio as follows:

You should change the URI above to point at your server by replacing 10.0.0.33
with the IP address or hostname of your Couchbase server machine. Be sure you
set your bucket name and password. You can also set the connection to use the
default bucket, by setting the bucket attribute to default and leaving the
bucketPassword attribute empty. In this case we have configured the server
with a bucket named ‘private’ and with a password ‘private.’

Connections that you create with the.Net SDK are also thread-safe objects; for
persisted connections, you can use a connection pool which contains multiple
connection objects. You should create only a single static instance of a
Couchbase client per bucket, in accordance with.Net framework. The persistent
client will maintain connection pools per server node. For more information, see
MSDN: AppDomain Class.

The Couchbase.NET Client Library store operations set information within the
Couchbase database. These are distinct from the update operations in that the
key does not have to exist within the Couchbase database before being stored.

The Store() methods add or replace a value in the database with the specified
key.

The behavior of Store and ExecuteStore operations is defined by setting the
first parameter to a value from the StoreMode enumeration.

StoreMode.Add - Add a key to the database, failing if the key exists

StoreMode.Replace - Replace a key in the database, failing if the key does not
exist

StoreMode.Set - Add a key to the database, replacing the key if it already
exists

JavaScript can store numbers up to a maximum size of 253. If you are storing
64-bit integers within Couchbase and want to use the numbers through the
Map/Reduce engine, numbers larger than 253 should be stored as a string to
prevent number rounding errors.

API Call

object.Store(storemode, key, value)

Asynchronous

no

Description

Store a value using the specified key, whether the key already exists or not. Will overwrite a value if the given key/value already exists.

Returns

Boolean ( Boolean (true/false) )

Arguments

StoreMode storemode

Storage mode for a given key/value pair

string key

Document ID used to identify the value

object value

Value to be stored

The Store() method is used to persist new values by key. Any class decorated
with the Serializable attribute may be stored.

Store a value using the specified key, whether the key already exists or not. Will overwrite a value if the given key/value already exists.

Returns

IStoreOperationResult ( Store operation result )

Arguments

StoreMode storemode

Storage mode for a given key/value pair

string key

Document ID used to identify the value

object value

Value to be stored

The ExecuteStore() methods may define persistence or replciation (durability)
requirements. These operations will either return success only when the
durability requirements have been met. The operation fails if it times out
before meeting the durability requirement.

When specifying a persistence requirement, the persistTo parameter is set to a
value from the PersistTo enumeration. These values specify the number of nodes
to which a key must be persisted to disk. PersistTo.One - Require master only
persistence

PersistTo.Two, PersistTo.Three, PersistTo.Four - Persist to master, plus one,
two or three replicas

When specifying a replication requirement, the replicateTo parameter is set to a
value from the ReplicateTo enumeration. These values specify the number of
nodes to which a key must be replicated. ReplicateTo.One, ReplicateTo.Two,
ReplicateTo.Three - Replicate to one, two or three replicas

The Append() methods allow you to add information to an existing key/value
pair in the database. You can use this to add information to a string or other
data after the existing data.

The Append() methods append raw serialized data on to the end of the existing
data in the key. If you have previously stored a serialized object into
Couchbase and then use Append, the content of the serialized object will not be
extended. For example, adding an List of integers into the database, and then
using Append() to add another integer will result in the key referring to a
serialized version of the list, immediately followed by a serialized version of
the integer. It will not contain an updated list with the new integer appended
to it. De-serialization of objects that have had data appended may result in
data corruption.

API Call

object.Append(key, value)

Asynchronous

no

Description

Append a value to an existing key

Returns

Object ( Binary object )

Arguments

string key

Document ID used to identify the value

object value

Value to be stored

The Append() method appends information to the end of an existing key/value
pair.

The sample below demonstrates how to create a csv string by appending new
values.

The Decrement() methods reduce the value of a given key if the corresponding
value can be parsed to an integer value. These operations are provided at a
protocol level to eliminate the need to get, update, and reset a simple integer
value in the database. All the.NET Client Library methods support the use of an
explicit offset value that will be used to reduce the stored value in the
database. Note that the Decrement methods may not be used with keys that were
first created with a Store method. To initialize a counter, you must first use
either Increment or Decrement with a default value.

API Call

object.Decrement(key, defaultvalue, offset)

Asynchronous

no

Description

Decrement the value of an existing numeric key. The Couchbase Server stores numbers as unsigned values. Therefore the lowest you can decrement is to zero.

Returns

CasResult<ulong> ( Cas result of bool )

Arguments

string key

Document ID used to identify the value

object defaultvalue

Value to be stored if key does not already exist

Integer offset

Integer offset value to increment/decrement (default 1)

Decrement the inventory counter by 1, defaulting to 100 if the key doesn’t
exist.

The ExecuteRemove() method may define persistence requirements. This operation
will return success only when the key has been removed from the specified number
of nodes.

PersistTo.One will ensure removal from the key’s master node and not consider
removal of its replicas. A common use of this option is to combine it with a
non-stale view query, to guarantee that a deleted key is not returned in a view
result.

The Increment() methods reduce the value of a given key if the corresponding
value can be parsed to an integer value. These operations are provided at a
protocol level to eliminate the need to get, update, and reset a simple integer
value in the database. All the.NET Client Library methods support the use of an
explicit offset value that will be used to reduce the stored value in the
database. Note that the Increment methods may not be used with keys that were
first created with a Store method. To initialize a counter, you must first use
either Increment or Increment with a default value.

API Call

object.Increment(key, defaultvalue, offset)

Asynchronous

no

Description

Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric result. If a key does not exist, this method will initialize it with the zero or a specified value.

Returns

CasResult<ulong> ( Cas result of bool )

Arguments

string key

Document ID used to identify the value

object defaultvalue

Value to be stored if key does not already exist

Integer offset

Integer offset value to increment/decrement (default 1)

Increment the inventory counter by 1, defaulting to 100 if the key doesn’t
exist.

Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric result. If a key does not exist, this method will initialize it with the zero or a specified value.

Returns

CasResult<ulong> ( Cas result of bool )

Arguments

string key

Document ID used to identify the value

object defaultvalue

Value to be stored if key does not already exist

Integer offset

Integer offset value to increment/decrement (default 1)

TimeSpan validfor

Expiry time (in seconds) for key

Increment the inventory counter by 1, defaulting to 100 if the key doesn’t exist
and set an expiry of 60 seconds.

client.Increment("inventory", 100, 1, TimeSpan.FromSeconds(60));

API Call

object.Increment(key, defaultvalue, offset, expiresat)

Asynchronous

no

Description

Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric result. If a key does not exist, this method will initialize it with the zero or a specified value.

Returns

CasResult<ulong> ( Cas result of bool )

Arguments

string key

Document ID used to identify the value

object defaultvalue

Value to be stored if key does not already exist

Integer offset

Integer offset value to increment/decrement (default 1)

DateTime expiresat

Explicit expiry time for key

Increment the inventory counter by 1, defaulting to 100 if the key doesn’t exist
and set an expiry of 5 minutes.

client.Increment("inventory", 100, 1, DateTime.Now.AddMinutes(5));

API Call

object.Increment(key, defaultvalue, offset, casunique)

Asynchronous

no

Description

Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric result. If a key does not exist, this method will initialize it with the zero or a specified value.

Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric result. If a key does not exist, this method will initialize it with the zero or a specified value.

Returns

CasResult<ulong> ( Cas result of bool )

Arguments

string key

Document ID used to identify the value

object defaultvalue

Value to be stored if key does not already exist

Integer offset

Integer offset value to increment/decrement (default 1)

TimeSpan validfor

Expiry time (in seconds) for key

ulong casunique

Unique value used to verify a key/value combination

Increment the inventory counter by 1, defaulting to 100 if the key doesn’t exist
and set an expiry of 60 seconds. Fail if CAS value doesn’t match CAS value on
server.

Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric result. If a key does not exist, this method will initialize it with the zero or a specified value.

Returns

CasResult<ulong> ( Cas result of bool )

Arguments

string key

Document ID used to identify the value

object defaultvalue

Value to be stored if key does not already exist

Integer offset

Integer offset value to increment/decrement (default 1)

DateTime expiresat

Explicit expiry time for key

ulong casunique

Unique value used to verify a key/value combination

Increment the inventory counter by 1, defaulting to 100 if the key doesn’t exist
and set an expiry of 5 minutes. Fail if CAS value doesn’t match CAS value on
server.

Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric result. If a key does not exist, this method will initialize it with the zero or a specified value.

Returns

IMutateOperationResult ( Mutate operation result )

Arguments

string key

Document ID used to identify the value

object defaultvalue

Value to be stored if key does not already exist

Integer offset

Integer offset value to increment/decrement (default 1)

ExecuteIncrement will return an instance of an IMutateOperationResult

Increment the inventory counter by 1, defaulting to 100 if the key doesn’t
exist.

Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric result. If a key does not exist, this method will initialize it with the zero or a specified value.

Returns

IMutateOperationResult ( Mutate operation result )

Arguments

string key

Document ID used to identify the value

object defaultvalue

Value to be stored if key does not already exist

Integer offset

Integer offset value to increment/decrement (default 1)

TimeSpan validfor

Expiry time (in seconds) for key

Increment the inventory counter by 1, defaulting to 100 if the key doesn’t exist
and set an expiry of 60 seconds.

Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric result. If a key does not exist, this method will initialize it with the zero or a specified value.

Returns

IMutateOperationResult ( Mutate operation result )

Arguments

string key

Document ID used to identify the value

object defaultvalue

Value to be stored if key does not already exist

Integer offset

Integer offset value to increment/decrement (default 1)

DateTime expiresat

Explicit expiry time for key

Increment the inventory counter by 1, defaulting to 100 if the key doesn’t exist
and set an expiry of 5 minutes.

Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric result. If a key does not exist, this method will initialize it with the zero or a specified value.

Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric result. If a key does not exist, this method will initialize it with the zero or a specified value.

Returns

IMutateOperationResult ( Mutate operation result )

Arguments

string key

Document ID used to identify the value

object defaultvalue

Value to be stored if key does not already exist

Integer offset

Integer offset value to increment/decrement (default 1)

TimeSpan validfor

Expiry time (in seconds) for key

ulong casunique

Unique value used to verify a key/value combination

Increment the inventory counter by 1, defaulting to 100 if the key doesn’t exist
and set an expiry of 60 seconds. Fail if CAS value doesn’t match CAS value on
server.

Increment the value of an existing numeric key. Couchbase Server stores numbers as unsigned numbers, therefore if you try to increment an existing negative number, it will cause an integer overflow and return a non-logical numeric result. If a key does not exist, this method will initialize it with the zero or a specified value.

Returns

IMutateOperationResult ( Mutate operation result )

Arguments

string key

Document ID used to identify the value

object defaultvalue

Value to be stored if key does not already exist

Integer offset

Integer offset value to increment/decrement (default 1)

DateTime expiresat

Explicit expiry time for key

ulong casunique

Unique value used to verify a key/value combination

Increment the inventory counter by 1, defaulting to 100 if the key doesn’t exist
and set an expiry of 5 minutes. Fail if CAS value doesn’t match CAS value on
server.

The Prepend() methods allow you to add information to an existing key/value
pair in the database. You can use this to add information to a string or other
data after the existing data.

The Prepend() methods prepend raw serialized data on to the end of the
existing data in the key. If you have previously stored a serialized object into
Couchbase and then use Prepend, the content of the serialized object will not be
extended. For example, adding an List of integers into the database, and then
using Prepend() to add another integer will result in the key referring to a
serialized version of the list, immediately followed by a serialized version of
the integer. It will not contain an updated list with the new integer prepended
to it. De-serialization of objects that have had data prepended may result in
data corruption.

API Call

object.Prepend(key, value)

Asynchronous

no

Description

Prepend a value to an existing key

Returns

Object ( Binary object )

Arguments

string key

Document ID used to identify the value

object value

Value to be stored

The Prepend() method prepends information to the end of an existing key/value
pair.

The sample below demonstrates how to create a csv string by prepending new
values.

The Touch() methods allow you to update the expiration time on a given key.
This can be useful for situations where you want to prevent an item from
expiring without resetting the associated value. For example, for a session
database you might want to keep the session alive in the database each time the
user accesses a web page without explicitly updating the session value, keeping
the user’s session active and available.

API Call

object.Touch(key, expiry)

Asynchronous

no

Description

Update the expiry time of an item

Returns

Boolean ( Boolean (true/false) )

Arguments

string key

Document ID used to identify the value

object expiry

Expiry time for key. Values larger than 30*24*60*60 seconds (30 days) are interpreted as absolute times (from the epoch).

The Touch method provides a simple key/expiry call to update the expiry time
on a given key. For example, to update the expiry time on a session for another
60 seconds:

The check-and-set methods provide a mechanism for updating information only if
the client knows the check (CAS) value. This can be used to prevent clients from
updating values in the database that may have changed since the client obtained
the value. Methods for storing and updating information support a CAS method
that allows you to ensure that the client is updating the version of the data
that the client retrieved.

The check value is in the form of a 64-bit integer which is updated every time
the value is modified, even if the update of the value does not modify the
binary data. Attempting to set or update a key/value pair where the CAS value
does not match the value stored on the server will fail.

The behavior of Cas and ExecuteCas operations is defined by setting the
first parameter to a value from the StoreMode enumeration. StoreMode.Add -
Add a key to the database, failing if the key exists

StoreMode.Replace - Replace a key in the database, failing if the key does not
exist

StoreMode.Set - Add a key to the database, replacing the key if it already
exists

API Call

object.Cas(storemode, key, value)

Asynchronous

no

Description

Compare and set a value providing the supplied CAS key matches

Returns

CasResult<bool> ( Cas result of bool )

Arguments

StoreMode storemode

Storage mode for a given key/value pair

string key

Document ID used to identify the value

object value

Value to be stored

The Cas() method is used to persist new values by key. Any class decorated
with the Serializable attribute may be stored. The CAS value is returned by
way of a CasResult

As you can see, when you iterate over a strongly typed view each item is of the
type you specified. If you use the non-generic version, each item you enumerate
over will be of type IViewRow. IViewRow provides methods for accessing details
of the row that are not present when using strongly typed views.

To get the original document from the datastore:

row.GetItem();

To get a Dictionary representation of the row:

row.Info;

To get the original document’s ID (key):

row.ItemId;

To get the key emitted by the map function:

row.ViewKey;

Before iterating over the view results, you can modify the query that is sent to
the server by using the fluent methods of IView. Refer to the sample document
and view below when exploring the IView API.

When you bulk load data to Couchbase Server, you can accidentally overwhelm
available memory in the Couchbase cluster before it can store data on disk. If
this happens, Couchbase Server will immediately send a response indicating the
operation cannot be handled at the moment but can be handled later.

This is sometimes referred to as “handling Temp OOM”, where where OOM means out
of memory. Note though that the actual temporary failure could be sent back for
reasons other than OOM. However, temporary OOM is the most common underlying
cause for this error.

To handle this problem, you could perform an exponential backoff as part of your
bulk load. The backoff essentially reduces the number of requests sent to
Couchbase Server as it receives OOM errors:

The following sections provide details on working with the IOperationResult
interface.

CouchbaseClient ’s standard CRUD operations return Boolean values. When
exceptions or failures occur, they are swallowed and false is returned.

While there might be scenarios where the cause of a failure is not important
(e.g., non-persistent cache), it is likely that access to error information is
necessary. To that end, the CouchbaseClient provides a set of complimentary
ExecuteXXX methods, where XXX is the name of a standard CRUD operation.

The Message property will contain details as to why an operation failed. The
message might be from the server or it could be from the client. The
StatusCode property is a Nullable<int> that will be populated from the
server’s response.

Note that the 1.1 release of the OperationResult API wrapped lower level
(networking) exceptions in an InnerResult object. Since release 1.2,
InnerResult is no longer populated. The property still remains so as to be
backwards compatible.

Like the standard CRUD methods, the Execute methods will swallow exceptions.
However, caught exceptions are passed back to the caller by way of the
Exception property. This allows the caller to check for an exception and throw
it if exception behavior is desired.

There are several interfaces that extend IOperationResult to provide
additional properties. Two important interfaces are the
INullableOperationResult<T> and ICasOperationResult

The IMutateOperationResult, IConcatOperationResult interfaces also return
the CAS value. These interfaces are returned by
ExecuteIncrement/ExecuteDecrement and ExecuteAppend/ExecutePrepend
respectively. IRemoveOperationResult includes only the properties found in
IOperationResult.

For more information on which API methods support ExecuteXXX variants, see the
API reference.

The following sections provide details on how to use the CouchbaseClient JSON
extensions.

The Couchbase.Extensions namespace contains a series of extension methods that
provide out of the box support for storing and retrieving JSON with Couchbase
Server. These methods use JSON.NET, and provide only limited customization. If
your JSON serialization needs are advanced, you will need to provide your own
methods to work with JSON.

To use the JSON extensions in your application, you’ll first need to include a
using block for the extensions namespace

using Couchbase.Extensions;

Once that using directive has been added, an instance of an ICouchbaseClient
will be able to execute various JSON methods.

Generally speaking, for each store or get method, there is a corresponding Json
method.

The JSON extensions make an important assumption about your model objects, and
how they serialize and deserialize them. It is important that you understand
this assumption before using these methods. Consider the following Person class:

When the JSON is saved, it will ignore the Id property and its value. Since it
is assumed that the Id is the key, it would be redundant to include it in the
saved JSON. Moreover, it would also be a challenge to keep the key in sync with
the JSON.

When the Person is retrieved, the ExecuteGetJson method will automatically
map the Id property to the key. This mapping is achieved by inserting the key
as an “id” property in the JSON document before it is deserialized.

The importance of how the “id” property is mapped is that you are able to take
advantage of JSON.NET attributes to have some control over which property is
your “Id” property. If you wanted to map the key to a Key property, then you
could use the JsonProperty attribute as below. Note however, that should you
use this mapping, it will override the ignore “id” on write and you’ll have your
key in the JSON.

The minimum configuration options are to include a couchbase section with a
servers element with at least one URI, which is used to bootstrap the client.
At least two node URIs should be provided, so that in the event that the client
can’t reach the first, it will try the second.

bucket (default) The bucket against which the client instance will perform
operations

bucketPassword The password for authenticated buckets.

username The username used to secure a cluster.

password The password associated with the cluster username

retryCount The number of times to retry a failed attempt to read cluster
config

retryTimeout (00:00:02) The amount of time to wait in between failed attempts
to read cluster config

observeTimeout (00:01:00) The amount of time to wait for persistence or
replication checks when using ExecuteStore or ExecuteRemove with durability
requirements

httpRequestTimeout (00:01:00) The amount of time to wait for the HTTP
streaming connection to receive cluster configuration

The socketPool element is used to configure the behavior of the client as it
connects to the Couchbase cluster. Defaults are in parentheses. minPoolSize
(10) The minimum number of connections in the connection pool

maxPoolSize (20) The maximum number of connections in the connection pool

connectionTimeout (00:00:10) The amount of time the client is waiting to a)
eastablish a connection to the memcached server, b) get a free connection from
the pool. If it times out the operation will fail. (And return false or null,
depending on the operation.)

deadTimeout (00:00:10) When all pool urls are unavailable the client will
check the first one again after deadTimeout time elapses. Additionally, the
client has a basic dead node detection mechanism which will also use this
timeout to reconnect servers which went offline.

queueTimeout (00:00:00.100) Specifies the amount of time after which the
getting of a connection from the pool will fail. The default is 100 msec.

receiveTimeout (00:00:10) The amount of time after which receiving data from
the socket fails.

The client will periodically check the health of its connection to the cluster
by performing a heartbeat check. By default, this test is done every 10 seconds
against the bootstrap URI defined in the servers element.

uri (defaults to first server Uri from servers element) The Uri used for the
heartbeat check

When executing view queries, HTTP requests are made by IHttpClient instances
which are created by factories. The factory is defined in the
httpClientFactory element.

type (Couchbase.RestSharpHttpClientFactory, Couchbase) The fully qualified
type name of an IHttpClientFactory implementation,
RestSharpHttpClientFactory is the default. HammockHttpClientFactory is also
supported, but has known issues.

It is not possible to configure (in app|web.config) a single instance of a
CouchbaseClient to work with multiple buckets. Though it is possible to
programmatically reconstruct a client to work with multiple buckets, it is not
recommended. The process of creating a client is expensive (relative to other
Couchbase operations) and should ideally be done once per app domain.

It is possible however to set multiple config sections in app|web.config to
allow for multiple client instances to be created, while still maintaining
bucket affinity.

After defining the config sections, bucket specific clients are created by
reading the appropriate config sections and passing the config section reference
to the constructor of the CouchbaseClient. Again, constructing the client should
not be done per operation, but rather per app domain.

The following sections provide details about using the Couchbase.NET Client to
manage buckets and design documents.

Cluster management is performed by using methods of the CouchbaseCluster
class, which implements the ICouchbaseCluster interface, both of which are in
the Couchbase.Management namespace.

using Couchbase.Management;

The CouchbaseCluster is configured using the same config definitions (code or
XML) used to create instances of a CouchbaseClient. When managing the cluster
with the.NET client, the cluster username and password must be provided.

To remove the data (but not design documents) from a bucket, use the
FlushBucket method. void FlushBucket(string bucketName) flushes data from a
bucket

cluster.FlushBucket("bucketName");

There are four methods for managing design documents with the
CouchbaseCluster. bool CreateDesignDocument(string bucket, string name,
string document) creates a design document on the server, using the provided
JSON string as the source of the document.

NCBC-301: added a new StatusCode enumeration for unifying client and server
status results of operations across all clients. This also fixes a bug where
socket time-out messages on the client were not returned with the operation
result.

NCBC-250: unit test improvements.

NCBC-257: Improvements to ensure that Disposed objects do not make it through
to the finalization phase of garbage collection. This should improve issues with
socket time-outs and generally improve client stability and performance.

The logging assemblies are now available via separate NuGet pacakges, which
reference NLog and log4net via NuGet, instead of local assemblies. See
CouchbaseLog4NetAdapter and CouchbaseNLogAdapater on NuGet.

NCBC-254: JSON extensions should default to ignore Id property on
add/replace/set. This change allows for compatibility with the generic view
queries, which map the key to an Id property.

NCBC-246: The.NET Client Library is now code compatible with the .NET Framework
version 3.5. The NuGet package and release zip file contain both 4.0 and 3.5
assemblies. The solution (see GitHub) now includes a Couchbase .Net35 project.

NCBC-247: RestSharp and Hammock are no longer dependencies of the Couchbase.NET
Client Library.

No change should be necessary, unless using explicit RestSharp or Hammock
configuration for the HttpClientFactory. If not, the default configuration will
use the new HttpClientFactory, which relies only on WebClient. In 1.2.4, the
default HttpClientFactory relied on RestSharp.

RestSharp and Hammock will be usable via a separate NuGet project, or from the
Couchbase.HttpClients project (via GitHub). These assemblies will not be signed,
to avoid collisions with a custom RestSharp, which is unsigned.

NCBC-165: IView now includes a CheckExists method, which will allow callers to
verifiy that a view exists in a design document prior to executing a view query.
This method will perform an HTTP request to get the design document contents.

NCBC-179: Additional JSON extensions are now available. For each Store or
ExecuteStore method in the ICouchbaseClient API, there is now a corresponding
JSON method. These additions include methods for CAS and expiry overloads. An
ExecuteGetJson method has also been provided. Note these methods are
intentionally not included in the ICouchbaseClient interface as they are
explicitly tied to Newtonsoft.Json and its default serialization rules.

NCBC-189: Fix to NRE when ExecuteIncrement or ExecuteDecrement returned null
StatusCode.

NCBC-195: NRE no longer thrown when client cannot locate a node on which to
execute a view. The lack of available nodes is logged in the debug log and an
InvalidOperationException is intentionally raised. NCBC-222: is tracking a 1.2.2
fix for an improved exception type.

NCBC-172: 1.2.0 Hammock dependency was throwing a null reference exception when
executing a view query against an offline node. The 1.2.1 release replaces
Hammock with RestSharp for view execution. Hammock is still supported, but
RestSharp is the new default. If Hammock is explicitly configured, then Hammock
will still be used for view execution. RestSharp is the suggested view REST
library. To ensure RestSharp is in use, App|Web.config must not contain snippet
below. If configured in code, the HttpClientFactory should not be set.

NCBC-197: When 0 bytes are received on sockets, but read was valid, Enyim client
was throwing an exception with the message “?.” A descriptive exception message
is now included.

NCBC-192: NRE was being thrown when executing ops against a down node. NRE was
also the symptom displayed when app client configuration was incorrect. Ops
against a bad node should now return the message “Unable to locate node” when
using the IOperationResult methods. There is a constant for this error.

NCBC-223: Mono support not included for 1.2.1.
ServicePointManager.SetTcpKeepAlive is not supported by Mono. A 1.2.0 build was
released with this call removed, however a better solution should be in place
for 1.2.2.

NCBC-168: Socket errors were previously being swallowed and did not bubble up
through ExecuteXXX method return values.

NCBC-161: Run views only on nodes in cluster supporting couchApiBase (Couchbase
nodes)

Known Issues in 1.2.0

NCBC-172: During a rebalance or fail over, view queries may result in an
unhandled NullReferenceException. This exception is raised by a thread in the
dependency Hammock.

NCBC-170: If an exception occurs before data are read, the PooledSocket may be
returned to the pool marked still alive and with a dirty buffer. In some
situations, a wrong magic value error may result.

NCBC-176: Flushing of buckets is not yet supported in Couchbase.Management API