尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
在后台服务中使用 Scoped 服务,为什么总是报错?
1.前言在使用framwork时构造对象都是直接new本身框架没有提供DI的能力当然也可以集成Autofac 因为Autofac 提供了完善的适配器可以无缝集成到各类项目中可以看出微软选择不是“修补旧船”而是“建造新航母”随着 .netcore 的发展依赖注入也是被作为.netcore 平台框架的基础核心功能之一。带来这个有好处最大的亮点就是依赖倒置容器帮你管理对象的生命周期在搭建框架时配置下你完全不需要操心只需要在构造函数写入就行了。internal class SingletonService : ISingletonService { public ITransientService Transient { get; } public Guid SingletonId { get; } Guid.NewGuid(); public SingletonService(ITransientService transient) { Transient transient; } }相信有大部分小伙伴也是实际应用过的只要按照项目内人家写的代码风格一样往构造函数里放就完事了其他的完全不用操心框架也是尽可能这么做的让你省心但是您是否仔细思考一下您真的对他了解吗因为新的技术意味着带来新的挑战要学习新的东西不然的话1.假设哪天启动时突然构造函数不能注入了搞半天不知道怎么回事2.人家问你单例服务注入瞬时会不会报错如果你没了解过或者实际操作过的话只能靠懵我就遇到过不过我不是靠懵我是斩钉截铁的说会!因为慢一秒都代表心虚底气来源就是他的枪里没有子弹,赌他可能也不知道接下来就聊聊一些需要注意的点如果您知道当看个热闹如果不知道就当做扩展知识了2. 三种服务生命周期的定义与行为Transient瞬时每次从容器请求时都创建新实例就跟每次直接new一样。Scoped作用域在同一个 IServiceScope 内是单例不同作用域之间实例不同一个Scope对应一个逻辑上下文如一次 HTTP 请求、一次后台任务同一作用域内Scoped:服务是单例。Transient:服务每次解析都是新实例但可共享同一个 Scoped 实例就是你有2个不同的Transient引用了一个scope的类在同一作用域2次解析的scope类都会是同一对象 。Singleton整个应用程序生命周期内只有一个实例就例如你定义的静态类。var services new ServiceCollection(); // 注入瞬时 services.AddTransientITransientService, TransientService(); //注入单例 services.AddSingletonISingletonService, SingletonService(); //注入作用域 services.AddSingletonIScopedService, ScopedService(); //构造服务对象 var serviceProvider services.BuildServiceProvider();3.生命周期依赖的规则这里说的就是你不同生命周期的类如果要相互引用需要参照并且按照以下的规则依赖方的生命周期不能长于其依赖的服务就是说你使用的类如果依赖其他类那么一定不能存在当前类还存在依赖的服务已经死了的情况。短生命周期 → 依赖 → 长生命周期Transient 依赖 Singleton 就可以长生命周期 → 依赖 → 短生命周期Singleton 依赖 Scoped 或 Transient有状态时单例是不能依赖作用域的依赖瞬时不会报错但是瞬时推荐要无状态的类消费者类型 \ 依赖类型TransientScopedSingletonTransient允许必须要在作用域内允许Scoped允许允许允许Singleton需要注意依赖不能长于自身不允许依赖 Scoped允许我们注意看这个表格中的关系后面依赖这个展开当然具体就是围绕3个特殊的来分析因为容易出错1.瞬时周期类依赖作用域周期类2.单例周期类依赖瞬时类3.单例周期类依赖作用域周期类4.瞬时周期类依赖作用域周期类控制台或者后台服务应用1.根容器IServiceProvider不能解析 Scoped 服务provider根容器来获取注册为作用域周期的类就直接报错了2.不能直接注入注册为作用域周期的类例如我在瞬时的对象中注入一个scoped周期的类internal class TransientService2 : ITransientService { public Guid Id { get; } Guid.NewGuid(); public IScopedService Scoped { get; } public TransientService2(IScopedService scoped) { Scoped scoped; Console.WriteLine($[Transient] 构造ID: {Id}持有 Scoped: {scoped.Id}); } }他就会出现如下错误WebApi 应用如果你善于观察你会发现一个有趣的现象这样的代码如果放在api的控制器中注入我这里分别注入依赖了作用域的瞬时直接注入作用域注入根容器通过根容器获取作用域服务他竟然全都不会报错。结论1.在控制台或者后台服务报错的原因是因为作用域服务不能在根容器解析这个如何理解呢因为作用域服务的生命周期是绑定在逻辑作用域如一个 HTTP 请求上的每个逻辑操作单元一个实例实例应该在该作用域内创建、共享、并在作用域结束时被释放。而根容器Root ServiceProvider是应用程序生命周期级别的它没有作用域的逻辑概念如果直接从根容器解析作用域服务的话就会1.作用域服务变成“伪单例”在整个应用程序生命周期内复用而不是每次请求一个新实例或作用域内共享如果是DbContext那么同一个DbContext实例被多个 HTTP 请求、多个线程共享虽然数据库连接本身可能被复用但DbContext持有连接状态长时间不释放 → 连接无法归还池 → 新请求无法获取连接 → 超时2.因为没有真正的作用域上下文破坏作用域的生命周期管理不能正确触发作用域服务的释放和 Dispose()可能造成内存泄漏或数据混乱。那如何解决这个问题呢答案就是我们需要通过作用域解析 Scoped 服务var services new ServiceCollection(); services.AddScopedIScopedService, ScopedService(); services.AddTransientITransientService, TransientService2(); var provider services.BuildServiceProvider(validateScopes: true); // 通过作用域解析 Scoped 服务和依赖了 Scoped 的 Transient 服务 using (var scopeed provider.CreateScope()) { var scopedProvider scopeed.ServiceProvider; var scopedService scopedProvider.GetRequiredServiceITransientService(); }可以发现scopedProvider和provider都是IServiceProvider但它们代表的是两个不同层级的 DI 容器实例生命周期和解析行为完全不同。根IServiceProvider是整个应用程序级别的。而scopedProvider是当前using块范围内区分他们很简单IServiceProvider有一个IsScope属性如果细心调试下会发现通过scopeed 创建的IServiceProvider的IsScope为true,根容器IServiceProvider的IsScope为false所以得出结论如果在后台服务线程或者控制台中要解析作用域周期对象或者解析依赖了作用域周期的对象必须使用scopeed 来创建一个根容器来获取。如果是在web中就不用管因为微软已经在web框架中的RequestServicesFeature帮我们实现了将IServiceProvider设为请求级别的 Scoped 根容器在注入时可以发现它的IsScope为true可以看到每一次请求创建一个新的作用域_scope _scopeFactory.CreateScope(); _requestServices _scope.ServiceProvider; // 这是请求级别的容器请求的生命周期执行过程1.在管道的最开始或通过HttpContextFactory会为这个请求创建一个HttpContext对象2.在这个过程中创建一个 请求级别的IServiceProvider然后将这个IServiceProvider赋值给HttpContext.RequestServices3.后续不管是中间件、Controller、Page 可以通过HttpContext.RequestServices获取到当前请求的 Scoped 服务注意点如果是在控制器或者他引用的类中开启了后台线程尽可能在主线程先获取子线程需要的数据传入如果不可避免在后台中解析服务依然还是要用根容器来创建一个Scoped的根容器来获取[HttpGet(run-task)] public IActionResult RunBackgroundTask() { // 只读取你需要的数据而不是拿服务对象var data 一些业务数据; Task.Run(() { // 这里不使用任何注入的服务 Console.WriteLine($Running in background with data: {data}); }); // 方法2 using (var scope _serviceProvider.CreateScope()) { var scopedService scope.ServiceProvider.GetRequiredServiceScopedService(); scopedService.DoSomething(); } return Ok(OK); }场景根容器 (IServiceProvider)如何获取 Scoped 服务Web API本身就是 Scoped (IsScopetrue)直接注入即可后台服务/控制台不是 Scoped (IsScopefalse)必须provider.CreateScope()
RELATED

