使用AspNetCore开发的都已经尝到了各种花式注入的甜头,其中最基本的注入方式莫过于IServiceCollection.Add[Scoped/Transient/Singleton]<TService,TImplementation>()了。而对于已经注册的Service,如果有临时更换的需求就会稍显麻烦。
拿一个事例做说明:比如以前你是使用网易云音乐听周杰伦的歌的,当网易云不再拥有周杰伦音乐授权的时候,你不得不开始使用QQ音乐来听周杰伦的歌,因为现在QQ音乐拥有了版权。这时候你就需要想办法怎么替换音乐播放器了。
这个问题我们可以抽象一下:
音乐播放器作为一个接口:IMusicPlayer,该接口拥有一个方法:PlayJayChou,而最初只是网易云音乐(NetEaseCloudMusic)继承并实现了该接口,且在你的正式环境中使用着,例如AddScoped<IMusicPlayer,NetEaseCloudMusic>()。
此时需要更换为QQ音乐了,按照一般做法是,OK,添加QQMusic,继承并实现IMusicPlayer,然后嗯,将代码替换:AddScoped<IMusicPlayer,QQMusic>(),发布上线;
试想,如果QQ版权也过了,最后百度音乐拥有了版权,你还想这样改一遍代码,再发布上线吗?
基于此,我写了一个小小的项目,基于扩展和配置,灵活的切换你的Service。该项目的能力就是在不需要修改主程序代码的情况下,添加扩展并修改配置,完成Service的切换。
干货:
先来个项目一览吧,只看src其实可以得知,项目代码量真的很小,我估计不超过250行:
配置:在appsettings.json中配置如下内容,属性意义截图中已经给出注释,数组形式。
上图配置的映射类:
主要的实现思路是,读取配置(IMusicPlayer、QQMusic、QQMusic所在程序集的相对路径),利用反射技术分别获取Service的接口和实现类型。
获取到serviceType和ImplementationType,离注入还会远吗?
如此,项目便已实现。
使用示例,Startup类的ConfigureServices方法中添加services.AddServiceRegister(),需要放在各类service的注册代码段落之后:
仓库地址:https://github.com/Med1tator/Medit.AspNetCore.ServiceRegister
该项目中已包含MusicPlayer的Sample。