用工厂模式解决ASP.NET Core中依赖注入的一个烦恼
这是最近在实际开发中遇到的一个问题,用 asp.net core 开发一个后端 web api ,根据指定的 key 清除 2 台 memcached 服务器上的缓存。背景是我们在进行 .net core 迁移工作,asp.net 项目与 asp.net core 项目并存,为了避免两种类型项目的缓存冲突,我们分别用了 2 台不同的 memcached 服务器。
之前使用 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 memcachedClientFactory)
{
_memcachedClientLegacy = memcachedClientFactory.Create("MemcachedLegacy");
_memcachedClientCore = memcachedClientFactory.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中依赖注入的一个烦恼的更多相关文章
- ASP.NET Core之依赖注入
本文翻译自:http://www.tutorialsteacher.com/core/dependency-injection-in-aspnet-core ASP.NET Core支持依赖注入,依赖 ...
- 几十行代码实现ASP.NET Core自动依赖注入
在开发.NET Core web服务的时候,我们习惯使用自带的依赖注入容器来进行注入. 于是就会经常进行一个很频繁的的重复动作:定义一个接口->写实现类->注入 有时候会忘了写Add这一步 ...
- 如何解决 ASP.NET Core 中的依赖问题
依赖性注入是一种技术,它允许我们注入一个特定类的依赖对象,而不是直接创建这些实例. 使用依赖注入的好处显而易见,它通过放松模块间的耦合,来增强系统的可维护性和可测试性. 依赖注入允许我们修改具体实现, ...
- 【ASP.NET Core】依赖注入高级玩法——如何注入多个服务实现类
依赖注入在 ASP.NET Core 中起中很重要的作用,也是一种高大上的编程思想,它的总体原则就是:俺要啥,你就给俺送啥过来.服务类型的实例转由容器自动管理,无需我们在代码中显式处理. 因此,有了依 ...
- Asp.net core自定义依赖注入容器,替换自带容器
依赖注入 在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repos ...
- asp.net core ioc 依赖注入
1.生命周期 内置的IOC有三种生命周期: Transient: Transient服务在每次被请求时都会被创建.这种生命周期比较适用于轻量级的无状态服务. Scoped: Scoped生命周期的服务 ...
- ASP.NET Core:依赖注入
ASP.NET Core的底层设计支持和使用依赖注入.ASP.NET Core应用程序可以利用内置的框架服务将它们注入到启动类的方法中,并且应用程序服务能够配置注入.由ASP.NET Core提供的默 ...
- .NET Core 中依赖注入框架详解 Autofac
本文将通过演示一个Console应用程序和一个ASP.NET Core Web应用程序来说明依赖注入框架Autofac是如何使用的 Autofac相比.NET Core原生的注入方式提供了强大的功能, ...
- .NET Core 中依赖注入 AutoMapper 小记
最近在 review 代码时发现同事没有像其他项目那样使用 AutoMapper.Mapper.Initialize() 静态方法配置映射,而是使用了依赖注入 IMapper 接口的方式 servic ...
随机推荐
- List or delete hidden files from command prompt(CMD)
In Windows, files/folders have a special attribute called hidden attribute. By setting this attribut ...
- Google 发布的15个 Android 性能优化典范
2015年伊始,Google发布了关于Android性能优化典范的专题,一共16个短视频,每个3-5分钟,帮助开发者创建更快更优秀的Android App.课程专题不仅仅介绍了Android系统中有关 ...
- linux内核剖析(零)linux系统启动过程详解-开机加电后发生了什么
本文参考了如下文章 深入理解linux启动过程 mbr (主引导记录(Master Boot Record)) 电脑从开机加电到操作系统main函数之前执行的过程 详解linux系统的启动过程及系统初 ...
- 容器网络——从CNI到Calico
从容器诞生开始,存储和网络这两个话题就一直为大家津津乐道.我们今天这个环境下讲网络这个问题,其实是因为容器对网络的需求,和传统物理.虚拟环境对网络环境需求是有差别的,主要面临以下两个问题: 过去Iaa ...
- 物联网架构成长之路(6)-EMQ权限控制
1. 前言 EMQTT属于一个比较小众的开源软件,很多资料不全,很麻烦,很多功能都是靠猜测,还有就是看官方提供的那几个插件,了解. 2. 说明 上一小节的插件 emq_plugin_wunaozai ...
- 启动TDS LDAP 服务器遇到的问题总结
在启动TDS LDAP服务器时遇到一些问题,由于习惯使用Oracle数据库,而对DB2数据库比较陌生,在遇到这些问题时也是摸不到头脑,好在现在解决了,并把所遇到的问题罗列如下: 使用命令启动TDS L ...
- TP支持菜单动态生成RBAC权限系统数据库结构设计方案
最简单基于RBAC权限系统数据库结构设计 包括如下几个表 1. 用户表 -- Table "t_user" DDL CREATE TABLE `t_user` ( `id` int ...
- hdoj:2027
#include <iostream> #include <string> #include <vector> using namespace std; int m ...
- Java知多少(上)
Java知多少(1)语言概述 Java知多少(2)虚拟机(JVM)以及跨平台原理 Java知多少(3) 就业方向 Java知多少(4)J2SE.J2EE.J2ME的区别 Java知多少(5) Java ...
- A Tour of ParallelExtensionsExtras
Throughout the development of Parallel Extensions for the .NET Framework 4, we've come across a myri ...