相关推荐

如何创建openEuler新语言翻译团队?完整申请与审批流程指南

如何创建openEuler新语言翻译团队?完整申请与审批流程指南

如何创建openEuler新语言翻译团队?完整申请与审批流程指南 【免费下载链接】G11N openEuler globalization (G11N) SIG. 项目地址: https://gitcode.com/openeuler/G11N 前往项目官网免费下载:https://ar.openeuler.org/ar/ 想要为openEuler操作…

📅 2026/11/2 23:21:11
DDR4 vs DDR5 PCB设计对比:从POD电平到DBI技术的3大布线调整

DDR4 vs DDR5 PCB设计对比:从POD电平到DBI技术的3大布线调整

DDR4到DDR5 PCB设计升级实战:POD电平、DBI技术与高速布线三大挑战解析当硬件工程师首次面对DDR5设计需求时,往往会低估其与DDR4的差异程度。最新测试数据显示,DDR5-4800的信号上升时间已缩短至DDR4-3200的60%,这意味着传统设计方法…

📅 2026/9/1 21:50:07
Notepad--:跨平台文本编辑的国产技术突围与深度定制化实践

Notepad--:跨平台文本编辑的国产技术突围与深度定制化实践

Notepad--:跨平台文本编辑的国产技术突围与深度定制化实践 【免费下载链接】notepad-- 一个支持windows/linux/mac的文本编辑器,目标是做中国人自己的编辑器,来自中国。 项目地址: https://gitcode.com/GitHub_Trending/no/notepad-- …

