web-dev-qa-db-fra.com

appsettings.json dans ASP.net Core 2.0 Configuration de la prévisualisation GetSection null

J'essayais d'appeler GetSection à partir de la configuration injectée dans le Startup.cs. La valeur était null, alors que indexer à une valeur de section concrète renvoie non-null valeur. Il me semble un bug derrière la méthode GetSection ou je me trompe?

appsettings.json:

{"MyConfig": { "ConfigA": "valeurA", "ConfigB": "valueB"}}

Program.cs:

    public static void Main(string[] args)
    {
        var Host = BuildWebHost(args);
        Host.Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();

Startup.cs:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        var mySection = this.Configuration.GetSection("MyConfig");

        var myVal = this.Configuration["MyConfig:ConfigA"];
14
Mojmir Rychly

J'ai tout d'abord vérifié s'il y avait des changements entre 1.1.1 et 2.x de JsonConfigurationProvider.cs, le code interne qui construit en définitive les valeurs récupérables à partir de votre fichier JSON. Il n'y a eu aucun changement à ce code ni à aucun autre code qui a finalement été appelé par votre this.Configuration.GetSection("MyConfig");.

Pour récupérer des valeurs, la méthode Configuration cherchera votre clé MyConfig dans chaque fournisseur de configuration dans l'ordre inverse, comme indiqué dans le code, jusqu'à ce qu'une valeur soit trouvée. Dans votre exemple, les fournisseurs (json, variables d’envois, arguments de ligne de commande) sont fournis dans Webhost.CreateDefaultBuilder()(voir ici) .

En regardant le code pour JsonConfigurationFileParser.cs , il crée un Dictionary<string, string> pour les clés et les valeurs, mais uniquement pour les valeurs primitives. C'est-à-dire qu'aucune clé n'est stockée pour MyConfig (à ce niveau, il s'agit d'un objet), mais il y aura une clé pour MyConfig:ConfigA et les valeurs d'un tableau ressembleraient à MyConfig:ConfigA:0, MyConfig:ConfigA:1, etc.

Enfin, vous découvrirez que Configuration.GetSection("MyConfig") _ { vous renvoie toujours une nouvelle construction } _ ConfigurationSection qui est never null, et au pire aura une Valuepropriété de null.

Ainsi, que se passe-t-il lorsque vous survolez une ConfigurationSection avec Intellisense et que vous examinez la propriété Value, c’est que chaque fournisseur de configuration a fait l’objet d’une recherche et qu’il n’a pas été détecté que la clé "MyConfig" était convertie en chaîne pour retourner . 

Vous aurez au moins besoin d'appeler:

services.Configure<MyConfigOptions>(configuration.GetSection("MyConfig"));
services.AddSingleton(cfg => cfg.GetService<IOptions<MyConfigOptions>>().Value);

de l'injecter dans l'ensemble de votre application en tant qu'objet C #. Sinon, appelez des valeurs individuelles avec la syntaxe de séparateur deux-points ["MyConfig:ConfigA"] ou avec var mySection = this.Configuration.GetSection("MyConfig")["ConfigA"];, qui est redondant mais l'illustre. Il n'est utilisé que pour récupérer des primitives.

Pour lier des objets C # et les injecter, j'ai créé la méthode d'extension suivante:

public static class IServiceCollectionExtensions
{
    public static IServiceCollection AddConfigOptions<TOptions>(this IServiceCollection services,
        IConfiguration configuration, string section) where TOptions : class, new()
    {
        services.Configure<TOptions>(configuration.GetSection(section));
        services.AddSingleton(cfg => cfg.GetService<IOptions<TOptions>>().Value);
        return services;
    }
}

qui peut s'appeler comme ceci:

public class Startup
{
    public Startup(IConfiguration configuration) => Configuration = configuration;

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddConfigOptions<EmailOptions>(Configuration, "Email")

et injecté comme ceci:

public class EmailSender : IEmailSender
{
    private EmailOptions _emailOptions;

    public EmailSender(EmailOptions options) => _emailOptions = options;
12

J'ai trouvé AspNetCore 2.0 tellement plus simple que 1.x en termes de configuration.

Si vous mettez un point d'arrêt dans le constructeur Startup(IConfiguration configuration), vous remarquerez que la variable configuration a environ 5 fournisseurs.

JsonConfigurationProvider est le fournisseur qui vous intéresse pour le fichier appsettings.json, mais vous remarquerez probablement que la propriété Data a un Count=0. Cela est probablement dû au fait que votre application recherche le fichier appsettings.json dans le répertoire spécifié dans JsonConfigurationProvider.Source.FileProvider.Root (qui est par défaut wwwroot).

J'ai simplement ajouté une tâche MSBuild dans le fichier .csproj comme suit:

<Copy SourceFiles="appsettings.json" DestinationFolder="wwwroot" />

Et cela semblait fonctionner parfaitement.

Ceci n’est évidemment utile que lors du développement local uniquement . Cependant, la pratique générale de nos jours est de ne jamais avoir de configuration dans un fichier en premier lieu, d'autant plus que cela finira par faire partie de votre historique de prise en pension. Au lieu de cela, lors du déploiement de votre application, les deux pratiques courantes de nos jours utilisent des variables d'environnement pour remplacer vos valeurs, voire mieux, en utilisant un magasin clé/valeur comme consul.

De plus, je vois toute une série d'exemples en ligne sur la façon d'utiliser la fonction services.Configure<>(), ce qui est correct, mais le Startup.cs utilise déjà DI pour injecter des valeurs dans IConfiguration configuration. Cela signifie que IConfiguration est déjà enregistré dans le conteneur IoC.. Cela signifie donc que vous pouvez déjà utiliser IConfiguration dans toute autre classe de votre application, de la manière suivante:

public JobsRepository(IConfiguration configuration)
{
    this.configA = configuration.GetSection("MyConfig:ConfigA").Value;
}
0
Adel Helal

Dans mon cas, il me manquait un paquet:

Microsoft.Extensions.Configuration.Binder

C'est en fait documenté comme un commentaire de code subtil dans ici

0
Bruno Garcia