当前位置: 首页 > article >正文

在AspNetCore中理解依赖注入生命周期冲突与解决方案

本文详细讲解AspNetCore依赖注入生命周期冲突问题通过BackgroundService后台托管服务示例分析Singleton、Scoped、Transient三种生命周期的区别及注入规则重点说明为什么Singleton不能直接依赖Scoped服务以及如何使用IServiceScopeFactory解决生命周期捕获问题并深入解析Transient为何不会触发生命周期冲突。在AspNetCore中理解依赖注入生命周期冲突在 ASP.NET Core 的日常开发中依赖注入Dependency Injection, DI几乎是贯穿所有功能的核心技术。而在学习 DI 时一个非常重要但又容易被忽略的问题就是 服务生命周期Service Lifetime之间的冲突。这篇文章通过一个简单的 后台托管服务BackgroundService 示例来展示不同生命周期的服务在注入时会出现什么问题以及如何正确解决这种冲突。生命周期的三种类型在 ASP.NET Core 中服务的生命周期有三种类型Transient每次请求都会创建一个新的实例Scoped每次请求都会创建一个新的实例但同一个请求中的不同控制器会共享同一个实例Singleton整个应用程序中只有一个实例所有请求都会共享这个实例而后台托管服务BackgroundService是 ASP.NET Core 中用于在后台运行异步任务的抽象基类。本文中选择它为案例是因为后台托管任务的生命周期是singleton。依赖注入的常用方式在 ASP.NET Core 中依赖注入的常用方式有三种构造函数注入Constructor InjectionpublicclassTestHostedService:BackgroundService{privatereadonlyILoggerTestHostedService_logger;privatereadonlyIIdGenService_idGenService;publicTestHostedService(ILoggerTestHostedServicelogger,IIdGenServiceidGenService){_loggerlogger;_idGenServiceidGenService;}}属性注入Property Injection在注册服务时需要使用 ActivatorUtilities 或 ConfigureServices 配置 才能给它写入属性publicclassMyService{publicILoggerMyService?Logger{get;set;}publicvoidDoWork(){Logger?.LogInformation(Working...);}}3.方法注入Method Injection csharppublicclassMyController:Controller{publicIActionResultIndex([FromServices]IIdGenServiceidGenService){stringididGenService.NewGuid();returnOk(id);}}其中构造函数注入和属性注入是比较常见的而方法注入则比较少见。建议使用构造函数注入因为它更方便更安全。方法和属性注入在这里就是补充说明一下因为它们的使用场景比较少所以这里就不再深入讲解了。示例代码一个依赖 IdGenService 的后台定时任务usingMicrosoft.EntityFrameworkCore;namespaceTestEFc_IEQable_AspNetCore01x02{publicclassTestHostedService:BackgroundService{privatereadonlyILoggerTestHostedService_logger;privatereadonlyIIdGenService_idGenService;privateint_executionCount;publicTestHostedService(ILoggerTestHostedServicelogger,IIdGenServiceidGenService){_loggerlogger;_idGenServiceidGenService;}protectedoverrideasyncTaskExecuteAsync(CancellationTokenstoppingToken){_logger.LogInformation(定时托管服务启动.);awaitDoWork();usingPeriodicTimertimernew(TimeSpan.FromSeconds(10));try{while(awaittimer.WaitForNextTickAsync(stoppingToken)){awaitDoWork();}}catch(OperationCanceledException){_logger.LogInformation(定时托管服务已停止.);}}privateasyncTaskDoWork(){stringidawait_idGenService.NewGuidAsync(5);_logger.LogInformation($生成Id:{id});intcountInterlocked.Increment(ref_executionCount);awaitTask.Delay(TimeSpan.FromSeconds(2));_logger.LogInformation(定时托管服务运行 {Count},count);}}}在Program.cs中注册服务builder.Services.AddHostedServiceTestHostedService();//builder.Services.AddTransientIIdGenService, IdGenService();//builder.Services.AddScopedIIdGenService, IdGenService();//builder.Services.AddSingletonIIdGenService, IdGenService();在这段代码中我们注册了后台托管服务 TestHostedService并使用不同的生命周期类型注册了 IdGenService。重点是 IIdGenService 的生命周期不同会带来不同效果。我们先分别解除注释看看使用情况解除 Scoped 的注释出现了报错运行截图核心原因是ASP.NET Core 的 后台托管服务HostedService默认是 Singleton单例DI 不允许 生命周期长的服务依赖生命周期短的服务因为这会产生所谓的捕获capture一个比自身短生命周期的依赖可能导致依赖被提前销毁或状态错误。例如在后台托管服务中直接注入DbContext就会出现这种情况。因为DbContext的生命周期默认是Scoped而导致后台托管服务在使用完这一个DbContext后却还一直持有占用数据库连接导致数据库连接池耗尽。Singleton 服务 在整个程序生命周期都活着它不能依赖随时都可能被释放的 Transient 或 Scoped 服务。然后我们把Scoped注释掉再解除Singleton的注释发现正常运行运行截图因为这时IdGenService是与托管服务TestHostedService是同一个生命周期所以没有问题。上面说了长的生命周期不允许依赖短的生命周期那我们猜一下解除 Transient 的注释会发生什么运行截图(⊙o⊙)不对怎么是正常的我去查了一下原来在ASP.NET Core 的 DI 系统中Transient 是不受生命周期“捕获”规则限制的。微软官方定义如下简化Transient 服务每次请求都会重新创建容器允许它被任何生命周期的服务注入。也就是说. Transient 本身没有“作用域”. 它也不依赖容器来管理生命周期. 所以不会产生“被提前释放”的风险因此单例依赖 Transient 是安全的没有生命周期冲突那为什么大家都以为 Transient 会报错因为很多教程、中文文章、视频讲解都把 Scoped 和 Transient 混在一起以为这两者都「生命周期短 → 都不能给单例用」。但实际情况是生命周期是否允许被 Singleton 依赖原因Singleton✔同生命周期 / 更长Transient✔不依赖 Scope由容器直接 newScoped❌必须在 Scope 内创建Http Request那如果我们非要在 Singleton 中注入 Scoped 呢解决方案使用 using 和 IServiceScopeFactory 来创建一个临时的 Scoped 作用域usingMicrosoft.EntityFrameworkCore;namespaceTestEFc_IEQable_AspNetCore01x02{publicclassTestHostedService:BackgroundService{privatereadonlyILoggerTestHostedService_logger;privatereadonlyIServiceScopeFactory_serviceScopeFactory;//看这里privateint_executionCount;publicTestHostedService(ILoggerTestHostedServicelogger,IServiceScopeFactoryserviceScopeFactory){_loggerlogger;_serviceScopeFactoryserviceScopeFactory;}protectedoverrideasyncTaskExecuteAsync(CancellationTokenstoppingToken){_logger.LogInformation(定时托管服务启动.);awaitDoWork();usingPeriodicTimertimernew(TimeSpan.FromSeconds(10));try{while(awaittimer.WaitForNextTickAsync(stoppingToken)){awaitDoWork();}}catch(OperationCanceledException){_logger.LogInformation(定时托管服务已停止.);}}privateasyncTaskDoWork(){//看这里///using和IServiceScopeFactoryusingvarscope_serviceScopeFactory.CreateScope();vardateContextscope.ServiceProvider.GetRequiredServiceDateContext();///using和IServiceScopeFactory/vartoDoListawaitdateContext.ToDoListTable.Include(tt.TransactionNodes).FirstOrDefaultAsync(xx.Id1ca);_logger.LogInformation($ToDoList Id:{toDoList.Id}, Title:{toDoList.ListTitle}, Description:{toDoList.ListDescription}, State:{toDoList.State});foreach(varitemintoDoList.TransactionNodes){_logger.LogInformation($TransactionNode Id:{item.Id}, SerialNumber:{item.SerialNumber}, Content:{item.Content}, State:{item.State});}intcountInterlocked.Increment(ref_executionCount);awaitTask.Delay(TimeSpan.FromSeconds(2));_logger.LogInformation(定时托管服务运行 {Count},count);}}}这样就解决了运行截图

