1、前言
在大多数的应用程序中,一些参数需要写在配置文件里,以此增加系统的灵活性。在ASP.NET
时代,配置参数一般会写在web.config
文件中,其本质上是对XML
文件的读取和写入。而在ASP.NET Core
中,配置文件变成了appsettings.json
文件。相较于XML
,JSON
文件更加轻量且灵活,下面就来介绍一下如何在ASP.NET Core
中对其进行读写操作。
2、添加配置参数
打开appsettings.json
文件,添加如下配置项。如果对JSON
文件的格式不熟悉,建议先了解一下其格式规范,其代码如下所示:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"ConnectionString": "Data Source=DSF-PC;Initial Catalog=Dao;User ID=sa;Password=123456"
},
"AppName": "ASP.NET Core API", // 应用程序名称
"Author": "HerryDong", // 作者
"AppSettings": {
"DefaultLanguage": "zh-CN", // 默认语言
"MinLevel": 10, // 地图最小层级
"MaxLevel": 16, // 地图最大层级
"Center": {
"Longitude": 120, // 地图中心点经度
"Latitude": 30 // 地图中心点维度
}
}
}
3、基于配置节点名称的读取
3.1、注入IConfiguration接口
在ASP.NET Core
中,如果希望通过配置项的名称获取配置参数,那就需要用到IConfiguration
接口。该接口已经默认存在于IoC
容器中,无需手动注册。创建一个新的控制器HomeController
,在构造函数中注入IConfiguration
接口,代码如下所示:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly IConfiguration configuration;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="configuration"></param>
public HomeController(IConfiguration configuration)
{
this.configuration = configuration;
}
}
}
3.2、读取配置参数
在HomeController
中添加一个Get
方法,添加如下代码:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly IConfiguration configuration;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="configuration"></param>
public HomeController(IConfiguration configuration)
{
this.configuration = configuration;
}
/// <summary>
/// 读取配置参数
/// </summary>
/// <returns></returns>
[HttpGet]
public string Get()
{
string connectionString = configuration.GetConnectionString("ConnectionString");
string appName = configuration["AppName"];
string author = configuration["Author"];
string defaultLanguage = configuration["AppSettings:DefaultLanguage"];
string minLevel = configuration["AppSettings:MinLevel"];
string maxLevel = configuration["AppSettings:MaxLevel"];
string longitude = configuration["AppSettings:Center:Longitude"];
string latitude = configuration["AppSettings:Center:Latitude"];
return connectionString + "\n" + appName + "\n" + author + "\n" +
defaultLanguage + "\n" + minLevel + "\n" + maxLevel + "\n" +
longitude + "\n" + latitude;
}
}
}
3.2.1、数据库连接字符串
对于数据库连接字符串ConnectionString
,可以直接通过IConfiguration
接口的GetConnectionString
方法进行获取:
string connectionString = configuration.GetConnectionString("ConnectionString");
3.2.2、一级子节点
由于AppName
、Author
位于一级节点,因此可通过如下方式进行获取:
string appName = configuration["AppName"];
string author = configuration["Author"];
3.2.3、二级子节点
二级节点DefaultLanguage
、MinLevel
、MaxLevel
位于一级节点AppSettings
下,因此需要通过添加一个冒号:
的方式进行获取:
string defaultLanguage = configuration["AppSettings:DefaultLanguage"];
string minLevel = configuration["AppSettings:MinLevel"];
string maxLevel = configuration["AppSettings:MaxLevel"];
3.2.4、三级子节点
三级节点Longitude
、Latitude
位于二级节点Center
下,因此需要通过添加两个冒号::
的方式进行获取:
string longitude = configuration["AppSettings:Center:Longitude"];
string Latitude = configuration["AppSettings:Center:Latitude"];
通过配置节点名称获取配置参数的方法比较直观,在写法上只需要注意配置节点所在的层级即可,程序运行结果如下图所示:
4、基于配置文件实体类的读取
4.1、构建配置文件实体类
ASP.NET Core
也允许通过配置文件实体类的方式读取配置文件。首先根据appsettings.json
中各个节点的层级关系构建相应实体类ConfigModel
,其代码如下所示:
namespace App
{
public class ConfigModel
{
public ConnectionStrings ConnectionStrings { get; set; }
public string AppName { get; set; }
public string Author { get; set; }
public AppSettings AppSettings { get; set; }
}
public class ConnectionStrings
{
public string ConnectionString { get; set; }
}
public class AppSettings
{
public string DefaultLanguage { get; set; }
public int MinLevel { get; set; }
public int MaxLevel { get; set; }
public Center Center { get; set; }
}
public class Center
{
public double Longitude { get; set; }
public double Latitude { get; set; }
}
}
4.2、注册配置文件实体类
在构建完配置文件实体类后,我们需要在Startup.cs
文件中对其进行注册,调用services.Configure
方法即可,代码如下所示:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace App
{
public class Startup
{
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();
// 注册配置文件实体类
services.Configure<ConfigModel>(Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
4.3、注入IOptions接口
这里需要注意,原先通过配置节点名称读取配置参数值的时候,我们注入的是IConfiguration
接口,而这里则需要换成IOptions
接口,最后通过IOptions.Value
获取实体类。由于IOptions
接口默认存在于IoC
容器中,因此无需手动对其进行注册。其代码如下所示:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly ConfigModel model;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="options"></param>
public HomeController(IOptions<ConfigModel> options)
{
this.model = options.Value;
}
}
}
4.4、读取配置参数
现在我们已经获取了配置文件实体类,接下来的工作很简单了,由于是强类型操作,Visual Studio 2019
会帮助你自动感知配置项,其代码如下所示:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly ConfigModel model;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="options"></param>
public HomeController(IOptions<ConfigModel> options)
{
this.model = options.Value;
}
/// <summary>
/// 读取配置参数
/// </summary>
/// <returns></returns>
[HttpGet]
public string Get()
{
string connectionString = model.ConnectionStrings.ConnectionString;
string appName = model.AppName;
string author = model.Author;
string defaultLanguage = model.AppSettings.DefaultLanguage;
int minLevel = model.AppSettings.MinLevel;
int maxLevel = model.AppSettings.MaxLevel;
double longitude = model.AppSettings.Center.Longitude;
double latitude = model.AppSettings.Center.Latitude;
return connectionString + "\n" + appName + "\n" + author + "\n" +
defaultLanguage + "\n" + minLevel + "\n" + maxLevel + "\n" +
longitude + "\n" + latitude;
}
}
}
与IConfiguration
接口读取配置参数的方法相比,IOptions
接口的优势是可以利用实体类进行映射和读取,这也可以杜绝由于写错配置项名称而引起错误的弊端。程序运行结果如下图所示:
5、写入配置文件
5.1、获取appsettings.json的路径
其实在实际开发过程中,微软并不推荐开发者对appsettings.json
文件进行动态修改,一些需要动态配置的参数最好写在其他文件中,但在某些特殊情况下我们还是得这么干。话说回来,既然涉及到文件修改,那我们肯定得先获取这个文件的路径,否则一切免谈。在ASP.NET Core
中,如果要获取一个文件的路径,我们可以使用IWebHostEnvironment
接口,在使用时只需要将其注入控制器的构造函数即可,由于它已经默认存在于IoC
容器中,因此我们无需进行手动注册,代码如下所示:
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using System.IO;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly IWebHostEnvironment webHostEnvironment;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="webHostEnvironment"></param>
public HomeController(IWebHostEnvironment webHostEnvironment)
{
this.webHostEnvironment = webHostEnvironment;
}
/// <summary>
/// 获取文件路径
/// </summary>
/// <returns></returns>
[HttpGet]
public string Get()
{
string filePath = Path.Combine(webHostEnvironment.ContentRootPath, "appsettings.json");
return filePath;
}
}
}
运行一下程序,发现可以正确获取appsettings.json
文件的路径,如下图所示:
5.2、修改配置参数
我们可以借助Newtonsoft.Json
来实现配置参数的修改,使用NuGet
将其引入,如下图所示:
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using System.IO;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly IWebHostEnvironment webHostEnvironment;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="webHostEnvironment"></param>
public HomeController(IWebHostEnvironment webHostEnvironment)
{
this.webHostEnvironment = webHostEnvironment;
}
/// <summary>
/// 修改配置参数
/// </summary>
/// <returns></returns>
[HttpGet]
public string Get()
{
try
{
// 读取appsettings.json文本内容
string filePath = Path.Combine(webHostEnvironment.ContentRootPath, "appsettings.json");
string text = System.IO.File.ReadAllText(filePath);
// 修改配置项
JObject obj = JObject.Parse(text);
obj["AppName"] = "API";
obj["Author"] = "Herry";
obj["AppSettings"]["DefaultLanguage"] = "en-US";
obj["AppSettings"]["MinLevel"] = 15;
obj["AppSettings"]["MaxLevel"] = 20;
obj["AppSettings"]["Center"]["Longitude"] = 130;
obj["AppSettings"]["Center"]["Latitude"] = 40;
// 重新写入appsettings.json
string result = obj.ToString();
System.IO.File.WriteAllText(filePath, result);
return "success";
}
catch
{
return "failed";
}
}
}
}
运行程序,发现appsettings.json
的配置项修改成功。但也可以发现一个问题:原先的注释都没了,因此最好不要对该文件进行动态修改。程序运行结果如下图所示:
5.3、注入IOptionsSnapshot接口
现在我们已经实现了appsettings.json
文件的修改,但如果仍旧使用IOptions
接口读取配置参数会怎么样呢?看下面一段代码:
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using System.IO;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly IWebHostEnvironment webHostEnvironment;
private readonly ConfigModel model;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="webHostEnvironment"></param>
/// <param name="options"></param>
public HomeController(IWebHostEnvironment webHostEnvironment,
IOptions<ConfigModel> options)
{
this.webHostEnvironment = webHostEnvironment;
this.model = options.Value;
}
/// <summary>
/// 修改配置参数
/// </summary>
/// <returns></returns>
[HttpGet]
public string Get()
{
try
{
// 读取appsettings.json文本内容
string filePath = Path.Combine(webHostEnvironment.ContentRootPath, "appsettings.json");
string text = System.IO.File.ReadAllText(filePath);
// 修改
JObject obj = JObject.Parse(text);
obj["AppName"] = "API";
obj["Author"] = "Herry";
obj["AppSettings"]["DefaultLanguage"] = "en-US";
obj["AppSettings"]["MinLevel"] = 15;
obj["AppSettings"]["MaxLevel"] = 20;
obj["AppSettings"]["Center"]["Longitude"] = 130;
obj["AppSettings"]["Center"]["Latitude"] = 40;
// 重新写入appsettings.json
string result = obj.ToString();
System.IO.File.WriteAllText(filePath, result);
return "success";
}
catch
{
return "failed";
}
}
/// <summary>
/// 读取配置参数
/// </summary>
/// <returns></returns>
[HttpGet]
public string Get_2()
{
string connectionString = model.ConnectionStrings.ConnectionString;
string appName = model.AppName;
string author = model.Author;
string defaultLanguage = model.AppSettings.DefaultLanguage;
int minLevel = model.AppSettings.MinLevel;
int maxLevel = model.AppSettings.MaxLevel;
double longitude = model.AppSettings.Center.Longitude;
double latitude = model.AppSettings.Center.Latitude;
return connectionString + "\n" + appName + "\n" + author + "\n" +
defaultLanguage + "\n" + minLevel + "\n" + maxLevel + "\n" +
longitude + "\n" + latitude;
}
}
}
在执行完Get
方法后,我们再执行Get_2
方法,发现好像不太对,怎么读出来的还是修改前的配置参数?
其实,如果对appsettings.json
文件做了修改,那么就不能使用IOptions
接口去读取配置参数了,因为该接口实例被注册为全局单例生命周期,因此无法读到最新的配置参数。在这种情况下,我们需要使用另一个接口来实现配置参数的读取,那就是IOptionsSnapshot
接口,由于该接口被注册为域生命周期,因此每次http
访问都能读取到最新配置,其代码如下所示:
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Newtonsoft.Json.Linq;
using System.IO;
namespace App.Controllers
{
[Route("api/[controller]/[action]")]
[ApiController]
public class HomeController : ControllerBase
{
private readonly IWebHostEnvironment webHostEnvironment;
private readonly ConfigModel model;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="webHostEnvironment"></param>
/// <param name="options"></param>
public HomeController(IWebHostEnvironment webHostEnvironment,
IOptionsSnapshot<ConfigModel> options)
{
this.webHostEnvironment = webHostEnvironment;
this.model = options.Value;
}
/// <summary>
/// 修改配置参数
/// </summary>
/// <returns></returns>
[HttpGet]
public string Get()
{
try
{
// 读取appsettings.json文本内容
string filePath = Path.Combine(webHostEnvironment.ContentRootPath, "appsettings.json");
string text = System.IO.File.ReadAllText(filePath);
// 修改
JObject obj = JObject.Parse(text);
obj["AppName"] = "API";
obj["Author"] = "Herry";
obj["AppSettings"]["DefaultLanguage"] = "en-US";
obj["AppSettings"]["MinLevel"] = 15;
obj["AppSettings"]["MaxLevel"] = 20;
obj["AppSettings"]["Center"]["Longitude"] = 130;
obj["AppSettings"]["Center"]["Latitude"] = 40;
// 重新写入appsettings.json
string result = obj.ToString();
System.IO.File.WriteAllText(filePath, result);
return "success";
}
catch
{
return "failed";
}
}
/// <summary>
/// 读取配置参数
/// </summary>
/// <returns></returns>
[HttpGet]
public string Get_2()
{
string connectionString = model.ConnectionStrings.ConnectionString;
string appName = model.AppName;
string author = model.Author;
string defaultLanguage = model.AppSettings.DefaultLanguage;
int minLevel = model.AppSettings.MinLevel;
int maxLevel = model.AppSettings.MaxLevel;
double longitude = model.AppSettings.Center.Longitude;
double latitude = model.AppSettings.Center.Latitude;
return connectionString + "\n" + appName + "\n" + author + "\n" +
defaultLanguage + "\n" + minLevel + "\n" + maxLevel + "\n" +
longitude + "\n" + latitude;
}
}
}
运行程序,发现可以读取到最新的配置参数,结果如下图所示:
6、结语
本文主要介绍了ASP.NET Core
中配置文件的读写方法。在实际开发过程中,如果涉及到项目迁移,即:之前已经存在很多配置参数,我们可以使用IConfiguration
接口读取配置参数,如果是新的项目,则可以考虑使用IOptions
接口读取,因为强类型的读取方法可以避免因配置项名称写错而引发的一系列问题。