Février 2016

Volume 31, numéro 2

Cet article a fait l'objet d'une traduction automatique.

Essential .NET - Configuration dans .NET Core

Par Mark Michaelis

Juste avant l'heure de publication, Microsoft a annoncé des changements de nom ASP.NET 5 et piles connexes. ASP.NET 5 est désormais ASP.NET Core 1.0. Entity Framework (EF) 7 est désormais cœur d'Entity Framework (EF) 1.0. Les packages de ASP.NET 5 et EF7 et les espaces de noms ne change pas, mais sinon la nouvelle nomenclature n'a aucun impact sur les enseignements tirés de cet article.

Mark MichaelisCeux d'entre vous qui travaillent avec ASP.NET 5 ont sans doute remarqué la nouvelle configuration prennent en charge dans cette plateforme et disponibles dans la collection Microsoft.Extensions.Configuration de packages NuGet. La nouvelle configuration permet à une liste de paires nom-valeur, qui peuvent être regroupés dans une hiérarchie à plusieurs niveaux. Par exemple, vous pouvez avoir un paramètre stocké dans SampleApp:Users:InigoMontoya:MaximizeMainWindow et un autre stocké dans SampleApp:AllUsers:Default:MaximizeMainWindow. N'importe quelle valeur stockée mappe à une chaîne, et une prise en charge de liaison intégrée qui vous permet de désérialiser les paramètres dans un objet POCO personnalisé. Vous vous êtes déjà familiarisé avec la nouvelle API de configuration probablement tout d'abord le rencontré dans ASP.NET 5. Toutefois, l'API est en aucune façon limité à ASP.NET. En fait, tous les exemples dans cet article ont été créés dans un projet de test unitaire 2015 Visual Studio avec Microsoft .NET Framework 4.5.1, référençant Microsoft.Extensions.Configuration packages à partir de ASP.NET 5 RC1. (Accédez à gitHub.com/IntelliTect/Articles pour le code source.)

L'API de configuration prend en charge les fournisseurs de configuration pour les objets .NET en mémoire, INI fichiers, JSON fichiers, XML fichiers, des arguments de ligne de commande, les variables d'environnement, un magasin d'utilisateur chiffré et n'importe quel fournisseur personnalisé que vous créez. Si vous souhaitez tirer parti des fichiers JSON pour votre configuration, ajoutez simplement le package NuGet de Microsoft.Extensions.Configuration.Json. Ensuite, si vous souhaitez autoriser la ligne de commande fournir des informations de configuration, ajoutez simplement le package NuGet de Microsoft.Extensions.Configuration.CommandLine, en plus ou au lieu d'autres références de configuration. Si aucun des fournisseurs de configuration par défaut sont satisfaisants, vous pouvez créer vos propres en implémentant les interfaces que qui se trouvent dans Microsoft.Extensions.Configuration.Abstractions.

Récupération des paramètres de Configuration

Pour vous familiariser avec la récupération des paramètres de configuration, examinez Figure 1.

Figure 1 principes de base de Configuration à l'aide de méthodes d'Extension de ConfigurationBinder les InMemoryConfigurationProvider

public class Program
{
  static public string DefaultConnectionString { get; } =
    @"Server=(localdb)\\mssqllocaldb;Database=SampleData-0B3B0919-C8B3-481C-9833-
    36C21776A565;Trusted_Connection=True;MultipleActiveResultSets=true";
  static IReadOnlyDictionary<string, string> DefaultConfigurationStrings{get;} =
    new Dictionary<string, string>()
    {
      ["Profile:UserName"] = Environment.UserName,
      [$"AppConfiguration:ConnectionString"] = DefaultConnectionString,
      [$"AppConfiguration:MainWindow:Height"] = "400",
      [$"AppConfiguration:MainWindow:Width"] = "600",
      [$"AppConfiguration:MainWindow:Top"] = "0",
      [$"AppConfiguration:MainWindow:Left"] = "0",
    };
  static public IConfiguration Configuration { get; set; }
  public static void Main(string[] args = null)
  {
    ConfigurationBuilder configurationBuilder =
      new ConfigurationBuilder();
      // Add defaultConfigurationStrings
      configurationBuilder.AddInMemoryCollection(
        DefaultConfigurationStrings);
      Configuration = configurationBuilder.Build();
      Console.WriteLine($"Hello {Configuration["Profile:UserName"]}");
      ConsoleWindow consoleWindow =
        Configuration.Get<ConsoleWindow>("AppConfiguration:MainWindow");
      ConsoleWindow.SetConsoleWindow(consoleWindow);
  }
}

