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

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

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

      【5min+】更好的選項(xiàng)實(shí)踐。.Net Core中的IOptions

      系列介紹

      【五分鐘的dotnet】是一個(gè)利用您的碎片化時(shí)間來(lái)學(xué)習(xí)和豐富.net知識(shí)的博文系列。它所包含了.net體系中可能會(huì)涉及到的方方面面,比如C#的小細(xì)節(jié),AspnetCore,微服務(wù)中的.net知識(shí)等等。

      通過(guò)本篇文章您將Get:

      • 不在AspNet CoreStartup.cs中完成mvc的選項(xiàng)配置(比如在其它地方為MVC添加過(guò)濾器等操作)
      • 了解Options的使用
      • 了解IOptionsIOptionsMonitorIOptionsSnapshot的區(qū)別

      時(shí)長(zhǎng)為五分鐘以?xún)?nèi),建議先投幣再上車(chē)觀看??

      正文

      .NET Core為咱們提供的默認(rèn)依賴(lài)注入方式[Microsoft.Extensions.DependencyInjection]相對(duì)來(lái)說(shuō)功能已經(jīng)很完善了,雖然有一些功能沒(méi)有實(shí)現(xiàn)(比如在使用factory進(jìn)行注冊(cè)時(shí)無(wú)法獲取type等),但并不影響我們令接口與實(shí)現(xiàn)進(jìn)行分離。

      某些情況下,您會(huì)發(fā)現(xiàn),當(dāng)我們的業(yè)務(wù)類(lèi)被添加到依賴(lài)注入容器中時(shí),該類(lèi)構(gòu)造函數(shù)中所依賴(lài)的其它類(lèi)都得一同添加到容器(雖然有某些奇技淫巧可以規(guī)避,但是構(gòu)造函數(shù)注入依舊是規(guī)范的手段)。可是,我的一些依賴(lài)類(lèi)為選型類(lèi)型怎么辦呢?比如下面的代碼:

      public class MyBusinessClass
      {
          public MyBusinessClass(SomeOptions options)
          {
              if (options.ShouldOpenTCP)
                  //do something.....
      
              if (options.ShouldLogIndo)
                  // do something
          }
      }
      

      SomeOptions是一個(gè)典型的選項(xiàng)項(xiàng)類(lèi)型,我們通過(guò)它公開(kāi)的一些屬性來(lái)對(duì)項(xiàng)目進(jìn)行配置。而當(dāng)MyBusinessClass被注入到容器的時(shí)候,意味著SomeOptions也需要被注入。

      對(duì)于這種選項(xiàng)類(lèi)型,微軟給出了專(zhuān)門(mén)的處理手段:Microsoft.Extensions.Options包。我們只需要使用該包為IServiceCollection提供的擴(kuò)展方法AddOptions<TOptions>()就可以完成注入選項(xiàng):

      services.AddOptions<SomeOptions>();
      
      public class MyBusinessClass
      {
          public MyBusinessClass(IOptions<SomeOptions> options)
          {
              SomeOptions value = options.Value;
          }
      }
      

      看起來(lái)這和上面的代碼好像區(qū)別也不是很大吧。都是把SomeOptions添加到容器中,那么第二種方法和第一種方法比起來(lái)有什么優(yōu)點(diǎn)呢?微軟專(zhuān)門(mén)推出該方式難道只是為了“年底沖業(yè)績(jī)”?

      x

      非也非也?第二種方式其實(shí)用了更好的解耦思想來(lái)設(shè)計(jì)。假如咱們的SomeOptions需要在其它模塊中修改怎么辦? 如果用第一種直接注入到容易的方案的話(huà),這就十分的困難。而使用AddOptions<TOptions>的方式您就可以輕而易舉。

      Microsoft.Extensions.Options提供了IConfigureOptionsIPostConfigureOptions這兩種類(lèi)似于生命周期鉤子的接口,讓您能夠在讀取選項(xiàng)的時(shí)候,進(jìn)行某些操作。

      在AspNetCore中試一試

      在AspnetCore中就有一個(gè)很明顯的選項(xiàng):MvcOptions,該選項(xiàng)提供了咱們配置MVC項(xiàng)目的各種各樣的參數(shù)。

      //Startup.cs
      
      public void ConfigureServices(IServiceCollection services)
      {
          services.AddControllers(options =>
          {
              options.Filters.Add(new MyFileter());
          });
      }
      

      上面代碼是我們?cè)?code>Startup.cs中配置MvcOptions最最常見(jiàn)的步驟,這里我用添加一個(gè)全局過(guò)濾器來(lái)舉例。

      如果我不想在Startup.cs中添加這句代碼怎么辦呢? 比如我寫(xiě)了一個(gè)第三方的庫(kù),庫(kù)中包含了N個(gè)過(guò)濾器,我肯定沒(méi)有辦法要求用戶(hù)在使用該庫(kù)的時(shí)候?qū)⑦@N個(gè)過(guò)濾器一個(gè)一個(gè)的添加到options中。(這里只是假設(shè),雖然可以使用特性的方式來(lái)完成同樣的過(guò)濾器功能

      這個(gè)時(shí)候就可以拿出我們上面講的一大殺器:IConfigureOptions.

      internal class MvcOptionsConfigure : IConfigureOptions<MvcOptions>
      {
          public void Configure(MvcOptions options)
          {
              options.Filters.Add(new MyFileter());
          }
      }
      
      services.AddSingleton<IConfigureOptions<MvcOptions>, MvcOptionsConfigure>();
      

      這樣就完成了關(guān)注點(diǎn)的分離,我們不需要一直死守著Startup.cs文件不放,也不需要讓用戶(hù)手動(dòng)去配置。只要我們知道IServiceCollection就可以往里面添加我們自己的業(yè)務(wù)點(diǎn)。當(dāng)然,Microsoft.Extensions.Options包還提供了另外的方式讓您可以完成IConfigureOptions的同樣操作,不過(guò)這些操作都是像語(yǔ)法糖一樣,實(shí)質(zhì)上是相同的:

      //和上面同樣的功能
      services.Configure<MvcOptions>(Options =>
      {
           options.Filters.Add(new MyFileter());
      });
      

      IOptions、IOptionsMonitor和IOptionsSnapshot

      在上面其實(shí)我們已經(jīng)見(jiàn)過(guò)了IOptions的尊容,我們可以通過(guò)注入IOptions<MyOptions>來(lái)獲取MyOptions實(shí)例。

      但是!但是!但是!!!! IOptions還有兩個(gè)兄弟IOptionsMonitorIOptionsSnapshot。光名字上長(zhǎng)的就很像了,它們都還有類(lèi)似于“Value”的屬性來(lái)獲取選項(xiàng)實(shí)例。

      媽呀,那么它們到底有什么不同呢?什么時(shí)候該用老大,什么使用該用老二呢? 接下來(lái),年度最佳找不同大戲即將開(kāi)始………………

      先來(lái)看看IOptionsIOptionsSnapshot吧,看看它們的接口定義:

      /// <summary>
      /// Used to access the value of <typeparamref name="TOptions"/> for the lifetime of a request.
      /// </summary>
      /// <typeparam name="TOptions">Options type.</typeparam>
      public interface IOptionsSnapshot<out TOptions> : IOptions<TOptions> where TOptions : class, new()
      {
          /// <summary>
          /// Returns a configured <typeparamref name="TOptions"/> instance with the given name.
          /// </summary>
          TOptions Get(string name);
      }
      

      我天,居然IOptionsSnapshot還繼承了IOptions,而且只是多了一個(gè)Get方法,那么是否這兩個(gè)類(lèi)其實(shí)很相似呢?我們直接來(lái)看看源碼:

      services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptions<>), typeof(OptionsManager<>)));
      services.TryAdd(ServiceDescriptor.Scoped(typeof(IOptionsSnapshot<>), typeof(OptionsManager<>)));
      

      納尼?這都還不是相似不相似的問(wèn)題,這TM不是同一個(gè)實(shí)現(xiàn)嗎?只是接口類(lèi)型不同而已,實(shí)現(xiàn)都是OptionsManager<>。 那為啥要搞兩個(gè)不同的接口。

      等等(手動(dòng)播放名偵探bgm),這倆生命周期咋不一樣? 一個(gè)是Singleton一個(gè)是Scoped。而再來(lái)看IOptionsSnapshot的說(shuō)明:“Used to access the value of TOptions for the lifetime of a request.”(用于在請(qǐng)求的生存期內(nèi)訪(fǎng)問(wèn)選項(xiàng)的值)。

      原來(lái)如此,這樣看來(lái)就很清晰了。它倆的區(qū)別其實(shí)就是依賴(lài)注入的生命周期不同而已,為單例的IOptions意味著,只要您注入之后以后獲取的都是同一個(gè)實(shí)例,而IOptionsSnapshot呢,作為Scoped級(jí)別,每再一個(gè)新的Scoped中獲取它一次,它就會(huì)請(qǐng)求一個(gè)新的實(shí)例。

      所以來(lái)舉個(gè)例子,在AspNet Core中咱們某個(gè)選項(xiàng)的值是根據(jù)一個(gè)文件的某個(gè)值來(lái)的。剛開(kāi)始文本的值是“A”,咱們?cè)谶\(yùn)行AspNet Core之后我們獲取IOptions<MyOptions>IOptionsSnapshot<MyOptions>,此時(shí)得到的MyOptions的該屬性的值都是"A"。但是假如我們更改了文本的值,改為“B”。如果在發(fā)起一個(gè)http請(qǐng)求去獲取MyOptions的結(jié)果,此時(shí)IOptions<MyOptions>依舊是“A”,而IOptionsSnapshot<MyOptions>則更改為了B。

      原因很簡(jiǎn)單,因?yàn)?code>IOptions<MyOptions>是單例的,所以從程序一開(kāi)始加載過(guò)一次之后,以后訪(fǎng)問(wèn)它都是這個(gè)結(jié)果,而IOptionsSnapshot<MyOptions>是Scoped級(jí)別的,所以每一個(gè)新的Scoped時(shí)都會(huì)又去訪(fǎng)問(wèn)文本文件獲取值,而一次Http請(qǐng)求就會(huì)開(kāi)啟一次新的Scoped,所以此時(shí)結(jié)果就成為“B”。這個(gè)時(shí)候我們大概就能讀懂上面IOptionsSnapshot<>接口的解釋了:“用于在請(qǐng)求的生存期內(nèi)訪(fǎng)問(wèn)選項(xiàng)的值”。

      三兄弟一下就干掉了倆,接下來(lái)看看最后一個(gè)好兄弟(毒瘤):IOptionsMonitor。還是直接看它的源代碼呢:

      services.TryAdd(ServiceDescriptor.Singleton(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>)));
      

      納尼?單例? 那是不是意味著它也一樣,一旦啟動(dòng)了之后還是保持原有的結(jié)果呢?先不急,看看它的接口定義再說(shuō):

      /// <summary>
      /// Used for notifications when <typeparamref name="TOptions"/> instances change.
      /// </summary>
      /// <typeparam name="TOptions">The options type.</typeparam>
      public interface IOptionsMonitor<out TOptions>
      {
          /// <summary>
          /// Returns the current <typeparamref name="TOptions"/> instance with the <see cref="Options.DefaultName"/>.
          /// </summary>
          TOptions CurrentValue { get; }
      
          /// <summary>
          /// Returns a configured <typeparamref name="TOptions"/> instance with the given name.
          /// </summary>
          TOptions Get(string name);
      
          /// <summary>
          /// Registers a listener to be called whenever a named <typeparamref name="TOptions"/> changes.
          /// </summary>
          /// <param name="listener">The action to be invoked when <typeparamref name="TOptions"/> has changed.</param>
          /// <returns>An <see cref="IDisposable"/> which should be disposed to stop listening for changes.</returns>
          IDisposable OnChange(Action<TOptions, string> listener);
      }
      

      可以看出它自己是一個(gè)單獨(dú)的接口,并不像其它倆兄弟是繼承關(guān)系。而且該接口居然有一個(gè)OnChange簽名?而且該方法需要一個(gè)Action<TOptions, string>的參數(shù)。

      握草(繼續(xù)手動(dòng)播放名偵探bgm),如果您有幸看過(guò)我的上一篇文章:《【5min+】 一個(gè)令牌走天下!.Net Core中的ChangeToken》,那么您可能一下就知道它扮演了什么樣的角色。(5min+系列居然是連續(xù)的.... ??)

      再看看該接口的說(shuō)明:"Used for notifications when TOptions instances change."(用于在選項(xiàng)實(shí)例更改時(shí)進(jìn)行通知)。果然和我們猜的一模一樣,那么它的實(shí)現(xiàn)類(lèi)里面一定有咱們上一篇文章中提到的:ChangeTokenIChangeToken等東西。

      來(lái)吧,扒開(kāi)它的具體實(shí)現(xiàn),驗(yàn)證咱們的猜想:

       public OptionsMonitor(IOptionsFactory<TOptions> factory, IEnumerable<IOptionsChangeTokenSource<TOptions>> sources, IOptionsMonitorCache<TOptions> cache)
      {
          _factory = factory;
          _sources = sources;
          _cache = cache;
      
          foreach (var source in _sources)
          {
              var registration = ChangeToken.OnChange(
                      () => source.GetChangeToken(),
                      (name) => InvokeChanged(name),
                      source.Name);
      
              _registrations.Add(registration);
          }
      }
      

      意料之中,也就是說(shuō)IOptionsMonitor<>的注入級(jí)別雖然是單例,但是因?yàn)樗哂?code>IChangeToken的實(shí)現(xiàn),所以它能夠在選項(xiàng)源改變的時(shí)候,“立馬對(duì)選項(xiàng)做出對(duì)應(yīng)的改變”。而改變依賴(lài)于IOptionsChangeTokenSource這個(gè)令牌源,目前.net core對(duì)很多常用工具都實(shí)現(xiàn)了該令牌源,比如Logger,Configuration等。所以當(dāng)我們某個(gè)選項(xiàng)依賴(lài)于IConfiguration(appsetting.json)的某一項(xiàng)時(shí),當(dāng)修改appsetting.json文件,該選項(xiàng)的值就能夠立馬得到更改。

      所以來(lái)回過(guò)頭來(lái)看這三兄弟。它們的區(qū)別其實(shí)在于變更的時(shí)效性:

      類(lèi)型 說(shuō)明 時(shí)效性
      IOptions 一旦程序啟動(dòng),該選項(xiàng)的值就無(wú)法更改 無(wú)時(shí)效性可言
      IOptionsSnapshot 當(dāng)開(kāi)啟一個(gè)新Scoped時(shí),就會(huì)重新計(jì)算選項(xiàng)的值 相對(duì)比較低,依賴(lài)于合適開(kāi)啟一個(gè)新的Scoped
      IOptionsMonitor 依賴(lài)于IChangeToken,只要令牌源變更則立刻做出反應(yīng)

      假如把IOptionsMonitor<MyOptions>添加到上面IOptions<MyOptions>IOptionsSnapshot<MyOptions>的文件變更案例,如果在一次HTTP請(qǐng)求中,文件變更了兩次,那么IOptionsSnapshot<MyOptions>不會(huì)在第二次更改中同步更改,而IOptionsMonitor<MyOptions>則可以。

      那么什么時(shí)候來(lái)使用什么樣的接口呢?相信這個(gè)時(shí)候,您的心里比我還要清楚。當(dāng)您的選項(xiàng)只是負(fù)責(zé)一次性處理的時(shí)候,應(yīng)用啟動(dòng)了就不需要更改,那么考慮使用IOptions<MyOptions>,如果是對(duì)數(shù)據(jù)源的變更要求很?chē)?yán)格,比如開(kāi)啟了一個(gè)“BackgroundJob”在后臺(tái)運(yùn)行,該job需要一個(gè)選項(xiàng)類(lèi)型,而該類(lèi)型依賴(lài)于配置文件,需要對(duì)配置文件更改時(shí)即刻做出改變,那么請(qǐng)考慮使用IOptionsMonitor<MyOptions>

      最后回過(guò)頭來(lái)看微軟官方文檔上關(guān)于“Options”的兩個(gè)點(diǎn)(ISP和關(guān)注點(diǎn)分離),您應(yīng)該一下就能理解。
      x

      如果您有興趣的話(huà)可以跳轉(zhuǎn)至官方文檔進(jìn)行閱讀:《ASP.NET Core 中的選項(xiàng)模式》

      好啦,今天的車(chē)就開(kāi)完了,如果您喜歡該系列文章可以點(diǎn)擊關(guān)注。??

      最后,偷偷說(shuō)一句:創(chuàng)作不易,點(diǎn)個(gè)推薦吧.....

      x

      我的博客即將同步至騰訊云+社區(qū),邀請(qǐng)大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=1fam5s82ttu5f

      posted @ 2020-03-27 18:14  句幽  閱讀(4594)  評(píng)論(8)    收藏  舉報(bào)
      主站蜘蛛池模板: 人妻精品动漫h无码| 泰兴市| 无码伊人久久大杳蕉中文无码| 免费人成网站免费看视频| 久久精品国产蜜臀av| 蜜臀av黑人亚洲精品| 国产成人综合久久精品下载| 亚洲中文久久久精品无码| 亚洲精品麻豆一二三区| 国产高清自产拍AV在线| 我国产码在线观看av哈哈哈网站| 中国女人熟毛茸茸A毛片| 日本激情久久精品人妻热| 国产18禁黄网站禁片免费视频| 欧美福利在线| 精品国产午夜福利在线观看| 国产午夜福利视频在线| 国产AV福利第一精品| 精品国产品香蕉在线| 精品国产乱码久久久久app下载| 国产一区二区三区黄色片| 亚洲一区二区三区久久受| 日韩有码av中文字幕| 国产亚洲精品成人aa片新蒲金| 精品乱人伦一区二区三区| 亚洲乱熟女一区二区三区| 欧美日韩国产图片区一区| 久久人妻少妇嫩草av无码专区| 国产精品自拍一二三四区| 中文字幕在线日韩| 伊人久久精品无码麻豆一区 | 国内精品久久黄色三级乱| 国产一区二区av天堂热| 久久99精品国产麻豆婷婷| 偷拍久久大胆的黄片视频| 国产影片AV级毛片特别刺激| 欧美人与动人物牲交免费观看| 国产偷人妻精品一区二区在线| 国产日韩AV免费无码一区二区三区| 国产老熟女一区二区三区| 精品亚洲国产成人av|