C# Web开发教程(十一)后台主动服务

news/2025/11/3 11:56:18/文章来源:https://www.cnblogs.com/qinganning/p/19186681

托管服务(HostedService,也称为"后台服务")

  • 托管服务,这个翻译是不准确的,我觉得应该翻译成主动服务:服务器自己主动发起的服务(任务)[相对于客户端发起请求,服务端才响应]

    • 它是一种在应用启动后自动运行、无需外部触发的服务
  • 使用场景

- 代码运行在后台,比如服务器启动的时候在后台预先加载数据到缓存,每天凌晨3点把数据导出到备份数据库,或者每隔5秒钟在两张表之间同步一次数据。- 定时任务
  • 代码实现流程
- 实现IHostedService接口(用起来麻烦),一般编写从BackgroundService继承的类(用起来简单).
- 注册服务: services.AddHostedService<DemoBgService>();
  • 注意事项
- 一旦托管服务的代码有错,整个项目就无法启动- 可以把HostOptions.BackgroundServiceExceptionBehavior设置为Ignore,程序会忽略异常,而不是停止程序.- 不过不推荐这么搞,因为“异常应该被妥善的处理,而不是被忽略”.- 要在ExecuteAsync方法中把代码用try....catch包裹起来,当发生异常的时候,记录日志中或发警报等.- 而在.net6.0之前的版本中,托管代码就算有异常,项目也可以启动起来(旧的设计其实不好,所以新的版本修复了)
// HostedServiceDemo1.csnamespace WebApplicationAboutJWTConfigRun
{public class HostedServiceDemo1 : BackgroundService{protected override async Task ExecuteAsync(CancellationToken stoppingToken){Console.WriteLine("HostedService1启动");await Task.Delay(3000);string txt = await File.ReadAllTextAsync("d:/text.txt");Console.WriteLine("文件读取中...");await Task.Delay(10000);Console.WriteLine(txt);Console.WriteLine("HostedService1启动任务结束!");}}
}// Program.cs
......
builder.Services.AddSwaggerGen(c =>
{......
});
// 主动服务(注册)
builder.Services.AddHostedService<HostedServiceDemo1>();
  • 故意触发异常的效果
