Packager un composant Windows Store Apps avec nuget. 1ère partie.

Aujourd’hui nous allons voir comment créer et surtout comment déployer des composants via nuget. Ces composants seront tous compatibles avec les applications Windows Store Apps. Nous allons parler de composants PCL, de composants WinMD et de composants natifs.

2eme partie : Packager un composant Windows Store apps : 2eme partie

Nous verrons notamment le déploiement de :

  1. Un composant simple créé avec un projet Portable Class Library (PCL)
  2. Un composant (PCL) nécessitant un autre composant nuget en tant que dépendance.
  3. Un composant WinRT (*.winmd)
  4. Un composant WinRT nécessitant un composant C++ compilé avec x86 / x64 et ARM et ne supportant pas le mode AnyCPU.

Introduction : Nuget et configuration de travail local

Lors de vos tests, je vous conseille d’utiliser un répertoire (ou repository) local que nuget utilisera comme source. Cela pour éviter d’avoir à déployer vos composants en mode test sur la plateforme nuget.

Pour ce faire, créer un répertoire et configurer nuget dans Visual Studio, comme indiqué dans la copie d’écran suivante :

image

Ce répertoire va contenir l’ensemble des packages au format .nupkg :

image

Une fois paramétré, lors de nos tests, via la console nuget (qui est une console powershell) nous pourrons spécifier la source et aller cherchez nos packages à partir de là :

image

Dans un premier temps, Il s’agit de comprendre les bases d’un déploiement avec nuget.

Pour découvrir les possibilités de la plateforme n’hésitez pas à aller jeter un coup d’œil sur le site officiel : https://www.nuget.org ainsi que la documentation : https://docs.nuget.org/

Pour créer notre .nupkg, il nous faut télécharger nuget et l’installer sur notre machine.
Une fois installé, vous pouvez créer votre package via :

  1. Une ligne de commande (le plus simple étant de copier nuget.exe dans le répertoire de travail)
  2. Un outil graphique (nuget package explorer) : la documentation de l’outil ici : https://docs.nuget.org/docs/creating-packages/using-a-gui-to-build-packagesimage

 

Création d’un composant Simple

  Notre premier composant sera une librairie créée à partir d’un projet Portable Class Library

image

Le code renvoie une simple chaine de caractère :

 namespace PclSimple
{
    public class GameHelper
    {
        public string GetUrl()
        {
            return "https://babylonjs.azure-mobile.net/api/";
        }
    }
}

Lors de la compilation de votre projet, préférez le mode Release. Le déploiement de composant en mode Debug peut faire échouer une validation sur le store.

Par soucis de simplicité, j’ai copié l’exécutable nuget.exe directement dans le répertoire de sortie, de façon à créer le package plus facilement.

Voici une copie d’écran de mon répertoire bin\Release :

image

Fichier de configuration .nuspec

