Comment accéder à la configuration dans n'importe quelle classe d'ASP.NET Core?

127

J'ai parcouru la documentation de configuration sur le noyau ASP.NET. La documentation indique que vous pouvez accéder à la configuration de n'importe où dans l'application.

Voici Startup.cs créé par le modèle

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

        if (env.IsEnvironment("Development"))
        {
            // This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
            builder.AddApplicationInsightsSettings(developerMode: true);
        }

        builder.AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container
    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddApplicationInsightsTelemetry(Configuration);

        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, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseApplicationInsightsRequestTelemetry();

        app.UseApplicationInsightsExceptionTelemetry();

        app.UseMvc();
    }
}

Donc, dans Startup.csnous configurons tous les paramètres, Startup.cs a également une propriété nomméeConfiguration

Qu'est-ce que je ne suis pas en mesure de comprendre comment accéder à cette configuration dans le contrôleur ou n'importe où dans l'application? MS recommande d'utiliser le modèle d'options mais je n'ai que 4-5 paires clé-valeur, donc je ne voudrais pas utiliser le modèle d'options. Je voulais juste avoir accès à la configuration en application. Comment puis-je l'injecter dans n'importe quelle classe?

LP13
la source
1
S'il s'agit de 4 à 5 paires de valeurs clés, vous pouvez simplement injecter ces paramètres individuels. Je recommanderais cette approche ou le modèle d'options à des fins de testabilité. Les trois méthodes (y compris celle que vous avez initialement posée) sont répertoriées comme réponses dans la question en double possible suivante: stackoverflow.com/questions/30263681/…
stephen.vakil
Pour accéder à la configuration en tant que dictionnaire de n'importe où, cochez cette réponse .
Amro
Vérifiez ici pour un exemple de code complet.
Arghya C
Si vous venez ici parce que vous êtes en difficulté avec la conversion de la configuration du Framework en configuration CORE, cette réponse est pour vous stackoverflow.com/a/56498687/1704458
TS

Réponses:

148

Mettre à jour

L'utilisation d'ASP.NET Core 2.0 ajoutera automatiquement l' IConfigurationinstance de votre application dans le conteneur d'injection de dépendances. Cela fonctionne également en conjonction avec ConfigureAppConfigurationsur le WebHostBuilder.

Par exemple:

public static void Main(string[] args)
{
    var host = WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration(builder =>
        {
            builder.AddIniFile("foo.ini");
        })
        .UseStartup<Startup>()
        .Build();

    host.Run();
}

C'est aussi simple que d'ajouter l' IConfigurationinstance à la collection de services en tant qu'objet singleton dans ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
   services.AddSingleton<IConfiguration>(Configuration);

   // ...
}

Configurationest l'instance dans votre Startupclasse.

Cela vous permet d'injecter IConfigurationdans n'importe quel contrôleur ou service:

