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

感谢各位的阅读!

本文转自博客园张占岭(仓储大叔)的博客,原文链接:DotNetCore跨平台~一起聊聊Microsoft.Extensions.DependencyInjection,如需转载请自行联系原博主。

时间: 2024-10-24 12:21:17

DotNetCore跨平台~一起聊聊Microsoft.Extensions.DependencyInjection的相关文章

DotNetCore跨平台~文章索引~永久更新

本索引目录主要包括仓储大叔对dotnet core架构的研究与知识积累,从2016年开始进行撰写,到今天已经有一年多了,其中有一些小知识,小技巧,小应用,希望给大家在开发时一些启发,也希望dotnet core越来越好,希望2.0正式版快点出来! 我们的框架应该是基于组件化的! 我们的系统应该是基于微服务化的! 我们的部署,应该是基于自动化的! DotNetCore跨平台目录 DotNetCore跨平台~Startup类的介绍(2016-05-31 16:25) Linux~centos上安装.

DotNetCore跨平台~组件化时代来了

进行dotnetcore之后,各种对象都是基于DI进行生产的,这就有了对象的生命周期一说,早在autofac里也有相关知识点,这与Microsoft.Extensions.DependencyInjection是完全温和的,方便大家理解,在讲今天的组件化之前,先对DI的三种生命周期进行理解一下: AddSingleton:单例,进程内它是唯一的 AddTransient:瞬息,在对象在当前环境内,作用域内是唯一的 AddScoped:请求,对象在一个HTTP请求内是唯一的 下面来看今天的组件化的

DotNetCore跨平台~聊聊中间件

在进行.net core平台之后,我们如果希望在请求过程中添加一些事件是非常容易的,你可以把这些事件做成一个中间件Middleware,然后这些中间件就会以Http pipeline的管道方式进行相应,并且它们就像是一个职责链,从你定义的第一个中间件开始,一个一个向下传递,直到最后一个中间件完成为止! 前几天我写了在.net core里实现模块化服务,DotNetCore跨平台~组件化时代来了 主要是将我们定义的组件添加到IServiceCollection集合里,然后在程序启动后去注册它们,而

DotNetCore跨平台~EFCore连接Mysql的方式

在.net frameworks的ef里连接mysql我们已经测试通过了,而在dotnet core里的efCore上去连接mysql我们需要测试一下,并且在测试过程中出现了一些问题,当然最后也是解决了,下面总结一下,分享给大家! mysql项目的依赖包 数据上下文和连接串 数据仓储 添加模块扩展 业务层注入 业务实现 mysql项目的依赖包 Microsoft.EntityFrameworkCore MySql.Data.EntityFrameworkCore 数据上下文和连接串 对于mysq

DotNetCore跨平台~EFCore废弃了TransactionScope取而代之的Context.Database.BeginTransaction

TransactionScope是.net平台基于的分布式事务组件,它默认为本地事务,同时当系统有需要时可以自动提升为分布式事务,而对系统的前提是要开启MSDTC服务,必要时需要在数据库服务器与应用服务器之间添加hosts的映射,这些在之前已经写过很多文章了,在这里不再说了. 之前对TransactionScope的一些理解和总结 第二十六回   将不确定变为确定~transactionscope何时提升为分布式事务? 第二十七回   将不确定变为确定~transactionscope何时提升为

DotNetCore跨平台~linux上还原自主nuget包需要注意的问题

问题的产生的背景 由于我们使用了jenkins进行部署(jenkins~集群分发功能和职责处理),而对于.net core项目来说又是跨平台的,所以对它的项目拉取,包的还原,项目的编译和项目的发布都是在一台linux的jenkins节点上进行的,而我们开发时是在windows系统,所以在进行还原和编译时出现了一些问题,今天的文章主要是解决这些问题的. .net frameworks时代 我们在.net时代有包管理工具nuget,并且已经知道了它的好处,类似于nodejs的npm,帮助我们管理项目

DotNetCore跨平台~Startup类的介绍

新宠儿 DotNetCore是.net5.0版本,之所以不叫.net5.0为的就是不让我们把它与前面的.net混为一淡,它将是真正意义的跨平台开发语言,在网上也有相关介绍,中国的一些大牛也发了相关文章,像张善友大牛也发了几个文章,来介绍.NetCore,这段时间,大叔将会一步一步说说这个跨平台的新宠儿! 重新起名了 ASP.NET 5 –> ASP.NET Core 1.0 .NET Core 5 –> .NET Core 1.0 Entity Framework 7 –> Entity

DotNetCore跨平台~性能测试~可以放心使用了

使用dotnetCore发布站点后,它的处理请求能力不逊色IIS等大型服务的能力,号称每秒能处理115万个请求,太牛X了也. 先看看它支持的数据库 以下主流数据库都是为支持的 Microsoft SQL Server SQLite Npgsql (PostgreSQL) MySQL Microsoft SQL Server Compact Edition IBM Data Servers InMemory (for testing) 再看看老外测试出来的结果 ASP.NET Core – 230

DotNetCore跨平台~服务总线_事件总线的重新设计

理论闲话 之前在.netFramework平台用的好好的,可升级到.net core平台之后,由于不再需要二进制序列化,导致咱们的事件机制遇到了问题,之前大叔的事件一直是将处理程序序列化后进行存储的,处理存储的参数为事件源,一个事件源可以由多个处理程序订阅,当事件源被发布时,这些被序列化的代码段会被回调执行,这是大叔之前的思路,在RedisBus和MemoryBus里已经得到了实现,读过大叔源代码的同学应该有所了解了. 事件源和处理程序 /// <summary> /// 事件源 /// &l