ChatGPT解决这个技术问题 Extra ChatGPT

如何访问 ASP.NET Core 中任何类的配置?

我在 ASP.NET 核心上浏览了 configuration documentation。文档说您可以从应用程序中的任何位置访问配置。

下面是模板创建的 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 建议使用 options pattern 但我只有 4-5 个键值对,所以我不想使用选项模式。我只是想访问应用程序中的配置。我如何在任何课程中注入它?

如果是 4-5 个键值对,那么您可以注入这些单独的设置。出于可测试性目的,我建议使用该方法或选项模式。所有三种方法(包括您最初询问的方法)都列为以下可能重复问题的答案:stackoverflow.com/questions/30263681/…

H
Henk Mollema

更新

使用 ASP.NET Core 2.0 将automatically将应用程序的 IConfiguration 实例添加到依赖项注入容器中。这也适用于 WebHostBuilder 上的 ConfigureAppConfiguration

例如:

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

    host.Run();
}

就像在 ConfigureServices 中将 IConfiguration 实例作为单例对象添加到服务集合一样简单:

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

   // ...
}

其中 Configuration 是您的 Startup 类中的实例。

这允许您在任何控制器或服务中注入 IConfiguration

public class HomeController
{
   public HomeController(IConfiguration configuration)
   {
      // Use IConfiguration instance
   }
}

Mollerna ....如果您想在解决方案中的单独类库项目中注入配置怎么办?像这样尝试过 private static IConfiguration _configuration { get;放; } 公共数据库助手(IConfiguration 配置){ _configuration = 配置;但 _configuration 始终为空...它永远不会在构造函数中被击中
也就是说,像这样绕过 IConfiguration 非常容易泄漏。使用 Options pattern 要好得多。
如何直接在自定义类中访问“appsettings.json”中的值?不从控制器传递数据?可能吗?
@HenkMollema 你能在这里添加一个例子吗?我将如何将它注入任何类(从哪里?)。
@HenkMollema问题是如何注入任何类......而不是如何注入“通过依赖注入解决的任何类”。我认为这就是沟通不畅的地方......他的类可能不是从以控制器或其他由自动 DI 过程自动解析的对象开始的链调用的。
B
Bernoulli IT

正确的做法:

在 .NET Core 中,您可以将 IConfiguration 作为参数注入到 Class 构造函数中,它将可用。

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

现在,当您想要创建您的类的实例时,由于您的类被注入了 IConfiguration,您将无法只执行 new MyClass(),因为它需要将 IConfiguration 参数注入到构造函数中,所以,您还需要将您的类注入到注入链中,这意味着两个简单的步骤:

1) 在 Startup.cs 中的 ConfigureServices() 方法中将您的 Class/es - 您要使用 IConfiguration 的位置添加到 IServiceCollection

services.AddTransient<MyClass>();

2) 定义一个实例 - 假设在 Controller 中,并使用构造函数注入它:

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

现在您应该可以自由地享受您的 _myClass.configuration...

另外的选择:

如果您仍在寻找一种无需将类注入控制器即可使其可用的方法,则可以将其存储在 static class 中,您将在 Startup.cs 中对其进行配置,例如:

public static class MyAppData
{
    public static IConfiguration Configuration;
}

您的 Startup 构造函数应如下所示:

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

然后在程序中的任意位置使用 MyAppData.Configuration

不要问我为什么第一个选项是正确的方法,我可以看到有经验的开发人员总是在他们的过程中避免垃圾数据,而且众所周知,始终在内存中提供大量数据并不是最佳实践,它对性能和开发都没有好处,也许只拥有你需要的东西也更安全。


所有这些配置文件的注入似乎有点毫无意义/混乱。 TY 为静态配置类的思想。
问题当然是关于访问任何类中的配置,而不仅仅是控制器。虽然随着精益服务(微服务)的新发展,可以想到这一点,但在迁移方面,这是一个很大的痛苦。这就是微软让 CORE 重回正轨的 System.Configuration 的原因。现在,您可以像过去一样访问您的旧 app.configs。我不是在这里谈论控制器。我们正在谈论具有自己配置的组件
它允许在任何类中访问,而不仅仅是在控制器中,它只需要被导入到控制器中以获得依赖注入。
任何一种方法都有效,在我看来,支持或反对每种方法的论点都是学术性的。我已经将两者用于不同的应用程序......现在,多亏了您非常简单的第二个选项。使用 DI 创建静态类相当困难。
第二种方法还有助于解决 .Net Core 2.0 中的一个常见问题 - 实例化为 POST 参数的对象(即从 JSON 自动反序列化),您没有机会注入构造函数(至少不是没有很多额外的代码)。这非常适合这种情况
S
ScottC

我知道这很旧,但鉴于 IOptions 模式实现起来相对简单:

