这是最近在实际开发中遇到的一个问题,用 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中依赖注入的一个烦恼的更多相关文章

  1. ASP.NET Core之依赖注入

    本文翻译自:http://www.tutorialsteacher.com/core/dependency-injection-in-aspnet-core ASP.NET Core支持依赖注入,依赖 ...

  2. 几十行代码实现ASP.NET Core自动依赖注入

    在开发.NET Core web服务的时候,我们习惯使用自带的依赖注入容器来进行注入. 于是就会经常进行一个很频繁的的重复动作:定义一个接口->写实现类->注入 有时候会忘了写Add这一步 ...

  3. 如何解决 ASP.NET Core 中的依赖问题

    依赖性注入是一种技术,它允许我们注入一个特定类的依赖对象,而不是直接创建这些实例. 使用依赖注入的好处显而易见,它通过放松模块间的耦合,来增强系统的可维护性和可测试性. 依赖注入允许我们修改具体实现, ...

  4. 【ASP.NET Core】依赖注入高级玩法——如何注入多个服务实现类

    依赖注入在 ASP.NET Core 中起中很重要的作用,也是一种高大上的编程思想,它的总体原则就是:俺要啥,你就给俺送啥过来.服务类型的实例转由容器自动管理,无需我们在代码中显式处理. 因此,有了依 ...

  5. Asp.net core自定义依赖注入容器,替换自带容器

    依赖注入 在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repos ...

  6. asp.net core ioc 依赖注入

    1.生命周期 内置的IOC有三种生命周期: Transient: Transient服务在每次被请求时都会被创建.这种生命周期比较适用于轻量级的无状态服务. Scoped: Scoped生命周期的服务 ...

  7. ASP.NET Core:依赖注入

    ASP.NET Core的底层设计支持和使用依赖注入.ASP.NET Core应用程序可以利用内置的框架服务将它们注入到启动类的方法中,并且应用程序服务能够配置注入.由ASP.NET Core提供的默 ...

  8. .NET Core 中依赖注入框架详解 Autofac

    本文将通过演示一个Console应用程序和一个ASP.NET Core Web应用程序来说明依赖注入框架Autofac是如何使用的 Autofac相比.NET Core原生的注入方式提供了强大的功能, ...

  9. .NET Core 中依赖注入 AutoMapper 小记

    最近在 review 代码时发现同事没有像其他项目那样使用 AutoMapper.Mapper.Initialize() 静态方法配置映射,而是使用了依赖注入 IMapper 接口的方式 servic ...

随机推荐

  1. Duplicate复制数据库并创建物理StandBy(pfile版本)

    1设定环境如下: Primary数据库 IP 172.17.22.16 SID orcl Standby数据库 IP 172.17.22.17 SID orcl 设置提示,以区分操作的位置 prima ...

  2. sublime text 3-right click context menu

    dd a system wide windows explorer button " Edit with Sublime" similar to how Notepad++ doe ...

  3. Effective Java 第三版——58. for-each循环优于传统for循环

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  4. Lambert漫反射的BRDF

    Lambert漫反射brdf=Albedo/pi. 推导: 如图,设Lambert面元获得入射照度Ei,各方向均匀释放亮度,每个方向释放的亮度都是Lo. 又设此表面反射率为Albedo,根据反射率定义 ...

  5. HttpURLConnection与HttpClient比较和使用示例

    1. GET请求与POST请求 HTTP协议是现在Internet上使用得最多.最重要的协议了,越来越多的Java应用程序需要直接通过HTTP协议来访问网络资源. 在介绍HttpURLConnecti ...

  6. [k8s]kube-dns架构图解

    kubedns DNS Policy http://blog.fleeto.us/translation/configuring-private-dns-zones-and-upstream-name ...

  7. [转]深刻理解Python中的元类(metaclass)以及元类实现单例模式

    使用元类 深刻理解Python中的元类(metaclass)以及元类实现单例模式 在看一些框架源代码的过程中碰到很多元类的实例,看起来很吃力很晦涩:在看python cookbook中关于元类创建单例 ...

  8. 【iCore4 双核心板_ARM】例程七:WWDG看门狗实验——复位ARM

    实验原理: STM32内部包含窗口看门狗,通过看门狗可以监控程序运行,程序运行错误时,未在 规定时间喂狗(提前或超时),自动复位ARM,本实验通过按键按下,停止喂狗,从而产 生复位. 核心代码: in ...

  9. 关于Unity中NGUI的Tab商城、Scrollview和打字机效果的实现

    Tab商城实例 UIToggle 和 UIToggledObjects+ Box Collider(实现商城功能必备) 1.创建两个个UI Sprite,Sprite1和Sprite2 2.给Spri ...

  10. 记录一次在安装双系统的过程(先有debian, 后加windows 8.1)

    突破的难题:  如何在一整个根目录的分区中切出来一半用于安装windows8.1呢? 当初安装debian系统时, 由于脑残,直接把整个500G的硬盘分给了根目录 /  ,所以整个磁盘就TMD的一个主 ...