L'accès à la configuration facilement commence avec une instance de la ConfigurationBuilder, une classe disponible à partir du package NuGet de Microsoft.Extensions.Configuration. Étant donné l'instance ConfigurationBuilder, vous pouvez ajouter des fournisseurs directement à l'aide de méthodes d'extension IConfigurationBuilder comme AddInMemoryCollection, comme indiqué dans Figure 1. Cette méthode prend une instance de Dictionary < string, string > de la configuration de paires nom-valeur, qu'il utilise pour initialiser le fournisseur de configuration avant de l'ajouter à l'instance de ConifigurationBuilder. Une fois que le Générateur de configuration est « configuré », vous appelez sa méthode Build pour récupérer la configuration.

Comme mentionné précédemment, une configuration est simplement une liste hiérarchique des paires nom-valeur dans lequel les nœuds sont séparés par un signe deux-points. Par conséquent, pour récupérer une valeur particulière, vous suffit d'accéder à l'indexeur de la Configuration avec la clé de l'élément correspondant :

Console.WriteLine($"Hello {Configuration["Profile:UserName"]}");

Toutefois, l'accès à une valeur n'est pas limité à récupérer uniquement des chaînes. Vous pouvez, par exemple, extraire des valeurs via des méthodes d'extension de la ConfigurationBinder Get < T >. Par exemple, pour récupérer la taille de mémoire tampon d'écran fenêtre principale vous pouvez utiliser :

Configuration.Get<int>("AppConfiguration:MainWindow:ScreenBufferSize", 80);

Cette prise en charge de la liaison requiert une référence au package NuGet de Microsoft.Extensions.Configuration.Binder.

