<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          .NET Core中間件與依賴注入的一些思考

          共 3998字,需瀏覽 8分鐘

           ·

          2020-09-28 12:37

          1.起源?

          為什么會(huì)有這篇文章呢? 源于我看了老A的aspnet core 3 框架揭秘[1]?請(qǐng)求管道?篇產(chǎn)生的疑惑?

          三點(diǎn)疑惑:

          1. Singleton服務(wù)中注入Scoped服務(wù)產(chǎn)生內(nèi)存泄露?
          2. 關(guān)于中間件的生命周期是Singleton的?
          3. 怎么避免中間件、Singleton服務(wù)中使用Scoped服務(wù)不產(chǎn)生內(nèi)存泄漏?

          2.知識(shí)面覆蓋

          示例中會(huì)覆蓋到aspnet core相關(guān)的配置、依賴注入(周期)、中間件的知識(shí)點(diǎn),若不清楚的需要先看看這些概念以及基本使用。

          收獲:和我一起帶著以上三個(gè)問題來進(jìn)行驗(yàn)證也就會(huì)收獲到相關(guān)知識(shí)點(diǎn)。

          3. 測(cè)試環(huán)境準(zhǔn)備

          創(chuàng)建三個(gè)服務(wù):

          1. IOrderAppService(singleton)
          2. IProductAppService(scoped)
          3. ITransientTestAppService(transient)

          創(chuàng)建請(qǐng)求控制器:

          public?class?ProductController?:?Microsoft.AspNetCore.Mvc.Controller
          {
          ????private?int?time?=?1;
          ????private?readonly?IHostApplicationLifetime?_lifetime;
          ????public?ProductController(IProductAppService?productAppService1,
          ????????IProductAppService?productAppService2,
          ????????IOrderAppService?orderAppService1,
          ????????IOrderAppService?orderAppService2,
          ????????ITransientTestAppService?transientTestAppService1,
          ????????ITransientTestAppService?transientTestAppService2,
          ????????IHostApplicationLifetime?lifetime
          )

          ????{
          ????????_lifetime?=?lifetime;
          ????}

          ????[HttpGet]
          ????[Route("/get")]
          ????public?Task<string>?Get()
          ????{
          ????????return?Task.FromResult($"第{time++}次請(qǐng)求成功!");
          ????}

          ????[HttpGet]
          ????[Route("/stop")]
          ????public?void?Stop()?=>?_lifetime.StopApplication();
          }

          創(chuàng)建中間件:

          public?sealed?class?UrlMiddleware
          {
          ????private?int?times?=?1;
          ????private?readonly?RequestDelegate?_next;
          ????public?UrlMiddleware(RequestDelegate?next,
          ????????IProductAppService?productAppService,
          ????????ITransientTestAppService?transientTestAppService
          )

          ????{
          ????????//構(gòu)造中的productAppService服務(wù)是由IApplicationBuilder.ApplicationServices根容器創(chuàng)建的
          ????????_next?=?next;
          ????}

          ????public?async?Task?InvokeAsync(HttpContext?context,IProductAppService?productAppService,ITransientTestAppService?transientTestAppService)
          ????{
          ????????//invoke中的productAppService其實(shí)是context.RequestServices子容器創(chuàng)建的。
          ????????//這里的context.RequestServices子容器也是由IApplicationBuilder.ApplicationServices根容器創(chuàng)建來的。
          ????????var?productService?=?context.RequestServices.GetRequiredService();//使用解析的方式和上面方法中注入進(jìn)來是一樣的作用,切記是使用子容器RequestServices解析
          ????????Console.WriteLine($"請(qǐng)求第{times++}次進(jìn)入U(xiǎn)rlMiddleware中間件。hash:{this.GetHashCode()}");
          ????????await?_next(context);
          ????}
          }

          注冊(cè)服務(wù):

          service.AddTransient()
          ???????.AddScoped()
          ???????.AddSingleton();

          這里若使用的IMiddleware創(chuàng)建中間件也記得需要注冊(cè)。

          4.開始驗(yàn)證

          4.1 關(guān)于中間件的生命周期是Singleton的?

          這里我們先驗(yàn)證下這個(gè)問題。為第一個(gè)問題做鋪墊。

          文章中我就不做過多的代碼介紹,主要是對(duì)代碼片段的解釋,有需要的可以看源代碼[2]

          • 開始運(yùn)行:

            dotnet?run

            會(huì)注意到中間件構(gòu)造中注入的服務(wù)會(huì)在項(xiàng)目啟動(dòng)完成前就會(huì)創(chuàng)建完成。

          • 開始請(qǐng)求:

            輸入http://localhost:5002/get, 這是因?yàn)榕渲昧?UseUrls,也可以直接使用UseSetting("urls"")

            使用UseSetting的key默認(rèn)定義在WebHostDefaultsHostDefaults

            為了驗(yàn)證問題我們請(qǐng)求兩次。

            開始請(qǐng)求
            中間件是否是單例

            分析總結(jié):從兩次請(qǐng)求中可以確定不管是強(qiáng)類型的中間件還是按照約定(弱類型)的中間件都是單例的(Singleton)

            這里穿插一下關(guān)于Singleton\Scoped\Transient生命周期控制臺(tái)輸出:分析總結(jié):

            • Scoped服務(wù)請(qǐng)求中只會(huì)創(chuàng)建一次并且請(qǐng)求完成后釋放
            • Transient服務(wù)每一次都會(huì)重新創(chuàng)建并且請(qǐng)求完成后全部釋放
            • Singleton整個(gè)應(yīng)用程序周期內(nèi)只會(huì)創(chuàng)建一次并且直到應(yīng)用程序關(guān)閉時(shí)才會(huì)釋放(慎用慎選擇)

          4.2 Singleton服務(wù)中注入Scoped服務(wù)產(chǎn)生內(nèi)存泄露?

          調(diào)用http://localhost:5002/stop?進(jìn)行遠(yuǎn)程關(guān)閉應(yīng)用程序。控制臺(tái)輸出:分析總結(jié):中間件構(gòu)造中注入scoped服務(wù)時(shí)會(huì)跟隨根容器的釋放才會(huì)釋放,相當(dāng)于說就是會(huì)在整個(gè)應(yīng)用程序生命周期中存在,所以也就容易導(dǎo)致內(nèi)存泄漏

          從這里還沒能表現(xiàn)出構(gòu)造中的服務(wù)和invoke方法中的服務(wù)區(qū)別。。。下面進(jìn)行驗(yàn)證:

          分析總結(jié):

          從圖中畫線中能看出請(qǐng)求完成后只有invoke方法中的scoped\transient服務(wù)釋放了,中間件構(gòu)造中的任何類型服務(wù)都不會(huì)得到釋放,所以需要在中間件使用
          關(guān)于非singleten服務(wù)時(shí)在方法中進(jìn)行注入,不要使用構(gòu)造注入,這是為什么呢?

          其實(shí)invoke方法中的服務(wù)是通過子容器(context.RequestServices)創(chuàng)建而來的,所以跟隨請(qǐng)求完成子容器釋放也就會(huì)釋放掉子容器內(nèi)創(chuàng)建出的服務(wù)。
          context.RequestServices是由IApplicationBuilder.ApplicationServices根容器創(chuàng)建而來的。

          以上內(nèi)容也只是使用中間件這種特殊來進(jìn)行了測(cè)試,那么怎么來驗(yàn)證Singleton服務(wù)中注入scoped來進(jìn)行驗(yàn)證呢?自行嘗試?應(yīng)該是不可以的哦?`ServiceProviderOptions`。

          4.3 怎么避免中間件、Singleton服務(wù)中使用Scoped服務(wù)不產(chǎn)生內(nèi)存泄漏?

          其實(shí)4.2中已經(jīng)有了答案了。

          如何避免?

          在中間件中使用invoke方法中注入服務(wù)或者使用context.RequestServices.GetRequiredService<>();來解析服務(wù),不推薦(反模式)。

          在singleton服務(wù)中使用使用IServiceProvider來創(chuàng)建子容器解析。

          要是以上內(nèi)容有什么不對(duì)的地方歡迎也希望得到指點(diǎn)。

          5 總結(jié)

          從自己看書到自己寫代碼來驗(yàn)證以及寫這篇文章多多少少算花了兩天的時(shí)間,但是感覺還是有收獲的,算是搞清楚了一些問題。

          強(qiáng)烈推薦老A的?aspnet core 3 框架揭秘[3]?,對(duì)深入aspnet core有很大的幫助,能 夠?qū)spnet core中的知識(shí)點(diǎn)有一個(gè)大體輪廓。


          往期精彩回顧




          【推薦】.NET Core開發(fā)實(shí)戰(zhàn)視頻課程?★★★

          .NET Core實(shí)戰(zhàn)項(xiàng)目之CMS 第一章 入門篇-開篇及總體規(guī)劃

          【.NET Core微服務(wù)實(shí)戰(zhàn)-統(tǒng)一身份認(rèn)證】開篇及目錄索引

          Redis基本使用及百億數(shù)據(jù)量中的使用技巧分享(附視頻地址及觀看指南)

          .NET Core中的一個(gè)接口多種實(shí)現(xiàn)的依賴注入與動(dòng)態(tài)選擇看這篇就夠了

          10個(gè)小技巧助您寫出高性能的ASP.NET Core代碼

          用abp vNext快速開發(fā)Quartz.NET定時(shí)任務(wù)管理界面

          在ASP.NET Core中創(chuàng)建基于Quartz.NET托管服務(wù)輕松實(shí)現(xiàn)作業(yè)調(diào)度

          現(xiàn)身說法:實(shí)際業(yè)務(wù)出發(fā)分析百億數(shù)據(jù)量下的多表查詢優(yōu)化

          關(guān)于C#異步編程你應(yīng)該了解的幾點(diǎn)建議

          C#異步編程看這篇就夠了


          瀏覽 56
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  韩国精品无码一区二区三区18 | 亚洲中文无码在线观看 | 日韩特级毛片在线视频 | 日本 Ⅴ一区二区三区色情 | 午夜福利国产 |