原文作者: Thomas Levesque

原文链接:https://thomaslevesque.com/2020/03/18/lazily-resolving-services-to-fix-circular-dependencies-in-net-core/

循环依赖的问题

在构建应用程序时,良好的设计应该应避免服务之间的循环依赖, 循环依赖是指某些组件直接或间接相互依赖,比如下面这样

如果您不小心在.NET Core应用程序使用了依赖项注入,并且引入了以下循环依赖关系,你要知道的是,项目启动会报一个循环依赖的错误,因为依赖关系周期中涉及的组件的解析将失败,比如,你具有以下组件:

  • A服务,它实现了接口IA并取决于IB
  • B服务,它实现了接口IB并取决于IC
  • C服务,它实现了接口IC并取决于IA

System.InvalidOperationException: A circular dependency was detected for the service of type 'Demo.IA'.

所以应该去避免这些设计。

注入 IServiceProvider

但是,当实际应用程序达到一定程度的复杂性时,有时可能很难避免,有一天不小心给服务添加了一个依赖项,启动报错了,事情突然浮出水面, 因此,您面临一个选择:重构,来解决循环依赖的问题,理想情况下,应该去选择重构,但是实际情况中,可能项目比较紧,可能没有时间重构代码,因为要做完整的回归测试。

一种方法是将注入 IServiceProvider 到您的类中,并services.GetRequiredService()在需要使用时使用T,例如,C我前面提到的类,最初可能看起来像这样:

class C : IC
{
private readonly IA _a; public C(IA a)
{
_a = a;
} public void Bar()
{
...
_a.Foo()
...
}
}

为了避免依赖性循环,可以注入 IServiceProvider, 然后这样重写它:

class C : IC
{
private readonly IServiceProvider _services; public C(IServiceProvider services)
{
_services = services;
} public void Bar()
{
...
var a = _services.GetRequiredService<IA>();
a.Foo();
...
}
}

由于在构建IA时不再需要解决问题C,因此中断了循环(至少在构建过程中),并解决了问题,但是,我不太喜欢这种方法,因为这样强制依赖了IOC,如果我使用了 Autofac 等,另一个问题是我很难看到类的依赖关系,它不明显。

巧用 Lazy<T>

下边的方法我利用了Lazy类,需要添加一个 IServiceCollection 的扩展,新建一个静态类

public static IServiceCollection AddLazyResolution(this IServiceCollection services)
{
return services.AddTransient(
typeof(Lazy<>),
typeof(LazilyResolved<>));
} private class LazilyResolved<T> : Lazy<T>
{
public LazilyResolved(IServiceProvider serviceProvider)
: base(serviceProvider.GetRequiredService<T>)
{
}
}

然后再 Startup.cs 中的 ConfigureServices 方法中这样写

services.AddLazyResolution();

在依赖的类中IA,注入Lazy,当您需要使用时IA,只需访问lazy的值 Value 即可:

class C : IC
{
private readonly Lazy<IA> _a; public C(Lazy<IA> a)
{
_a = a;
} public void Bar()
{
...
_a.Value.Foo();
...
}
}

注意:不要访问构造函数中的值,保存Lazy即可 ,在构造函数中访问该值,这将导致我们试图解决的相同问题。

这个解决方案不是完美的,但是它解决了最初的问题却没有太多麻烦,并且依赖项仍然在构造函数中明确声明,我可以看到类之间的依赖关系。

最后

欢迎扫码关注我们的公众号 【全球技术精选】,专注国外优秀博客的翻译和开源项目分享,也可以添加QQ群 897216102

