这篇文章是 ASP.NET 6 依赖注入系列文章的第 4 篇。
在上一篇文章中,我们讨论了依赖注入的服务注册与注入方式的内容。
接下来,在这篇文章中,我们将继续了解服务的批量注册与服务定位模式。.
Scrutor
虽然 .NET 中的依赖注入很好用,但在功能性上还是难以满足很多场景的。
比如我们在注册服务的时候,都是一项项的注册。
如果应用中,有大量的服务需要注册,逐项注册的方式就会显得很繁琐, 还很可能会有遗漏。
想要解决这个问题,我们可以使用第三方的依赖注入框架,比如 Autofac。
但是,Autofac 功能又过于强大,其中大部分的功能我们可能并不需要。
我们想要的仅仅是能够解决逐项注册服务的问题,那么还有一个轻量级的选择,就是使用一个名为 Scrutor的 .NET 依赖注入扩展库。
它可以很简单地添加到现有的 ASP.NET 应用程序中,我们只需要在项目中通过 Nuget 安装:
Install-Package Scrutor
除此之外,不需要编写任何额外的集成代码,因为它仅仅是对 .NET 依赖注入系统服务注册功能上的扩展。
Scrutor 相对于第三方依赖注入框架的好处就是,它更加轻量和便捷。
由于它只是扩展库,所以即便是 .NET 依赖注入系统在未来的更新中有所变化,Scrutor 受的影响也不会太大。
装配扫描
Scrutor 有两个针对服务集合ServiceCollection
类的扩展方法:Scan
和Decorate
。
-
Scan
方法用于扫描指定程序集,并按指定规则进行批量注册; -
Decorate
方法用于装饰已注册服务。
这里我们主要是用它的Scan
方法,它的基本使用方式如下示例:
services.Scan(
scan => scan
// 扫描 Program 类所在的程序集
.FromAssemblyOf<Program>()
// 筛选需要注册的类型
.AddClasses(classes => classes.Where(
t => t.Name.EndsWith("Service", StringComparison.OrdinalIgnoreCase)))
// 暴露注册类型的接口为服务标识
.AsImplementedInterfaces()
// 指定生命周期模式为 Scoped
.WithScopedLifetime());
Scan
方法的参数是一个配置委托,在这个委托中一般需要定义四个东西:
-
选择程序集,选择要注册的服务类型在哪个程序集中,也就是要扫描哪个程序集,常用的有:
-
FromAssemblyOf<>
,FromAssembliesOf
扫描包含所提供的类型的程序集; -
FromCallingAssembly
,扫描调用该方法的程序集; -
FromExecutingAssembly
,扫描当前执行的程序集; -
FromEntryAssembly
,扫描入口程序集。
-
-
筛选注册类,筛选注册扫描程序集中的类型:
-
AddClasses()
添加所有公共的非抽象类; -
AddClasses(publicOnly)
添加所有非抽象类,设置publicOnly=false
可以添加internal/private
修饰的类; -
AddClass(predicate)
添加符合筛选条件的类; -
AddClasses(predicate, publicOnly)
前面两种方法的结合。
-
-
暴露服务标识,注册类型应该以何种方式作为标识暴露:
-
AsImplementedInterface()
,暴露实现类所有的接口; -
AsSelf()
,有时我们注册的类是没有实现接口的,所以也可以用自身作为标识暴露; -
AsMatchingInterface()
,大多数情况下,接口和实现类都会根据IClass/Class
这样的习惯来命名,因此当我们需要暴露匹配类型名称的接口时,就可以使用该方法; -
As<>
可以自由选择任何类型作为标识进行暴露。
-
-
生命周期,注册服务使用的生命周期模式:
-
WithTransientLifetime()
,瞬时生命周期; -
WithScopedLifetime()
,作用域生命周期; -
WithSingletonLifetime()
,单例生命周期模式。
-
重复注册策略
有时候可能会出现重复注册的情况,也就是同一个服务,有多个不同的实现类。
因此注册过程有先后,所以这个时候可以利用 Scrutor 提供的重复注册处理策略:Append
、Skip
、Throw
和Replace
。
-
Append
叠加注册,这是默认的策略,也就是所有实现类都注册,但默认情况只有最先注册的才会生效。 -
Skip
跳过重复的注册服务,已注册的服务,不再为其注册其它实现类。 -
Throw
抛弃已注册的接口,已注册的服务实现类将被抛弃,而是为该服务注册新的实现类。 -
Replace
替换策略,它有三种替换方式:替换重复的实现类、替换重复的接口、替换任意重复。
services.Scan(
scan => scan
.FromAssemblyOf<Startup>()
.AddClasses()
// 重复注册处理策略
.UsingRegistrationStrategy(RegistrationStrategy.Skip));