zoukankan      html  css  js  c++  java
  • 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. 在任意对象的构造方法中使用它

    一步一步的揭秘

    一 它的开源地址

    https://github.com/aspnet/DependencyInjection

    可以看看它的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的分享就到这里,希望大家也尽量把模块从项目中解放出来

    感谢各位的阅读!

    回到目录

  • 相关阅读:
    testNg vs junit 4.X @Test
    lombok+slf4j+logback SLF4J和Logback日志框架详解
    IntelliJ IDEA 当pom.xml更新时,自动加载pom.xml
    运算符重载具体解释
    设计模式之十八:桥接模式(Bridge)
    无限层级的组织机构
    实战Jquery(一)--username校验
    Android错误之--Error retrieving parent for item: No resource found that matches the given name &#39;Theme.A
    hibernate 缓存
    android --多线程下载
  • 原文地址:https://www.cnblogs.com/lori/p/7651787.html
Copyright © 2011-2022 走看看