133 votes

Comment extraire une liste de appsettings.json en .net core

J'ai un fichier appsettings.json qui ressemble à ceci :

{
    "someSetting": {
        "subSettings": [
            "one",
            "two",
            "three"
         ]
    }
}

Lorsque je construis ma configuration Root, et que je fais quelque chose comme config["someSetting:subSettings"] il renvoie null et les paramètres disponibles sont quelque chose comme ceci :

config["someSettings:subSettings:0"]

Existe-t-il un meilleur moyen de récupérer le contenu du fichier someSettings:subSettings comme une liste ?

0 votes

Peut-être que ça marche weblog.west-wind.com/posts/2016/may/23/

0 votes

Peut-être. J'utilise une application console qui n'est pas asp.net mais je vais voir si je peux mettre la main sur la collection de services.

0 votes

Oui, cela fonctionne aussi dans les applications de la console. Ce n'est pas spécifique à asp.net

230voto

cypressious Points 1696

En supposant que votre appsettings.json ressemble à ça :

{
  "foo": {
    "bar": [
      "1",
      "2",
      "3"
    ]
  }
}

Vous pouvez extraire les éléments de la liste comme suit :

Configuration.GetSection("foo:bar").Get<List<string>>()

18 votes

Cela a fonctionné pour moi, mais j'ai dû installer d'abord le paquet NuGet "Microsoft.Extensions.Configuration.Binder", comme décrit ci-après. ici .

1 votes

Et pour obtenir une paire clé-valeur-objet, il faudrait créer les classes C# avec json2csharp, puis utiliser Configuration.GetSection( "foo" ).Get<List<Bar>>()

1 votes

Ceci devrait être la réponse. Merci @Glorfindel pour l'astuce supplémentaire !

69voto

Helzgate Points 11

Dans .NetCore, c'est ce que j'ai fait :

Configuration normale :

Dans votre appsettings.json, créez une section de configuration pour vos définitions personnalisées :

    "IDP": [
    {
      "Server": "asdfsd",
      "Authority": "asdfasd",
      "Audience": "asdfadf"
    },
    {
      "Server": "aaaaaa",
      "Authority": "aaaaaa",
      "Audience": "aaaa"
    }
  ]

Créez une classe pour modéliser les objets :

public class IDP
{
    public String Server { get; set; }
    public String Authority { get; set; }
    public String Audience { get; set; }

}

dans votre Démarrage -> ConfigureServices

services.Configure<List<IDP>>(Configuration.GetSection("IDP"));

Remarque : si vous devez accéder immédiatement à votre liste dans votre méthode ConfigureServices vous pouvez utiliser...

var subSettings = Configuration.GetSection("IDP").Get<List<IDP>>();

Puis dans votre contrôleur quelque chose comme ceci :

Public class AccountController: Controller
{
    private readonly IOptions<List<IDP>> _IDPs;
    public AccountController(IOptions<List<Defined>> IDPs)
    {
        _IDPs = IDPs;
    }
  ...
}

juste à titre d'exemple, je l'ai utilisé ailleurs dans le contrôleur ci-dessus comme ceci :

       _IDPs.Value.ForEach(x => {
            // do something with x
        });

Cas limite

Dans le cas où vous avez besoin de plusieurs configurations mais qu'elles ne peuvent pas être dans un tableau et que vous n'avez aucune idée du nombre de sous-configurations que vous aurez à un moment donné. Utilisez la méthode suivante.

appsettings.json

"IDP": {
    "0": {
      "Description": "idp01_test",
      "IDPServer": "https://intapi.somedomain.com/testing/idp01/v1.0",
      "IDPClient": "someapi",
      "Format": "IDP"
    },
    "1": {
      "Description": "idpb2c_test",
      "IDPServer": "https://intapi.somedomain.com/testing/idpb2c",
      "IDPClient": "api1",
      "Format": "IDP"
    },
    "2": {
      "Description": "MyApp",
      "Instance": "https://sts.windows.net/",
      "ClientId": "https://somedomain.com/12345678-5191-1111-bcdf-782d958de2b3",
      "Domain": "somedomain.com",
      "TenantId": "87654321-a10f-499f-9b5f-6de6ef439787",
      "Format": "AzureAD"
    }
  }

Modèle

public class IDP
{
    public String Description { get; set; }
    public String IDPServer { get; set; }
    public String IDPClient { get; set; }
    public String Format { get; set; }
    public String Instance { get; set; }
    public String ClientId { get; set; }
    public String Domain { get; set; }
    public String TenantId { get; set; }
}

Créer une extension pour l'objet Expando

