Any web developer knows that new applications are increasingly oriented towards API. As seen with the examples of RESTful and GraphQL, modern patterns use a back-end API to provide data and feature a front-end application (using, among others, React or Angular). All trendy technology aims to improve and ease developers’ lives by making it as straight forward as possible to create a Web API, and .NET Core is not an exception, as you will see in this article, the third from the series .NET Core is Sexy (and you should know it).

This article is part of a series about .NET Core and how it is now as easy and efficient as any other stack like Node or Rails to create modern applications. .NET Core is sexy and you should know it .NET Core is sexy — Command Line Application .NET Core is sexy — Building a Web API

In the previous part, we created a multi-platform console line application to handle our curation, by adding topics, listing them and removing a completed topic. We have put in place a nice and simple architecture, using some separation between the database access — via Entity Framework with Sqlite — and the application itself. We also took the time to create a simple but useful abstraction for the database, allowing us to easily write tests and comply to some Clean Code patterns.

TL;DR

If you want to see the final implementation, here is the repository for the completed Web API : https://gitlab.com/jbuisson/curator/tree/webapi

Let’s start from the beginning



cd curator

dotnet build git clone --branch console git@gitlab.com :jbuisson/curator.gitcd curatordotnet build

Using these commands, we can continue our development exactly from where we stopped in the last part. First, we clone the Gitlab repository, using the git branch named console. Then, we build the whole project based on the solution file (.sln) at the root of the project.

This is what you should have in terms of folders tree:

├── data

├── src

├── Curator.Console

└── Curator.Data

├── Curator.Data.Entities

└── Curator.Data.EntityFramework

├── Curator.Data.EntityFramework.Context

├── Curator.Data.EntityFramework.Memory

└── Curator.Data.EntityFramework.Sqlite

└── tests

├── Curator.Console.Tests

├── Curator.Data.Entities.Tests

└── Xunit.AssertExtensions

We will now add a new project, Curator.Api, in which we will create our Web API.

Minimum Viable Api

Here, we will concentrate on manually developing the strict minimum to have a working Web API, doing the exact same thing as our command line application.

In the first article in this series, we saw how to self-host a web server and handle http requests. We will now do the same thing but using ASP.NET Core MVC to manage routing, controllers and all the stuff we do not want to do by ourselves.

dotnet new console -o src/Curator.Api

cd src/Curator.Api

dotnet add package Microsoft.AspNetCore

dotnet add package Microsoft.AspNetCore.Mvc

Go to the Program.cs file and setup our web hosting:

From within our newly created Curator.Api project, run the application using the command dotnet run. This command should start the server and listen for any requests, by default, on http://localhost:5000. However, we have not configured any controllers, so all requests will throw a 404 not found error. Below is an example of using cURL in a new terminal:



> HTTP/1.1 404 Not Found

> Date: Sun, 08 Sep 2019 12:01:57 GMT

> Server: Kestrel

> Content-Length: 0 curl -i http://localhost:5000 > HTTP/1.1 404 Not Found> Date: Sun, 08 Sep 2019 12:01:57 GMT> Server: Kestrel> Content-Length: 0

Let’s now add a first controller to handle curation items. This controller will use our CuratorContext to interact with the Sqlite database’s Items, so we need to start by adding references to our already existing projects.

dotnet add reference ../Curator.Data/Curator.Data.Entities dotnet add reference ../Curator.Data/Curator.Data.EntityFramework/Curator.Data.EntityFramework.Context dotnet add reference ../Curator.Data/Curator.Data.EntityFramework/Curator.Data.EntityFramework.Sqlite

Next, here is the code with the controller itself, in the Program.cs file:

The important lines of code here are the class and method’s attributes, defining the URL and the request parameters we need.

[Route(“items”)] declares the controller’s endpoint. All action methods in this controller will inherit from this URL, as it is on the whole controller class.

[HttpGet] declares the following method to be only available for GET HTTP request. There is no routing path defined, so it will be at the root path of the controller: /items.

[HttpPost] does the same thing as [HttpGet], but for POST HTTP requests.

