iT邦幫忙

2022 iThome 鐵人賽

DAY 12
1
自我挑戰組

[Dot Net Core](圖解系列與常用套件)系列 第 12

[Dot Net Core] (圖解系列) 12. 以最簡單方法驗證架構中 Resolved Singleton 特性

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20220912/20144614seBF9TIYtR.jpg

上一節,透過描述我們看到controller class在被產生instance過程中,其中IActionInvokerFactory 會被Resolve成ActionInvokerFactory實體。這時候建構子內的參數物件也會繼續透過DI機制被Resolve成實體。

而在”UseEndpoint to Map Controller”這節中,實際上ApplicationPartManager此instance的產出是因為它的身分是ControllerActionDescriptorProvider的建構子參數物件。在被Resolve 出來時,ApplicationPartManager 的ApplicationParts 集合已經包含 Controller Class 所屬的組件資訊。

回顧下圖在”UseEndpoint to Map Controller”這節中的圖:
https://ithelp.ithome.com.tw/upload/images/20220912/20144614Ju7VOIz0Zl.jpg

但是令人好奇的是,建構子內並沒有去新增ApplicationPartManager 的ApplicationParts 集合內容的程式碼,但為何剛開始被建構出來的這個物件此集合內已經有值了?

原因是在這個時間點之前就已經被Resolve 過了,Resolve 的形式是 Singleton;且透過ApplicationPartManager.PopulateDefaultParts將組件資訊包裝到ApplicationPartManager.ApplicationParts 集合,供後續再進一步取出Controller與Action 資訊。在確切的時間點會在不久之後做描述。

我們可以在Dot Net Core架構中做一個簡單的Resolve Singleton 物件,證明其記憶體位置與內容是可以被保存到下一次被 Resolve 出來(仍為Singleton的實體)。

以下步驟:

Step1: 建立簡單的類別TestClass ,如下:

public class TestClass
{

    public List<string> ListStringCollection;

    public TestClass()
    {
        if (ListStringCollection is null)
            ListStringCollection = new List<string>();
    }

    public void AddString(string strText)
    {
        ListStringCollection?.Add(strText);
    }

}

Step2: 於Startup 類別新增一個static欄位IApplicationBuilder AppBuilder,於ConfigureServices函式中註冊此類別;於Configure函式中 Resolve TestClass,並於TestClass. ListStringCollection字串集合加入一個日期字串。然後把IapplicationBuilder的實體指派到
Startup. AppBuilder。 如下:

public class Startup
    {

        public static IApplicationBuilder AppBuilder;   


        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();

            services.AddSingleton<TestClass>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });


            //Demo Singleton
            TestClass ts = (TestClass)app.ApplicationServices.GetService(typeof(TestClass));
            ts.ListStringCollection.Add(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
            System.Diagnostics.Debug.Write( $" The class memory location is  {AddressHelper.GetAddress(ts)}" );
            System.Diagnostics.Debug.Write($"The first element in collection is : {ts.ListStringCollection[0]}  ");

            //cache IApplicationBuilder instance
            AppBuilder = app;
        }
    }

Step3: 執行專案,並觀察Startup. Configure中,利用AppBuilder的serviceProviderEngineScope來做IOC的Resolve Service,所被Resolve 出來的 TestClass 記憶體位置與其成員內容。
https://ithelp.ithome.com.tw/upload/images/20220912/20144614skxwEcicBH.jpg

Step4: Request to Controller Action (Default Controller “WeatherForecastController”)
https://ithelp.ithome.com.tw/upload/images/20220912/20144614rD8SXplk0d.jpg

Step5: 觀察執行到Controller的Action 時,再次Resolve出的TestClass 是否記憶體位置與ListStringCollection字串集合所存的字串內容是否與之前一致。
https://ithelp.ithome.com.tw/upload/images/20220912/20144614PdBCdpPdOf.jpg

如上圖,最後Resolve 出 TestClass時,都未再對其成員內容做任何變動,建構子也是如第一張圖一樣沒有更動成員的內容;而記憶體位置與ListStringCollection字串集合所存的字串內容都與在 Startup. Configure中所指定的時間字串是一致的。

在Startup. ConfigureServices中,如果是register service 前就先產生實體且設定內容,也可以有一樣的結果。方式如下:

public class Startup
{

    public static IApplicationBuilder AppBuilder;   


    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();

        // original 
        //services.AddSingleton<TestClass>();
        
        // new instance then register service 
        TestClass ts = new TestClass();
        ts.ListStringCollection.Add(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
        System.Diagnostics.Debug.Write($" The class memory location is  {AddressHelper.GetAddress(ts)} \n ");
        System.Diagnostics.Debug.Write($"The first element in collection is : {ts.ListStringCollection[0]}  ");
        services.AddSingleton(ts);
        
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });


        //Demo Singleton
        TestClass ts = (TestClass)app.ApplicationServices.GetService(typeof(TestClass));
        System.Diagnostics.Debug.Write( $" The class memory location is  {AddressHelper.GetAddress(ts)} \n " );
        System.Diagnostics.Debug.Write($"The first element in collection is : {ts.ListStringCollection[0]}  ");

        //cache IApplicationBuilder instance
        AppBuilder = app;
    }
}

所以透過上述證明,Singleton的實體一旦被Resolve出來,記憶體位置都會保留起來。同理可以說明,當處理Resolve Controller Class時 ,ApplicationPartManager 這個Class,在執行endpoint middleware階段被Resolve出來時已經包含Controller所在的組件資訊。不久之後會再詳細說明。


上一篇
[Dot Net Core] (圖解系列) 11. Dot Net Core MVC 與 Asp.NET MVC 比較 - Controller的 Factory 與 Provider 的決定時機
下一篇
[Dot Net Core] (圖解系列) 13.闡述ApplicationPartManager 為何在被Resolve的時候就包含 Controller 的組件資訊
系列文
[Dot Net Core](圖解系列與常用套件)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言