.NET Core est un framework open source permettant de créer des applications web avec le langage C#. Dans cet article je présente les étapes de la mise en place d’une API REST avec .NET Core.

Article initialement posté sur le blog SofteamOuest.

Quelques technos utilisées:

  • .NET Core 2.0 (ASP.NET MVC)
  • Docker / Kubernetes / Jenkins pipeline
  • Swashbuckle pour l’intégration Swagger
  • Moq pour les tests unitaires

L’application

Il s’agit d’une API REST de gestion d’une liste de widgets. Chaque widget a un nom et une URL. Le code source du projet est disponible sous Github.

L’API implémente un CRUD. Pour la mise en place, je me suis basé sur ce tutoriel disponible dans la documentation officielle de Microsoft.

Les ressources REST sont crées à l’aide de classes contrôleur, décorées avec l’attribut [Route]. Les verbes REST sont implémentés à l’aide des attributs [HttpGet], [HttpPut], etc.

[Route("api/[controller]")]
public class WidgetsController : Controller
...
[HttpGet]
public IEnumerable<Widget> GetAll()
...

source de cet exemple

Une base de données en mémoire est accédée à l’aide d’un database context EntityFramework.

L’application est “bootstrapée” dans Startup.cs, qui contient la configuration des classes, configure ASP.NET MVC et active l’injection de dépendances.

Environnement de développement

J’ai préféré utiliser la commande dotnet (dotnet new, dotnet add, etc.) fournie avec le SDK, pour initialiser le projet en ligne de commande. On peut également le faire via Visual Studio, mais je trouve qu’on comprend mieux ce qui se passe avec dotnet. Les tutoriels indiqués présentent les deux approches.

Pour l’environnement de développement, il est possible d’utiliser (en théorie) un simple éditeur ou (mieux) VSCode: on trouve pas mal d’aides et de plugins. A la longue, un IDE plus intégré se justifie plus facilement, pour les outils de refactoring et de génération de code automatique.

J’ai donc installé Visual Studio Community Edition (gratuit, sous conditions) Vous pouvez également essayer Rider de JetBrains, si vous arrivez à négocier une licence 🤑.

Activation de CORS

Pour utiliser l’API avec une autre application, j’ai eu besoin d’activer CORS et Access-Control-Allow-Origin. Ca se met en place en quelques lignes avec .NET MVC, je me suis basé sur ce tutoriel.

Activation de Swagger

Pour simplifier l’utilisation de l’API lors du développement, j’ai ajouté Swagger et son interface graphique SwaggerUI.

L’explication pour la mise en place de Swagger dans ce tutoriel. En l’occurence j’ai utilisé la librairie Swashbuckle comme décrit ici.

Là aussi c’est assez rapide. Par contre j’ai rencontré un souci pour servir Swagger dans un sous-répertoire de mon domaine, par exemple sous exemple.com/back/swagger.json. Je n’ai pu configurer Swashbuckle que directement à la racine exemple.com/swagger.json. Il faudrait creuser 🤔.

Dockerisation

L’idée est de conteneuriser l’application avec Docker pour la déployer dans le cluster Kubernetes de l’usine logicielle de la communauté SofteamOuest.

La théorie

Il existe plusieurs images Docker officielles permettant de conteneuriser et d’exécuter une application .NET Core.

L’image dotnet:sdk permet de construire les binaires de l’application (.dll) à partir du code source. Elle est assez lourde (plus d’un gigaoctet) donc patience.

Il est généralement préférable d’utiliser l’image dotnet:runtime, plus légère, pour l’exécution.

Il est évidemment possible tout faire avec l’image dotnet:sdk, mais le conteneur généré pour l’application est alors très volumineux et ce n’est pas recommandé en production.

En pratique

La construction de l’image de l’application nécessite donc d’utiliser consécutivement deux images dans le Dockerfile : dotnet:sdk pour compiler le binaire puis dotnet:runtime pour l’image finale.

FROM microsoft/dotnet:sdk AS build-env
RUN dotnet publish -c Release -o out
...
FROM microsoft/aspnetcore:2.0
COPY --from=build-env /app/out .
...

C’est ce qui est d’ailleurs conseillé dans les tutoriels Docker et Microsoft

Malheureusement cette solution appelée multistage build nécessite une version de Docker assez récente, non possible sur notre plateforme (mars 2018). Nous allons donc utiliser les deux images mais séparément, grâce aux facilités proposées par le Jenkins pipeline, de la manière suivante:

Déploiement sur le cluster

L’image dotnet:sdk est donc utilisée localement sur la plateforme d’intégration pour construire les binaires dans le répertoire out de l’environnement de travail de Jenkins

...
containerTemplate(name: 'dotnet', image: 'microsoft/dotnet'),
...
container('dotnet') {
    sh 'dotnet publish -c Release -o out'
}
...

source de cet exemple

Le Dockerfile utilise alors uniquement l’image dotnet:runtime et récupère les binaires générés précédemment.

FROM microsoft/dotnet:runtime
...
COPY ./WallboardBack/out ./
...

source de cet exemple

Une fois l’image Docker créee, elle est publiée sur le Nexus. Le déploiement sur le clusteur peut alors être réalisé à l’aide d’un job de déploiement Kubernetes (comme expliqué ici et ici)

Conclusion

J’ai trouvé la création de cette API REST à l’aide de .NET Core assez rapide et efficace. J’ai notamment apprécié la facilité avec laquelle on peut ajouter des outils de sécurisation ou d’aide au développement, comme CORS ou Swagger, avec un minimum de code.

C’est l’avantage d’arriver après tout le monde 😄 : proposer un framework moderne avec des technos éprouvées, adaptable rapidement avec une configuration minimale.

Le framework est suffisament bien documenté, sauf lorsqu’on veut faire des choses un peu plus inhabituelles, et là il faut vraiment chercher…