这篇文章给大家介绍如何在.Net Core中自定义配置源,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
模拟配置中心
我们新建一个asp.net core webapi站点来模拟配置中心服务,端口配置到5000,并添加相应的controller来模拟配置中心对外的接口。
[Route("api/[controller]")]
[ApiController]
public class ConfigsController : ControllerBase
{
public List<KeyValuePair<string,string>> Get()
{
var configs = new List<KeyValuePair<string, string>>();
configs.Add(new KeyValuePair<string, string>("SecretKey","1238918290381923"));
configs.Add(new KeyValuePair<string, string>("ConnectionString", "user=123;password=123;server=."));
return configs;
}
}
添加一个configscontroller,并修改Get方法,返回2个配置键值对。
访问下/api/configs看下返回是否正确
自定义配置源
从现在开始我们真正开始来定义一个自定义的配置源然后当程序启动的时候从配置中心读取配置文件信息,并提供给后面的代码使用配置。
新建一个asp.net core mvc站点来模拟客户端程序。
MyConfigProvider
public class MyConfigProvider : ConfigurationProvider
{
/// <summary>
/// 尝试从远程配置中心读取配置信息
/// </summary>
public async override void Load()
{
var response = "";
try
{
var serverAddress = "http://localhost:5000";
var client = new HttpClient();
client.BaseAddress = new Uri(serverAddress);
response = await client.GetStringAsync("/api/configs");
}
catch (Exception ex)
{
//write err log
}
if (string.IsNullOrEmpty(response))
{
throw new Exception("Can not request configs from remote config center .");
}
var configs = JsonConvert.DeserializeObject<List<KeyValuePair<string, string>>>(response);
Data = new ConcurrentDictionary<string, string>();
configs.ForEach(c =>
{
Data.Add(c);
});
}
}
新建一个MyConfigProvider的类,这个类从ConfigurationProvider继承,并重写其中的Load方法。使用HttpClient从配置中心读取信息后,进行反序列化,并把配置转换为字典。这里注意一下,虽然Data的类型为IDictionary<string,string>,但是这里实例化对象的时候使用了ConcurrentDictionary<string, string>类,因为Dictionary<string,string>是非线程安全的,如果进行多线程读写会出问题。
MyConfigSource
public class MyConfigSource : IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new MyConfigProvider();
}
}
新建一个MyConfigSource的类,这个类实现IConfigurationSource接口,IConfigurationSource接口只有一个Build方法,返回值为IConfigurationProvider,我们刚才定义的MyConfigProvider因为继承自ConfigurationProvider所以已经实现了IConfigurationProvider,我们直接new一个MyConfigProvider并返回。
MyConfigBuilderExt
public static class MyConfigBuilderExt
{
public static IConfigurationBuilder AddMyConfig(
this IConfigurationBuilder builder
)
{
return builder.Add(new MyConfigSource());
}
}
给IConfigurationBuilder定义一个AddMyConfig的扩展方法,跟.Net Core自带的几个配置源使用风格保持一致。当调用AddMyConfig的时候给IConfigurationBuilder实例添加一个MyConfigSource的源。
使用配置源
在Program中添加MyConfigSource
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, configBuiler) =>
{
configBuiler.AddMyConfig();
})
.UseStartup<Startup>();
}
在ConfigureAppConfiguration的匿名委托方法中调用AddMyConfig扩展方法,这样程序启动的时候会自动使用MyConfigSource源并从配置中心读取配置到本地应用程序。
修改HomeController
public class HomeController : Controller
{
IConfiguration _configuration;
public HomeController(IConfiguration configuration)
{
_configuration = configuration;
}
public IActionResult Index()
{
var secretKey = _configuration["SecretKey"];
var connectionString = _configuration["ConnectionString"];
ViewBag.SecretKey = secretKey;
ViewBag.ConnectionString = connectionString;
return View();
}
}
修改homecontroller,把IConfiguration通过构造函数注入进去,在Index Action方法中读取配置,并赋值给ViewBag
修改Index视图
@{
ViewData["Title"] = "Test my config";
}
<h4>
SecretKey: @ViewBag.SecretKey
</h4>
<h4>
ConnectionString: @ViewBag.ConnectionString
</h4>
修改Index视图的代码,把配置信息从ViewBag中读取出来并在网页上展示。
运行一下
先运行配置中心站点再运行一下网站,首页出现了我们在配置中心定义的SecretKey跟ConnectionString信息,表示我们的程序成功的从配置中心读取了配置信息。我们的自定义配置源已经能够成功运行了。
改进
以上配置源虽然能够成功运行,但是仔细看的话显然它有2个比较大的问题。
配置中心的服务地址是写死在类里的。我们的配置中心很有可能会修改ip或者域名,写死在代码里显然不是高明之举,所以我们还是需要保留本地配置文件,把配置中心的服务地址写到本地配置文件中。
配置中心作为微服务的基础设施一旦故障会引发非常严重的后果,新启动或者重启的客户端会无法正常启动。如果我们在配置中心正常的时候冗余一份配置在本地,当配置中心故障的时候从本地读取配置,至少可以保证一部分客户端程序能够正常运行。
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"myconfigServer": "http://localhost:5000"
}
修改本地appsettings.json文件,添加myconfigServer的配置信息。
public class MyConfigProvider : ConfigurationProvider
{
private string _serverAddress;
public MyConfigProvider()
{
var jsonConfig = new JsonConfigurationSource();
jsonConfig.FileProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());
jsonConfig.Path = "appsettings.json";
var jsonProvider = new JsonConfigurationProvider(jsonConfig);
jsonProvider.Load();
jsonProvider.TryGet("myconfigServer", out string serverAddress);
if (string.IsNullOrEmpty(serverAddress))
{
throw new Exception("Can not find myconfigServer's address from appsettings.json");
}
_serverAddress = serverAddress;
}
/// <summary>
/// 尝试从远程配置中心读取配置信息,当成功从配置中心读取信息的时候把配置写到本地的myconfig.json文件中,当配置中心无法访问的时候尝试从本地文件恢复配置。
/// </summary>
public async override void Load()
{
var response = "";
try
{
var client = new HttpClient();
client.BaseAddress = new Uri(_serverAddress);
response = await client.GetStringAsync("/api/configs");
WriteToLocal(response);
}
catch (Exception ex)
{
//write err log
response = ReadFromLocal();
}
if (string.IsNullOrEmpty(response))
{
throw new Exception("Can not request configs from remote config center .");
}
var configs = JsonConvert.DeserializeObject<List<KeyValuePair<string, string>>>(response);
Data = new ConcurrentDictionary<string, string>();
configs.ForEach(c =>
{
Data.Add(c);
});
}
private void WriteToLocal(string resp)
{
var file = Directory.GetCurrentDirectory() + "/myconfig.json";
File.WriteAllText(file,resp);
}
private string ReadFromLocal()
{
var file = Directory.GetCurrentDirectory() + "/myconfig.json";
return File.ReadAllText(file);
}
}
关于如何在.Net Core中自定义配置源就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。