Notez qu'il existe un argument facultatif suivant la clé pour laquelle vous pouvez spécifier une valeur par défaut à retourner lors de la clé n'existe pas. (Sans la valeur par défaut, la valeur de retour sera attribué default (t), plutôt que lever une exception, comme vous pouvez l'imaginer.)

Valeurs de configuration ne sont pas limités à valeurs scalaires. Vous pouvez récupérer des objets POCO ou des graphiques d'objets complets. Pour récupérer une instance de ConsoleWindow dont les membres mappent à la section de configuration AppConfiguration:MainWindow, Figure 1 utilise :

ConsoleWindow consoleWindow =
  Configuration.Get<ConsoleWindow>("AppConfiguration:MainWindow")

Sinon, vous pouvez définir un graphique de configuration telles que AppConfiguration, illustré Figure 2.

Figure 2 exemple Configuration objet graphique

class AppConfiguration
{
  public ProfileConfiguration Profile { get; set; }
   public string ConnectionString { get; set; }
  public WindowConfiguration MainWindow { get; set; }
  public class WindowConfiguration
  {
    public int Height { get; set; }
    public int Width { get; set; }
    public int Left { get; set; }
    public int Top { get; set; }
  }
  public class ProfileConfiguration
  {
    public string UserName { get; set; }
  }
}
public static void Main()
{
  // ...
  AppConfiguration appConfiguration =
    Program.Configuration.Get<AppConfiguration>(
      nameof(AppConfiguration));
  // Requires referencing System.Diagnostics.TraceSource in Corefx
  System.Diagnostics.Trace.Assert(
    600 == appConfiguration.MainWindow.Width);
}

Avec cet un graphique d'objet, vous pouvez définir tout ou partie de votre configuration avec une hiérarchie d'objets fortement typés que vous pouvez ensuite utiliser pour récupérer vos paramètres en même temps.

Plusieurs fournisseurs de Configuration

Le InMemoryConfigurationProvider est efficace pour le stockage de valeurs par défaut ou des valeurs calculées éventuellement. Toutefois, avec uniquement ce fournisseur, vous vous retrouvez avec la charge de la récupération de la configuration et de son chargement dans un dictionnaire < string, string > avant l'inscription avec le ConfigurationBuilder. Heureusement, il existe plusieurs fournisseurs de configuration plus intégrées, notamment les trois fournisseurs basé sur fichier (XmlConfigurationProvider, IniConfigurationProvider et JsonConfigurationProvider) ; un fournisseur de variables d'environnement (EnvironmentVariableConfigurationProvider) ; un argument de ligne de commande fournisseur et (CommandLineConfigurationProvider). En outre, ces fournisseurs peuvent être mélangés et mis en correspondance en fonction de votre logique d'application. Par exemple, imaginez que vous pouvez spécifier des paramètres de configuration dans l'ordre de priorité croissant suivant :

  • InMemoryConfigurationProvider
  • JsonFileConfigurationProvider de Config.json
  • JsonFileConfigurationProvider pour Config.Production.json
  • EnvironmentVariableConfigurationProvider
  • CommandLineConfigurationProvider

En d'autres termes, les valeurs de configuration par défaut peuvent être stockés dans le code. Ensuite, le fichier config.json, suivi de la Config.Production.json peut remplacer le InMemory spécifié des valeurs — où ultérieure fournisseurs tels que ceux JSON sont prioritaires pour toutes les valeurs qui se chevauchent. Ensuite, lors du déploiement, vous pouvez avoir des valeurs de configuration personnalisées stockées dans des variables d'environnement. Par exemple, au lieu de coder Config.Production.json, vous pouvez récupérer le paramètre d'environnement à partir d'une variable d'environnement Windows et accéder au fichier spécifique (par exemple Config.Test.Json) qui identifie la variable d'environnement. (Excuser toute ambiguïté dans le paramètre d'environnement terme relatives à la production, de test, de pré-production ou de développement, par rapport aux variables d'environnement Windows comme % nom_utilisateur % ou % UserDomain%). Enfin, vous spécifiez (ou remplacer) les paramètres fournis précédemment via la ligne de commande, peut-être comme une modification unique pour, par exemple, activez la journalisation.

Pour spécifier chacun des fournisseurs, ajoutez-les au Générateur de configuration (via l'extension méthode AddX API fluent), comme indiqué dans Figure 3.

Figure 3 Ajout de plusieurs fournisseurs de Configuration, le dernier spécifié est prioritaire

public static void Main(string[] args = null)
{
  ConfigurationBuilder configurationBuilder =
    new ConfigurationBuilder();
  configurationBuilder
    .AddInMemoryCollection(DefaultConfigurationStrings)
    .AddJsonFile("Config.json",
      true) // Bool indicates file is optional
    // "EssentialDotNetConfiguartion" is an optional prefix for all
    // environment configuration keys, but once used,
    // only environment variables with that prefix will be found        
    .AddEnvironmentVariables("EssentialDotNetConfiguration")
    .AddCommandLine(
      args, GetSwitchMappings(DefaultConfigurationStrings));
  Console.WriteLine($"Hello {Configuration["Profile:UserName"]}");
  AppConfiguration appConfiguration =
    Configuration.Get<AppConfiguration>(nameof(AppConfiguration));
}
static public Dictionary<string,string> GetSwitchMappings(
  IReadOnlyDictionary<string, string> configurationStrings)
{
  return configurationStrings.Select(item =>
    new KeyValuePair<string, string>(
      "-" + item.Key.Substring(item.Key.LastIndexOf(':')+1),
      item.Key))
      .ToDictionary(
        item => item.Key, item=>item.Value);
}

Pour le JsonConfigurationProvider, vous pouvez soit demander le fichier existe ou facultative. Par conséquent, le paramètre facultatif supplémentaire sur AddJsonFile. Si aucun paramètre n'est fourni, le fichier est obligatoire et un System.IO.FileNotFoundException se déclenche si elle est introuvable. Étant donné la nature hiérarchique de JSON, la configuration s'adapte très bien dans l'API de configuration (voir Figure 4).

Données de Configuration de la figure 4 JSON pour le JsonConfigurationProvider

{
  "AppConfiguration": {
    "MainWindow": {
      "Height": "400",
      "Width": "600",
      "Top": "0",
      "Left": "0"
    },
    "ConnectionString":
      "Server=(localdb)\\\\mssqllocaldb;Database=Database-0B3B0919-C8B3-481C-9833-
      36C21776A565;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

Le CommandLineConfigurationProvider, vous devez spécifier les arguments lorsqu'il est enregistré avec le Générateur de configuration. Les arguments sont spécifiés par un tableau de paires nom-valeur, chaque paire du format de chaînes / < nom > = < valeur >, où le signe égal est nécessaire. La barre oblique de début est également requise, mais le deuxième paramètre de la AddCommandLine (string [] args, Dictionary < string, string > switchMappings), la fonction vous permet de fournir des alias doivent être préfixés avec l'un - ou--. Par exemple, un dictionnaire de valeurs permet à une ligne de commande « program.exe - LogFile = « c:\programdata\Application Data\Program.txt » pour charger dans l'élément de configuration AppConfiguration:LogFile :

["-DBConnectionString"]="AppConfiguration:ConnectionString",
  ["-LogFile"]="AppConfiguration:LogFile"

Avant la fin de désactiver les principes de base de configuration, voici quelques points supplémentaires à noter :

  • Le CommandLineConfigurationProvider présente plusieurs caractéristiques qui ne sont pas intuitifs d'IntelliSense dont vous devez être conscient :
    • Les switchMappings de la CommandLineConfigurationProvider autorise uniquement un préfixe de commutateur de - ou--. Même une barre oblique (/) n'est pas autorisée comme un paramètre booléen. Cela vous empêche de fournissant des alias pour les commutateurs de barre oblique via les mappages de commutateur.
    • CommandLineConfigurationProviders n'autorise pas d'arguments de ligne de commande basée sur le commutateur, les arguments qui n'incluent pas une valeur assignée. Spécification d'une clé de « / optimiser, », par exemple, n'est pas autorisée.
    • Alors que vous pouvez transmettre les arguments de Main vers une nouvelle instance de CommandLineConfigurationProvider, vous ne pouvez pas passer Environment.GetCommandLineArgs sans supprimer au préalable le nom du processus. (Notez que Environment.GetCommandLineArgs se comporte différemment lorsqu'un débogueur est attaché. En particulier, avec les espaces de noms des fichiers exécutables sont fractionnées dans des arguments individuels lorsqu'il n'existe aucun débogueur attaché. (Voir itl.ty\GetCommandLineGotchas).
    • Une exception est émise lorsque vous spécifiez un préfixe de commutateur de ligne de commande - ou--pour lequel il n'existe aucun mappage de commutateur correspondant.
  • Bien que les configurations peuvent être mises à jour (Configuration [« profil : nom_utilisateur »] = « Inigo Montoya »), la valeur mise à jour n'est pas rendu persistant dans le magasin d'origine. Par exemple, lorsque vous affectez un fournisseur JSON de valeur de configuration, le fichier JSON ne sont pas mis à jour. De même, une variable d'environnement ne seraient pas mis à jour lors de son élément de configuration est affecté.
  • La EnvironmentVariableConfigurationProvider permet éventuellement de spécifier un préfixe de la clé. Dans ce cas, il chargera uniquement les variables d'environnement avec le préfixe spécifié. De cette façon, vous pouvez automatiquement limiter les entrées de configuration à celles contenues dans une variable d'environnement « section » ou, plus généralement, ceux qui sont pertinentes pour votre application.
  • Variables d'environnement avec deux-points sont pris en charge. Par exemple, attribution AppConfiguration:ConnectionString définir = Console sur la ligne de commande est autorisée.
  • Toutes les clés de configuration (noms) respectent la casse.
  • Chaque fournisseur se trouve dans son propre package NuGet où le nom du package NuGet correspond au fournisseur : Microsoft.Extensions.Configuration.CommandLine, Microsoft.Extensions.Configuration.EnvironmentVariables, Microsoft.Extensions.Configuration.Ini, Microsoft.Extensions.Configuration.Json et Microsoft.Extensions.Configuration.Xml.

Présentation de la Structure orientée objet

La modularité et la structure orientée objet de l'API de configuration sont bien conçus, en fournissant des classes détectables, modulaires et facilement extensibles et les interfaces à utiliser (voir Figure 5).

Modèle de classe de fournisseur de configuration
Modèle de classe de fournisseur de Configuration figure 5

Chaque type de mécanisme de configuration a une classe de fournisseur de configuration correspondant qui implémente IConfigurationProvider. Dans la plupart des implémentations de fournisseur intégré, l'implémentation est motivation à l'origine par dérivation à partir de ConfigurationBuilder au lieu d'utiliser des implémentations personnalisées pour toutes les méthodes de l'interface. Peut-être étonnamment, il n'existe aucune référence directe à un des fournisseurs dans Figure 1. Cela tient au lieu d'instancier manuellement chaque fournisseur et l'enregistrement avec la méthode Add de la classe ConfigurationBuilder, package NuGet de chaque fournisseur inclut une classe d'extension statique avec les méthodes d'extension IConfigurationBuilder. (Le nom de la classe d'extension est généralement identifié par le suffixe ConfigurationExtensions.) Avec les classes d'extension, vous pouvez commencer à accéder aux données de configuration directement à partir de ConfigurationBuilder (qui implémente IConfigurationBuilder) et appeler directement la méthode d'extension associée à votre fournisseur. Par exemple, la classe JasonConfigurationExtensions ajoute les méthodes d'extension AddJsonFile IConfigurationBuilder afin que vous puissiez ajouter la configuration JSON avec un appel à ConfigurationBuilder.AddJsonFile (nom de fichier, facultatif). Build();.

La plupart du temps, une fois que vous avez une configuration, tous les vous devez commencer la récupération des valeurs.

IConfiguration inclut un indexeur de chaîne, ce qui vous permet de récupérer toute valeur de configuration spécifique à l'aide de la clé pour accéder à l'élément pour lequel vous avez besoin. Vous pouvez récupérer un ensemble de paramètres (appelé une section) avec les méthodes GetSection ou GetChildren (selon que vous souhaitez Descendre d'un niveau supplémentaire de la hiérarchie). Notez que sections d'élément de configuration vous permettent d'extraire les éléments suivants :

  • clé : le dernier élément du nom.
  • chemin d'accès : le nom complet qui pointe à partir de la racine à l'emplacement actuel.
  • valeur : la valeur de la configuration stockée dans le paramètre de configuration.
  • valeur en tant qu'objet : via le ConfigurationBinder, vous pouvez récupérer un objet POCO qui correspond à la section de configuration auquel vous accédez (et potentiellement de ses enfants). Voici comment le Configuration.Get < AppConfiguration > (nameof(AppConfiguration)) fonctionne dans Figure 3, par exemple.
  • IConfigurationRoot inclut une fonction de rechargement qui vous permet de recharger les valeurs pour mettre à jour la configuration. ConfigurationRoot (qui implémente IConfigurationRoot) inclut une méthode GetReloadToken qui permet de vous inscrire pour les notifications de lorsqu'un rechargement se produit (et la valeur peut changer).

Paramètres chiffrés

Parfois, que vous souhaitez récupérer les paramètres qui sont chiffrées au lieu de texte Ouvrir stockée dans. Cela est important, par exemple, lorsque vous le stockage des clés d'application OAuth ou des jetons ou le stockage des informations d'identification pour une chaîne de connexion de base de données. Heureusement, le système Microsoft.Extensions.Configuration prend en charge pour la lecture des valeurs chiffrées. Pour accéder à la banque d'informations sécurisé, vous devez ajouter une référence au package NuGet de Microsoft.Extensions.Configuration.UserSecrets. Une fois qu'elle est ajoutée, vous disposerez d'une nouvelle méthode d'extension IConfigurationBuilder.AddUserSecrets qui accepte un argument de chaîne d'élément configuration appelé userSecretsId (stocké dans le fichier project.json). Évidemment, une fois la configuration de UserSecrets est ajoutée à votre générateur de configuration, vous pouvez commencer la récupération des valeurs chiffrées, uniquement accessible aux utilisateurs auxquels les paramètres sont associés.

Évidemment, la récupération des paramètres sont quelque peu inutile si vous ne pouvez pas également les définir. Pour ce faire, utilisez l'outil utilisateur-secret.cmd comme suit :

user-secret set <secretName> <value> [--project <projectPath>]

--Projet permet d'associer le paramètre avec la valeur userSecretsId stockée dans votre fichier project.json (créé par défaut par l'Assistant Nouveau projet d'ASP.NET 5). Si vous n'avez pas l'outil clé secrète de l'utilisateur, vous devez l'ajouter dans l'invite de commandes développeur à l'aide de l'utilitaire DNX (actuellement dnu.exe).

Pour plus d'informations sur l'option de configuration secret principal d'utilisateur, consultez l'article « Safe stockage d'Application Secrets, » par Rick Anderson et David Roth à bit.ly/1mmnG0L.

Synthèse

Ceux d'entre vous qui ont été avec .NET pendant un certain temps ont probablement été déçus avec la prise en charge intégrée pour la configuration via System.Configuration. Il s'agit probablement particulièrement vrai si vous utilisiez précédemment ASP.NET classique, où la configuration était limitée aux fichiers Web.Config ou App.config, puis en accédant uniquement par le nœud AppSettings dans ce. Heureusement, le nouveau ouvre source que Microsoft.extensions.Configuration API va bien au-delà de ce qui a été initialement disponible en ajoutant une multitude de nouveaux fournisseurs de configuration, ainsi que d'un système facilement extensible dans lequel vous pouvez incorporer n'importe quel fournisseur personnalisé que vous souhaitez. Pour ceux toujours vivant (coincé?) dans un monde de versions antérieures à ASP.NET 5, l'ancienne fonction toujours System.Configuration APIs, mais vous pouvez lentement commencer à migrer (même côte à côte) à la nouvelle API simplement en faisant référence à nouveaux packages. En outre, les packages NuGet peuvent servir à partir de projets de client Windows tels que les applications console et Windows Presentation Foundation. Par conséquent, la prochaine fois que vous avez besoin d'accéder aux données de configuration, il est peu ne pas pour tirer parti de l'API Microsoft.Extensions.Configuration.


Mark Michaelisest le fondateur de IntelliTect, où il sert de son poste d'architecte en chef technique et un formateur. Depuis près de deux décennies, il a été MVP Microsoft et un directeur régional Microsoft depuis 2007. Michaelis fait plusieurs logiciels conception révision équipes Microsoft, notamment c#, Microsoft Azure, SharePoint et Visual Studio ALM. Il participe à des conférences de développeurs et a écrit de nombreux ouvrages, y compris sa plus récente, « Essential c# 6.0 (5e édition) » (itl.tc/EssentialCSharp). Contactez-le sur Facebook à facebook.com/Mark.Michaelis, sur son blog à l'adresse IntelliTect.com/Mark, sur Twitter : @markmichaelis ou par courrier électronique à mark@IntelliTect.com.

Je remercie les experts techniques IntelliTect suivants d'avoir relu cet article : Grant Erickson, Derek Howard, Phil Spokas et Michael Stokesbary