在Main Program.cs中读取appsettings.json文件

94

首先,我的主要目的是动态设置应用程序的IP和端口。

我正在使用IConfiguration来注入一个JSON配置文件,就像一些教程中提到的那样。

然而,在Program.cs中无法检索配置,因为我的WebHostBuilder将同时使用StartUp和Url。

因此,在主机构建时,我的配置中没有任何内容。

WebProtocolSettings settings_Web = new WebProtocolSettings();
var host = new WebHostBuilder()
                .UseIISIntegration()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseStartup<Startup>()
                .UseUrls(settings_Web.Url + ":" + settings_Web.Port)
                .Build();

在 Startup.cs 中

public Startup(IHostingEnvironment env)
{
    // Set up configuration sources.
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

    Configuration = builder.Build();
}

public IConfigurationRoot Configuration { get; set; }

public void ConfigureServices(IServiceCollection services)
{
    // Adds services required for using options.
    services.AddOptions();

    var _WebProtocolSettings = Configuration.GetSection("WebProtocolSettings");

    // Register the IConfiguration instance
    services.Configure<WebProtocolSettings>(_WebProtocolSettings);
}

我的 appsettings.json 文件:

{
    "WebProtocolSettings": {
        "Url": "127.0.0.1",
        "Port": 5050
    }
}

我的WebProtocolSettings.cs文件:

public class WebProtocolSettings
{
    public string Url { get; set; }
    public int Port { get; set; }
}
9个回答

120
在 .NET 6 中
var builder = WebApplication.CreateBuilder(args);

// Using the GetValue<type>(string key) method
var configValue = builder.Configuration.GetValue<string>("Authentication:CookieAuthentication:LoginPath");

// or using the index property (which always returns a string)
var configValue = builder.Configuration["Authentication:CookieAuthentication:LoginPath"];

9
谢谢,正是我需要的。应该放在最前面,因为其他大多数答案已经过时了。 - Aileron79
4
这也可以写成var configValue = builder.Configuration["Authentication:CookieAuthentication:LoginPath"]; - Tod

112

更新 .Net 6

现在通过调用 GetValue<type>(string key) 扩展方法,从 ConfigurationManager 轻松获取任何设置。您还可以使用 Index(string key) 返回字符串。请参见这个答案


您必须在主方法中构建一个配置,获取该节并将其绑定到您的模型。没有其他办法。

public static void Main(string[] args)
{
    var config = new ConfigurationBuilder()
        .AddJsonFile("appsettings.json", optional: false)
        .Build();

    WebProtocolSettings settings_Web = new WebProtocolSettings();
    config.GetSection("WebProtocolSettings").Bind(settings_Web);

    var host = new WebHostBuilder()
            .UseIISIntegration()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup<Startup>()
            .UseUrls(settings_Web.Url + ":" + settings_Web.Port)
            .Build()

    host.Run();
}

##更新

另一种实现方法是将配置传递给UseConfiguration,如所述

public static void Main(string[] args)
{
    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("hosting.json", optional: true)
        .AddCommandLine(args)
        .Build();

    var host = new WebHostBuilder()
        .UseUrls("http://*:5000")
        .UseConfiguration(config)
        .UseKestrel()
        .Configure(app =>
        {
            app.Run(context => 
                context.Response.WriteAsync("Hello, World!"));
        })
        .Build();

    host.Run();
}

或在 ASP.NET Core > 2.0 中

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

public static IWebHost BuildWebHost(string[] args)
{
    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("hosting.json", optional: true)
        .AddCommandLine(args)
        .Build();

    return WebHost.CreateDefaultBuilder(args)
        .UseUrls("http://*:5000")
        .UseConfiguration(config)
        .Configure(app =>
        {
            app.Run(context => 
                context.Response.WriteAsync("Hello, World!"));
        })
        .Build();
}

嗨@Tseng,感谢您的回答,但是我该如何在Main Program.cs中存档“appsettings.json”的路径? - Jacky
1
我找到了方法:.SetBasePath(Directory.GetCurrentDirectory())。另外,应该是 config.GetSection 而不是 Configuration.GetSection。感谢您的帮助。 - Jacky
4
如果你需要访问 hostingContext.HostingEnvironment.EnvironmentName,因为你有特定环境的 hosting.json 文件,该怎么办? - Learner
当部署时,这个解决方案还能正常工作吗?例如,Json中的应用程序设置是否会被应用服务中找到的应用程序设置覆盖? - Dan Cundy
1
@DanCundy: (Azure)应用服务的值通过环境变量设置,因此您需要添加.AddEnvironmentVariables()AddXxx的顺序是将被覆盖的顺序(最新的键获胜,因此最后注册的内容将覆盖先前的内容-如果定义了特定的键)。但是这些天,您可以使用[Generic Host](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-3.1)轻松引导运行服务。 - Tseng
显示剩余3条评论

5

.UseConfiguration(Tseng的替代方案)是最简单的方法,但请注意,当以此方式配置时,在运行时对配置文件进行的更改不会应用于您的IConfiguration对象。要保持配置动态,必须使用.ConfigureAppConfiguration - 但然后你必须额外构建配置以在Main()中使用。您可以重复使用配置代码。