📅 2026/9/1 21:59:05
MORE NEWS

更多资讯

📰

关键基础设施的数字瘫痪战防御与零信任架构实践

1. 数字瘫痪战的威胁本质2022年某跨国能源企业遭遇的供应链攻击事件,暴露出关键基础设施的致命弱点——攻击者通过入侵其 HVAC 系统供应商,在软件更新包中植入恶意代码,最终导致17个国家的输油管道系统停摆72小时。这种新型"数字瘫痪战&…

📰

声音制作工具VoiceStudio拆解:从降噪到响度标准化的完整流程

1. 项目缘起与定位拆解1.1 VoiceStudio 到底解决什么问题先说说我为什么要把 VoiceStudio 单拎出来掰开揉碎讲一遍。现在做短视频、做播客、做有声内容的人太多了,但是真正好用的声音制作工具,要么是动辄几千块的 DAW(数字音频工作站&#xf…

📰

C++访问者模式:双分派机制与AST遍历实践

1. 访问者模式的核心价值与应用场景在C开发中,当我们需要对复杂对象结构添加新操作时,访问者模式(Visitor Pattern)提供了一种优雅的解决方案。这种设计模式的核心价值在于:它允许你在不修改现有类层次结构的情况下&am…

📰

Python电影数据可视化分析系统:爬虫、清洗与Flask展示全流程

简介:这是一套面向高校计算机相关专业学生的毕业设计完整源码,围绕豆瓣电影数据构建可视化分析系统,适合需要完成课程设计或毕设、希望快速上手数据分析与Web开发的学习者。项目将爬取到的电影数据存入SQLite数据库,再借助Flask搭…

📰

Anaconda虚拟环境重命名全攻略:从conda rename到克隆法避坑指南

Anaconda 用久了,虚拟环境列表里总会冒出几个名字让人抓狂的条目。比如当初随手敲的test、myenv、env1,过两个月再看,完全想不起来哪个是跑深度学习的、哪个是爬虫专用的。更尴尬的是团队协作时,你让同事conda activate myenv&…

📰

回形针不只能夹文件:从办公小工具到收纳高手的实用指南

办公桌上要是没几个回形针(Paperclip),我总觉得少了点什么。这东西小到经常被忽略,但它能解决的问题比你想的多得多。今天不打算讲什么大道理,就把它当一个值得研究的项目,从设计、材质、用法到改造&#x…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