ASP.NET Core提供的依赖注入模块支持我们在容器中为一个类型注册一个或者多个实现,并提供了GetService
和GetServices
两个扩展方法来获取类型的实例,前者会根据注册的顺序返回指定类型的最后一次注册的实例,后者会返回指定类型注册的所有实例。虽然我们注册了多个实现,但是通常情况下我们都是希望程序在运行的时候能够获取其中一个指定的实现,而不是所有的实现,但是ASP.NET Core本身对这个支持并不是友好,我们需要使用一些其它变通的方法来实现。
我用ASP.NET Core控制台程序做了一个工具,这个工具能够通过命令行参数来运行指定的任务。它的使用方式如下所示,在运行时通过设置start
参数来指定需要运行的任务:
1 | dotnet TaskTools.dll --start=one |
本文接下来的内容将介绍该工具如何实现注册多个实现以及根据参数获取指定的实例。
我设计了一个IServiceTask
接口类,它拥有一个方法Start()
,所有实际的任务类都需要继承这个接口,为了演示这里实现了两个类OneTask
和TwoTask
:
1 | interface IServiceTask |
2 | { |
3 | void Start(); |
4 | } |
5 | |
6 | class OneTask : IServiceTask |
7 | { |
8 | public void Start() |
9 | { |
10 | Console.WriteLine("OneTask"); |
11 | } |
12 | } |
13 | |
14 | class TwoTask : IServiceTask |
15 | { |
16 | public void Start() |
17 | { |
18 | Console.WriteLine("TwoTask"); |
19 | } |
20 | } |
在容器中我首先分别注册了所有实现类:
1 | services.AddSingleton<OneTask>(); |
2 | services.AddSingleton<TwoTask>(); |
因为ASP.NET Core允许我们使用工厂的方式去注册我们的类型,所以我这里采用了该方式注册了一个Func类型,在委托中根据传过来的参数返回相应的类型:
1 | services.AddTransient<Func<string, IServiceTask>>(provider => start => |
2 | { |
3 | switch (start) |
4 | { |
5 | case "one":return provider.GetService<OneTask>(); |
6 | case "two":return provider.GetService<TwoTask>(); |
7 | default:throw new NotImplementedException(); |
8 | } |
9 | }); |
这样就可以根据参数动态获取指定的任务实例并执行了:
1 | var func = serviceProvider.GetService<Func<string, IServiceTask>>(); |
2 | var task = func(configuration["start"]); |
3 | task.Start(); |