用工厂模式解决ASP.NET Core中依赖注入的一个烦恼
2017-05-21 12:10
1036 查看
这是最近在实际开发中遇到的一个问题,用 asp.net core 开发一个后端 web api ,根据指定的 key 清除 2 台 memcached 服务器上的缓存。背景是我们在进行 .net core 迁移工作,asp.net 项目与 asp.net core 项目并存,为了避免两种类型项目的缓存冲突,我们分别用了 2 台不同的 memcached 服务器。
之前使用 1 台 memcached 服务器时,只需要一个客户端,所以只需创建一个 MemcachedClient 单例并注入到 IMemcachedClient 接口。
(注:memcached 的配置存储在 appsettings.json 中)
而现在需要用 2 个 memcached 客户端实例分别连接 2 台不同的 memcached 服务器,需要 2 个不同配置的 MemcachedClient 单例,而之前针对 1 个 IMemcachedClient 接口的依赖注入方法不管用了。咋整?
首先想到的是一个变通的方法,1 个接口不行,那就用 2 个接口,于是增加下面的 2 个接口:
因为 MemcachedClient 并没有实现这个这 2 个接口,还要另外增加这 2 个接口的实现:
沿着这条路发现越走越不对劲,还要增加更多的接口与实现。由于 2 个 memcached 客户端的不同在于 IMemcachedClientConfiguration 的不同,而上面的 MemcachedClientCore 与 MemcachedClientLegacy 的构造函数都注入 IMemcachedClientConfiguration 是不行的,还要基于 IMemcachedClientConfiguration 再增加 2 个接口,增加了接口就又不得不再增加实现。。。这样解决问题岂不让人疯掉,遂弃之。
后来转念一想,自己解决问题的思路走偏了,一味地将关注的焦点放在如何通过 Dependency Injection 注入 2 个不同的 MemcachedClient 实例,而忽略了一个很简单的解决方法 —— 用工厂类创建 MemcachedClient 实例,通过 Dependency Injection 注入工厂类,就像 ILoggerFactory 那样。
于是通过基于依赖注入的工厂模式轻松解决了这个问题。
定义一个 IMemcachedClientFactory 接口:
添加 MemcachedClientFactory 类实现 IMemcachedClientFactory 接口:
在 Startup.ConfigureServices() 中注入 MemcachedClientFactory 的单例:
在 Startup.Configure() 中调用 IMemcachedClientFactory 接口的 Add() 方法,根据不同配置创建 MemcachedClient 的实例:
在使用 MemcachedClient 的地方通过 IMemcachedClientFactory 接口的 Create() 方法获取所需 MemcachedClient 的实例:
之前使用 1 台 memcached 服务器时,只需要一个客户端,所以只需创建一个 MemcachedClient 单例并注入到 IMemcachedClient 接口。
public void ConfigureServices(IServiceCollection services) { services.AddOptions(); services.Configure<MemcachedClientOptions>(Configuration.GetSection("memcached")); services.Add(ServiceDescriptor.Transient<IMemcachedClientConfiguration, MemcachedClientConfiguration>()); services.Add(ServiceDescriptor.Singleton<IMemcachedClient, MemcachedClient>()); }
(注:memcached 的配置存储在 appsettings.json 中)
而现在需要用 2 个 memcached 客户端实例分别连接 2 台不同的 memcached 服务器,需要 2 个不同配置的 MemcachedClient 单例,而之前针对 1 个 IMemcachedClient 接口的依赖注入方法不管用了。咋整?
首先想到的是一个变通的方法,1 个接口不行,那就用 2 个接口,于是增加下面的 2 个接口:
public interface IMemcachedClientCore : IMemcachedClient { } public interface IMemcachedClientLegacy : IMemcachedClient { }
因为 MemcachedClient 并没有实现这个这 2 个接口,还要另外增加这 2 个接口的实现:
public class MemcachedClientCore : MemcachedClient, IMemcachedClientCore { public MemcachedClientCore( ILogger<MemcachedClient> logger, IMemcachedClientConfiguration configuration) : base(logger, configuration) { } } public class MemcachedClientLegacy : MemcachedClient, IMemcachedClientLegacy { public MemcachedClientLegacy( ILogger<MemcachedClient> logger, IMemcachedClientConfiguration configuration) : base(logger, configuration) { } }
沿着这条路发现越走越不对劲,还要增加更多的接口与实现。由于 2 个 memcached 客户端的不同在于 IMemcachedClientConfiguration 的不同,而上面的 MemcachedClientCore 与 MemcachedClientLegacy 的构造函数都注入 IMemcachedClientConfiguration 是不行的,还要基于 IMemcachedClientConfiguration 再增加 2 个接口,增加了接口就又不得不再增加实现。。。这样解决问题岂不让人疯掉,遂弃之。
后来转念一想,自己解决问题的思路走偏了,一味地将关注的焦点放在如何通过 Dependency Injection 注入 2 个不同的 MemcachedClient 实例,而忽略了一个很简单的解决方法 —— 用工厂类创建 MemcachedClient 实例,通过 Dependency Injection 注入工厂类,就像 ILoggerFactory 那样。
于是通过基于依赖注入的工厂模式轻松解决了这个问题。
定义一个 IMemcachedClientFactory 接口:
public interface { IMemcachedClientFactory Add(string keyOfConfiguration); IMemcachedClient Create(string keyOfConfiguration); }
添加 MemcachedClientFactory 类实现 IMemcachedClientFactory 接口:
public class MemcachedClientFactory : IMemcachedClientFactory { private readonly ILoggerFactory _loggerFactory; private readonly IConfiguration _configuration; private readonly Dictionary<string, IMemcachedClient> _clients = new Dictionary<string, IMemcachedClient>(); public MemcachedClientFactory( ILoggerFactory loggerFactory, IConfiguration configuration) { _loggerFactory = loggerFactory; _configuration = configuration; } public IMemcachedClientFactory Add(string keyOfConfiguration) { var options = new MemcachedClientOptions(); _configuration.GetSection(keyOfConfiguration).Bind(options); var memcachedClient = new MemcachedClient( _loggerFactory, new MemcachedClientConfiguration(_loggerFactory, options)); _clients.Add(keyOfConfiguration, memcachedClient); return this; } public IMemcachedClient Create(string keyOfConfiguration) { return _clients[keyOfConfiguration]; } }
在 Startup.ConfigureServices() 中注入 MemcachedClientFactory 的单例:
public void ConfigureServices(IServiceCollection services) { services.AddSingleton<IMemcachedClientFactory, MemcachedClientFactory>(); }
在 Startup.Configure() 中调用 IMemcachedClientFactory 接口的 Add() 方法,根据不同配置创建 MemcachedClient 的实例:
public void Configure(IApplicationBuilder app, IMemcachedClientFactory memcachedClientFactory) { memcachedClientFactory.Add("MemcachedLegacy").Add("MemcachedCore"); }
在使用 MemcachedClient 的地方通过 IMemcachedClientFactory 接口的 Create() 方法获取所需 MemcachedClient 的实例:
public class CacheController : Controller { private readonly IMemcachedClient _memcachedClientLegacy; private readonly IMemcachedClient _memcachedClientCore; public CacheController(IMemcachedClientFactory memcachedClientFacotry) { _memcachedClientLegacy = memcachedClientFacotry.Create("MemcachedLegacy"); _memcachedClientCore = memcachedClientFacotry.Create("MemcachedCore"); } [HttpDelete("{key}")] public async Task<IActionResult> Delete(string key) { var removeCoreTask = _memcachedClientCore.RemoveAsync(key); var removeLegacyTask = _memcachedClientLegacy.RemoveAsync(key); await removeCoreTask; await removeLegacyTask; return Ok(); } }
相关文章推荐
- ASP.NET Core中的依赖注入(2):依赖注入(DI)
- [.NET开发] ASP.NET Core 1.0基础之依赖注入
- ASP.NET Core 在 JSON 文件中配置依赖注入
- ASP.NET Core依赖注入解读&使用Autofac替代实现
- ASP.NET Core 中文文档 第四章 MVC(4.4)依赖注入和控制器
- ASP.NET Core中的依赖注入(4): 构造函数的选择与服务生命周期管理
- ASP.NET Core中的依赖注入(1):控制反转(IoC)
- 【无私分享:ASP.NET CORE 项目实战(第二章)】添加EF上下文对象,添加接口、实现类以及无处不在的依赖注入(DI)
- ASP.NET Core 中文文档 第三章 原理(10)依赖注入
- 使用依赖关系注入在 ASP.NET Core 中编写干净代码
- ASP.NET Core中的依赖注入(5):ServicePrvider实现揭秘【补充漏掉的细节】
- 【无私分享:ASP.NET CORE 项目实战(第二章)】添加EF上下文对象,添加接口、实现类以及无处不在的依赖注入(DI)
- ASP.NET Core依赖注入解读&使用Autofac替代实现
- ASP.NET Core 中的依赖注入 [共7篇]
- ASP.NET Core中的依赖注入(2):依赖注入(DI)
- ASP.NET Core 中文文档 第四章 MVC(3.8)视图中的依赖注入
- ASP.NET Core中的依赖注入(5): ServiceProvider实现揭秘 【总体设计 】
- ASP.NET Core 1.0基础之依赖注入
- 使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(六)-- 依赖注入
- Asp.Net Core 项目实战之权限管理系统(4) 依赖注入、仓储、服务的多项目分层实现