public class HomeController
{
   public HomeController(IConfiguration configuration)
   {
      // Use IConfiguration instance
   }
}
Henk Mollema
la source
4
Mollerna .... et que diriez-vous si vous souhaitez injecter la configuration dans un projet de bibliothèque de classes distinct dans la solution? J'ai essayé comme ça IConfiguration statique privée _configuration {get; ensemble; } public DatabaseHelpers (configuration IConfiguration) {_configuration = configuration; } mais _configuration est toujours nulle ... il n'est jamais touché dans le
contstructor
2
Cela dit, passer IConfigurationcomme ça est très fuyant. Il est préférable d'utiliser le modèle Options .
Marc L.
7
Comment accéder aux valeurs du "appsettings.json" directement dans une classe personnalisée? Sans transmettre les données d'un responsable du traitement? C'est possible?
Tadej
2
@HenkMollema Pourriez-vous en ajouter un exemple ici? Comment pourrais-je l'injecter dans n'importe quelle classe (d'où?).
Tadej
5
@HenkMollema La question était de savoir comment injecter dans n'importe quelle classe ... pas comment injecter dans "n'importe quelle classe résolue via l'injection de dépendances". Je pense que c'est là que se trouve le problème de communication ... sa classe n'est probablement pas appelée à partir d'une chaîne qui commence par un contrôleur ou un autre objet résolu automatiquement par un processus DI automatique.
BVernon
35

La bonne façon de le faire:

Dans .NET Core, vous pouvez injecter le en IConfigurationtant que paramètre dans votre constructeur de classe, et il sera disponible.

public class MyClass 
{
    private IConfiguration configuration;
    public MyClass(IConfiguration configuration)
    {
        ConnectionString = new configuration.GetValue<string>("ConnectionString");
    }

Maintenant, lorsque vous voulez créer une instance de votre classe, puisque votre classe est injectée dans IConfiguration, vous ne pourrez pas simplement le faire new MyClass(), car elle a besoin d'un IConfigurationparamètre injecté dans le constructeur, vous devrez donc injecter votre classe comme bien à la chaîne d'injection, ce qui signifie deux étapes simples:

1) Ajoutez vos classes - où vous voulez utiliser le IConfiguration, IServiceCollectionà la ConfigureServices()méthode dansStartup.cs

services.AddTransient<MyClass>();

2) Définissez une instance - disons dans le Controller, et injectez-la en utilisant le constructeur:

public class MyController : ControllerBase
{
    private MyClass _myClass;
    public MyController(MyClass myClass)
    {
        _myClass = myClass;
    }

Vous devriez maintenant pouvoir profiter _myClass.configurationlibrement de votre ...

Une autre option:

Si vous cherchez toujours un moyen de le rendre disponible sans avoir à injecter les classes dans le contrôleur, vous pouvez le stocker dans un static class, que vous configurerez dans le Startup.cs, quelque chose comme:

public static class MyAppData
{
    public static IConfiguration Configuration;
}

Et votre Startupconstructeur devrait ressembler à ceci:

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
    MyAppData.Configuration = configuration;
}

Ensuite, utilisez MyAppData.Configurationn'importe où dans votre programme.

Ne me demandez pas pourquoi la première option est la bonne façon, je peux juste voir que les développeurs expérimentés évitent toujours les données inutiles en cours de route, et il est bien entendu que ce n'est pas la meilleure pratique d'avoir des tonnes de données disponibles en mémoire tout le temps, ce n'est pas non plus bon pour les performances et ni pour le développement, et il est peut-être aussi plus sûr de n'avoir avec vous que ce dont vous avez besoin.