namespace WebApplicationAboutJWTConfigRun
{public class HostedServiceDemo1 : BackgroundService{protected override async Task ExecuteAsync(CancellationToken stoppingToken){try{Console.WriteLine("HostedService1启动");await Task.Delay(3000);string txt = await File.ReadAllTextAsync("d:/text.ext"); // 故意写错Console.WriteLine("文件读取中...");await Task.Delay(10000);Console.WriteLine(txt);Console.WriteLine("HostedService1启动任务结束!");}catch(Exception Ex){Console.WriteLine("启动代码异常" + Ex);}}}
}- 测试效果: 项目正常跑起来了,日志记录异常
......
启动代码异常System.IO.FileNotFoundException: Could not find file 'd:\text.ext'.
File name: 'd:\text.ext'
......
  • 托管服务中使用DI(依赖注入(DI)限制)
- 托管服务是以单例的生命周期注册到依赖注入容器中的。因此不能注入生命周期为范围或者瞬态的服务(不能直接注入 Scoped 或 Transient 服务(如 DbContext))。比如注入FCore的上下文的话,程序就会抛出异常。- 可以通过构造方法注入一个IServiceScopeFactory服务,它可以用来创建一个IServiceScope对象,这样我们就可以通过IServiceScope来创建短生命周期的服务了(记得在Dispose中释放IServiceScope)。
  • 异常实例演示
// HostedServiceDemo2.csnamespace WebApplicationAboutJWTConfigRun
{public class HostedServiceDemo2{public int Add(int a,int b){return a + b;}}
}// Program.cs
......
// 主动服务
builder.Services.AddHostedService<HostedServiceDemo1>();
// 注入生命周期为范围或者瞬态的服务
builder.Services.AddScoped<HostedServiceDemo2>();// HostedServiceDemo1.cs 测试
namespace WebApplicationAboutJWTConfigRun
{public class HostedServiceDemo1 : BackgroundService{private readonly HostedServiceDemo2 hostedServiceDemo2;// 依赖注入public HostedServiceDemo1(HostedServiceDemo2 hostedServiceDemo2){this.hostedServiceDemo2 = hostedServiceDemo2;}protected override async Task ExecuteAsync(CancellationToken stoppingToken){try{Console.WriteLine("HostedService1启动");// 执行逻辑,这里会触发异常Console.WriteLine("执行HostedService2服务"+hostedServiceDemo2.Add(1,1));......}catch(Exception Ex){Console.WriteLine("启动代码异常" + Ex);}}}
}
  • 现在,修复上面的异常
namespace WebApplicationAboutJWTConfigRun
{public class HostedServiceDemo1 : BackgroundService{//private readonly HostedServiceDemo2 hostedServiceDemo2;//public HostedServiceDemo1(HostedServiceDemo2 hostedServiceDemo2)//{//    this.hostedServiceDemo2 = hostedServiceDemo2;//}// 声明 IServiceScopeprivate IServiceScope serviceScope;// 依赖注入public HostedServiceDemo1(IServiceScopeFactory serviceScopeFactory){this.serviceScope = serviceScopeFactory.CreateScope();}protected override async Task ExecuteAsync(CancellationToken stoppingToken){try{var testService = serviceScope.ServiceProvider.GetRequiredService<HostedServiceDemo2>();Console.WriteLine("HostedService1启动");Console.WriteLine("执行HostedService2服务"+ testService.Add(1,1));await Task.Delay(3000);string txt = await File.ReadAllTextAsync("d:/text.txt");Console.WriteLine("文件读取中...");await Task.Delay(10000);Console.WriteLine(txt);Console.WriteLine("HostedService1启动任务结束!");}catch(Exception Ex){Console.WriteLine("启动代码异常" + Ex);}}public override void Dispose(){this.serviceScope.Dispose();base.Dispose();}}
}

✅ 总结要点

要点 说明
用途 后台任务、定时任务、数据同步等
实现方式 继承 BackgroundService
注册方式 AddHostedService()
异常处理 必须用 try-catch 包裹
DI 限制 不能直接注入 Scoped/Transient 服务
解决方案 使用 IServiceScopeFactory 创建作用域

连接数据库示例: 使用托管服务(BackgroundService)实现的定时数据导出任务

- 安装工具包<Project Sdk="Microsoft.NET.Sdk.Web">......<ItemGroup><PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.0" /><PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /><PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.0" /><PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0" /><PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.0" /><PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.0"><PrivateAssets>all</PrivateAssets><IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets></PackageReference></ItemGroup></Project>// MyUser.csusing Microsoft.AspNetCore.Identity;namespace WebApplicationAboutJWTConfigRun
{public class MyUser:IdentityUser<long>{public string? WeiXinAccount { get; set; }}
}// MyRole.csusing Microsoft.AspNetCore.Identity;namespace WebApplicationAboutJWTConfigRun
{public class MyRole:IdentityRole<long>{}
}// MyDbContext.csusing Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;namespace WebApplicationAboutJWTConfigRun
{public class MyDbContext : IdentityDbContext<MyUser,MyRole,long>{public MyDbContext(DbContextOptions<MyDbContext> options) : base(options){}}
}// Program.cs
......
builder.Services.AddDbContext<MyDbContext>(opt =>
{opt.UseSqlServer("Server=.;Database=idtest2;Trusted_Connection=True;");
});- 作迁移和更新db// ScheduledService.csusing Microsoft.EntityFrameworkCore;namespace WebApplicationAboutJWTConfigRun
{public class ScheduledService : BackgroundService{// 解决单例服务无法直接使用Scoped服务的问题private readonly IServiceScope serviceScope;public ScheduledService(IServiceScopeFactory serviceScopeFactory){// 创建独立的作用域来获取DbContextthis.serviceScope = serviceScopeFactory.CreateScope();}protected override async Task ExecuteAsync(CancellationToken stoppingToken){try{var dbCtx = serviceScope.ServiceProvider.GetRequiredService<MyDbContext>();// 检查取消令牌:stoppingToken.IsCancellationRequested - 应用关闭时自动停止while (!stoppingToken.IsCancellationRequested){long c = await dbCtx.Users.LongCountAsync();await File.WriteAllTextAsync("d:/text.txt",c.ToString());await Task.Delay(5000);}Console.WriteLine("导出成功" + DateTime.Now);}catch (Exception ex){Console.WriteLine($"出错了: {ex.Message}, 堆栈跟踪: {ex.StackTrace}");}}public override void Dispose(){// 手动释放作用域:避免内存泄漏this.serviceScope.Dispose();// 调用基类Dispose:确保BackgroundService正确清理base.Dispose();}}
}// Program.cs
......
// 主动服务
builder.Services.AddHostedService<ScheduledService>();
builder.Services.AddDbContext<MyDbContext>(opt =>
{......  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/954416.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025 年国际高中学校最新推荐榜,聚焦办学资质与升学成果深度解析及教学质量与综合实力全面评估松江区 / 青浦区 / 奉贤区 / 崇明区国际高中推荐

引言 国际教育协会近期发布的国际高中综合测评报告显示,本次测评覆盖近百所国际高中,从办学资质、师资团队、课程认证、升学成果、教学设施五大维度设置 28 项细分指标,采用量化评分与质性评估结合的方式,其中办学…

2025年汽车超薄低音源头厂家权威推荐榜单:汽车音响超薄低音/汽车超薄低音炮/汽车音响超薄低音炮源头厂家精选

技术创新正推动汽车超薄低音炮市场蓬勃发展,其中定制化需求占比已突破40%。 随着汽车智能化转型加速,超薄低音炮市场年复合增长率达12.7%。在这场技术竞赛中,拥有核心技术的超薄低音设备厂家表现尤为突出,它们通过…

2025年保洁服务公司新排行榜推荐,海獭顾家无忧保洁服务详细介绍

在保洁服务市场日益繁荣的当下,众多企业和家庭都在寻找一家可靠、专业且服务优质的保洁公司。海獭顾家无忧保洁服务在市场上逐渐崭露头角,不少人也在询问海獭顾家保洁服务口碑好吗。以下为您呈上一份2024年保洁服务公…

基于开源操作系统搭建K8S高可用集群

准备环境:安装Rocky Linux操作系统到每个节点上。 为每个节点配置静态IP地址。 确保节点之间可以互相通信。安装Docker:在每个节点上安装Docker,这将成为Kubernetes的容器运行时。运行以下命令来安装Docker: sudo …

2025 年阳台光伏厂家推荐:昱电宝依托昱能科技技术积淀,打造场景化光伏解决方案与服务体系

行业背景 2025 年成为中国阳台光伏市场启动元年,在新能源电价市场化改革政策推动下,传统光伏项目收益模式面临转型,阳台光伏因初始投资小、适配场景广成为行业新增长点。数据显示,2025 年国内阳台光伏装机量预计攀…

【2025-11-01】连岳摘抄

23:59善欲人见,不是真善;恶恐人知,便是大恶。——《朱子家训》人人都想长寿。长寿者占有更多的时间。有更多的时间,就有更多的可能性。时间有两重属性。一个是长度,一个是深度。我们往往只看到长度,没有看到深度…

2025年11月全屋定制环保材料公司推荐榜单:五家优质企业综合对比分析

在现代家居装修过程中,选择全屋定制环保材料公司成为许多家庭的重要决策环节。根据中国室内装饰协会2025年发布的行业白皮书显示,超过78%的消费者将环保性能作为选择全屋定制材料的首要考量因素。这类用户通常是对生…

2025年度锂电池回收再利用机器制造厂排名:口碑好的锂电池回收设备厂家推荐

随着新能源汽车产业的爆发式增长,锂电池退役潮来临,锂电池回收再利用成为环保与资源循环领域的核心议题。选择靠谱的锂电池回收再利用机器制造厂,是企业高效开展回收业务、解决原料供应不稳定、环保安全等痛点的关键…

2025年五大游乐设备优质厂家推荐,景区游乐设备厂实力全解析

在文旅产业爆发式增长的当下,一款安全、新颖的游乐设备是景区吸引客流、提升营收的核心引擎。面对市场上良莠不齐的供应商,如何找到既靠谱又能带来的景区游乐设备厂?以下依据安全资质、创新能力、项目经验三大核心维…

2025年11月全屋定制环保材料公司评测:从资质到服务的全面考察

随着居住品质需求的提升,全屋定制环保材料成为许多家庭装修的核心关注点。您可能正在为新居装修或旧房改造寻找可靠的材料供应商,尤其注重材料的环保性、耐用性及设计适配性。当前行业中存在品牌众多但质量参差不齐的…

using关键字笔记

这世间有多少爱恨情仇,就有多少生死离别🧩 一、using 是什么?为什么它如此重要? 想象一下,你走进一个巨大的图书馆,里面有成千上万本书,分门别类放在不同的书架上。如果你想找一本叫《C# 编程入门》的书,你不…

2025年郑州口碑不错的大巴车租赁专业公司推荐,知名的大巴车租赁企业实力全解析

在郑州这座枢纽之城,团体出行的需求如毛细血管般渗透在商务通勤、研学旅游、企业团建等各个场景中。一辆安全舒适的大巴车,是保障行程顺利的移动基石。面对市场上众多大巴车租赁服务商,如何避开陷阱、找到真正专业靠…

【程序算法题】洛谷, P1760 通天之汉诺塔, java实现。

题目背景直达通天路小A历险记第四篇题目描述在你的帮助下,小 A 成功收集到了宝贵的数据,他终于来到了传说中连接通天路的通天山。但是这距离通天路仍然有一段距离,但是小 A 突然发现他没有地图!!!但是幸运的是,…

雷池 WAF 免费版深度体验:企业用 Lua 脚本拓展,护住跨境电商

雷池 WAF 免费版深度体验:企业用 Lua 脚本拓展,护住跨境电商我们公司做跨境电商,之前一直被安全防护和成本的矛盾困扰 —— 付费 WAF 每年要花几万,免费的要么防护弱,要么无法定制化。直到用了雷池 WAF 免费版,尤…

2025年度中国靠谱房地产模型公司排行:房地产模型服务商推荐

本榜单依托全维度市场调研与真实行业口碑,深度筛选出十家标杆房地产模型企业,重点考量技术实力、服务经验与客户反馈三大维度,为企业选型提供客观依据,助力精准匹配适配的服务伙伴。 TOP1 推荐:深圳市绿建模型设计…

vscode配置MCP

vscode配置MCPvscode配置MCP

2025年深度解析福田欧曼:技术驱动下的多维度价值演进

本文将从技术发展维度切入,为读者剖析福田欧曼在重卡领域的创新路径与行业影响。欧曼重卡是北汽福田汽车旗下重卡品牌,起步即与世界同步。自2001年面世以来,欧曼始终坚持市场与客户导向,秉承技术驱动引领行业创新。…

2025年11月数控加工中心厂家推荐榜:权威排名与综合评测分析

作为机械加工领域的核心设备,数控加工中心的选择直接影响生产效率和产品质量。许多用户可能是中小制造企业的管理者或技术负责人,他们需要平衡设备性能、预算限制和长期维护成本。当前制造业正面临智能化转型趋势,政…

2025年11月数控加工中心制造厂家榜单:诚信企业参数对比与专业评测

作为机械加工领域的核心设备,数控加工中心的选择直接关系到生产效率和产品质量。本文将从用户实际需求出发,结合行业现状与权威数据,为不同应用场景提供系统化推荐。当前制造业加速智能化转型,数控加工中心市场需求…

2025年11月数控加工中心权威排名榜:供应厂家口碑与性能评测分析

在制造业升级与智能化转型的背景下,数控加工中心作为核心生产设备,其选择直接影响企业效率与竞争力。本文聚焦2025年11月市场趋势,结合政策导向与行业需求,为不同场景用户提供系统化推荐。当前,数控加工中心市场呈…