相关文章:

在AspNetCore中理解依赖注入生命周期冲突与解决方案

本文详细讲解AspNetCore依赖注入生命周期冲突问题,通过BackgroundService后台托管服务示例,分析Singleton、Scoped、Transient三种生命周期的区别及注入规则,重点说明为什么Singleton不能直接依赖Scoped服务,以及如何使用IService…...

智炬星图:如何在AI服务商洪流中,做出最明智的专业选择?

在人工智能浪潮席卷全球的今天,从企业智能化转型到个人效率工具,AI大模型已成为驱动创新的核心引擎。然而,面对市场上林林总总的AI公司,决策者们常常陷入选择困境:是追求概念新颖的初创团队,还是青睐底蕴深…...

我用 OpenClaw + 飞书多维表格,搭了一套自媒体内容工厂

引言 做自媒体三年,我最大的感受是:内容生产永远是瓶颈。选题、资料收集、撰写、排版、多平台分发,每一步都耗时耗力。尤其是当你想做内容矩阵,同时运营多个账号时,人力成本会呈指数级增长。 直到我接触到 OpenClaw 和…...

GEO被315爆了!净与染的博弈 —— 论大模型的语料污染与治理‌

目录引言‌一、GEO:定义与危害‌二、治理挑战:信息残留与隐蔽攻击‌1、技术革新,源头防治2、法律与监管,划定红线3、行业自律,共筑堤坝结论‌引言‌ 昨晚的大会直接爆出了GEO对大模型的“投毒”,说明AI大环…...

