zoukankan      html  css  js  c++  java
  • 一文读懂Asp.net core 依赖注入(Dependency injection)

    一、什么是依赖注入

    1. 首先在Asp.net core中是支持依赖注入软件设计模式,或者说依赖注入是asp.net core的核心
    2. 依赖注入(DI)和控制反转(IOC)基本是一个意思,因为说起来谁都离不开谁;或者可以说他们是同一个概念的不同角度描述;
    3. 软件设计原则中有一个依赖倒置原则(DIP),就是为了解耦;高层模块不应该依赖于底层模块。二者都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象;而依赖注入是实现这种原则的方式之一;
    4. 举个现实中例子:小明去行政领一节5号电池,然后行政给了小明一节黑象牌5号电池来分析 ;
      1. 小明只需要向行政领一节5号电池即可,小明不需要关心什么牌子的电池,电池从哪来的,电池的价格等等。他们俩共同需要关心的是一节5号电池即可;
      2. 即使后期行政给了小明北孚电池,小明仍可以正常使用;他们只需要满足一个规则(5号电池)即可;
      3. 小明(高层模块)不应该依赖黑象牌电池(低层模块),两者应该都依赖5号电池(抽象)。
      4. 如果小明直接获取到(new)黑象牌电池,如果后期业务变更提供的是北孚电池,那么我们就需要更改小明的代码;再如果公司有几百个小明,代码量可想而知;
      5. 为了解决直接获取(new)黑象牌电池,简单说为了解耦,我们让每位员工通过行政领取(构造函数,属性,方法等),这种即使更改其他品牌,而小明压根不需要关心;
    5. 举个.Net core中的例子:.Net core中使用分布式缓存;

      1. 我们只需要在构造函数中获取IDistributedCache,然后就可以在方法中直接使用缓存,我们不需要关心缓存的实现方式,存储位置等等;
      2. 如果缓存从内存变成Redis或者sqlserver,甚至自己实现缓存,而我们只需要在ConfigureServices中更改具体实现方式即可,而不需要更改任何使用缓存的地方;

     

    二、Asp.net core中依赖注入的生命周期

    依赖注入的生命周期有三种Transient,Scoped和Singleton;

    1、Transient每次调用都是不同的实例,比如常用的Microsoft.Extensions.Options.IConfigureOptions<T>;

    2、Scoped每次请求是同一个实例,如 Entity Framework contexts;

    3、Singleton只有一个实例,如Microsoft.Extensions.Logging.ILogger<T>;

    具体使用哪种,要根据具体情况而定;

    1、比如我们一般的业务逻辑都是Transient,这个也是比较常用的;

    2、Scoped相对用的比较少,当然也有很多业务逻辑也有用Scoped的;当然他的妙用肯定是每次请求一个实例,比如我们在系统中获取登录系统用户的Id,这时就可以用Scoped,不管在Service层或者Repository层等等,获取的都是同一个用户; 

    3、Singleton很多都是系统级别设计用单利,比如日志;

    三、在Asp.net core中使用依赖注入

    基础业务逻辑代码,获取用户列表

    public interface IUserInfoService
        {
            IEnumerable<UserInfo> GetUserInfo();
        } 
        public class UserInfoService : IUserInfoService
        {
            public IEnumerable<UserInfo> GetUserInfo()
            {
                // 模拟db获取数据
                return new List<UserInfo> { new UserInfo { Id = 1, Name = "Emrys" }, new UserInfo { Id = 2, Name = "梅林" } };
            }
        } 
        public class UserInfoMongoService : IUserInfoService
        {
            public IEnumerable<UserInfo> GetUserInfo()
            {
                // 模拟Mongodb获取数据
                return new List<UserInfo> { new UserInfo { Id = 1, Name = "Emrys" }, new UserInfo { Id = 2, Name = "梅林" } };
            }
        } 
        public class UserInfo
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }

    1、传统方式

     public class ValuesController : ControllerBase
        {
            IUserInfoService _userInfoService = new UserInfoService();
             
            [HttpGet]
            public IEnumerable<UserInfo> Get()
            { 
                return _userInfoService.GetUserInfo();
            }
    
        }

    在传统方式中,获取用户的服务类直接用new的方式,这也是很多初学者或者很多老手最经常使用的方式;从中可以发现代码耦合度太高,非常不利于维护,在所有使用到IUserInfoService的地方都要new出对象;

    如果后期需求变更,需要替换IUserInfoService的实现,比如从Mongodb中获取数据(现实示例中,从黑象牌变成北孚电池),那么就需要在所有new出UserInfoService的地方更改代码换成UserInfoMongoService,IUserInfoService _userInfoService = new UserInfoMongoService();

    我们如果需要new的对象需要实现单例模式(Singleton),每次请求new一个对象(Scoped)模式,那么还要另写代码实现;

     2、依赖注入方式

    1、在Startup类的ConfigureServices方法中设置注入

    public void ConfigureServices(IServiceCollection services)
    { 
        services.AddTransient<IUserInfoService, UserInfoService>(); 
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

     2、在构造函数中获取实例

    public class ValuesController : ControllerBase
    {
        IUserInfoService _userInfoService; 
        public ValuesController(IUserInfoService userInfoService)
        {
            _userInfoService = userInfoService;
        }
    
        [HttpGet]
        public IEnumerable<UserInfo> Get()
        { 
            return _userInfoService.GetUserInfo();
        }
    
    }

    在使用依赖注入方式时,解决了传统方式耦合度,如果后期变更实现,只要在 services.AddTransient<IUserInfoService, UserInfoService>();变更成UserInfoMongoService即可;

    在所有使用IUserInfoService的地方无须做任何改动;而且可以非常简单的设置生命周期(Transient,Scoped,Singleton);

    四、总结

    1、设置注入和获取注入的方式不止一种,示例只是演示了最简单和最常用的使用方式,其他方式可以参考文档;

    2、可以替换.net core中的默认注入容器, 如常用的autofac,可以实现更强大的功能;详情参考 https://autofac.org/;其他容器可以参考  https://github.com/aspnet/Extensions/tree/master/src/DependencyInjection

    3、可以直接在View中获取注入 @inject IUserInfoService userInfoService

    4、可以在httpcontext里直接获取注入HttpContext.RequestServices.GetService<IUserInfoService >();

    5、Startup中的ConfigureServices方法就是为了设置注入而存在的;

    记得推荐 ^_^

    作者:Emrys
    出处:http://www.cnblogs.com/emrys5/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    BFS visit tree
    Kth Largest Element in an Array 解答
    Merge k Sorted Lists 解答
    Median of Two Sorted Arrays 解答
    Maximal Square 解答
    Best Time to Buy and Sell Stock III 解答
    Best Time to Buy and Sell Stock II 解答
    Best Time to Buy and Sell Stock 解答
    Triangle 解答
    Unique Binary Search Trees II 解答
  • 原文地址:https://www.cnblogs.com/emrys5/p/aspnetcoredi.html
Copyright © 2011-2022 走看看