具有与配置中的设置匹配的公共 get/set 属性的类 public class ApplicationSettings { public string UrlBasePath { get;放; } } 注册您的设置 public void ConfigureServices(IServiceCollection services) { ... services.Configure(Configuration.GetSection("ApplicationSettings")); ... } 通过 IOptions 注入 public class HomeController { public HomeController(IOptions appSettings) { ... appSettings.Value.UrlBasePath ... // 或者更好的做法是创建一个只读的私有引用 } }

我不知道你为什么不这样做。


如何直接在自定义类中访问“appsettings.json”中的值?
@JedatKinports 您需要添加 Nuget 依赖项 Microsoft.Extensions.ConfigurationMicrosoft.Extensions.Configuration.BinderMicrosoft.Extensions.Configuration.Json,然后加载 appsettings.json 文件,如 var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); ..您还必须确保将 appsettings.json 复制到输出目录设置为copy always
在你的例子中。如何使用一些在 ApplicationSettings.cs 中也使用 ApplicationSettings 的 DI 类?
k
konzo

还有一个选项可以在 startup.cs 中将 configuration 设为静态,以便您可以在任何地方轻松访问它,静态变量很方便哈!

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

internal static IConfiguration Configuration { get; private set; }

这使得使用 Startup.Configuration.GetSection... 可以在任何地方访问配置会出现什么问题?


这是迄今为止最简单的一个。
是的,我喜欢它。如果有人看到缺点,请分享。
T
Tadej

我现在正在这样做:

// 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"]

最后是在静态方法中工作的东西,而不依赖于喷油器的疯狂。矛盾的独立终于来了! ;-)...但是太多的 NuGet 包依赖啊啊啊!
值得一提的是,将 Microsoft.Extensions.Configuration 和 Microsoft.Extensions.Configuration.Json 添加到该代码工作中。
这种方法是否意味着您必须牺牲在开发时使用 appsettings.Development.json 自动覆盖 appsettings.json 中的值的可能性?
u
user1058637

我知道可能有几种方法可以做到这一点,我正在使用 Core 3.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();
}

我的 appsettings.json 是这样的

{
  "CompanySettings": {
    "name": "Fake Co"
  }
}

我的类是一个 API 控制器,所以我首先添加了 using 引用,然后注入了 IConfiguration 接口

using Microsoft.Extensions.Configuration;

public class EmployeeController 
{
    private IConfiguration _configuration;
    public EmployeeController(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}

最后我使用了 GetValue 方法

public async Task<IActionResult> Post([FromBody] EmployeeModel form)
{
    var companyName = configuration.GetValue<string>("CompanySettings:name");
    // companyName = "Fake Co"
}

我们需要访问它是一个单独的项目的类库。这是控制器。
P
Pieter Heemeryck

我查看了选项模式示例并看到了这个:

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
}

如果没有在 Startup.cs 中明确提及 MyClass,它是否可以工作,像这样? services.AddTransient();
是的,实际上,您应该提及要在 Startup.cs 中注入的类,而不是相反。但我认为默认情况下 IConfiguration 已经可以注入。
是的,它有效。我在发表评论后尝试了这个,并且配置实现被注入到 IConfiguration 中。不管怎么说,多谢拉 :)
@netfed 正如 Mayer Spitzer 在他的回答中所说,当然,您需要将 MyClass 添加到启动并将其注入到您需要的任何地方,因此您不需要自己创建 MyClass 的新实例,您可以在需要的地方注入它。
T
T.S.

在 8-2017 年,Microsoft 推出了用于 .NET CORE v4.4 的 System.ConfigurationCurrently v4.5 和 v4.6 预览版。

对于我们这些致力于从 .Net Framework 到 CORE 的转换的人来说,这是必不可少的。它允许保留和使用当前的 app.config 文件,可以从任何程序集中访问这些文件。它甚至可能是 appsettings.json 的替代品,因为 Microsoft 意识到需要它。它与以前在 FW 中的工作方式相同。有一个区别:

在 Web 应用程序中,[例如 ASP.NET CORE WEB API] 您需要为您的 appSettingsconfigurationSection 使用 app.confignot web.config。您可能需要使用 web.config,但前提是您通过 IIS 部署站点。您将 IIS 特定设置放入 web.config

我已经使用 netstandard20 DLL 和 Asp.net Core Web Api 对其进行了测试,并且一切正常。


M
Martin Brandl

使用 Options pattern in ASP.NET Core 是可行的方法。我只想补充一点,如果您需要访问您的 startup.cs 中的选项,我建议您这样做:

CosmosDbOptions.cs:

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

启动.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 模式做到这一点吗?我需要将它注入到我正在配置我的公共交通巴士的静态扩展方法中。另外,微软关于不在 ConfigureServices 中使用 IOptions 模式的建议docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/…
F
FredyWenger

我必须通过启动读取自己的参数。这必须在 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 有错误)