public static class ExpandObjectExtension
    {
        public static TObject ToObject<TObject>(this IDictionary<string, object> someSource, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
               where TObject : class, new()
        {
            Contract.Requires(someSource != null);
            TObject targetObject = new TObject();
            Type targetObjectType = typeof(TObject);

            // Go through all bound target object type properties...
            foreach (PropertyInfo property in
                        targetObjectType.GetProperties(bindingFlags))
            {
                // ...and check that both the target type property name and its type matches
                // its counterpart in the ExpandoObject
                if (someSource.ContainsKey(property.Name)
                    && property.PropertyType == someSource[property.Name].GetType())
                {
                    property.SetValue(targetObject, someSource[property.Name]);
                }
            }

            return targetObject;
        }
    }

ConfigureServices

var subSettings = Configuration.GetSection("IDP").Get<List<ExpandoObject>>();

var idx = 0;
foreach (var pair in subSettings)
{

    IDP scheme = ((ExpandoObject)pair).ToObject<IDP>();
    if (scheme.Format == "AzureAD")
    {
        // this is why I couldn't use an array, AddProtecedWebApi requires a path to a config section
        var section = $"IDP:{idx.ToString()}";
        services.AddProtectedWebApi(Configuration, section, scheme.Description);
        // ... do more stuff

    }
    idx++;
}

0 votes

J'ai créé une classe pour se lier à public class Definitions : List<Defined> {} . ` { "Définitions" : [ { "Name" : "somename", "Title" : "sometitle", "Image" : "some image url" }, { "Name" : "somename", "Title" : "sometitle", "Image" : "some image url" } ] }`

53voto

Victor Hurdugaci Points 3794

Vous pouvez utiliser le classeur de configuration pour obtenir une représentation de type fort des sources de configuration.

Voici un exemple tiré d'un test que j'ai écrit auparavant, j'espère que cela vous aidera :

    [Fact]
    public void BindList()
    {
        var input = new Dictionary<string, string>
        {
            {"StringList:0", "val0"},
            {"StringList:1", "val1"},
            {"StringList:2", "val2"},
            {"StringList:x", "valx"}
        };

        var configurationBuilder = new ConfigurationBuilder();
        configurationBuilder.AddInMemoryCollection(input);
        var config = configurationBuilder.Build();

        var list = new List<string>();
        config.GetSection("StringList").Bind(list);

        Assert.Equal(4, list.Count);

        Assert.Equal("val0", list[0]);
        Assert.Equal("val1", list[1]);
        Assert.Equal("val2", list[2]);
        Assert.Equal("valx", list[3]);
    }

La partie importante est l'appel à Bind .

Le test et d'autres exemples sont disponibles sur GitHub

1 votes

Note à soi-même : Dépend de Microsoft.Extensions.Configuration.Binder

4 votes

Des conseils pour faire cela avec services.Configure<TOptions> ? Je veux injecter des options à partir des champs de configuration qui incluent un tableau.

12voto

Marc S Points 71
var settingsSection = config.GetSection["someSettings:subSettings"];
var subSettings = new List<string>;

foreach (var section in settingsSection.GetChildren())
{
    subSettings.Add(section.Value);
}

Cela devrait vous donner les valeurs dont vous avez besoin, stockées dans le fichier subSettings

Je m'excuse d'avoir remis sur le tapis un sujet semi-ancien. J'ai eu du mal à trouver une réponse car un bon nombre de méthodes sont dépréciées, comme par exemple Get et GetValue . Cela devrait convenir si vous n'avez besoin que d'une solution simple sans le liant de configuration :)

1 votes

Une réponse simple, mais pour moi avec quelques changements : var settingsSection = config.GetSection("someSettings:subSettings"); . Dans l'autre mot, [] remplacé par ()

0 votes

C'est celui qui a le mieux fonctionné dans mon cas.

6voto

Michael Freidgeim Points 4002

Dans mon cas, la configuration

 services.Configure<List<ApiKey>>(Configuration.GetSection("ApiKeysList"));

n'a pas été chargé parce que les propriétés étaient en lecture seule et qu'il n'y avait pas de constructeur par défaut.

 **//not working** 
  public class ApiKey : IApiKey
    {
        public ApiKey(string key, string owner)
        {
            Key = key;
            OwnerName = owner;
        }
        public string Key { get;  }
        public string OwnerName { get;}
    } 

//Travail

    public class ApiKey : IApiKey
    {
        public ApiKey(){}//Added default constructor
        public ApiKey(string key, string owner)
        {
            Key = key;
            OwnerName = owner;
        }
        public string Key { get; set; }        //Added set property
        public string OwnerName { get; set; }  //Added set property
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X