Building a microservice with C#, .NET Core and MongoDB - Part 1
Tags: tutorial, csharp, beginners, webdev
Published: 2020-08-25 20:47:52

If you are interested in reading this article in Spanish 🇪🇸, check out my blog:
[The Developer's Dungeon](https://www.patferraggi.dev/blog/2020/aug/csharp-mongo/)

Hey guys! how have you been? In the latest weeks, I have been on going some interview process for C# Developer positions.

I work with asp.net core every day which means that when I am at home I don't pick C# as my training language. So the C# code I have in my Github is fairly old and belongs to the early years of my career.

So I decided to use the coding challenges that employers are giving me to create some newer C# code for my Github and at the same time create a nice guide that you can follow to improve your personal development.

----

## What to expect from this tutorial?

At the end of the series, we will have a microservice with the following characteristics:

* Integrated to `MongoDB`
* Layered architecture with clear separation of concerns
* API documentation
* Docker support for deployment
* Unit tested

## Introduction

We have a small business, we sell 💻. Every time a new computer is sold we need to record the order with the amount and client who bought it.

We are gonna create a small microservice that connects to a [MongoDB](https://www.mongodb.com/) and allows us to create/read/update/delete orders and also get some extra computation about users spending.

Our `Order` model will be the following:

```json
{
  "id": "guid",
  "userId": "guid",
  "amount": "int"
}
```

## Basic Definition

We start by creating an ASP.NET Core 3.1 Web Application with the API template and enabled Docker support in Visual Studio 2019.

![ApplicationTemplate](https://dev-to-uploads.s3.amazonaws.com/i/0sldfc9i411ztnje7t6c.png)

Once that is created you will see a model and a controller for `WeatherForecast` which is the default template way of showing you that there is an API out of the box.

![InitialStatus](https://dev-to-uploads.s3.amazonaws.com/i/20daydhqd7cjp13vhhg6.png)

After we delete the default code we start by creating our model and a basic OrdersController. We are gonna start by the `Get and Post` endpoints, that way we will be able to test adding and getting orders.

```csharp
    [Route("v1/[controller]")]
    [ApiController]
    public class OrdersController : ControllerBase
    {
        /// <summary>
        /// Retrieves all orders
        /// </summary>
        /// <returns>a list with all the orders available</returns>
        [HttpGet]
        public async Task<IEnumerable<Order>> GetAll()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Retrieves the order that matches the id supplied
        /// </summary>
        /// <returns>one order model</returns>
        [HttpGet("{orderId}")]
        public async Task<ActionResult<Order>> Get(Guid orderId)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Creates a new order
        /// </summary>
        /// <returns>the newly created order</returns>
        [HttpPost]
        public async Task<ActionResult<Order>> Post([FromBody]OrderCreateUpdate orderRequest)
        {
            throw new NotImplementedException();
        }
    }
```

In the previous code, we create the `GetAll`, `Get` and `Post` endpoints, we also include comments for the public API and we already versioned our API by using `v1/[controller]` naming in the endpoints. If you are paying attention you might have noticed that the `Post` has a model we haven't defined yet, `OrderCreateUpdate`. 

When you are creating items in a database, you should not provide an `OrderId`, since the order doesn't exist yet, then it is a good practice to separate the API model in two so they can change independently. This is the model for `OrderCreateUpdate`:

```json
{
  "userId": "guid",
  "amount": "int"
}
```

```csharp
        public Guid UserId { get; set; }
        public int Amount { get; set; }
```

## Connecting to the Database

For now, instead of creating a database or messing with docker from the start, we are gonna use an online database like the ones provided by [MongoDBAtlas](https://www.mongodb.com/try).

Back in the project, we need to find a way to configure the settings for connecting to our database, we do that by using the [Options Pattern](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-3.1). We define the following configuration:

```csharp
    public class OrdersServiceOptions
    {
        public string DatabaseConnectionString { get; set; }
        public string DatabaseName { get; set; }
        public string CollectionName { get; set; }
    }
```

Now that we have our configuration ready we can move on to create our first [Repository](https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application) that will have the responsibility of connecting to our `MongoDB` instance.

This is the code for our `OrdersRepository`:

```csharp
    public class OrdersRespository
    {
        private readonly IMongoDatabase database;
        private readonly IMongoCollection<Order> collection;
        private readonly ILogger<OrdersRespository> logger;

        public OrdersRespository(IOptions<OrdersProcessingServiceOptions> options, ILogger<OrdersRespository> logger)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            var configuration = options.Value;
            var client = new MongoClient(configuration.DatabaseConnectionString);

            this.database = client.GetDatabase(configuration.DatabaseName);
            this.collection = database.GetCollection<Order>(configuration.CollectionName);
            this.logger = logger;
        }
    }
```

As you can see the `Repository` creates the connection with the `MongoDB` by using the configuration options we define previously, it also accepts a logger we are gonna use in our methods. Next, we are gonna create the methods we will use for getting and creating `Orders`.

```csharp
        public async Task<Order> GetOrder(Guid orderId) => await collection.Find(x => x.Id == orderId).FirstOrDefaultAsync();

        public async Task<IEnumerable<Order>> GetAll() => await collection.Find(_ => true).ToListAsync();

        public async Task<Order> CreateOrder(Order order)
        {
            try
            {
                await collection.InsertOneAsync(order);

                return order;
            }
            catch (Exception ex)
            {
                logger.LogError(ex.Message, ex);
                return null;
            }
        }
```

The 3 methods are very simple, we get a single order by id, we get all orders and we create a new order (with the proper logging if the creation fails). After adding these methods we create an interface of this repository so we can start using the [Dependency Injection](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1) that comes with **.NET Core**.

```csharp
   public interface IOrdersRespository
    {
        Task<Order> GetOrder(Guid orderId);
        Task<IEnumerable<Order>> GetAll();
        Task<Order> CreateOrder(Order order);
    }
```

## Connecting the pieces

Let's go back to our `Controller` and let's make the proper calls to our `Repository`.

```csharp
    [ApiController]
    [Route("v1/[controller]")]
    public class OrdersController : ControllerBase
    {
        private readonly IOrdersRepository ordersRepository;

        public OrdersController(IOrdersRepository ordersRepository)
        {
            this.ordersRepository = ordersRepository;
        }

        /// <summary>
        /// Retrieves all orders
        /// </summary>
        /// <returns>a list with all the orders available</returns>
        [HttpGet]
        public async Task<IEnumerable<Order>> GetAll()
        {
            return await ordersRepository.GetAll();
        }

        /// <summary>
        /// Retrieves the order that matches the id supplied
        /// </summary>
        /// <returns>one order model</returns>
        [HttpGet("{orderId}")]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status404NotFound)]
        public async Task<ActionResult<Order>> Get(Guid orderId)
        {
            var result = await ordersRepository.GetOrder(orderId);

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

            return Ok(result);
        }

        /// <summary>
        /// Creates a new order
        /// </summary>
        /// <returns>the newly created order</returns>
        [HttpPost]
        [ProducesResponseType(StatusCodes.Status201Created)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<ActionResult<Order>> Post([FromBody]OrderCreateUpdate orderRequest)
        {
            var order = new Order()
            {
                Amount = orderRequest.Amount,
                UserId = orderRequest.UserId
            };

            var result = await ordersRepository.CreateOrder(order);

            if (result == null) return BadRequest();

            return StatusCode(201, result);
        }
    }
```

We add the dependency of the `IOrdersRepository` in the constructor and we use it from the endpoints. We also handle different responses depending on the result of `Repository` and we explicitly define the possible responses using `ProducesResponseType`.

## Today's result?

`POST`

![POST](https://dev-to-uploads.s3.amazonaws.com/i/4idtrl7pjox48hhr8s4p.png)

`GET`

![GET](https://dev-to-uploads.s3.amazonaws.com/i/puhluqh6303n6elif4pj.png)

`GET ALL`

![GET ALL](https://dev-to-uploads.s3.amazonaws.com/i/zvr7b6z43jap340sbtx7.png)

If you have some experience building modern API's you are probably in shock. Is this guy really gonna use the same model for the API and database? is he gonna call the repository from the controller? why is everything in the same project?

Don't worry, we will handle everything before this series end, I promise you it is gonna something worth putting in your Github :smile:

----

That was a lot, I know, I also didn't go into detail of all the application patterns used since it would have been impossible, but on every pattern used there is a link to the official guide on how to implement it in **ASP.NET Core**, Microsoft tutorials are super good and they will give you the details missing.

I hope you liked this first part, in the next one we will add the `Update`, `Delete`, and the combined information endpoint and if there is time we will also start separating concerns better and polish our service.

As always, if you liked or not please let me know in the comments, and share it :smile: