Как получить доступ к конфигурации в любом классе в ASP.NET Core?

127

Я просмотрел документацию по настройке ядра ASP.NET. В документации говорится, что вы можете получить доступ к конфигурации из любого места в приложении.

Ниже представлен Startup.cs, созданный по шаблону

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();
    }
}

Итак, когда Startup.csмы настраиваем все параметры, Startup.cs также имеет свойство с именемConfiguration

Что я не могу понять, как получить доступ к этой конфигурации в контроллере или где-либо в приложении? MS рекомендует использовать шаблон параметров, но у меня всего 4-5 пар ключ-значение, поэтому я бы не хотел использовать шаблон параметров. Я просто хотел получить доступ к конфигурации в приложении. Как мне вводить его в любом классе?

LP13
источник
1
Если это 4-5 пар ключ-значение, вы можете просто ввести эти индивидуальные настройки. Я бы порекомендовал этот подход или шаблон опций для проверки. Все три метода (включая тот, о котором вы изначально спрашивали) перечислены как ответы в следующем возможном повторяющемся вопросе: stackoverflow.com/questions/30263681/…
stephen.vakil
Чтобы получить доступ к конфигурации в виде словаря из любого места, отметьте этот ответ .
Амро
Проверьте здесь для полного примера кода.
Arghya C
Если вы пришли сюда, потому что не можете преобразовать конфигурацию Framework в конфигурацию CORE, этот ответ для вас stackoverflow.com/a/56498687/1704458
TS

Ответы:

148

Обновить

Использование ASP.NET Core 2.0 автоматически добавит IConfigurationэкземпляр вашего приложения в контейнер внедрения зависимостей. Это также работает в сочетании с ConfigureAppConfigurationнаWebHostBuilder .

Например:

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

    host.Run();
}

Это так же просто, как добавить IConfigurationэкземпляр в коллекцию сервисов как одноэлементный объект ConfigureServices:

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

   // ...
}

Где Configurationэкземпляр в вашем Startupклассе.

Это позволяет вам вводить IConfigurationв любой контроллер или службу:

public class HomeController
{
   public HomeController(IConfiguration configuration)
   {
      // Use IConfiguration instance
   }
}
Хенк Моллема
источник
4
Моллерна .... а как насчет того, чтобы добавить конфигурацию в отдельный проект библиотеки классов в решении? Пробовал как эту частную статическую IConfiguration _configuration {get; устанавливать; } общедоступные DatabaseHelpers (конфигурация IConfiguration) {_configuration = конфигурация; } но _configuration всегда имеет значение null ... он никогда не попадает в конструктор
dinotom
2
Тем не менее, IConfigurationтакое движение очень неплотно. Намного лучше использовать паттерн Параметры .
Marc L.
7
Как получить доступ к значениям из "appsettings.json" непосредственно в настраиваемом классе? Без передачи данных от контроллера? Является ли это возможным?
Tadej
2
@HenkMollema Не могли бы вы добавить сюда пример? Как бы мне ввести это в любой класс (откуда?).
Tadej
5
@HenkMollema Вопрос заключался в том, как внедрить в любой класс ... а не в том, как внедрить в «любой класс, разрешенный посредством внедрения зависимостей». Я думаю, что здесь недопонимание ... его класс, вероятно, не вызывается из цепочки, которая начинается с контроллера или другого объекта, автоматически разрешаемого автоматическим процессом DI.
BVernon
35

Правильный способ сделать это:

В .NET Core вы можете ввести IConfigurationкак параметр в свой конструктор класса, и он будет доступен.

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

Теперь, когда вы хотите создать экземпляр своего класса, поскольку ваш класс вводит IConfiguration, вы не сможете просто сделать new MyClass(), потому что ему нужен IConfigurationпараметр, введенный в конструктор, поэтому вам нужно будет ввести свой класс как хорошо для инъекционной цепочки, что означает два простых шага:

1) Добавьте свой Class / es - где вы хотите использовать IConfiguration, к методу IServiceCollectionat ConfigureServices()вStartup.cs

services.AddTransient<MyClass>();

2) Определите экземпляр - скажем, в Controller, и введите его с помощью конструктора:

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

Теперь у вас должна быть возможность _myClass.configurationсвободно наслаждаться ...

Другой вариант:

Если вы все еще ищете способ сделать его доступным без внедрения классов в контроллер, вы можете сохранить его в a static class, который вы настроите в Startup.cs, например:

public static class MyAppData
{
    public static IConfiguration Configuration;
}

И ваш Startupконструктор должен выглядеть так:

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

Затем используйте MyAppData.Configurationгде угодно в вашей программе.