[FromBody] allows us to add a string parameter to the Post() method, which will be parsed from the request body. ASP.NET Core will handle the format for us depending on the request Content-Type.

[HttpDelete(“{id:int}”)] declares the following method to be only available for DELETE HTTP requests, and it adds a named parameter to the path that must be an integer and will be available by its name in the Delete() method.

Example path: /items/42.

Finally, we need to add some configuration for the Sqlite data-source, using an appsettings.json file, exactly like we did for the command line application. Simply copy the file from Curator.Console into Curator.Api.

Start the server again using the command dotnet run and in another terminal, use cURL to play with the API on the items endpoint:



> HTTP/1.1 200 OK

> Date: Sun, 08 Sep 2019 12:09:48 GMT

> Content-Type: application/json; charset=utf-8

> Server: Kestrel

> Transfer-Encoding: chunked curl -i http://localhost:5000/items > HTTP/1.1 200 OK> Date: Sun, 08 Sep 2019 12:09:48 GMT> Content-Type: application/json; charset=utf-8> Server: Kestrel> Transfer-Encoding: chunked > []

If you have not emptied your database used by the console application, you should see items displayed in JSON instead of an empty array in the example. Add a new item to the curation database like this:

Do not forget to specify the Content-Type HTTP header so that ASP.NET Core knows how to parse the body’s data. Now you can fetch the created item. I’m using jq to prettify the JSON output, but it’s completely optional:

If you do not want to use cURL, you can use tools like Postman to execute requests on the API.

Using Postman to fecth items

Congratulations! We have built a working web API with only a few lines of very simple code!

Here, I have voluntarily written all code by hand, and I did not use any helpers. I wanted to show you, without any magic, how to create a Web API in .NET Core. However, there is a better and easier way to do this.

Easy API setup

In the same way that we have created our first application, we can use the dotnet command line interface (CLI) to scaffold for us a nice Web API. This may break your heart, but delete all the code we just wrote. Delete the Curator.Api folder, and replace it with a new api project from scratch.

dotnet new webapi -o Curator.Api

This new project already has some new files:

Program.cs is, as always, our application entry point, and creates a new self-hosting web server, using the Startup class.

Startup.cs is a new file. This is where we setup and configure our api within the Startup class. Most of the code is explicit here, and default comments with documentation link should be enough if you have any interrogation.

appsettings.**.json are configuration files. You have a default configuration and an override one for the Development runtime’s environment. Environments are declared in the next file.

Properties/launchSettings.json contains launch configuration. It is where you find the configured environment and startup properties of the application. Part of the settings is used for Visual Studio (not VS Code) and could be simply ignored (like the ISS Express profile).

Controllers/ValuesController.cs is a sample controller with fixed values to show how to create your own. You will spot several differences with the controller we have created:

You should now be able to create your own ItemsController based on the one we created previously and the ValuesController the CLI created for us.

Now we have two applications, the first being our command line application and the second being our newly created Web API. So, the issue that we are facing is that we have duplicated the logic, both in Curator.Console/Commands and in Curator.Api/Controllers. Code duplication is not only bad (to maintain, debug, etc…), but it can be dangerous for your application. So, you should already have guessed, now is the…

Time to refactor

What we need to do is to create a single service that will handle the curation logic regarding fetching, adding and removing items. This service should be used by the two applications we have developed. We will also be able to write tests for this service, avoiding to duplicate unit tests as well.

First, we will create another separated project alongside Curator.Api and Curator.Console, which will be called Curator.Core.

dotnet new classlib -o Curator.Core

In this project replace the generated class by our own service:

Do not forget to add the references:

dotnet add reference ../Curator.Data/Curator.Data.Entities dotnet add reference ../Curator.Data/Curator.Data.EntityFramework/Curator.Data.EntityFramework.Context

I have also created a custom exception to handle not found items by the service.

Let’s take some time to consider all the classes that we have created and their relation to one another.

CuratorContext is the EntityFramework context, defining our data repository.

is the context, defining our data repository. DesignTimeDbContextFactory are the CuratorContext providers, configuring it for both InMemory dans Sqlite databases.