Mayer Spitzer
la source
5
Toute cette injection de fichiers de configuration semble un peu inutile / désordonnée. TY pour l'idée de classe de configuration statique.
Andrew
1
La question, bien sûr, était d'accéder à la configuration dans n'importe quelle classe et pas seulement au contrôleur. Et alors qu'avec le nouveau développement de services lean (microservices), cela peut être pensé, quand il s'agit de migrations, c'est une grande douleur. C'est pourquoi Microsoft a remis System.ConfigurationCORE sur les rails. Maintenant, vous pouvez accéder à votre bon vieux app.configs comme au bon vieux temps. Et je ne parle pas ici de contrôleurs. Nous parlons de composants qui ont leurs propres configurations
TS
Il permet l'accès dans n'importe quelle classe et pas seulement dans le contrôleur, il nécessite simplement d'être importé dans le contrôleur afin d'obtenir l'injection de dépendances.
Mayer Spitzer
1
Les deux méthodes fonctionnent, et les arguments pour ou contre chacun sont à mon avis théoriques. J'ai utilisé les deux pour différentes applications ... maintenant, grâce à votre deuxième option extrêmement simple. Créer une classe statique est assez difficile avec DI.
iGanja
La deuxième méthode aide également à résoudre un problème courant dans .Net Core 2.0 - les objets instanciés en tant que paramètre POST (c'est-à-dire désérialisés automatiquement à partir de JSON), où vous n'avez pas la possibilité d'injecter dans le constructeur (du moins pas sans beaucoup de code supplémentaire). Cela fonctionne très bien pour ce scénario
Joe Moon
30

Je sais que c'est vieux mais étant donné les modèles IOptions, c'est relativement simple à mettre en œuvre:

  1. Classe avec des propriétés publiques get / set qui correspondent aux paramètres de la configuration

    public class ApplicationSettings
    {
        public string UrlBasePath { get; set; }
    }
  2. enregistrer vos paramètres

    public void ConfigureServices(IServiceCollection services)
    {
     ...
     services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
    ...
    }
  3. injecter via IOptions

    public class HomeController
    {
       public HomeController(IOptions<ApplicationSettings> appSettings)
       { ...
        appSettings.Value.UrlBasePath
        ...
        // or better practice create a readonly private reference
        }
     }

Je ne sais pas pourquoi vous ne feriez pas cela.

ScottC
la source
2
Comment accéder aux valeurs du "appsettings.json" directement dans une classe personnalisée?
Tadej
2
@JedatKinports vous devez ajouter des dépendances NuGet Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Binderet Microsoft.Extensions.Configuration.Jsonpuis vous chargez le appsettings.jsonfichier comme var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();..et aussi vous devez vous assurer appsettings.jsoncopie au répertoire de sortie est réglé surcopy always
LP13
7

Je le fais comme ça en ce moment:

// Requires NuGet package Microsoft.Extensions.Configuration.Json

using Microsoft.Extensions.Configuration;
using System.IO;

namespace ImagesToMssql.AppsettingsJson
{
    public static class AppSettingsJson
    {           
        public static IConfigurationRoot GetAppSettings()
        {
            string applicationExeDirectory = ApplicationExeDirectory();

            var builder = new ConfigurationBuilder()
            .SetBasePath(applicationExeDirectory)
            .AddJsonFile("appsettings.json");

            return builder.Build();
        }

        private static string ApplicationExeDirectory()
        {
            var location = System.Reflection.Assembly.GetExecutingAssembly().Location;
            var appRoot = Path.GetDirectoryName(location);

            return appRoot;
        }
    }
}

Et puis j'utilise ceci où j'ai besoin d'obtenir les données du fichier appsettings.json:

var appSettingsJson = AppSettingsJson.GetAppSettings();
// appSettingsJson["keyName"]
Tadej
la source
Enfin quelque chose qui fonctionne de manière statique sans dépendre de la folie des injecteurs. L'indépendance paradoxale enfin! ; -) ... mais tellement de dépendances NuGet packacge aaargh!
Louis Somers il y a
7

Il existe également une option pour rendre configurationstatique dans startup.cs afin que vous puissiez y accéder facilement n'importe où, les variables statiques sont pratiques, hein!

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

internal static IConfiguration Configuration { get; private set; }

Cela rend la configuration accessible n'importe où en utilisant Startup.Configuration.GetSection...Qu'est-ce qui ne va pas?

Konzo
la source
3

J'ai regardé dans l'exemple de modèle d'options et j'ai vu ceci:

public class Startup
{
    public Startup(IConfiguration config)
    {
        // Configuration from appsettings.json has already been loaded by
        // CreateDefaultBuilder on WebHost in Program.cs. Use DI to load
        // the configuration into the Configuration property.
        Configuration = config;
    }
...
}

Lors de l'ajout d'Iconfiguration dans le constructeur de ma classe, je pouvais accéder aux options de configuration via DI.

Exemple:

public class MyClass{

    private Iconfiguration _config;

    public MyClass(Iconfiguration config){
        _config = config;
    }

    ... // access _config["myAppSetting"] anywhere in this class
}
Pieter Heemeryck
la source
Cela fonctionne-t-il sans mentionner explicitement MyClass dans Startup.cs, quelque chose comme ça? services.AddTransient <MyClass> ();
Le Parrain
Oui, en fait, vous devriez mentionner les classes que vous souhaitez injecter dans Startup.cs, et non l'inverse. Mais IConfiguration est je pense par défaut déjà disponible pour l'injection.
Pieter Heemeryck
Oui cela fonctionne. J'ai essayé cela après avoir fait le commentaire et l'implémentation de la configuration a été injectée dans IConfiguration. Merci quand même :)
Le Parrain
1
@netfed Comme Mayer Spitzer l'indique dans sa réponse, bien sûr, vous devrez ajouter MyClass au démarrage et l'injecter là où vous en avez besoin, vous n'avez donc pas besoin de créer une nouvelle instance de MyClass vous-même, vous l'injectez là où vous en avez besoin.
Pieter Heemeryck
2

