NET Core的DI注册
# 用Scrutor来简化ASP.NET Core的DI注册
以MS的DependencyInjection为例: 在要注册的服务数量比较少时,我们会选择一个一个的去注册
services.AddScoped<ISampleService, SampleService>();
在数量小于5个的时候,这样的做法还可以接受,但是,数量一多,代码会变的庞大、不容易读、容易忘记添加注入。
为了避免这种情况,我们往往会根据规律在注册的时候,用反射进行批量注册,后面按照对应的规律去写业务代码,就可以避免上面这种问题了。
Scrutor是 Kristian Hellang 大神写的一个基于Microsoft.Extensions.DependencyInjection的一个扩展库,主要是为了简化我们对DI的操作。
Scrutor主要提供了两个扩展方法给我们使用,一个是Scan,一个是Decorate。
本文主要讲的是Scan这个方法。
根据类命名规则批量注入
1、根据类的命名规则(包含某个前缀或后缀过滤)。
services.Scan(scan => scan
.FromAssemblyOf<Startup>()
.AddClasses(classes => classes.Where(t => t.Name.EndsWith("Service", StringComparison.OrdinalIgnoreCase)))
.AsImplementedInterfaces()
.WithTransientLifetime()
var list = services.Where(x => x.ServiceType.Namespace.Equals("WebApplication1.Service", StringComparison.OrdinalIgnoreCase)).ToList();
foreach (var item in list)
{
Console.WriteLine($"-----------{item.Lifetime},{item.ImplementationType},{item.ServiceType}");
}
2
3
4
5
6
7
8
9
10
11
12
13
14
输出:
-----------Transient,WebApplication1.Service.BookService,WebApplication1.Service.IBookService
-----------Transient,WebApplication1.Service.SampleService,WebApplication1.Service.ISampleService
2
3
FromAssemblyOf<Startup>
表示加载Startup这个类所在的程序集- AddClasses 表示要注册那些类,上面的代码还做了过滤,只留下了以 repository 结尾的类
- AsImplementedInterfaces 表示将类型注册为提供其所有公共接口作为服务
- WithTransientLifetime 表示注册的生命周期为 Transient
2、 很多时候,我们写一些接口和实现类的时候,都会根据这样的习惯来命名,定义一个接口IClass,它的实现类就是Class。
针对这种情形,Scrutor提供了一个简便的方法来帮助我们处理。
使用 AsMatchingInterface 方法就可以很轻松的帮我们处理注册好对应的信息。
services.Scan(scan => scan
.FromAssemblyOf<Startup>()
.AddClasses()
.AsMatchingInterface()
.WithTransientLifetime()
);
2
3
4
5
6
注册类自身
services.Scan(scan => scan
.AddTypes(typeof(MyClass))
.AsSelf()
.WithSingletonLifetime()
);
2
3
4
5
等同于:
services.AddSingleton<MyClass>();
2
相对来说批量操作的时候还是有点繁锁,因为需要把每个类型都扔进去,我们不可能事先知道所有的类。
下面的方法可以把MyClass所在的程序集的类都注册了。
services.Scan(scan => scan
.FromAssemblyOf<MyClass>()
.AddClasses()
.AsSelf()
.WithSingletonLifetime()
);
2
3
4
5
6
7
这样的做法也有一个缺点,会造成部分我们不想让他注册的,也注册进去了。
过滤一下或者规范一下自己的结构,就可以处理这个问题了。
重复注册处理策略 还有一个比较常见的情形是,重复注册,即同一个接口,有多个不同的实现。
Scrutor提供了三大策略,Append、Skip和Replace。 Append是默认行为,就是叠加。
public interface IDuplicate { }
public class FirstDuplicate : IDuplicate { }
public class SecondDuplicate : IDuplicate { }
services.Scan(scan => scan
.FromAssemblyOf<Startup>()
.AddClasses(classes=>classes.AssignableTo<IDuplicate>())
.AsImplementedInterfaces()
.WithTransientLifetime()
);
2
3
4
5
6
7
8
9
10
11
这个时候的输出如下
Transient,ScrutorTest.FirstDuplicate,ScrutorTest.IDuplicate
Transient,ScrutorTest.SecondDuplicate,ScrutorTest.IDuplicate
2
下面我们用Skip策略来替换默认的策略
services.Scan(scan => scan
.FromAssemblyOf<Startup>()
.AddClasses(classes=>classes.AssignableTo<IDuplicate>())
//手动高亮
.UsingRegistrationStrategy(RegistrationStrategy.Skip)
.AsImplementedInterfaces()
.WithTransientLifetime()
);
2
3
4
5
6
7
8
9
这个时候的输出如下
ransient,ScrutorTest.FirstDuplicate,ScrutorTest.IDuplicate