小孩沉迷OPPO手机难管?这招让家长拿捏管控,轻松松松不费神!

自从给孩子配了一台OPPO手机,他越用越上瘾,晚上关灯睡觉后还悄悄蜷缩在被窝里玩手机,光线昏暗,屏幕光刺眼,近期感觉孩子的眼睛视力都下降了,这么下去也不是办法,怎样控制小孩玩手机的时间&#…...

674. 最长连续递增序列-day48打卡-代码随想录

674. 最长连续递增序列 思路 本题相对于昨天的动态规划:300.最长递增子序列最大的区别在于“连续”。 本题要求的是最长连续递增序列 动态规划 动规五部曲分析如下: 确定dp数组(dp table)以及下标的含义 dp[i]:以下…...

基于改进粒子群算法的微电网多目标优化调度探索

【基于改进粒子群算法的微电网多目标优化调度】基于改进粒子群算法的微电网多目标优化调度 %一种综合考虑微电网系统运行成本和环境保护成本的并网模式下微电网多目标优化调度模型 同时采用改进的粒子群算法对优化模型进行求解在如今追求可持续能源发展的大背景下,微…...

登录微信可以但无法访问浏览器

登录微信可以但无法访问浏览器,这通常是由于DNS解析问题导致的,这是最常见的原因。微信等即时通讯应用可能使用内置IP地址或备用连接通道,而浏览器完全依赖系统的DNS服务来解析域名。当DNS配置错误、缓存污染或服务器不稳定时,就会…...

三大 AI 芯片架构

