1. 前言
面向对象设计 (OOD) 里有一个重要的思想就是依赖倒置原则 (DIP), 并由该原则牵引出依赖注入(DI), 控制反转(IoC) 及其容器等老生常谈的概念, 初学者很容易被这些概念搞晕 (包括我在内), 在学习 Core 依赖注入服务之前, 下面让我们先了解下依赖倒置原则(DIP), 依赖注入(DI), 控制反转(IoC) 等概念, 然后再深入学习 Core 依赖注入服务.
2. 依赖倒置原则(DIP)
高层模块不依赖于低层模块的实现, 而低层模块依赖于高层模块定义的接口. 通俗的讲, 就是高层模块定义接口, 低层模块负责实现.
2. 依赖注入(DI)
2.1 依赖(D)
当一个类需要另一个类协作来完成工作的时候就产生了依赖.
示例 1:
- public class MyDependency
- {
- public MyDependency()
- {
- }
- public Task WriteMessage(string message)
- {
- Console.WriteLine($"MyDependency.WriteMessage called. Message: {message}");
- return Task.FromResult(0);
- }
- }
- public class IndexModel : PageModel
- {
- MyDependency _dependency = new MyDependency();
- public void OnGet()
- {
- _dependency.WriteMessage("IndexModel.OnGet created this message.");
- }
- }
由上述代码可以看到 IndexModel 模块输出消息必须要实例化 MyDependency 模块, 也就是说 IndexModel 模块业务的实现必须依赖于 MyDependency 模块, 这就是依赖.
2.2 注入(I)
根据 DIP 设计原则: 高层模块不依赖于低层模块的实现, 而低层模块依赖于高层模块定义的接口, 所以我们在这里定义一个接口供高层模块调用, 底层模块负责实现.
示例 2:
- public interface IMyDependency
- {
- Task WriteMessage(string message);
- }
- public class MyDependency: IMyDependency
- {
- public MyDependency()
- {
- }
- public Task WriteMessage(string message)
- {
- Console.WriteLine($"MyDependency.WriteMessage called. Message: {message}");
- return Task.FromResult(0);
- }
- }
- public class IndexModel : PageModel
- {
- IMyDependency _dependency = new MyDependency();
- public void OnGet()
- {
- _dependency.WriteMessage("IndexModel.OnGet created this message.");
- }
- }
从上述代码可以看到当我们调用 IndexModel 模块 OnGetAsync 方法的时候, 是通过 IMyDependency 接口实例化 MyDependency 类去实现其方法内容的, 这叫控制正转. 但是 Master 说, 我们不应该创建 MyDependency 类, 而是让调用者给你传递, 于是你通过构造函数让外界把这两个依赖给你.
示例 3:
- public interface IMyDependency
- {
- Task WriteMessage(string message);
- }
- public class MyDependency : IMyDependency
- {
- private readonly ILogger<MyDependency> _logger;
- public MyDependency(ILogger<MyDependency> logger)
- {
- _logger = logger;
- }
- public Task WriteMessage(string message)
- {
- _logger.LogInformation(
- "MyDependency.WriteMessage called. Message: {MESSAGE}",
- message);
- return Task.FromResult(0);
- }
- }
- public class IndexModel : PageModel
- {
- private readonly IMyDependency _dependency;
- public IndexModel(IMyDependency dependency)
- {
- _dependency = dependency;
- }
- public void OnGet()
- {
- _dependency.WriteMessage("IndexModel.OnGet created this message.");
- }
- }
从上述代码可以看到把依赖的创建丢给第三方系统 (例: Autofac,Unity 容器), 也叫控制反转(IoC) 容器. 自己只负责使用, 其它人丢给你依赖的这个过程理解为注入. 也叫控制反转(IoC). 注意, 框架内部 ILogger 接口已注入, 无需手动再重新注入.
2.3 IoC 容器
IoC 容器可以看作是负责统一管理依赖关系的地方. 常见有 Autofac,Unity.
容器只要负责两件事情:
●绑定服务与实例之间的关系
●获取实例, 并对实例进行管理(创建与销毁)
3. 依赖倒置原则 (DIP) 与控制反转 (IoC) 的区别
DIP 是一种软件设计原则, 它仅仅告诉你高低层模块之间应该如何依赖, 但是它并没有告诉我们如何解除相互依赖模块的耦合. 而 IoC 则是一种软件设计模式, 它告诉我们该如何解除模块的耦合, 它为相互依赖的组件提供抽象, 将依赖 (低层模块) 对象的获得交给第三方系统 (例: Autofac,Unity 容器) 来控制, 即依赖对象不在被依赖模块的类中直接通过 new 来获取.
4.NET Core 依赖注入 (DI) 服务
经过上面描述, 大家应该应该对依赖倒置原则 (DIP), 依赖注入(DI), 控制反转(IoC) 这几个概念有一定了解对吧. 在. NET Core 中 DI 的核心分为两个组件: IServiceCollection 和 IServiceProvider.
●IServiceCollection 负责注册
●IServiceProvider 负责提供实例
下面让我们来学习下 NET Core 是怎么依赖注入 (DI) 服务.
第一步: 使用接口来实现依赖反转. 定义 IMyDependency 服务.
- public interface IMyDependency
- {
- Task WriteMessage(string message);
- }
第二步: 定义 IMyDependency 服务的实现类 MyDependency.
- public class MyDependency : IMyDependency
- {
- private readonly ILogger<MyDependency> _logger;
- public MyDependency(ILogger<MyDependency> logger)
- {
- _logger = logger;
- }
- public Task WriteMessage(string message)
- {
- _logger.LogInformation(
- "MyDependency.WriteMessage called. Message: {MESSAGE}",
- message);
- return Task.FromResult(0);
- }
- }
第三步: 把 IMyDependency 服务注册到服务容器中.
- public void ConfigureServices(IServiceCollection services)
- {
- // 注册将服务生命期的范围限定为单个请求的生命期, 下节再来聊服务生命期
- services.AddScoped<IMyDependency, MyDependency>();
- }
第四步: 把服务注入到使用它的类的构造函数中. 在 HomeController 里面调用 IndexModel.OnGet 方法输出 WriteMessage 消息.
- public class IndexModel : PageModel
- {
- private readonly IMyDependency _dependency;
- public IndexModel(IMyDependency dependency)
- {
- _dependency = dependency;
- }
- public void OnGet()
- {
- _dependency.WriteMessage("IndexModel.OnGet created this message.");
- }
- }
- private readonly IMyDependency _iMyDependency;
- public HomeController(IMyDependency iMyDependency)
- {
- _iMyDependency = iMyDependency;
- }
- public IActionResult Index()
- {
- IndexModel _IndexModel = new IndexModel(_iMyDependency);
- _IndexModel.OnGet();
- return View();
- }
WriteMessage 日志消息如下:
5. 默认服务容器替换
下面我们将来演示内置容器怎么替换为其他容器示例, 比如替换第三方 Autofac 容器, 我们需要在 Startup.ConfigureServices 方法里面注册 Autofac 容器, 具体代码如下:
- public IServiceProvider ConfigureServices(IServiceCollection services)
- {
- // Add Autofac
- var containerBuilder = new ContainerBuilder();
- containerBuilder.RegisterModule<DefaultModule>();
- containerBuilder.Populate(services);
- var container = containerBuilder.Build();
- return new AutofacServiceProvider(container);
- }
这里需要注意的是如果需要使用第三方容器, Startup.ConfigureServices 必须返回 IServiceProvider. 然后自定义一个模块类配置依赖关系, 具体代码如下:
- public class DefaultModule : Module
- {
- protected override void Load(ContainerBuilder builder)
- {
- builder.RegisterType<CharacterRepository>().As<ICharacterRepository>();
- }
- }
应用程序在运行时, 使用 Autofac 来解析类型, 并注入依赖关系.
参考文献:
在 ASP.NET Core 依赖注入
来源: https://www.cnblogs.com/wzk153/p/10892444.html