.NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了 (2)

这里有两种业务需求!第一种业务中只需要对其中一种实现方式进行调用,如:业务需要SqlServer数据库的实现就行了。第二种是业务中对这两种实现方式都有用到,如:业务急需要用到Oracle的数据库实现同时也有用到SqlServer的数据库实现,需要同时往这两个数据库中插入相同的数据。下面分别对这两种需求进行解决。

业务中对这两种实现方式都有用到

针对这种情况有如下两种实现方式:

第二种实现方式

其实,在ASP.NET Core中,当你对一个接口注册了多个实现的时候,构造函数是可以注入一个该接口集合的,这个集合里是所有注册过的实现。

下面我们先改造下ConfigureServices,分别注入下这两种实现

services.AddTransient<ISayHello, A.SayHello>(); services.AddTransient<ISayHello,B.SayHello>();

接着继续改造下注入的方式,这里我们直接注入IEnumerable<ISayHello>如下代码所示:

private readonly ISayHello sayHelloA; private readonly ISayHello sayHelloB; public ValuesController(IEnumerable<ISayHello> sayHellos) { sayHelloA = sayHellos.FirstOrDefault(h => h.GetType().Namespace == "MultiImpDemo.A"); sayHelloB = sayHellos.FirstOrDefault(h => h.GetType().Namespace == "MultiImpDemo.B"); } // GET api/values [HttpGet] public ActionResult<IEnumerable<string>> Get() { return new string[] { sayHelloA.Talk() , sayHelloB.Talk()}; } private readonly ISayHello sayHelloA; private readonly ISayHello sayHelloB; public ValuesController(IEnumerable<ISayHello> sayHellos) { sayHelloA = sayHellos.FirstOrDefault(h => h.GetType().Namespace == "MultiImpDemo.A"); sayHelloB = sayHellos.FirstOrDefault(h => h.GetType().Namespace == "MultiImpDemo.B"); }

然后运行起来看下效果吧

1546870734607

利用AddTransient的扩展方法public static IServiceCollection AddTransient<TService>(this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory) where TService : class; 然后根据我们的配置的实现来进行服务实现的获取。下面就让我们利用代码来实现一番吧:

services.AddTransient<A.SayHello>(); services.AddTransient<B.SayHello>(); services.AddTransient(implementationFactory => { Func<string, ISayHello> accesor = key => { if (key.Equals("MultiImpDemo.A")) { return implementationFactory.GetService<A.SayHello>(); } else if (key.Equals("MultiImpDemo.B")) { return implementationFactory.GetService<B.SayHello>(); } else { throw new ArgumentException($"Not Support key : {key}"); } }; return accesor; });

当然了,既然用到了我们配置文件中的代码,因此我们需要设置下这个配置:

然后我们具体调用的依赖注入的方式需要变化一下:

private readonly ISayHello sayHelloA; private readonly ISayHello sayHelloB; private readonly Func<string, ISayHello> _serviceAccessor; public ValuesController(Func<string, ISayHello> serviceAccessor) { this._serviceAccessor = serviceAccessor; sayHelloA = _serviceAccessor("MultiImpDemoA"); sayHelloB = _serviceAccessor("MultiImpDemoB"); } // GET api/values [HttpGet] public ActionResult<IEnumerable<string>> Get() { return new string[] { sayHelloA.Talk() , sayHelloB.Talk()}; }

然后运行看下效果吧:

1546869793187

可以看到A跟B的实现都获取到了!效果实现!

业务只需要对其中一种实现方式的调用

这时候我们可以根据我们预设的配置来动态获取我们所需要的实现。这段话说的我自己都感觉拗口。话不多少,开鲁吧!这里我将介绍三种实现方式。

根据我们的配置文件中设置的key来进行动态的注入。

这种方式实现之前首先得进行相应的配置,如下所示:

"CommonSettings": { "ImplementAssembly": "MultiImpDemo.A" }

然后在注入的时候根据配置进行动态的进行注入:

services.AddTransient<ISayHello, A.SayHello>(); services.AddTransient<ISayHello, B.SayHello>();

然后在服务调用的时候稍作修改:

private readonly ISayHello sayHello; public ValuesController(IEnumerable<ISayHello> sayHellos,IConfiguration configuration) { sayHello = sayHellos.FirstOrDefault(h => h.GetType().Namespace == configuration.GetSection("CommonSettings:ImplementAssembly").Value); } // GET api/values [HttpGet] public ActionResult<IEnumerable<string>> Get() { return new string[] { sayHello.Talk() }; }

OK,到这里运行一下看下效果吧!然后改下配置文件再看下效果!

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyddxw.html