AI(尤其是深度学习)最核心的工作,就是海量、重复的数学计算(矩阵乘法、向量运算)。训练 ChatGPT:要算几十亿、上万亿次数学题。自动驾驶:每秒要算上千次环境识别。普通 CPU(电脑 / 手…...

智能传感器:从概念解析到设计实践与未来展望

在上一篇文章中,我们探讨了数字孪生技术如何为工业制造带来革命性变革。作为数字孪生系统的“感官神经”,智能传感器是实现虚实映射、数据采集的关键基石。今天,武汉利又德的小编将继续深入,带您全面了解智能传感器的内涵、核心特…...

晶振作用 → 频率怎么来 → PLL 倍频 → 分频 → MCU 主频

一、晶振电路的核心作用:给 MCU 一个「精准的原始心跳」MCU 是数字同步电路,所有动作:执行指令、读写 Flash、ADC 采样、串口通信、定时器计时……全部必须按统一时钟节拍来干。1. 晶振本身干什么?晶振是石英晶体谐振器&#xff0…...

晶振电路的工作原理是什么?新手必懂!

一、先搞懂:晶振本身是什么? 晶振的核心是一片石英晶体,它靠一个物理效应工作: 压电效应(晶振的本质) 给石英晶体加电压 → 晶体发生微小机械形变让石英晶体受外力振动 → 会产生电压 石英有个超级关键…...

专业的负氧离子座舱公司

在追求高品质生活的今天,健康出行已成为人们关注的焦点。[吉品森氧]作为专业的负氧离子座舱公司,正引领着这一领域的革新潮流。负氧离子,被誉为“空气维生素”,具有净化空气、促进新陈代谢、增强免疫力等多重功效。[吉品森氧]深谙…...

模块化仪器接口技术纵览:PXIe、VXI、LXI、VPX

引言 现代测试测量系统正朝着模块化、可重构、高速化的方向快速发展。模块化仪器,作为一种将仪器功能封装在标准尺寸模块中,并通过标准总线接口集成到机箱或背板上的解决方案,因其灵活性、可扩展性和易于维护的特性,在研发、生产和自动化测试领域扮演着至关重要的角色。其…...

PANASONIC松下 AXE530127 SMD 板对板与背板连接器

特性 1.“坚固接触”结构提供对各种环境的高抗性。 2.简单的锁结构提供触觉反馈,确保良好的插拔操作手感。 3.提供用于检查的连接器。...

第7章:Docker network网络管理(网络模式和创建docker网络)

第7章:Docker network网络管理(网络模式和创建docker网络) 7.2、Docker网络模式 Docker 服务安装完成之后,默认在每个宿主机会生成一个名称为 docker0 的网卡其 IP 地址都是 172.17.0.1/16。 每次新建一个容器后,宿主机就会多了个虚拟网卡,与容器的网卡组合成一个网卡,例…...

扔掉提示词,开始养“龙虾”:2026 AI自动化执行新逻辑

01. 2026的十字路口:为什么单模型走不下去了? 如果你还在纠结于提示词怎么写才能让GPT-4o一次性生成完美代码,你可能已经落后于这个时代了。 2026年被行业普遍视为“AI元年”,但这个元年并非因为某个模型突破了万亿参数&#xf…...

open claw安装后启动运行web UI界面 - wsl版

以管理员身份打开 PowerShell 查看wsl中安装的发行版 wsl --list --verbose进入打wsl中指定的发行版 wsl -d Ubuntu查看 Gateway 状态 openclaw gateway status启动服务(通过 systemd/launchd) openclaw gateway start查看基础的网页端 openclaw gateway…...

好用的广东出书服务

大家好,我是你们的老朋友小明。今天咱们聊聊一个特别的话题——出书。可能很多人觉得出书是一件很遥远的事情,但实际上,随着互联网的发展,越来越多的人开始尝试自己写书、出书。但是,如何选择一家靠谱的出书服务公司呢…...

中红外BIC 全介质超表面 光谱调制 FDTD仿真 作品介绍: 复现论文:2018年 Science

中红外BIC 全介质超表面 光谱调制 FDTD仿真 作品介绍: 复现论文:2018年 Science:Imaging-based molecular barcoding with pixelated dielectric metasurfaces 论文介绍:中红外 全介质 硅纳米柱超表面模型,双椭圆纳米柱…...

2026年,人生仓库集团发展如何?看其独特优势与市场表现

大家好,今天咱们聊聊人生仓库集团在未来几年的发展前景。人生仓库集团,这个名字听起来就充满了故事和温度。它不仅仅是一个企业,更像是一个为奋斗者储存价值和赋能成长的“仓库”。独特优势1. 强大的品牌背书系统人生仓库集团的GEO品牌背书系…...

国内OpenClaw玩家圈共识:智创聚合API才是真香选择

你是否也曾对OpenClaw(龙虾)的强大能力心动不已,却在部署第一步——配置AI大模型时望而却步?直接使用官方API,高昂的Token费用让人肉疼;尝试部署本地开源模型,繁琐的技术门槛又令人头疼。但在国…...

CnOpenData 中国历史地震表-发生时间1年内

地震是全球发生频率最高、影响最严重的自然灾害之一,是当今人类生存和发展所面临的一个重大全球性问题。地震灾害有以下突出特征:巨大的破坏性。地震会造成山体、地面及其附着物(如植被、建筑)等破坏,往往还伴随着海啸…...

【Iced】core库Size 结构体源码解析(size.rs)

这是 iced_core 中定义的 2D尺寸 类型&#xff0c;用于表示宽度和高度。 &#x1f3d7;️ 结构体定义 /// 2维空间中的尺寸大小 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub struct Size<T f32> {/// 宽度pub width: T,/// 高度pub height: T, }关…...

PMP自学笔记

...

【Matlab】MATLAB教程:多维数组索引(案例:A(1,2,3)、A(:,:,2),聚焦多维数据提取)

MATLAB教程:多维数组索引(案例:A(1,2,3)、A(:,:,2),聚焦多维数据提取) 在MATLAB科学计算、工程仿真、数据分析及数据可视化中,多维数组(三维及以上)是存储复杂关联数据的核心载体——无论是时间-空间-指标三维监测数据、多通道传感器数据,还是三维空间坐标数据,都需…...

视频去字幕工具横评:本地 AI、云端方案与传统方法的实战对比

> 做视频二创&#xff0c;最头疼的莫过于硬编码字幕。本文实测 5 种主流去字幕方案&#xff0c;从技术原理到实际效果&#xff0c;给你一份客观的选型指南。---## 一、为什么去字幕这么难&#xff1f;视频字幕分为两种&#xff1a;**软字幕**和**硬字幕**。- **软字幕**&…...

Infoseek:以智能舆情监测,为企业品牌筑牢安全防线

当前网络舆论场迭代速度快&#xff0c;一条负面评价、一次认知误解&#xff0c;均可能通过网络快速扩散&#xff0c;对企业品牌形象造成影响。传统舆情监测服务普遍存在成本偏高、操作门槛高的问题&#xff0c;导致多数中小企业陷入“事后补救”的被动局面。Infoseek舆情监测系…...

告别手动复制:C# + Spire.XLS 实现HTML转Excel的完整方案

告别手动复制&#xff1a;C# Spire.XLS 实现HTML转Excel的完整方案 在Web开发和数据处理中&#xff0c;C# HTML to Excel转换需求频现。网页表格数据手动复制到Excel常导致样式丢失、格式混乱&#xff0c;费时费力。随着Web爬取数据自动化趋势&#xff0c;高效实现HTML 到 XLS…...

做跨境电商和出国旅行必备:世界各国电压、频率、插座类型查询整理

平时做工具网站时&#xff0c;经常会遇到一些非常实用但又不太容易找到完整资料的小问题。 前段时间在整理电器相关资料时&#xff0c;我需要查询 **世界各国的电压、频率以及插座类型**。 原本以为这种信息网上很多&#xff0c;但实际查找之后发现&#xff1a; * 有的网站只…...