.Net依赖注入神器Scrutor(下)
前言
上一篇文章我们讲到了Scrutor第一个核心功能Scanning,本文讲解的是Scrutor第二个核心的功能Decoration 装饰器模式在依赖注入中的使用。
- 装饰器模式允许您向现有服务类中添加新功能,而无需改变其结构
Install-Package Scrutor
本文的完整源代码在文末
Decoration 依赖注入代理模式
首先首先一个 获取 User 的服务
定义 User 类
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string? Email { get; set; }
}
定义接口和实现
public interface IUserService
{
List<User> GetAllUsers();
}
public class UserService : IUserService
{
public List<User> GetAllUsers()
{
Console.WriteLine("GetAllUsers方法被调用~");
List<User> users = [
new User(){
Id= 1,
Name="张三",
Age=18,
Email="zhangsan@163.com"
},
new User(){
Id= 2,
Name="李四",
Age=19,
Email="lisi@163.com"
},
];
return users!;
}
}
现在有了我们的获取全部用户的服务了,需求是在不破坏当前类的添加装饰器模式,为 GetAllUsers 接口添加缓存。
创建装饰器类
public class UserDecorationService(IUserService userService, IMemoryCache cache) : IUserService
{
public List<User> GetAllUsers()
{
Console.WriteLine("GetAllUsers代理方法被调用~");
return cache.GetOrCreate("allUser", cacheEntry =>
{
cacheEntry.SetAbsoluteExpiration(
TimeSpan.FromMinutes(5));
var allUsers = userService.GetAllUsers();
return allUsers ?? [];
})!;
}
}
DI 容器添加服务
builder.Services.AddTransient<IUserService, UserService>();
builder.Services.AddMemoryCache();
builder.Services.Decorate<IUserService, UserDecorationService>();
创建接口测试一下
app.MapGet("/GetAllUsers", ([FromServices] IUserService userService) => userService.GetAllUsers()).WithSummary("获取全部用户接口");
调用第一次
GetAllUsers代理方法被调用~
GetAllUsers方法被调用~
第二次调用
GetAllUsers代理方法被调用~
可以看出第一次没缓存装饰器类和我们 UserService 都调用了,第二次因为只有了缓存所以只调用了装饰器类,可以看出我们的装饰器模式生效了。
依赖注入装饰器底层核心实现
/// <summary>
/// Decorates all registered services using the specified <paramref name="strategy"/>.
/// </summary>
/// <param name="services">The services to add to.</param>
/// <param name="strategy">The strategy for decorating services.</param>
public static bool TryDecorate(this IServiceCollection services, DecorationStrategy strategy)
{
Preconditions.NotNull(services, nameof(services));
Preconditions.NotNull(strategy, nameof(strategy));
var decorated = false;
for (var i = services.Count - 1; i >= 0; i--)
{
var serviceDescriptor = services[i];
if (IsDecorated(serviceDescriptor) || !strategy.CanDecorate(serviceDescriptor))
{
continue;
}
var serviceKey = GetDecoratorKey(serviceDescriptor);
if (serviceKey is null)
{
return false;
}
// Insert decorated
services.Add(serviceDescriptor.WithServiceKey(serviceKey));
// Replace decorator
services[i] = serviceDescriptor.WithImplementationFactory(strategy.CreateDecorator(serviceDescriptor.ServiceType, serviceKey));
decorated = true;
}
return decorated;
}
这个代码是在 dotNet8 的环境下编译的,可以看出做了几件事:
第一 IServiceCollection 集合倒序遍历,找到符合条件的ServiceType
核心代码一
// Insert decorated
services.Add(serviceDescriptor.WithServiceKey(serviceKey));
将原先的ServiceDescription作为基础,添加了ServiceKey后再进行添加操作,新的服务描述符会被添加到服务集合的末尾,
核心代码二
// Replace decorator
services[i] = serviceDescriptor.WithImplementationFactory(strategy.CreateDecorator(serviceDescriptor.ServiceType, serviceKey));
这一步是将原有的服务描述符替换为一个新的服务描述符,新的服务描述符使用装饰器工厂方法创建,实现了服务的装饰功能。
用的时候
app.MapGet("/GetAllUsers", ([FromServices] IUserService userService) => userService.GetAllUsers()).WithSummary("获取全部用户接口");
这样就可以获取到装饰器类提供服务,之前看到services.Add(serviceDescriptor.WithServiceKey(serviceKey));在代码的最后添加了一个服务,那 IOC 获取的时候肯定是从后面优先获取,这地方用了 dotNet8 的键控依赖注入(KeyedService),以 ServiceType 获取服务只会获取到我们提供的装饰器实例,这一手简直是神来之笔 。
最后
Scrutor的装饰器模式可以用于动态地给依赖注入的实例添加额外职责,实现动态增加和撤销功能,而无需改变原有对象结构。可以在不影响其他对象的情况下,以透明且动态的方式给对象添加新功能,实现系统的灵活扩展和维护。
本文完整源代码
.Net依赖注入神器Scrutor(下)的更多相关文章
- 【半小时大话.net依赖注入】(下)详解AutoFac+实战Mvc、Api以及.NET Core的依赖注入
系列目录 上|理论基础+实战控制台程序实现AutoFac注入 下|详解AutoFac+实战Mvc.Api以及.NET Core的依赖注入 前言 本来计划是五篇文章的,每章发个半小时随便翻翻就能懂,但是 ...
- <Pro .NET MVC4> 三大工具之依赖注入神器——Ninject
这篇内容是对<Pro .NET MVC4>一书中关于Ninject介绍的总结. Ninject是.NET MVC的一款开源的依赖注入工具. 使用场景:当MVC项目中使用了依赖注入技术来给程 ...
- 从零开始,搭建博客系统MVC5+EF6搭建框架(2),测试添加数据、集成Autofac依赖注入
一.测试仓储层.业务层是否能实现对数据库表的操作 1.创建IsysUserInfoRepository接口来继承IBaseRepository父接口 namespace Wchl.WMBlog.IRe ...
- Spring的核心机制——依赖注入(Dependency Inject)
Spring不仅提供对象,还提供对象的属性值,而不是由使用该对象的程序所提供的. Java应用是由一些相互协作的对象所组成的,在Spring中这种相互协作的关系就叫依赖关系. 如果A组件调用了B组件的 ...
- (五)Angularjs - 依赖注入
如何找到API? AngularJS提供了一些功能的封装,但是当你试图通过全局对象angular去 访问这些功能时,却发现与以往遇到的库大不相同. 比如,AngularJS暴露了一个全局对象:angu ...
- AngularJS应用开发思维之3:依赖注入
找不到的API? AngularJS提供了一些功能的封装,但是当你试图通过全局对象angular去 访问这些功能时,却发现与以往遇到的库大不相同. $http 比如,在jQuery中,我们知道它的AP ...
- 基于ABP模块组件与依赖注入组件的项目插件开发
注意,阅读本文,需要先阅读以下两篇文章,并且对依赖注入有一定的基础. 模块系统:http://www.cnblogs.com/mienreal/p/4537522.html 依赖注入:http://w ...
- angular2的依赖注入
更好阅读体验,请看原文 在读这篇文章之前,你要先了解一下什么是依赖注入,网上关于这个的解释很多,大家可以自行Google. 我们这一篇文章还是以QuickStart项目为基础,从头开始讲解怎么在Ang ...
- Spring的核心机制——依赖注入(Dependency Inject)
Spring不仅提供对象,还提供对象的属性值,而不是由使用该对象的程序所提供的. Java应用是由一些相互协作的对象所组成的,在Spring中这种相互协作的关系就叫依赖关系. 如果A组件调用了B组件的 ...
- SignalR中的依赖注入
什么是依赖注入? 如果你已经熟悉依赖注入可以跳过此节. 依赖注入 (DI) 模式下,对象并不为自身的依赖负责. 下边的例子是一个主动 DI. 假设你有个对象需要消息日志.你可能定义了一个日志接口: C ...
随机推荐
- python 不显示科学计数法
pandas方法 import pandas as pd pd.set_option('display.float_format',lambda x : '%.3f' % x) 禁用科学计数法,小数保 ...
- NC24755 [USACO 2010 Dec S]Apple Delivery
题目链接 题目 题目描述 Bessie has two crisp red apples to deliver to two of her friends in the herd. Of course ...
- 【Unity3D】立方体纹理(Cubemap)和天空盒子(Skybox)
1 立方体纹理(Cubemap) 本文完整资源见 → 立方体纹理(Cubemap)和天空盒子(Skybox) . 1)立方体纹理简介 立方体纹理是指由上.下.左.右.前.后 6 张纹理组成 ...
- 使用JS快速读取TXT文件
1 前言 最近有个需求,需要使用JS快速读取外部大数据文件(60w条记录的表).笔者尝试过使用JS读取Excel文件,但是跑了十几分钟仍未出结果,后来笔者尝试将原数据保存为TXT文件,再从TXT文件中 ...
- Java Console类
用于从控制台设备读取字符信息,通常是文本和密码.尤其读取密码字符时是看不见的. 下面给出一个例子: import java.io.Console; /** * @author xusucheng * ...
- win32 - 关于GDI的RGB的数据分析
此文章为小结,仅供参考. 第一种情况,从桌面DC获取RGBA的数据. 32位 HDC hdc, hdcTemp; RECT rect; BYTE* bitPointer; int x, y; int ...
- Redis客户端汇总
编程客户端 已经支持了许多编程语言,详见:https://redis.io/docs/clients/ 图形客户端 1.Another Redis Desktop Manager 支持哨兵, 集群, ...
- nosql几种热门数据库的优缺点及应用场景
MongoDB.ElasticSearch.Redis.HBase这四种热门数据库的优缺点及应用场景 https://www.cnblogs.com/chong-zuo3322/p/12869059. ...
- django中的一些装饰器用法
1.require_http_methods() 1.要求视图只接受特定的请求方法 2.该装饰器允许传递多个请求方法参数,以列表的形式,请求方法名要大写 from django.views.decor ...
- CXP2.0的相机是否可以使用CXP1.1的Grabber
可以 答案是肯定的. 目前CXP共有2个发布版本: 2011年发布CXP1.1 2021年发布CXP2.1,向后兼容,新标准增加了同步功能.数据率放大了一倍. 只要是符合CXP标准.接插件匹配,那么C ...