巧用 Lazy 解决.NET Core中的循环依赖关系的更多相关文章

  1. 在.NET Core中遭遇循环依赖问题"A circular dependency was detected"

    今天在将一个项目迁移至ASP.NET Core的过程中遭遇一个循环依赖问题,错误信息如下: A circular dependency was detected for the service of ...

  2. 解决vs code中golang插件依赖安装失败问题

    解决vs code中golang插件依赖安装失败问题 Installing github.com/nsf/gocode SUCCEEDED Installing github.com/uudashr/ ...

  3. Spring中的循环依赖解决详解

    前言 说起Spring中循环依赖的解决办法,相信很多园友们都或多或少的知道一些,但当真的要详细说明的时候,可能又没法一下将它讲清楚.本文就试着尽自己所能,对此做出一个较详细的解读.另,需注意一点,下文 ...

  4. 【Spring】Spring中的循环依赖及解决

    什么是循环依赖? 就是A对象依赖了B对象,B对象依赖了A对象. 比如: // A依赖了B class A{ public B b; } // B依赖了A class B{ public A a; } ...

  5. OSGI中的service依赖关系管理

    众所周知.对于高动态高可扩展的应用,OSGI是一个很好的平台.可是.也因此添加了复杂性.开发中对service的依赖变得复杂. 这也是service的关系管理成为OSGI中一个很重要的部分,我们来看看 ...

  6. 面试必杀技,讲一讲Spring中的循环依赖

    本系列文章: 听说你还没学Spring就被源码编译劝退了?30+张图带你玩转Spring编译 读源码,我们可以从第一行读起 你知道Spring是怎么解析配置类的吗? 配置类为什么要添加@Configu ...

  7. 面试阿里,腾讯,字节跳动90%都会被问到的Spring中的循环依赖

    前言 Spring中的循环依赖一直是Spring中一个很重要的话题,一方面是因为源码中为了解决循环依赖做了很多处理,另外一方面是因为面试的时候,如果问到Spring中比较高阶的问题,那么循环依赖必定逃 ...

  8. 从一部电影史上的趣事了解 Spring 中的循环依赖问题

    title: 从一部电影史上的趣事了解 Spring 中的循环依赖问题 date: 2021-03-10 updated: 2021-03-10 categories: Spring tags: Sp ...

  9. 在SQL Server中查看对象依赖关系

    原文 在SQL Server中查看对象依赖关系 Viewing object dependencies in SQL Server   Deleting or changing objects may ...

随机推荐

  1. Flask框架登录日志模块编写

    web扫描器网站的框架搭建逐渐进入尾声,边搭建框架的时候负责前端的小姐姐也在完善页面设计,过两天就可以进行功能点的完善了. 在扫描器中我们用到了用户登录模块,想法是初始化一个账户和密码,比如说admi ...

  2. 【APIO2019】路灯(ODT & (树套树 | CDQ分治))

    Description 一条 \(n\) 条边,\(n+1\) 个点的链,边有黑有白.若结点 \(a\) 可以到达 \(b\),需要满足 \(a\to b\) 的路径上的边不能有黑的.现给出 \(0\ ...

  3. Java集合源码分析(八)——WeakHashMap

    简介 WeakHashMap 继承于AbstractMap,实现了Map接口. 和HashMap一样,WeakHashMap 也是一个散列表,它存储的内容也是键值对(key-value)映射,而且键和 ...

  4. MVC部署出现403.14问题记录

    1.问题截图 2.解决办法有几种 1)在system.webServer下增加,这种是不推荐的. <modules runAllManagedModulesForAllRequests=&quo ...

  5. Springboot 项目 无法读取resources下的mapper文件夹的.xml文件

    之前学习的时候遇到的一个问题 org.springframework.beans.factory.BeanCreationException: Error creating bean with nam ...

  6. 【UIautomator2 安卓自动化】教程

    一.环境准备: [安装] 安装uiautomator2 pip install --pre uiautomator2 pip install pillow [初始化] 部署相关的守护进程. 电脑连接上 ...

  7. base64 基本使用 和os模块使用

    1  base64 的基本使用 import base64 with open('../static/upload/63bc620d1594779d6a98c53a3a8db1e5.png','rb' ...

  8. C#跳过工作日,计算几个工作日之后到期的方法

    需求:消费者投诉企业,企业在2个工作日之内做出应答. 分析:1.工作日要刨去周末和法定节假日,而且每年的节假日不一样. 2.消费者可以在任意时间发起投诉,如果在非工作日发起了投诉,那么计算时间应该从工 ...

  9. Flink批处理读写Hive

    import org.apache.flink.table.api.*; import org.apache.flink.table.catalog.hive.HiveCatalog; /** * @ ...

  10. WP | [MRCTF2020]Ezpop

    2020.10.14 最近开始努力提高代码能力 题目代码 Welcome to index.php <?php //flag is in flag.php //WTF IS THIS? //Le ...