<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      邁向現(xiàn)代化的 .Net 配置指北

      1. 歡呼 .NET Standard 時(shí)代

      我現(xiàn)在已不大提 .Net Core,對(duì)于我來(lái)說(shuō),未來(lái)的開發(fā)將是基于 .NET Standard,不僅僅是 面向未來(lái) ,也是 面向過(guò)去;不只是 .Net Core 可以享受便利, .NET Framework 不升級(jí)一樣能享受 .NET Standard 帶來(lái)的好處。(目前 .NET Standard 支持 .NET Framework 4.6.1+)

      2. 傳統(tǒng)配置的不足

      在我剛步足 .Net 的世界時(shí),曾經(jīng)有過(guò)一個(gè) 困惑,是不是所有的配置都必須寫在 Web.Config 中?而直到開始學(xué)習(xí) .Net Core 的配置模式,才意識(shí)到傳統(tǒng)配置的不足:

      • 除了 XML ,我們可能還需要更多的配置來(lái)源支持,比如 Json
      • 配置是否可以直接序列化成對(duì)象或者多種類型(直接取出來(lái)就是 int),而不只是 string
      • 修改配置后,IIS 就重啟了,是否有辦法不重啟就能修改配置
      • 微服務(wù)(或者說(shuō)分布式)應(yīng)用下管理配置帶來(lái)的困難

      很顯然微軟也意識(shí)到這些問(wèn)題,并且設(shè)計(jì)出了一個(gè)強(qiáng)大并且客制化的配置方式,但是這也意味著從 AppSettings 中取出配置的時(shí)代也一去不復(fù)返。

      3. 初識(shí) IConfiguration

      在開始探討現(xiàn)代化配置設(shè)計(jì)之前,我們先快速上手 .Net Core 中自帶的 Microsoft.Extensions.Configuration

      如前面提到的,這不是 .Net Core 的專屬。我們首先創(chuàng)建一個(gè)基于 .NET Framework 4.6.1 的控制臺(tái)應(yīng)用 ( 代碼地址),然后安裝我們所需要的依賴。

      Nuget Install Microsoft.Extensions.Configuration.Json
      Nuget Install Microsoft.Extensions.Configuration.Binder
      

      然后引入我們的配置文件 my.conf:

      {
        "TestConfig": {
          "starship": {
            "name": "USS Enterprise",
            "registry": "NCC-1701",
            "class": "Constitution",
            "length": 304.8,
            "commissioned": false
          },
          "trademark": "Paramount Pictures Corp. http://www.paramount.com"
        }
      }
      

      最后,輸入如下的代碼,并啟動(dòng):

        var configurationBuilder = new ConfigurationBuilder().AddJsonFile("my.conf", optional: true, reloadOnChange: true)
                                      .AddInMemoryCollection(new List<KeyValuePair<String, String>>
                      {
                          new KeyValuePair<String,String>("myString","myString"),
                          new KeyValuePair<String,String>("otherString","otherString")
                      });
                  IConfiguration config = configurationBuilder.Build();
                  String myString = config["myString"]; //myString
                  TestConfig testConfig = config.GetSection("TestConfig").Get<TestConfig>();
                  var length = testConfig.Starship.Length;//304.8
                  Console.WriteLine($"myString:{myString}");
                  Console.WriteLine($"myString:{JsonConvert.SerializeObject(testConfig)}");
                  Console.ReadKey();
      

      微信截圖_20180908172500.png

      微軟 支持 的來(lái)源除了有內(nèi)存來(lái)源、還有系統(tǒng)變量Json 文件、XML 文件等多種配置來(lái)源,同時(shí)社區(qū)的開源帶來(lái)了更多可能性,還支持諸如 consuletcdapollo分布式配置中心

      除了支持更多的配置來(lái)源外,我們還觀察到,來(lái)源是否可以 缺省 、是否可以 重載 ,都是可以配置的。特別是自動(dòng)重載,這在 .NETFramework 時(shí)代是無(wú)法想象的,每當(dāng)我們修改 Web.config的配置文件時(shí),熱心的 IIS 就會(huì)自動(dòng)幫我們重啟應(yīng)用,而用戶在看到 500 的提示或者一片空白時(shí),不禁會(huì)發(fā)出這網(wǎng)站真爛的贊美。(同時(shí)需要注意配置 iis 的安全,避免可以直接訪問(wèn)配置的 json 文件,最好的方法是把json后綴改為諸如 conf 等)

      4. 配置防腐層

      雖然微軟自帶的 IConfiguration 已經(jīng)足夠用了,但是讓我們暢享下未來(lái),或者回到我讓我困惑的問(wèn)題。是不是所有的配置都將基于 IConfiguration ? 答案自然是否定的,編程技術(shù)不停地在發(fā)展,即使老而彌堅(jiān)的 AppSetting 也難逃被淘汰的一天。所以為了讓我們的架構(gòu)更長(zhǎng)遠(yuǎn)一些,我們需要進(jìn)行 防腐層的設(shè)計(jì)。而且,如果你還在維護(hù)以前的老項(xiàng)目時(shí),你更是需要借助防腐層的魔法去抵消同事或者上司的顧慮。

      讓我們重新審視配置的用法,無(wú)非就是從某個(gè) key 獲取對(duì)應(yīng)的值(可能是字符串、也可能是個(gè)對(duì)象),所以我們可以在最底層的類庫(kù)或全局類庫(kù)中定義一個(gè) IConfigurationGeter 來(lái)滿足我們的要求。

      namespace ZHS.Configuration.Core
      
      public interface IConfigurationGeter
       {
          TConfig Get<TConfig>(string key);
          String this[string key] { get;}
      }
      

      而關(guān)于 IConfigurationGeter 的實(shí)現(xiàn),我們姑且叫它 ConfigurationGetter ,基于防腐層的設(shè)計(jì),我們不能在底層的類庫(kù)安裝任何依賴。所以我們需要新建一個(gè)基礎(chǔ)設(shè)施層或者在應(yīng)用入口層實(shí)現(xiàn)。(代碼示例中可以看到是在不同的項(xiàng)目中)

         namespace ZHS.Configuration.DotNetCore
      
         public class ConfigurationGetter : IConfigurationGeter
          {
              private readonly IConfiguration _configuration;
      
              public ConfigurationGetter(IConfiguration configuration)
              {
                  _configuration = configuration;
              }
      
              public TConfig Get<TConfig>(string key)
              {
                  if (string.IsNullOrWhiteSpace(key))
                      throw new ArgumentException("Value cannot be null or whitespace.", nameof(key));
                  var section = _configuration.GetSection(key);
                  return section.Get<TConfig>();
              }
              public string this[string key] => _configuration[key];
          }
      

      以后我們所有的配置都是通過(guò) IConfigurationGeter 獲取,這樣就避免了在你的應(yīng)用層(或者三層架構(gòu)中的 BAL 層) 中引入 Microsoft.Extensions.Configuration 的依賴。當(dāng)然可能有些人會(huì)覺得大材小用,但實(shí)際上等你到了真正的開發(fā),你就會(huì)覺得其中的好處。不止是我,.Net Core 的設(shè)計(jì)者早就意識(shí)到防腐層的重要性,所以才會(huì)有 Microsoft.Extensions.Configuration.Abstractions 等一系列的只有接口的抽象基庫(kù)。

      5. 靜態(tài)獲取配置

      雖然我們已經(jīng)有了防腐層,但顯然我們還沒考慮到實(shí)際的用法,特別是如果你的應(yīng)用還沒有引入依賴注入的支持,我們前面實(shí)現(xiàn)的防腐層對(duì)于你來(lái)說(shuō),就是摸不著頭腦。同時(shí),我還是很喜歡以前那種直接從 AppSetting 中取出配置的便捷。所以,這里我們需要引入 服務(wù)定位器模式 來(lái)滿足 靜態(tài)獲取配置 的便捷操作。

      namespace ZHS.Configuration.Core
      
      public class ConfigurationGeterLocator
      {
         private readonly IConfigurationGeter _currentServiceProvider;
      
         private static IConfigurationGeter _serviceProvider;
      
          public ConfigurationGeterLocator(IConfigurationGeter currentServiceProvider)
          {
            _currentServiceProvider = currentServiceProvider;
          }
      
          public static ConfigurationGeterLocator Current => new ConfigurationGeterLocator(_serviceProvider);
      
          public static void SetLocatorProvider(IConfigurationGeter serviceProvider)
          {
           _serviceProvider = serviceProvider;
          }
      
          public TConfig Get<TConfig>(String key)
           {
             return _currentServiceProvider.Get<TConfig>(key);
           }
      
           public  String this[string key] => _currentServiceProvider[key];
      }
      
             public static IConfiguration AddConfigurationGeterLocator(this IConfiguration configuration)
              {
                  ConfigurationGeterLocator.SetLocatorProvider(new ConfigurationGetter(configuration));
                  return configuration;
              }
      

      做完這些基礎(chǔ)工作,我們還需要在應(yīng)用入口函數(shù)念一句咒語(yǔ)讓他生效。

      config.AddConfigurationGeterLocator();
      var myString = ConfigurationGeterLocator.Current["myString"];// "myString"
      

      現(xiàn)在,我們就能像以前一樣,直接調(diào)用 ConfigurationGeterLocator.Current 來(lái)獲取我們想要的配置了。

      6. 依賴注入的曙光

      現(xiàn)在假設(shè)我們擺脫了蠻荒時(shí)代,有了依賴注入的武器,使用配置最方便的用法莫不過(guò)直接注入一個(gè)配置對(duì)象,在 .Net Core 中做法大致如下:

      public void ConfigureServices(IServiceCollection services)
      {
          services.AddScoped<TestConfig>(provider =>Configuration.GetSection("TestConfig").Get<TestConfig>());
      }
      

      而它的使用就十分方便:

      public class ValuesController : ControllerBase
          {
              private readonly TestConfig _testConfig;
      
              public ValuesController(TestConfig testConfig)
              {
                  _testConfig = testConfig;
              }
      
              // GET api/values
              [HttpGet]
              public JsonResult Get()
              {
                  var data = new
                  {
                     TestConfig = _testConfig
                  };
                  return new JsonResult(data);
              }
          }
      

      看到這里你可能會(huì)困惑,怎么和官方推薦的 IOptions 用法不一樣? 盡管它在官方文檔備受到推崇,然而在實(shí)際開發(fā)中,我是幾乎不會(huì)使用到的,在我看來(lái):

      • 不使用 IOptions 就已經(jīng)得到了對(duì)應(yīng)的效果
      • 使用 IOptionsSnapshot 才能約束配置是否需要熱重載,但實(shí)際這個(gè)并不好控制(所以雞肋)
      • 我們已經(jīng)有防腐層了,再引入就是破壞了設(shè)計(jì)

      7. 約定優(yōu)于配置的福音

      在微服務(wù)應(yīng)用流行的今天,我們需要的配置類會(huì)越來(lái)越多。我們不停地注入,最終累死編輯器,是否有自動(dòng)化注入的方法來(lái)解放我們的鍵盤?答案自然是有的,然而在動(dòng)手實(shí)現(xiàn)之前,我們需要立下 約定優(yōu)于配置 的海誓山盟。

      首先,對(duì)于所有的配置類,他們都可以看作是一類或者某個(gè)接口的實(shí)現(xiàn)。

      public interface IConfigModel{ }
      
      public class TestConfig : IConfigModel
       {
           public String DefauleVaule { get; set; } = "Hello World";
           public Starship Starship { get; set; }
           public string Trademark { get; set; }
      }
      
      public class Starship
      {
          public string Name { get; set; }
          public string Registry { get; set; }
          public string Class { get; set; }
          public float Length { get; set; }
          public bool Commissioned { get; set; }
      }
      

      聯(lián)想我們剛剛注入 TestConfig 的時(shí)候,是不是指定了配置節(jié)點(diǎn) "TestConfig" ,那么如果我們要自動(dòng)注入的話,是不是可以考慮直接使用類的唯一標(biāo)志,比如類的全名,那么注入的方法就可以修改為如下:

      public static IServiceCollection AddConfigModel(this IServiceCollection services)
      {
                var types = AppDomain.CurrentDomain.GetAssemblies()
                      .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IConfigModel))))
                      .ToArray();
      
                foreach (var type in types)
                  {
                      services.AddScoped(type, provider =>
                      {
                          var config = provider.GetService<IConfiguration>().GetSection(type.FullName).Get(type);
                          return config;
                      });
                  }
                  return services;
      }
      

      僅僅用了類的全名還不夠體現(xiàn) 約定優(yōu)于配置 的威力,聯(lián)系現(xiàn)實(shí),是不是配置的某些選項(xiàng)是有默認(rèn)值的,比如 TestConfigDefauleVaule 。在沒有配置 DefauleVaule 的情況下,DefauleVaule 的值將為 默認(rèn)值 ,即我們代碼中的 "Hello World" ,反之設(shè)置了 DefauleVaule 則會(huì)覆蓋掉原來(lái)的默認(rèn)值。

      8. 分布式配置中心

      在微服務(wù)流行的今天,如果還是像以前一樣人工改動(dòng)配置文件,那是十分麻煩而且容易出錯(cuò)的一件事情,這就需要引入配置中心,同時(shí)配置中心也必須是分布式的,才能避免單點(diǎn)故障。

      8.1 Consul

      Consul 目前是我的首選方案,首先它足夠簡(jiǎn)單,部署方便,同時(shí)已經(jīng)夠用了。如果你還使用過(guò) Consul,可以使用 Docker 一鍵部署:

      docker run -d -p 8500:8500  --name consul  consul
      

      然后在應(yīng)用入口項(xiàng)目中引入 Winton.Extensions.Configuration.Consul 的依賴。因?yàn)槭莻€(gè)人開源,所以難免會(huì)有一些問(wèn)題,比如我裝的版本就是 2.1.0-master0003,它解決了 2.0.1 中的一些問(wèn)題,但還沒有發(fā)布正式版。

      8.1.1 .Net Core 使用 Consul 配置中心

      如果你是 .Net Core 應(yīng)用,你需要在 Program.cs 配置 ConfigureAppConfiguration:

          public class Program
          {
              public static readonly CancellationTokenSource ConfigCancellationTokenSource = new CancellationTokenSource();
      
              public static void Main(string[] args)
              {
                  CreateWebHostBuilder(args).Build().Run();
              }
      
              public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
                  WebHost.CreateDefaultBuilder(args)
                      .ConfigureAppConfiguration((builderContext, config) =>
                      {
                          IHostingEnvironment env = builderContext.HostingEnvironment;
                          var tempConfigBuilder = config;
                          var key = $"{env.ApplicationName}.{env.EnvironmentName}";//ZHS.Configuration.DotNetCore.Consul.Development
                          config.AddConsul(key, ConfigCancellationTokenSource.Token, options =>
                          {
                              options.ConsulConfigurationOptions =
                                  co => { co.Address = new Uri("http://127.0.0.1:8500"); };
                              options.ReloadOnChange = true;
                              options.Optional = true;
                              options.OnLoadException = exceptionContext =>
                              {
                                  exceptionContext.Ignore = true;
                              };
                          });
                      })
                      .UseStartup<Startup>();
          }
      

      同時(shí)由于 .Net 客戶端與 Consul 之間交互會(huì)使用長(zhǎng)輪詢,所以我們需要在關(guān)閉應(yīng)用的同時(shí)也要記得把連接回收,這就需要在 Startup.csConfigure 中處理:

      public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime appLifetime)
       {
           appLifetime.ApplicationStopping.Register(Program.ConfigCancellationTokenSource.Cancel);
       }
      

      8.1.2 .NET Framework 使用 Consul 配置中心

      同理,對(duì)于 .NET Framework 應(yīng)用來(lái)說(shuō),也是需要做對(duì)應(yīng)的處理,在 Global.asax 中:

      public class WebApiApplication : System.Web.HttpApplication
          {
              public static readonly CancellationTokenSource ConfigCancellationTokenSource = new CancellationTokenSource();
      
              protected void Application_Start()
              {
                  AddConsul();
                  GlobalConfiguration.Configure(WebApiConfig.Register);
              }
      
              private static void AddConsul()
              {
                  var config = new ConfigurationBuilder();
                  config.AddConsul("ZHS.Configuration.DotNetCore.Consul.Development", ConfigCancellationTokenSource.Token, options =>
                  {
                      options.ConsulConfigurationOptions =
                          co => { co.Address = new Uri("http://127.0.0.1:8500"); };
                      options.ReloadOnChange = true;
                      options.Optional = true;
                      options.OnLoadException = exceptionContext =>
                      {
                          exceptionContext.Ignore = true;
                      };
                  });
                  //var test = config.Build();
                  config.Build().AddConfigurationGeterLocator();
              }
      
              protected void Application_End(object sender, EventArgs e)
              {
                  ConfigCancellationTokenSource.Cancel();
              }
          }
      

      8.1.3 配置 Consul

      我們所說(shuō)的配置,對(duì)于 Consul 來(lái)說(shuō),就是 Key/Value 。我們有兩種配置,一種是把以前的json配置文件都寫到一個(gè)key 中。

      單個(gè)key包含全部配置

      另一種就是創(chuàng)建一個(gè) key 的目錄,然后每個(gè) Section 分開配置。

      分開配置

      9. 結(jié)語(yǔ)

      寫這篇文章很大的動(dòng)力是看到不少 .Net Core 初學(xué)者抱怨使用配置中的各種坑,抱怨微軟文檔不夠清晰,同時(shí)也算是我兩年來(lái)的一些開發(fā)經(jīng)驗(yàn)總結(jié)。

      最后,需要談一下感想。感受最多的莫過(guò)于 .Net Core 開源帶來(lái)的沖擊,有很多開發(fā)者興致勃勃地想要把傳統(tǒng)的項(xiàng)目重構(gòu)成 .Net Core 項(xiàng)目,然而思想?yún)s沒有升級(jí)上去,反而越覺得 .Net Core 各種不適。但是只要思想升級(jí)了,即使開發(fā) .NET Framework 應(yīng)用, 一樣也是能享受 .NET Standard 帶來(lái)的便利。


      在本文的撰寫過(guò)程中,可能會(huì)存在疏漏,但我會(huì)盡量及時(shí)做出一些增刪改,所以如果是在轉(zhuǎn)載上看到的,內(nèi)容可能是過(guò)時(shí)的,還請(qǐng)移步 我的博客 ,同時(shí)本文的 示例代碼 也會(huì)做相應(yīng)的修改。

      posted @ 2018-09-08 19:36  張蘅水  閱讀(3059)  評(píng)論(18)    收藏  舉報(bào)
      主站蜘蛛池模板: 亚洲卡1卡2卡3精品| 放荡的少妇2欧美版| 久久精品国产一区二区蜜芽| 亚洲产在线精品亚洲第一站一| 丁香婷婷色综合激情五月| 日本熟妇浓毛hdsex| 九九久久人妻一区精品色| 日本高清视频网站www| 女同另类激情在线三区| 亚洲av无码一区二区三区网站| 国产自拍偷拍视频在线观看| 女主播扒开屁股给粉丝看尿口| 国产另类ts人妖一区二区| 久久久久国产精品人妻| 国产很色很黄很大爽的视频| 洪湖市| 亚洲熟女乱综合一区二区| 影音先锋啪啪av资源网站| 久久国产乱子伦免费精品| 成人区人妻精品一区二蜜臀| 国产999久久高清免费观看| 日日躁夜夜躁狠狠久久av | 好吊视频一区二区三区人妖| 成年女人片免费视频播放A| 天堂网av一区二区三区| 亚洲av无码专区在线亚| AV人摸人人人澡人人超碰| 国产色婷婷亚洲99精品小说| 国产成人精品高清不卡在线| 在线播放深夜精品三级| 亚洲精品一区二区三区蜜臀| 午夜福利国产精品视频| 威信县| 欧美成人午夜精品免费福利| 四虎成人免费视频在线播放| 国产精品有码在线观看| 免费无码黄十八禁网站| 亚洲国产成人久久精品app| 加勒比无码人妻东京热| 乱女乱妇熟女熟妇综合网| 日韩精品av一区二区三区|