Je sais qu'il peut y avoir plusieurs façons de faire cela, j'utilise Core 3.1 et je cherchais l'option optimale / plus propre et j'ai fini par faire ceci:

  1. Ma classe de démarrage est par défaut
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.AddControllers();
}
  1. Mon appsettings.json est comme ça
{
  "CompanySettings": {
    "name": "Fake Co"
  }
}
  1. Ma classe est un contrôleur d'API, j'ai donc d'abord ajouté la référence d'utilisation, puis j'ai injecté l'interface IConfiguration
using Microsoft.Extensions.Configuration;

public class EmployeeController 
{
    private IConfiguration _configuration;
    public EmployeeController(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}
  1. Enfin, j'ai utilisé la méthode GetValue
public async Task<IActionResult> Post([FromBody] EmployeeModel form)
{
    var companyName = configuration.GetValue<string>("CompanySettings:name");
    // companyName = "Fake Co"
}
user1058637
la source
0

En 8-2017, Microsoft a sorti System.Configurationpour .NET CORE v4.4. Actuellement v4.5 et v4.6.

Pour ceux d'entre nous qui travaillent sur la transformation de .Net Framework vers CORE, c'est essentiel. Il permet de conserver et d'utiliser les app.configfichiers actuels , accessibles depuis n'importe quel assemblage. C'est probablement même une alternative à appsettings.json, puisque Microsoft en a réalisé la nécessité. Cela fonctionne comme avant dans FW. Il y a une différence:

Dans les applications Web, [par exemple l'API WEB ASP.NET CORE] vous devez utiliser app.configet non web.config pour votre appSettingsou configurationSection. Vous devrez peut-être utiliser, web.configmais uniquement si vous déployez votre site via IIS. Vous placez des paramètres spécifiques à IIS dansweb.config

Je l'ai testé avec netstandard20 DLL et Asp.net Core Web Api et tout fonctionne.

TS
la source
0

L'utilisation du modèle Options dans ASP.NET Core est la solution. Je veux juste ajouter, si vous avez besoin d' accéder aux options de votre startup.cs , je vous recommande de le faire de cette façon:

CosmosDbOptions.cs:

public class CosmosDbOptions
{
    public string ConnectionString { get; set; }
}

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    // This is how you can access the Connection String:
    var connectionString = Configuration.GetSection(nameof(CosmosDbOptions))[nameof(CosmosDbOptions.ConnectionString)];
}
Martin Brandl
la source
Donc, si j'ai comme une sous-section entière avec une douzaine de valeurs de configuration auxquelles j'ai besoin d'accéder dans ConfigureServices, je dois le faire pour tous? N'y a-t-il pas d'autre moyen de le faire via le modèle IOptions? Je dois injecter ceci dans une méthode d'extension statique où je configure mon bus de transport en commun. Qu'en est-il également de cette suggestion de Microsoft de ne pas utiliser le modèle IOptions dans ConfigureServices docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/…
kuldeep
Je n'utilise pas les IOPtions dans ConfigureService ici ...
Martin Brandl
-3

Je dois lire mes propres paramètres au démarrage.
Cela doit être là avant que le WebHost ne démarre (car j'ai besoin de l'url / IP et du port "pour écouter" du fichier de paramètres et de l'appliquer au WebHost). De plus, j'ai besoin des paramètres publics dans l'ensemble de l'application.

Après avoir cherché pendant un certain temps (aucun exemple complet trouvé, seulement des extraits de code) et après plusieurs essais et erreurs, j'ai décidé de le faire à l'ancienne avec un propre fichier .ini.
Donc .. si vous voulez utiliser votre propre fichier .ini et / ou définissez le "pour écouter url / IP" votre propre et / ou avez besoin des paramètres publics, ceci est pour vous ...

Exemple complet, valable pour le noyau 2.1 (mvc):

Créez un fichier .ini - exemple:

[Démarrage]
URL = http://172.16.1.201:22222
[Paramètre]
* Dummy1 = gew7623
Dummy1 = true
Dummy2 = 1

où les Dummyx ne sont inclus qu'à titre d'exemple pour d'autres types de date que string (et aussi pour tester le cas «mauvais param» (voir code ci-dessous).

Ajout d'un fichier de code à la racine du projet, pour stocker les variables globales:

namespace MatrixGuide
{
    public static class GV
    {
        // In this class all gobals are defined

        static string _cURL;
        public static string cURL // URL (IP + Port) on that the application has to listen
        {
            get { return _cURL; }
            set { _cURL = value; }
        }

        static bool _bdummy1;
        public static bool bdummy1 // 
        {
            get { return _bdummy1; }
            set { _bdummy1 = value; }
        }

        static int _idummy1;
        public static int idummy1 // 
        {
            get { return _idummy1; }
            set { _idummy1 = value; }
        }

        static bool _bFehler_Ini;
        public static bool bFehler_Ini // 
        {
            get { return _bFehler_Ini; }
            set { _bFehler_Ini = value; }
        }

        // add further  GV variables here..
    }
    // Add further classes here... 
}

Modification du code dans program.cs (avant CreateWebHostBuilder ()):

namespace MatrixGuide
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Read .ini file and overtake the contend in globale
            // Do it in an try-catch to be able to react to errors
            GV.bFehler_Ini = false;
            try
            {
                var iniconfig = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddIniFile("matrixGuide.ini", optional: false, reloadOnChange: true)
                .Build();
                string cURL = iniconfig.GetValue<string>("Startup:URL");
                bool bdummy1 = iniconfig.GetValue<bool>("Parameter:Dummy1");
                int idummy2 = iniconfig.GetValue<int>("Parameter:Dummy2");
                //
                GV.cURL = cURL;
                GV.bdummy1 = bdummy1;
                GV.idummy1 = idummy2;
            }
            catch (Exception e)
            {
                GV.bFehler_Ini = true;
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("!! Fehler beim Lesen von MatrixGuide.ini !!");
                Console.WriteLine("Message:" + e.Message);
                if (!(e.InnerException != null))
                {
                    Console.WriteLine("InnerException: " + e.InnerException.ToString());
                }

                Console.ForegroundColor = ConsoleColor.White;
            }
            // End .ini file processing
            //
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>() //;
            .UseUrls(GV.cURL, "http://localhost:5000"); // set the to use URL from .ini -> no impact to IISExpress

    }
}

Par ici:

  • Ma configuration d'application est séparée de appsettings.json et je n'ai aucun effet secondaire à craindre, si MS fait des changements dans les versions futures ;-)
  • J'ai mes paramètres dans des variables globales
  • Je suis en mesure de définir "pour écouter l'url" pour chaque appareil, l'application est activée (ma machine de développement, le serveur intranet et le serveur Internet)
  • Je peux désactiver les paramètres, à l'ancienne (il suffit de définir un * avant)
  • Je suis capable de réagir, si quelque chose ne va pas dans le fichier .ini (par exemple, incompatibilité de type)
    Si - par exemple - un mauvais type est défini (par exemple, le * Dummy1 = gew7623 est activé à la place du Dummy1 = true) l'hôte est rouge les informations sont sur la console (y compris l'exception) et je peux également réagir dans l'application (GV.bFehler_Ini est défini sur true, s'il y a des erreurs avec le .ini)
FredyWenger
la source