DocumentDB is a highly scalable, NoSQL document database service in Azure. On azure.microsoft.com you can find a lot information about DocumentDB. For example how you can create a DocumentDB or how to build your first app. But in a “real life” scenario (for example in project for a customer) this information is probably not enough or even relevant because the samples are often console applications and maybe you want to create a Mobile or a Web App. Often you also need to modify the data from the client or add meta data to it. For example a creation date or an order status. Therefore its good practice to create a custom Web API to handle the inserts, updates, deletes and data retrievals. There you have complete control on the object that is sent by the client. But how do you do that if you want to store the data in DocumentDB?  In that case it can take quite some time to find the additional info that you need. Therefore I created an API App to show how you can insert, update, delete or get a customer order and how to add additional (meta data) to the orders! The following sample can easy be modified for other type of objects.

Prerequisites

First you have to create a DocumentDB database and a collection inside it. The easiest way to do that is in the Azure Portal. This blog post doesn’t show how to do that because you can also find that information in “How to create a database for DocumentDB” on the Azure website. The result is similar like below:

 

 

 

 

 

 

 

 

Steps

This post also doesn’t give an intro on how to create an API App but rather focuses on the part that is specific for DocumentDB, (Here you can find more information on how to create an API App.)

Create an Order

First create a Data Access Layer (DAL) helper class that stores the order in DocumentDB. The order that is sent to the API App from the client is put in a server order object that has extra properties like OrderStatus and CreationDate. This construction makes it possible to create properties on the order that are not visible for the client or for example read only for the client. When an object is stored in DocumentDB is automatically a guid created for the object. This guid is sent back to client and can be used to retrieve the order.

public async Task<string> CreateOrder(ClientOrder order)
{
    string id = null;

    //Create a server order with extra properties
    ServerOrder s = new ServerOrder();

    s.customer = order.customer;
    s.item = order.item;

    //Add meta data to the order
    s.OrderStatus = "in progress";
    s.CreationDate = DateTime.UtcNow;

    //Get a Document client
    using (client = new DocumentClient(new Uri(endpointUrl), 
authorizationKey)) { string pathLink = string.Format("dbs/{0}/colls/{1}",
databaseId, collectionId); ResourceResponse<Document> doc = await client.
CreateDocumentAsync(pathLink, s); //Return the created id id = doc.Resource.Id; } return id; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 
Create a POST method in the API App Controller class to post a new order to the API App. Call the helper class to insert the order in DocumentDB and return the generated id (guid) to client.
public async Task<IHttpActionResult> Post([FromBody]ClientOrder order)
{
    OrderResult result = new OrderResult();

    try
    {
        OrderManager mgr = new OrderManager();
        string id = await mgr.CreateOrder(order);

        if (id != null)
        {
            result.Id = id;
        }

        //Return a HTTP 200 with the created id
        return Ok(result);
    }
    catch
    {
        return InternalServerError();
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 
You can test the API App with the test page that is automatically generated with Swagger.
 
Check in the Azure Portal with the Document Explorer if the order really is stored in DocumentDB. 
Below you can see that the server object with additional properties is stored.
 
 

Read an Order by Id

Create a method in the DAL helper class the get the order by its generated id. There are several ways to get data from DocumentDB. You can use a SQL query but in the sample below is LINQ used.

public ServerOrder GetOrderById(string id)
{
    ServerOrder order = null;

    //Get a Document client
    using (client = new DocumentClient(new Uri(endpointUrl), 
authorizationKey)) { string pathLink = string.Format("dbs/{0}/colls/{1}",
databaseId, collectionId); dynamic doc = client.CreateDocumentQuery<Document>(pathLink).
Where(d => d.Id == id)
.AsEnumerable().FirstOrDefault(); if (doc != null) { order = doc; } } return order; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 
Create a GET method in the API App Controller class to get the order by its id. Call the DAL helper class to get the order from DocumentDB and return the server order to client. The NotFound() en Ok() methods are used to return the necessary status code to the client.
public IHttpActionResult Get(string id)
{              
    OrderManager mgr = new OrderManager();
    var order = mgr.GetOrderById(id);

    if (order == null)
    {
        return NotFound();
    }
    return Ok(order);           
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 
The Swagger test page makes it easy to test the API App but you can also use other tools like Postman to test your API App.
 
 

Update an Order

Create a method in the DAL helper class to update the order in DocumentDB. At first you needed a SelLink to update or delete an object in DocumentDB but in that case you first have to query for the document if you only have an id. This is not necessary anymore because now you can also create an Uri. In the example below is still searched first for the order with a query.
public async Task<string> UpdateOrderById(string id, ClientOrder order)
{
    string result = null;

    //Get a Document client
    using (client = new DocumentClient(new Uri(endpointUrl), authorizationKey))
    {

        string pathLink = string.Format("dbs/{0}/colls/{1}", databaseId, collectionId);

        dynamic doc = client.CreateDocumentQuery<Document>(pathLink).
Where(d => d.Id == id)
.AsEnumerable().FirstOrDefault(); if (doc != null) { ServerOrder s = doc; s.customer = order.customer; s.item = order.item; s.ModifiedDate = DateTime.UtcNow; //Update document using self link. ResourceResponse<Document> x = await
client.ReplaceDocumentAsync(doc.SelfLink, s); result = x.StatusCode.ToString(); } } return result; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 
Create a PUT method in the API App Controller class to update the order. Call the DAL helper class to update the order in DocumentDB.
public async Task<IHttpActionResult> Put(string id, [FromBody]ClientOrder order)
{
    try
    {
        OrderManager mgr = new OrderManager();
        string result = await mgr.UpdateOrderById(id, order);

        if (result == null)
        {
            return NotFound();
        }

        return Ok("Order updated");
    }
    catch
    {
        return InternalServerError();
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 
 

Delete an order

Create a method in the DAL helper class to delete the order in DocumentDB. In the example below is an Uri created to directy delete the order by its id.
public async Task<string> DeleteOrderById(string id)
{
    string result = null;

    //Get a Document client
    using (client = new DocumentClient(new Uri(endpointUrl), 
authorizationKey)) { var docLink = string.Format("dbs/{0}/colls/{1}/docs/{2}",
databaseId, collectionId, id); // Delete document using an Uri. var x = await client.DeleteDocumentAsync(docLink); if (x != null) { result = x.StatusCode.ToString(); } } return result; }

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 
Create a DELETE method in the API App Controller class to delete the order. Call the DAL helper class to delete the order in DocumentDB.
public async Task<IHttpActionResult> Delete(string id)
{
    try
    {
        OrderManager mgr = new OrderManager();
        string result = await mgr.DeleteOrderById(id);

        if (result == null)
        {
            return NotFound();
        }

        return Ok("Order deleted");
    }
    catch 
    {
        return InternalServerError();
    }            
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

Conclusion

I really like DocumentDB because it’s a very powerful database. You don’t have to create tables anymore in the database because you store the entire JSON object in a collection. That makes it easier for developers. It’s also incredibly fast so that’s all great but as always there also a couple of things that I miss. What I really like about SQL Server is the SQL Server Management Studio and that is something you don’t have that for DocumentDB. Sure, you can do a lot of things in the Azure Portal but it doesn’t give the same user experience. (There are also some open source initiatives like Azure DocumentDB Studio) Another good thing about SQL Server is the documentation. You have a lot of documentation about SQL Server. Maybe this is because the Microsoft team are still developing new features in it. 
In the meantime you will have to read the Azure blog posts to keep track of all the new stuff in DocumentDB!

Download the API App sample on:

code.msdn.microsoft.com