ASP.NET Core 2.2:

    public static void Main(string[] args)
    {
        IConfigurationBuilder configBuilderForMain = new ConfigurationBuilder();
        ConfigureConfiguration(configBuilderForMain);
        IConfiguration configForMain = configBuilderForMain.Build();

        // ... use configForMain to read config here ...

        var host = new WebHostBuilder()
            .ConfigureAppConfiguration(ConfigureConfiguration)
            // ... the rest of it ...
            .Build();
    }

    public static void ConfigureConfiguration(IConfigurationBuilder config)
    {
        config.SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
    }

4
在asp.net core 3.1中,你可以通过hostContext访问配置。这个示例是基于Worker Service项目的。
public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    //Access configuration here with the Host Context.  For example, to get a connection string from AppSettings.json:
                    var connectionString = hostContext.Configuration.GetConnectionString("MyConnectionString");
                    services.AddHostedService<Worker>();
                });
    }

3
在调用ConfigureWebHostDefaults之后才会调用ConfigureServices。因此,在这种情况下,这将不起任何帮助作用。 - mmavcy
正是我所寻找的。 - Fakhar Ahmad Rasul

3

这是一个旧问题,但有一些新的解决方案,以下是我喜欢的做法。

  1. Define the config in appsettings.json

         "ServiceConfig": { "PortNumber": 5005 },
    
  2. Create a class for the config:

         public class ServiceConfig
         {
             private readonly IConfiguration configuration;
             public const string SectionName = "ServiceConfig";
             public ServiceConfig(IConfiguration config)
             {
                 configuration = config;            
                 configuration.GetSection(SectionName).Bind(this);            
             }
             public int PortNumber { get; set; }
         }
    
  3. In Program.cs use the config:

         var config = new ServiceConfig(builder.Configuration);
         builder.WebHost.UseUrls($"http://*:{config.PortNumber}");
    

这种方法还有一个额外的好处,就是可以作为依赖注入的服务来使用:

         builder.Services.AddSingleton<ServiceConfig>();

1
在 .NET 7 中,您需要使用 BuildServiceProvider()
因此,您的 program.cs 的顶部将看起来像这样;
var builder = WebApplication.CreateBuilder(args);
var provider = builder.Services.BuildServiceProvider();
var _configuration = provider.GetRequiredService<IConfiguration>();

然后,您可以像这样访问您的appsettings.json值;

var configVal = _configuration.GetSection("Foo").GetValue<string>("Bar");

使用最新的.NET 7套件,应该是这样的:var builder = WebAssemblyHostBuilder.CreateDefault(args); var configVal = builder.Configuration.GetSection("Foo").GetValue<string>("Bar"); - undefined

1
支持命令行参数和默认appsettings文件的方法:
public static class Configuration
{
    public static IConfigurationRoot BuildConfigurationRoot()
    {

        var args = Environment.GetCommandLineArgs();
        var envArg = Array.IndexOf(args, "--environment");
        var envFromArgs = envArg >= 0 ? args[envArg + 1] : null;

        var aspnetcore = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
        var dotnetcore = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");

        var environment = envFromArgs ?? (string.IsNullOrWhiteSpace(aspnetcore)
            ? dotnetcore
            : aspnetcore);

        var configuration = new ConfigurationBuilder()
            .AddCommandLine(Environment.GetCommandLineArgs())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile(
                $"appsettings.{environment}.json",
                optional: true)
            .Build();

        return configuration; 
    }
}

你是否想在 .Build() 之前加入 ".AddEnvironmentVariables()" 作为一行代码? - Dale Holborow
IndexOf() 方法存在一个小错误。该方法是 Array 类中的静态方法。因此,您需要使用 Array.IndexOf("--environment") 而不是 args.IndexOf()。数组的实例无法用于访问 IndexOf 静态方法。 - Stack Undefined

-2
在 .net core 3.1 中,您可以使用 ConfigurationHelper.GetConfiguration() 方法来获取 appSetting 变量:

appSettings.json

"Endpoint": {
"ip": "170.888.88.888",
"port": 88888}

Program.cs

public class Program
{
    public static void Main(string[] args)
    {
     var config = ConfigurationHelper.GetConfiguration();
     var ip = config["Endpoint:ip"];
     var port = config["Endpoint:port"];
    }
 }

2
“ConfigurationHelper” 是从哪里来的?我看到一些自定义类的例子都是用这个名字,但在幕后它们做的事情与被接受的答案相同。 - k3davis

-3
请使用这段代码:
public class Program
{
    private static string _environmentName;

    public static void Main(string[] args)
    {
        var webHost = BuildWebHost(args);

        var config = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile($"appsettings.{_environmentName}.json", optional: true, reloadOnChange: true)
            .AddCommandLine(args)
            .Build();

        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureLogging((hostingContext, config) =>
    {
        config.ClearProviders();
        _environmentName = hostingContext.HostingEnvironment.EnvironmentName;
    }).UseStartup<Startup>().Build();
}

我忘记在完成Main()方法时加入BuildWebHost(args).Run();这一行代码。 - Caio Augusto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接