are the providers, configuring it for both dans databases. ItemsService is the service using the CuratorContext to interact with the database without knowing which kind of provider we are using.

is the service using the to interact with the database without knowing which kind of provider we are using. ItemsController is the ASP.NET Core controller and should use the ItemsService to expose this service’s method on a Web API.

is the ASP.NET Core controller and should use the to expose this service’s method on a Web API. CuratorCommand is the command’s definition for our existing console application. It should also use the ItemsService like we should for ItemsController.

To properly configure all of this, we will use the Dependency Injection mechanism already in place in .NET Core.

Let’s update our already existing Console application, using CommandLineUtils (by Nate McMaster) with the Dependency Injection:

In this application, we are using the ItemsService with a Sqlite CuratorContext implementation. It is now up to you to update the Commands using the ItemsService instead of the CuratorContext.

We can now do the same thing in our Curator.Api project, using the Startup class to configure the application. Simply add the following lines of code in the ConfigureServices(…) method:

services.AddScoped<CuratorContext>(provider => new DesignTimeDbContextFactory(m_configuration).CreateDbContext(null)); services.AddTransient<ItemsService>();

Our final implementation for the ItemsController should now look like this:

The only thing left to do before considering our application “Production Ready” is to have a proper database that multiple servers hosting our application (for example, behind a load balancer) could access at the same time. Also, Sqlite strives to provide local data storage for individual applications or devices and does not compete with client/server databases, so we are going to use MySql instead.

Adding a new database provider

We already have two database providers, one using Sqlite and another using InMemory for testing purposes. It should then be easy to create a new one, but by using MySql.Data.EntityFrameworkCore instead of Microsoft.EntityFrameworkCore.Sqlite.

To do this, start with the same usual first step — create a new project. It is still verbose but you should know by now that I prefer explicit naming conventions:

dotnet new classlib -o src/Curator.Data/Curator.Data.EntityFramework/Curator.Data.EntityFramework.Mysql

Next, in the newly created project, we need to add references and packages for both Configurations and EntityFramework to finally create the DesignTimeDbContextFactory implementation:

cd src/Curator.Data/Curator.Data.EntityFramework/Curator.Data.EntityFramework.Mysql dotnet add package Microsoft.Extensions.Configuration

dotnet add package Microsoft.Extensions.Configuration.Json

dotnet add package MySql.Data.EntityFrameworkCore

Do not forget to add an appsettings.json file in which you should put the ConnectionString to the Mysql server you’re using. We will need it in both the newly created Mysql project and the Web API project.

In the previous article from this series, I encouraged you to create clean separation between the Entities, the Context implementation, and the Sqlite provider. You should now understand the benefit of this separation, having a third provider (do not forget the InMemory for tests). It is even better now that we have a dedicated and separated service, ItemsService, in the Curator.Core project. We have configured the Console application to use the Sqlite provider and the Web Api application to use the Mysql one, without changing anything with the ItemsService logic!

These are the main true benefits of using code abstraction and code segregation on our implementations.

We now need a Mysql server for our local environment, and for that we will use Docker. If you are not familiar with Docker, I really encourage you to read a tutorial or follow the get started information.

If your prefer, you can of course use a standard Mysql installation on your local computer, or even an instance on AWS RDS accessible publicly if you want to.

If you have not already installed Docker, here are the links for the install on Mac, Ubuntu, and Windows. Once done, you should have access to the docker-compose tool that we will use to create our Mysql container.

Create a file named docker-compose.yml at the root of the project, containing the following YML code:

You should be able to start the container as follows:

docker-compose up -d

If you have followed along, you just need to update the Web API application to use Mysql instead of Sqlite, for that you can simply update the Curator.Api.csproj file and replace Sqlite with Mysql in the ProjectReference block, do not forget the ConnectionString in the appsettings.json file.

And, that’s it for now! We have already achieved a lot here. We have upgraded our console application as a Web API, and we have done some refactoring to clean it up and use the dependency injection mechanism to exploit all the benefits of the architecture that we have implemented. We have even set up a new database with a working local environment using Docker.

In the next article I will show you how you can package and deploy the API, with some Continuous Integration and Continuous Delivery.