.Net Core自定义配置源从配置中心读取配置的方法

 更新时间:2019年03月06日 09:06:53   作者:Agile.Zhou  
这篇文章主要给大家介绍了关于.Net Core自定义配置源从配置中心读取配置的相关资料,文中通过示例代码以及图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

前言

配置,几乎所有的应用程序都离不开它。.Net Framework时代我们使用App.config、Web.config,到了.Net Core的时代我们使用appsettings.json,这些我们再熟悉不过了。然而到了容器化、微服务的时代,这些本地文件配置有的时候就不太合适了。当你把本地部署的服务搬到docker上后,你会发现要修改一个配置文件变的非常麻烦。你不得不通过宿主机进入容器内部来修改文件,也许容器内还不带vi等编辑工具,你连看都不能看,改都不能。更别说当你启动多个容器实例来做分布式应用的时候,一个个去修改容器的配置,这简直要命了。

因为这些原因,所以“配置中心”就诞生了。配置中心是微服务的基础设施,它对配置进行集中的管理并对外暴露接口,当应用程序需要的时候通过接口读取。配置通常为Key/Value模式,然后通过http接口暴露。好了,配置中心不多说了,感觉要偏了,这次是介绍怎么自定义一个配置源从配置中心读取配置。废话不多说直接上代码吧。

模拟配置中心

我们新建一个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";
}

<h3>
 SecretKey: @ViewBag.SecretKey
</h3>
<h3>
 ConnectionString: @ViewBag.ConnectionString
</h3>

修改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);
  }
 }

修改MyConfigProvider,修改构造函数,通过JsonConfigurationProvider从本地读取appsettings.json中的myconfigServer配置信息。新增WriteToLocal方法把配置中心返回的json数据写到本地文件中。新增ReadFromLocal方法,从本地文件读取json信息。

再次运行

先运行配置中心站点,再运行客户端网站,可以看到配置信息展示到首页界面上。关闭配置中心客跟客户端网站,并且重启客户端网站依然能够展示配置信息,说明自定义配置源当配置中心故障的时候成功从本地文件恢复了配置。图跟上面的图是一致的,就不贴了。

总结

通过以上我们定义了一个比较简单的自定义配置源,它能够通过http从配置中心读取配置,并且提供了同传统json配置文件一致的使用风格,最大程度的复用旧代码,减少因为引入配置中心而大规模改动代码。我们从上面的代码可以更清楚的知道.Net Core的配置源是如何工作的。ConfigurationSource只是ConfigurationProvider的建造器。真正完成配置加载、查找工作的是ConfigurationProvider。

以上代码还是演示级别的代码,还有很多改进的空间,比如http访问失败的重试,我们可以使用polly重构;比如支持定时从配置中心刷新配置等,有兴趣可以自己去实践一下。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • .Net集成敏感词组件的步骤

    .Net集成敏感词组件的步骤

    现如今大部分服务都会有用户输入,为了服务的正常运行,很多时候不得不针对输入进行敏感词的检测、替换。如果人工做这样的工作,不仅效率低,成本也高。水弟在这里写了一个让小编姐姐都觉得快的敏感词组件接入示例,不需要依赖第三方服务,只需两分钟即可享受清爽文字。
    2021-05-05
  • 详解ASP.NET Core WebApi 返回统一格式参数

    详解ASP.NET Core WebApi 返回统一格式参数

    这篇文章主要介绍了详解ASP.NET Core WebApi 返回统一格式参数,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • .NET性能调优之一:ANTS Performance Profiler的使用介绍

    .NET性能调优之一:ANTS Performance Profiler的使用介绍

    本系列文章主要会介绍一些.NET性能调优的工具、Web性能优化的规则(如YSlow)及方法等等内容。成文前最不希望看到的就是园子里不间断的“哪个语言好,哪个语言性能高”的争论,不多说,真正的明白人都应该知道这样的争论有没有意义,希望我们能从实际性能优化的角度去讨论问题
    2013-01-01
  • 五步掌握OOM框架AutoMapper基本使用

    五步掌握OOM框架AutoMapper基本使用

    本文主要介绍了OOM框架AutoMapper的相关知识,本篇的五个实例可以帮你解决常见的基本问题。具有一定的参考价值,下面跟着小编一起来看下吧
    2017-01-01
  • asp.net 使用Silverlight操作ASPNETDB数据库

    asp.net 使用Silverlight操作ASPNETDB数据库

    asp.net下使用Silverlight操作ASPNETDB数据库的实现代码
    2010-01-01
  • ASP.NET MVC:Filter和Action的执行介绍

    ASP.NET MVC:Filter和Action的执行介绍

    ASP.NET MVC之Filter和Action的执行介绍,需要的朋友可以参考
    2012-11-11
  • 在vs2008中使用AJAX开发.net 2.0下的Web程序的方法

    在vs2008中使用AJAX开发.net 2.0下的Web程序的方法

    最近做项目需要用到AJAX,但是工作需要必须使用.net 2.0版本;但发现如果项目为.net2.0版本则没有Ajax(web.config已经配置上ajax) ,、工具栏中并不出现Ajax选项卡. 而且新建页面也没有AJAX页面;后来查了很多资料 发现了一种解决方法
    2011-06-06
  • Winform OpenFileDialog打开文件对话框

    Winform OpenFileDialog打开文件对话框

    这篇文章主要为大家详细介绍了Winform OpenFileDialog打开文件对话框 的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • 提取HTML代码中文字的C#函数

    提取HTML代码中文字的C#函数

    提取HTML代码中文字的C#函数...
    2006-09-09
  • 打造自己的.NET Core项目模板

    打造自己的.NET Core项目模板

    这篇文章主要介绍了打造自己的.NET Core项目模板,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04

最新评论