Не спорите со мной, почему первый вариант является правильным, я просто вижу, что опытные разработчики всегда избегают мусора на своем пути, и хорошо понимают, что постоянно держать в памяти множество данных - не лучшая практика, это плохо ни для производительности, ни для разработки, и, возможно, также более безопасно иметь с собой только то, что вам нужно.

Майер Спитцер
источник
5
Все это введение файлов конфигурации кажется бессмысленным / беспорядочным. TY за идею класса статической конфигурации.
Эндрю
1
Вопрос, конечно же, касался доступа к конфигурации в любом классе, а не только в контроллере. И хотя с новой разработкой бережливых сервисов (микросервисов) об этом можно подумать, когда дело доходит до миграции, это большая проблема. Вот почему Microsoft System.Configurationвернулась к CORE. Теперь вы можете получить доступ к своему старому доброму app.configs, как в старые добрые времена. И я не говорю здесь о контроллерах. Мы говорим о компонентах, у которых есть собственные конфигурации
TS
Он разрешает доступ в любом классе, а не только в контроллере, его просто нужно импортировать в контроллер, чтобы получить внедрение зависимостей.
Mayer Spitzer
1
Любой метод работает, и аргументы за или против каждого, на мой взгляд, академичны. Я использовал оба для разных приложений ... теперь, благодаря вашему чрезвычайно простому второму варианту. Создание статического класса с использованием DI довольно сложно.
iGanja
Второй метод также помогает решить общую проблему в .Net Core 2.0 - объекты, созданные как параметр POST (т. Е. Автоматически десериализованные из JSON), когда у вас нет возможности внедрить в конструктор (по крайней мере, не без большого количества дополнительного кода). Это отлично подходит для этого сценария
Джо Мун
30

Я знаю, что это старый, но, учитывая шаблоны IOptions, относительно просто реализовать:

  1. Класс с общедоступными свойствами получения / установки, которые соответствуют настройкам в конфигурации

    public class ApplicationSettings
    {
        public string UrlBasePath { get; set; }
    }
  2. зарегистрируйте свои настройки

    public void ConfigureServices(IServiceCollection services)
    {
     ...
     services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings"));
    ...
    }
  3. вводить через IOptions

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

Не знаю, почему бы тебе просто не сделать это.

ScottC
источник
1
Просто для справки: docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/…
gatsby
2
Как получить доступ к значениям из "appsettings.json" непосредственно в настраиваемом классе?
Tadej
2
@JedatKinports вам нужно добавить зависимости Nuget Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Binderа Microsoft.Extensions.Configuration.Jsonзатем вы загрузите appsettings.jsonфайл, например .., а var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();также вы должны убедиться, что для appsettings.jsonкопии в выходной каталог установлено значениеcopy always
LP13
7

Сейчас делаю вот так:

// 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;
        }
    }
}

Затем я использую это там, где мне нужно получить данные из файла appsettings.json:

var appSettingsJson = AppSettingsJson.GetAppSettings();
// appSettingsJson["keyName"]
Tadej
источник
Наконец то, что работает статическим методом, не зависящим от безумия инжектора. Наконец-то парадоксальная независимость! ; -) ... но ооочень много зависимостей пакетов NuGet aaargh!
Луи Сомерс,
7

Также есть возможность сделать configurationstatic в startup.cs, чтобы вы могли легко получить к нему доступ из любого места, статические переменные удобны, да!

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

internal static IConfiguration Configuration { get; private set; }

Это делает конфигурацию доступной где угодно с помощью Startup.Configuration.GetSection...Что может пойти не так?

konzo
источник
3

Я просмотрел образец шаблона опций и увидел следующее:

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;
    }
...
}

При добавлении Iconfiguration в конструктор моего класса я мог получить доступ к параметрам конфигурации через DI.

Пример:

public class MyClass{

    private Iconfiguration _config;

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

    ... // access _config["myAppSetting"] anywhere in this class
}
Питер Хемерик
источник
Работает ли это без явного упоминания MyClass в Startup.cs, что-то вроде этого? services.AddTransient <MyClass> ();
Крестный отец
Да, на самом деле, вам следует упомянуть классы, которые вы хотите внедрить в Startup.cs, а не наоборот. Но я думаю, что IConfiguration по умолчанию уже доступен для инъекций.
Питер Хемерик
Да, это работает. Я попробовал это после того, как сделал комментарий, и реализация конфигурации была введена в IConfiguration. В любом случае спасибо :)
Крестный отец
1
@netfed Как заявляет Майер Спитцер в своем ответе, конечно, вам нужно будет добавить MyClass в автозагрузку и внедрить его туда, где вам нужно, поэтому вам не нужно создавать новый экземпляр MyClass самостоятельно, вы вводите его там, где вам это нужно.
Питер Хемерик,
2