Pour créer notre .nupkg, nous allons passer par l’instruction en ligne de commande (se référer à la documentation pour plus d’informations : https://docs.nuget.org/docs/creating-packages/creating-and-publishing-a-package) qui va créer un fichier xml de configuration.

Nous verrons ensuite comment enrichir ce fichier xml.

 nuget spec PclSimple.dll

image

Résultat du fichier généré PclSimple.dll.nuspec :

 <?xml version="1.0"?>
<package >
  <metadata>
    <id>PclSimple.dll</id>
    <version>1.0.0</version>
    <authors>spertus</authors>
    <owners>spertus</owners>
    <licenseUrl>https://LICENSE_URL_HERE_OR_DELETE_THIS_LINE</licenseUrl>
    <projectUrl>https://PROJECT_URL_HERE_OR_DELETE_THIS_LINE</projectUrl>
    <iconUrl>https://ICON_URL_HERE_OR_DELETE_THIS_LINE</iconUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>Package description</description>
    <releaseNotes>Summary of changes made in this release of the package.</releaseNotes>
    <copyright>Copyright 2013</copyright>
    <tags>Tag1 Tag2</tags>
    <dependencies>
      <dependency id="SampleDependency" version="1.0" />
    </dependencies>
  </metadata>
</package>

Résultat du fichier modifié PclSimple.dll.nuspec :

 <?xml version="1.0"?>
<package >
  <metadata>
    <id>PclSimple.dll</id>
    <version>1.0.0</version>
    <authors>Sébastien Pertus</authors>
    <owners>Sébastien Pertus</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>My very first component</description>
    <releaseNotes>First component to test deploying with nuget</releaseNotes>
    <copyright>Copyright 2013</copyright>
  </metadata>
</package>

Création du package .nupkg

Pour créer votre package nuget, vous devez déplacer vos assemblys dans des répertoires nomenclaturés.

  1. Répertoire lib : Contient les assemblys qui seront ajoutées en tant que référence.
  2. Répertoire content : Contient des fichiers qui seront déployés dans le répertoire de sortie de votre application.
  3. Répertoire tools : Contient des fichiers powershell de déploiement spécifique.
  4. Répertoire build : Contient des fichiers .props et .targets qui permettront d’enrichir votre fichier .csproj

Suivant la documentation nuget, l’arborescence de mon répertoire de sortie devient :

Root

---\Lib

---------\netcore45

  Voici mon répertoire de sortie après modification :

image

Le contenu du répertoire lib\netcore45 :

image

Il ne reste plus qu’à exécuter la ligne de commande nuget :

 nuget pack PclSimple.dll.nuspec

image

Le résultat est un nouveau fichier généré et nomenclaturé avec la version : PclSimple.dll.1.0.0.nupkg

image

Note : Vous pouvez aussi utiliser l’outil graphique pour créer votre fichier de configuration ainsi que le package lui même.

Dans la copie d’écran suivante, j’ai ouvert directement le fichier .nuspec et j’ai créé le fichier .nupkg depuis l’outil (Save As):

image

image

Note : Le fichier .nupkg n’est autre qu’un fichier compressé '(zip) qui contient l’ensemble des informations nécessaires à son déploiement. Il suffit de le renommer en .zip et d’ouvrir le package pour voir son contenu :

image

Déploiement depuis le répertoire local

Pour tester, il suffit de copier / coller ce fichier dans le répository local configuré au début de cet article.

image

Evidemment cette étape peut être ignoré si vous utilisez l’option -OutputDirectory de l’outil en ligne de commande nuget.exe.

Notre projet de test est une simple application Windows Store Apps. L’ajout de la référence nuget se fait via le Nuget Package Manager Console:

image

Your project is ready !

image

Création d’un package composant ayant une dépendance

Nous allons faire évoluer notre composant en ajoutant une fonctionnalité qui requiert l’envoi d’une requête HTTP. Pour cela nous pouvons utiliser la classe Portable Library HttpClient, qui est déjà packagé dans nuget sous le nom Microsoft Http Client libraries.

Nous ajoutons la librairie via la commande nuget. Notre nouveau projet ressemble à ça :

image

Le code de notre composant est relativement simple :

     public class GamingHelper
    {

        public async Task<String> GetGame()
        {
            try
            {
                HttpClient client = new HttpClient();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                var uri = "https://babylonjs.azure-mobile.net/api/GetGameByName/Omega Crusher.json";

                HttpRequestMessage hrm = new HttpRequestMessage(HttpMethod.Get, uri);

                hrm.Headers.Add("X-ZUMO-APPLICATION", "dHfEVuqRtCczLCvSdtmAdfVlrWpgfU55");
                var gameString = await client.SendAsync(hrm);
                
                return await gameString.Content.ReadAsStringAsync();
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
           

        }
        
    }

(Pour info, il s’agit d’un appel vers Mobile Services, sans l’utilisation du SDK :) )

Voici le contenu du répertoire Release :

image

Cette fois ci, j’utilise l’outil graphique pour préparer mon package:

image

L’ajout de dépendances, se fait par une boite de dialogue associée :

image

Vous venez de créer votre fichier .nuspec, que vous pouvez d’ailleurs regarder directement depuis l’outil:

image

Voici le fichier XML, avec l’ajout de la dépendance à Microsoft.NET.Http :

 <?xml version="1.0" encoding="utf-8"?>
<package xmlns="https://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
    <metadata>
        <id>PclMobS</id>
        <version>1.0.0</version>
        <authors>Sébastien Pertus</authors>
        <owners>Sébastien Pertus</owners>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <description>Simple component with a dependency</description>
        <dependencies>
            <dependency id="Microsoft.Net.Http" version="2.2.13" />
        </dependencies>
    </metadata>
</package>

Lors de l’ajout de notre package dans notre projet, la dépendance est automatiquement résolue :

image

Un peu d’intégration continue

Nous allons automatiser toutes les étapes de fabrication du .nupkg, pour avoir à chaque compilation en mode Release, un package prêt à déployer, sans avoir à retravailler le répertoire Release.

D’ailleurs, nous allons utiliser un nouveau répertoire de travail, spécialement dédié à Nuget, qui se trouvera à la racine de la solution.

Ce répertoire contiendra le fichier .nuspec, et le répertoire lib :

image

L’automatisation de la procédure de création du package .nupkg se fera à l’aide de taches MSBuild, que nous allons ajouter à notre projet. L’ajout de commandes MSBuild s’effectue directement dans votre fichier projet.

Vous devez le décharger pour pouvoir le modifier :

image

Nous allons utiliser plusieurs taches MSBuild dans le target AfterBuild:

Une tache de Copy, chargée de copier la (ou les) .dll vers le répertoire au niveau de la solution:

   <Target Name="AfterBuild">
    <Copy Condition="'$(Configuration)'=='Release'" 
          SourceFiles="$(TargetFileName)"  
          DestinationFolder="$(SolutionDir)Nuget\lib\" />
  </Target>

Une tache d’exécution en ligne de commande chargée de lancer le packaging nuget. Auparavant on aura pris soin de mettre le fichier .nuspec correctement dans le répertoire Nuget.

Attention à :

  1. Bien spécifier le chemin complet d’accès à Nuget.exe
  2. Bien positionner le répertoire de travail sur le répertoire de sortie

La tache MSBuild Exec à la suite de la tache Copy:

  <Target Name="AfterBuild">
 
    <Copy Condition="'$(Configuration)'=='Release'" 
          SourceFiles="$(TargetPath)" ContinueOnError="true" 
          DestinationFolder="$(SolutionDir)Nuget\lib\" />

    <Exec 
      WorkingDirectory="$(SolutionDir)Nuget\" 
      Command="%22C:\Program Files (x86)\NuGet\NuGet.exe%22 pack PclMobS.nuspec" />
    
  </Target>

A la compilation, dans la fenêtre Output vous devriez avoir :

image

Dans la prohaine partie, nous aborderons:

  1. La problématique des composants WinRT (notamment les fichiers winmd)
  2. La problématique des composants natifs non compilables en mode AnyCPU

 
Bon déploiement !

Seb