C# Azure Functions to access CosmosDB
Tags: cosmosdb, csadvent, csharp, serverless
Published: 2021-12-05 01:44:21

> This article is part of [The Fifth Annual C# Advent Calendar](https://www.csadvent.christmas/) initiative by [Matthew D. Groves](https://twitter.com/mgroves). You'll find other helpful articles and tutorials published daily by community members and experts there, so make sure to check it out every day.

Interacting with **CosmosDB** from a **serverless** application can be achieved with very few lines of code using C#.

Pre-requisites:
- A _CosmosDB_ resource
- An _Azure Functions_ resource
- An _input binding_ (the CosmosDB resource) is required for read operations, while an _output binding_ (the CosmosDB resource) is needed for the write operations. For each operation, I share the specific _function.json_ required.

Considerations:
- In each code there is a model (class) of your data. In our example, we are using a [Student](https://gist.github.com/icebeam7/f7b780eea1154ed857d25c52ce7d91e5) class.
- Each operation is an **HTTP trigger**.


Let's go!

**Operation 1. Retrieving data:**
function.json is available [here](https://gist.github.com/icebeam7/e09ffb46fb3056920944d39e2b858742).

```
using System.Net;
using Microsoft.AspNetCore.Mvc;

public static async Task<IActionResult> Run(HttpRequest req, IEnumerable<Student> inputDocument, ILogger log)
{
  var students = (List<Student>) inputDocument;
  return new OkObjectResult(students);
}
```

_Comments:_ 
No "special" library/SDK is required to read from CosmosDB since this is handled by the binding in _function.json_!

_Testing:_
Simply send a GET request to the URL provided by Azure Functions and you'll get your data:

![Retrieving data](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e3vfcf8qxtpyoy7lrhr6.png)

**Operation 2. Adding data:**
function.json is available [here](https://gist.github.com/icebeam7/82017d03956adf2098c9cc66026766d4)

```
#r "Newtonsoft.Json"

using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;

public static IActionResult Run(HttpRequest req, out object outputDocument, ILogger log)
{
  var body = new StreamReader(req.Body).ReadToEnd();
  dynamic data = JsonConvert.DeserializeObject(body);
  
  outputDocument = new
  {
    id = data.id,
    faculty = data.faculty,
    Name = data.Name,
    Semester = data.Semester
  };
  
  return (ActionResult)new OkResult();
}
```

_Comments:_ 
The _return_ statement writes new data in CosmosDB since we set that resource as an output binding (see the associated function.json). 

_Testing:_
Send a POST request to the URL provided by Azure Functions including the new data (Student object) in the Body.

![Adding data](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0bimr4vq0dksxj8yc4sz.png)

Result is 200 OK =)

![Result of adding data](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5e7xxqypvgf211yiotok.png)

**Operation 3. Updating data:**
function.json is available [here](https://gist.github.com/icebeam7/8199e45f4356f83c82daac30b7138c65)

```
#r "Newtonsoft.Json"
#r "Microsoft.Azure.DocumentDB.Core"
#r "Microsoft.Azure.WebJobs.Extensions.CosmosDB"

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using Microsoft.Azure.Documents.Client;

public static async Task<IActionResult> Run(
  HttpRequest req, 
  [CosmosDB(ConnectionStringSetting = "universitylb7_DOCUMENTDB")] DocumentClient outputDocument, 
  ILogger log, string id, string faculty)
{
  string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
  var updated = JsonConvert.DeserializeObject<Student>(requestBody);
  
  var option = new FeedOptions { EnableCrossPartitionQuery = true };
  var collectionUri = UriFactory.CreateDocumentCollectionUri("studentsdb", "students");
  
  var document = outputDocument.CreateDocumentQuery(collectionUri, option).Where(t => t.Id == id)
        .AsEnumerable().FirstOrDefault();
  
  if (document == null)
  {
    return new NotFoundResult();
  }

  document.SetPropertyValue("Name", updated.Name);
  document.SetPropertyValue("Semester", updated.Semester);
  
  await outputDocument.ReplaceDocumentAsync(document);
  
  return new OkResult();
}
```

_Comments:_ 
To update (and delete) we need the libraries ( _Microsoft.Azure.DocumentDB.Core_ and _Microsoft.Azure.WebJobs.Extensions.CosmosDB_) since we need to search and then replace the document with the latest content. 

Moreover, in the _function.json_ you will see that a _route_ is specified: it means that the URL must include the id and partition key of the document we want to update (the combination of both elements must be unique in a collection). And of course, you will include the new data in the Body request.

![Updating data with query parameters](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ftzrys5fvo0dyw2e0cs1.png)

Once again, the result is a nice 200 OK.

![200 OK](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kjnbrzgkdyd5sptend0k.png)

**Operation 4. Deleting data:**
function.json is available [here](https://gist.github.com/icebeam7/d7b8f2fa22e6afd2caf801d40b51455b)

```
#r "Newtonsoft.Json"
#r "Microsoft.Azure.DocumentDB.Core"
#r "Microsoft.Azure.WebJobs.Extensions.CosmosDB"

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Documents.Client;

public static async Task<IActionResult> Run(
  HttpRequest req, 
  [CosmosDB(ConnectionStringSetting = "universitylb7_DOCUMENTDB")] DocumentClient outputDocument, 
  ILogger log, string id, string faculty)
{
    var option = new FeedOptions { EnableCrossPartitionQuery = true };
    var collectionUri = UriFactory.CreateDocumentCollectionUri("studentsdb", "students");
    
    var document = outputDocument.CreateDocumentQuery(collectionUri, option).Where(t => t.Id == id).AsEnumerable().FirstOrDefault();

    if (document == null)
    {
        return new NotFoundResult();
    }

    await outputDocument.DeleteDocumentAsync(document.SelfLink, new RequestOptions
    {
    PartitionKey = new Microsoft.Azure.Documents.PartitionKey(faculty)
    });
  
    return new OkResult();
}
```

_Comments:_ 
The code to delete is quite similar to the update one, except we don't replace here (but delete) the document.

_Testing:_
Just include the id and faculty in the URL query parameters.


![Deleting data](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m166z67x0mdadeazbbuf.png)

Bye-bye data!

![Begone!](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0jnokwhvxrmhy6nozl3s.png)

------------

And with that, we have set a serverless API that can interact with CosmosDB. 

I hope that this blog post was interesting and useful for you. I invite you to visit [my blog](https://www.luisbeltran.mx/) for more technical posts about _Xamarin, Azure, and the .NET ecosystem_. I write in Spanish language =)

Thanks for your time, and enjoy the rest of the [C# Advent Calendar](https://www.csadvent.christmas/) publications!

See you next time,
Luis