Я знаю, что для этого может быть несколько способов, я использую Core 3.1 и искал оптимальный / более чистый вариант, и в итоге я сделал это:

  1. Мой класс запуска по умолчанию
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. Мой appsettings.json похож на этот
{
  "CompanySettings": {
    "name": "Fake Co"
  }
}
  1. Мой класс является контроллером API, поэтому сначала я добавил ссылку using, а затем внедрил интерфейс IConfiguration
using Microsoft.Extensions.Configuration;

public class EmployeeController 
{
    private IConfiguration _configuration;
    public EmployeeController(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}
  1. Наконец, я использовал метод GetValue
public async Task<IActionResult> Post([FromBody] EmployeeModel form)
{
    var companyName = configuration.GetValue<string>("CompanySettings:name");
    // companyName = "Fake Co"
}
user1058637
источник
0

В 8-2017 Microsoft выпустила System.Configurationдля .NET CORE v4.4. В настоящее время предварительная версия v4.5 и v4.6.

Для тех из нас, кто работает над преобразованием .Net Framework в CORE, это важно. Это позволяет хранить и использовать текущие app.configфайлы, к которым можно получить доступ из любой сборки. Возможно, это даже может быть альтернативой appsettings.json, поскольку Microsoft осознала необходимость в этом. В FW работает так же, как и раньше. Есть одно отличие:

В веб-приложениях [например, ASP.NET CORE WEB API] вам необходимо использовать, app.configа не web.config для вашего appSettingsили configurationSection. Возможно, вам придется использовать, web.configно только если вы развертываете свой сайт через IIS. Вы помещаете специфичные для IIS настройки вweb.config

Я тестировал его с помощью netstandard20 DLL и Asp.net Core Web Api, и все работает.

TS
источник
0

Использование шаблона параметров в ASP.NET Core - лучший вариант . Я просто хочу добавить, что если вам нужно получить доступ к параметрам в вашем startup.cs , я рекомендую сделать это следующим образом:

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)];
}
Мартин Брандл
источник
Итак, если у меня есть целый подраздел с десятком значений конфигурации, к которым мне нужно получить доступ в ConfigureServices, тогда мне нужно сделать это для всех? Нет ли другого способа сделать это с помощью шаблона IOptions? Мне нужно ввести это в метод статического расширения, в котором я настраиваю свой общественный транспорт. Также как насчет предложения Microsoft об отказе от использования шаблона IOptions в ConfigureServices docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/…
kuldeep
Я здесь не использую IOPtions в ConfigureService ...
Мартин Брандл,
-3

Мне нужно при запуске читать собственные параметры.
Это должно быть до того, как WebHost будет запущен (поскольку мне нужен URL-адрес / IP-адрес «для прослушивания» и порт из файла параметров и применить его к WebHost). Кроме того, мне нужны общедоступные настройки во всем приложении.

После некоторого поиска (полного примера не найдено, только фрагменты) и после различных попыток и ошибок я решил сделать это «по-старому» с собственным файлом .ini.
Итак ... если вы хотите использовать свой собственный .ini файл и / или установите "для прослушивания url / IP" ваш собственный и / или вам нужны общедоступные настройки, это для вас ...

Полный пример, действительный для ядра 2.1 (mvc):

Создайте .ini-файл - пример:

[Запуск]
URL = http://172.16.1.201:22222
[Параметр]
* Dummy1 = gew7623
Dummy1 = true
Dummy2 = 1

при этом Dummyx включены только в качестве примера для других типов даты, кроме строки (а также для проверки случая «неправильный параметр» (см. код ниже).

Добавлен файл кода в корень проекта для хранения глобальных переменных:

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... 
}

Изменил код в program.cs (до 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

    }
}

Сюда:

  • Конфигурация моего приложения отделена от appsettings.json, и у меня нет побочных эффектов, которых следует опасаться, если MS внесет изменения в будущих версиях ;-)
  • У меня свои настройки в глобальных переменных
  • Я могу установить "URL-адрес прослушивания" для каждого устройства, на котором запущено приложение (моя машина разработчика, сервер интрасети и Интернет-сервер)
  • Я могу деактивировать настройки старым способом (просто поставьте * раньше)
  • Я могу отреагировать, если что-то не так в файле .ini (например, несоответствие типов)
    Если, например, установлен неправильный тип (например, * Dummy1 = gew7623 активирован вместо Dummy1 = true), хост показывает красный информация на консоли (включая исключение), и я могу реагировать также в приложении (GV.bFehler_Ini имеет значение true, если есть ошибки с .ini)
FredyWenger
источник