Build VSTS et migration EntityFramework Core

Les migrations EF Core c’est bien… dans Visual Studio

Les migrations Entity Framework rendent assez simple le versionning des bases de données applicatives et permettent de garantir l’alignement d’une modèle de données avec une version de l’application qui l’exploite.
La mise à jour de la base de données se fait alors en appelant le snippet powershell update-database depuis le package manager de Visual Studio dès lors que les outils EF Core sont installés dans celui-ci.
Là où le problème arrive, c’est lorsqu’on souhaite utiliser ce mécanisme dans le cadre d’un déploiement continu, particulièrement sur VSTS avec un hosted agent 2017.

En effet, tant que les migrations EntityFrameworkCore ne font l’objet d’aucune tâche dédiée dans VSTS, nous ne disposons pas d’outillage pour exécuter ces update-database.
Une option est de forcer la mise à jour de la base lors du démarrage de l’application (dans le statup.cs). Cette solution n’est pas satisfaisante si on souhaite que le mécanisme de Release nous prévienne d’un éventuel soucis de migration puisque ce serait la première requête http qui déclencherait la mise à jour de la base (alors que la Release serait déjà validée sans condition).
Voici un petit bricolage pour les faire fonctionner sur un Hosted agent 2017 :

Mettre à disposition de l’agent de build les outils EF core

Considérons que nous disposons déjà d’une migration dans un projet de model MyService.Models et d’un projet Web MyService.Web qui contient la chaîne de connexion dans ses appsettings.

En observant le fonctionnement de VS lors d’un Update-database (en activant le verbose avec l’option -v), on constate que la formule magique à exécuter s’appuie en fait sur EF.dll.
Cette assembly descend avec le package nugget microsoft.entityframeworkcore.tools
Pour appliquer les mises à jour de base de données, le contenu des packages microsoft.entityframeworkcore.design et microsoft.entityframeworkcore est également nécessaire.
Ce qui tout mis bout à bout produit une commande du type :

dotnet.exe exec
--depsfile C:\Source\Workspaces\MyApp\MyService\Main\MyService.Web\bin\Debug\netcoreapp2.0\MyService.Web.deps.json
--additionalprobingpath C:\.nuget\packages
--runtimeconfig C:\Source\Workspaces\MyApp\MyService\Main\MyService.Web\bin\Debug\netcoreapp2.0\MyService.Web.runtimeconfig.json
"C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.entityframeworkcore.tools\2.0.1\tools\netcoreapp2.0\ef.dll" database update
--context MediaContext
--verbose
--no-color
--prefix-output
--assembly C:\Source\Workspaces\MyApp\MyService\Main\MyService.Web\bin\Debug\netcoreapp2.0\MyService.Models.dll
--startup-assembly C:\Source\Workspaces\MyApp\MyService\Main\MyService.Web\bin\Debug\netcoreapp2.0\MyService.Web.dll
--project-dir C:\Source\Workspaces\MyApp\MyService\Main\MyService.Models\
--root-namespace MyService.Models

Notons que pour réaliser cette tâche, Visual Studio s’appuie une dll EF.dll, sur différents fichiers résultat de la compilation et fournit des configurations nécessaires.

Nous y reviendrons plus tard, dans l’immédiat, il faut mettre à disposition de l’agent de build Ef.dll et ses dépendances.
Le hosted agent ne partageant pas facilement ses packages nugget mutualisés (ce qui est le cas de ceux qui nous intéressent), le plus simple est de créer un dossier dans le projet MyService.Models intitulé EF-Build contenant ce dont nous avons besoin :

  • ef.dll (à trouver dans le dossier du package microsoft.entityframeworkcore.tools)
  • ef.runtimeconfig.json (package microsoft.entityframeworkcore.tools)
  • Microsoft.EntityFrameworkCore.Design.dll (package microsoft.entityframeworkcore.design)
  • Microsoft.EntityFrameworkCore.Design.xml (package microsoft.entityframeworkcore.design)
  • Microsoft.EntityFrameworkCore.dll (package microsoft.entityframeworkcore)
  • Microsoft.EntityFrameworkCore.xml (package microsoft.entityframeworkcore)

 

Archivons ça dans le contrôleur de source. Attention à bien archiver les dll qui par défaut sont exclues.

En aparté, si vous utilisez un agent de build privé, vous pouvez vous passer de cette étape et de la suivante et aller directement référencer les dll dans le repository de package de votre agent dans la section Mettre à jour la base de donnée lors de la release  de cet article.

Propager les outils EF Core pendant le build jusqu’à la Release

Les outils n’ont pas vocation à être utilisés pendant le build, mais lors de la release. Il faut cependant les ajouter aux artefacts du build.

Depuis VSTS, considérons un build sur le modèle de build pour Asp.net core et ajoutons une étape pour propager les outils jusqu’à la release :

Mettre à jour la base de donnée lors de la release

Trois étapes sont nécessaires lors de la release pour mettre à jour la base de données :

Extraire les outils Ef Core

Nous allons commencer par ajouter une tâche d’extraction des outils et accessoirement du résultat de la compilation lui-même puisqu’il contient les assemblies MyService.Model et MyService.Web :

Générer un script SQL et mise à jour de la base de données

L’étape clé, celle qui consiste à exécuter Ef.dll dans une configuration correcte, nous amène à reprendre ce qui se passe dans Visual Studio (retour au début de l’article si besoin). Il aurait été formidable de le faire en une seule tâche, mais n’ayant pas trouver de solution satisfaisante pour donner les droits à mon agent de Release de toucher le serveur SQL Azure dans une tâche ligne de commande, nous allons d’abord créer un script Update.sql idempotent avec une tâche d’exécution de ligne de commande :

NB : Un script IdemPotent (le -i en option ci-dessus) est un script SQL de mise à jour qui consulte la table __EFMigrationsHistory pour appliquer les modifications en tentant compte de la version de la base de données de destination.

Puis Exécuter le script en question au travers d’une tâche Execute Azure SQL Task (je passe ici sur la configuration de la base de donnée cible pour ne conserver que la configuration liée au script ):

Plus qu’à configurer l’exécution de la release et la base suivra (ou précédera suivant les goûts) 😉

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion /  Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion /  Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion /  Changer )

w

Connexion à %s