1. 程式人生 > >DotNetCore跨平臺~一起聊聊Microsoft.Extensions.DependencyInjection

DotNetCore跨平臺~一起聊聊Microsoft.Extensions.DependencyInjection

回到目錄

寫這篇文章的心情:激動

Microsoft.Extensions.DependencyInjection在github上同樣是開源的,它在dotnetcore裡被廣泛的使用,比起之前的autofac,unity來說,它可以說是個包裹,或者叫介面卡,它自己提供了預設的DI實現,同時也支援第三方的IOC容器,在這段時間裡使用了它,就想,這東西為什麼被在dotnetcore裡大放異彩?為什麼會全程使用它?從程式的開始到程式啟動起來,你可以發現它無處不在,在框架裡是這樣,在業務層同時也是這樣。

聊聊Microsoft.Extensions.DependencyInjection知識點包括

  1. 它的開源地址
  2. IServiceCollection和IApplicationBuilder
  3. 自定義模組用它
  4. 在Startup.ConfigureServices中註冊自定義模組
  5. 在Startup.Configure中使用它,進行預設模組的初始化
  6. 在任意物件的構造方法中使用它

一步一步的揭祕

一 它的開源地址

可以看看它的README.md,就知道它是個大包裹,類似於大叔LindAgile裡的Container,完全可以擴充套件支援其它第三方的IOC容器,這就像大叔經常說的那句話一樣,在IT江湖中,英雄總是所風略同……

二 dotnetcore整個框架在用它

在你的dotnetcore應用程式裡,你會發現在Startup類中有很多像services.AddMvc()這樣的方法,這實質是像應用程式中註冊一個元件,這裡的MVC是一個統一的元件,它不依賴於windows,不依賴於dotnet,整個dotnetcore裡把很多元件都解耦了,這樣在維護和nuget包升級時都更靈活,自己有問題就優化自己,而不影響其它模組。(越說越像微服務的宗旨)。

IServiceCollection主要用來註冊服務,就是某個介面和某種實現的對應關係,這種註冊是我們在Startup.ConfigureServices方法裡完成的,如下面的AddLind()這個方法,它完成了對Lind模組的註冊,在方法內部可以註冊本模組的其它服務。

        /// <summary>
        /// 新增Lind框架和它們依賴子模組
        /// </summary>
        /// <param name="services"></param>
        /// <param name="setupAction"></param>
        /// <returns></returns>
        public static LindBuilder AddLind(
            this IServiceCollection services,
            Action<LindOptions> setupAction)
        {
            if (setupAction == null) throw new ArgumentNullException(nameof(setupAction));
            services.Configure(setupAction);
            var options = new LindOptions();
            //註冊框架所依賴的基礎模組
            //options.Extensions.Add();
            //註冊外部模組
            setupAction(options);
            foreach (var serviceExtension in options.Extensions)
                serviceExtension.AddServices(services);
            services.AddSingleton(options);
            return new LindBuilder(services);
        }

IApplicationBuilder是指對應該程式的啟動,或者理解為初始化,當上面的服務註冊完成後就執行它了,我們一般在Startup.Configure去啟用它,它的目的比較單純,就是對模組進行初始化,如果沒什麼特殊的功能,這個程式碼可以是空的,下面Builder中初始化了日誌元件。

        /// <summary>
        /// 在應用程式中開啟-Lind框架
        /// </summary>
        /// <param name="app">The <see cref="IApplicationBuilder" /> instance this method extends.</param>
        /// <returns>The <see cref="IApplicationBuilder" /> instance this method extends.</returns>
        public static IApplicationBuilder UseLind(this IApplicationBuilder app)
        {
            if (app == null)
                throw new ArgumentNullException(nameof(app));
            var provider = app.ApplicationServices;

            //註冊Lind框架所需要的底層服務
            LoggerFactory.SetLogger((ILogger)provider.GetService(typeof(ILogger)));
            return app;
        }

三 自定義模組用它

如果希望定義自己的功能模組實現與dotnetcore框架的結合可以自定義Options和OptionsExtensions,前者主要實現的是服務列表的註冊,而後臺主要是對現有模組提供註冊的入口,下面的程式碼主要實現了一個EF倉儲模組的註冊過程。

模組所需的模型

    public class RepositoryOptions
    {
        public string ConnString { get; set; }
    }

註冊服務列表

    /// <summary>
    /// 註冊有關-EF倉儲的服務列表
    /// </summary>
    public class EFOptionsExtension : ILindOptionsExtension
    {
        private readonly Action<RepositoryOptions> _configure;

        public EFOptionsExtension(Action<RepositoryOptions> configure)
        {
            _configure = configure;
        }
        public void AddServices(IServiceCollection services)
        {
            services.AddSingleton(typeof(IRepository), typeof(EFRepository));
            var mysqlOptions = new RepositoryOptions();
            _configure(mysqlOptions);
        }
    }

在外部使用這個模組,就是在Startup中註冊它

  public static class RepositoryOptionsExtensions
  {
        public static LindOptions UseEF(this LindOptions options, Action<RepositoryOptions> configure)
        {
            options.RegisterExtension(new EFOptionsExtension(configure));

            return options;
        }
   }

四 在Startup.ConfigureServices中註冊自定義模組

上面的程式碼主要是自定義一個模組,而在startup中使用它,就像下面的程式碼,十分簡潔,當前有些配置資訊可以到在基於環境變數的json檔案裡!

       public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddLind(x =>
            {
                x.UseEF(o =>
                {
                    o.ConnString = "localhost:1433";
                });
                x.UseDapper(o =>
                {
                    o.ConnString = "localhost:3306";
                });
            });
        }

五 在Startup.Configure中使用它,進行預設模組的初始化

上面的程式碼實現了對模組下一些服務進行註冊,然後下面程式碼主要是進行一些初始化的工作。

       public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc();
            app.UseLind();
        }

六 在任意物件的構造方法中使用它

當我們把服務註冊後,可以在任意型別的構造方法中使用它,而不是隻能在控制器中使用,這一點dotnetcore DI做的確實不錯,給它100個贊!

這種註冊

    public class ApiLoggerOptionsExtension : IPilipaOptionsExtension
    {
        Action<ApiLoggerConfig> _config;
        public ApiLoggerOptionsExtension(Action<ApiLoggerConfig> config)
        {
            _config = config;
        }
        public void AddServices(IServiceCollection services)
        {
            ApiLoggerConfig apiLoggerConfig = new ApiLoggerConfig();
            _config(apiLoggerConfig);//裝飾
            services.AddSingleton(apiLoggerConfig);//註冊物件裡的屬性,在物件的構造方法被注入
            services.AddSingleton(typeof(ILogger), typeof(ApiLogger));//註冊物件,在使用物件的類的構造方法被注入
        }
    }

這種使用

        ApiLoggerConfig _config;
        public ApiLogger(ApiLoggerConfig config)
        {
            _config = config;
        }

對於上面的程式碼實現了在OptionsExtension裡進行註冊,然後在任意型別中使用它,感覺這點確實靈活了不少!

今天咱們對dotnetcore DependencyInjection的分享就到這裡,希望大家也儘量把模組從專案中解放出來

感謝各位的閱讀!

回到目錄