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

Asp.Net Core 托管服务

文章目录

  • 前言
  • 一、说明
  • 二、使用步骤
    • 1.创建托管服务
      • 方式一:继承 BackgroundService
      • 方式二:直接实现 IHostedService
    • 2.注册托管服务
    • 3.处理作用域服务
    • 4.使用定时器(System.Threading.Timer)
    • 5.结合 Quartz.NET 实现复杂调度
  • 三、. 注意事项
  • 总结


前言

ASP.NET Core中,托管服务(Hosted Services)允许你在后台运行长时间运行的任务,例如定时任务、消息队列处理、数据清理等。

一、说明

托管服务需要实现IHostedService接口,或者继承BackgroundService类。BackgroundServiceASP.NET Core提供的抽象类,可能更方便,因为它已经实现了部分接口方法。

二、使用步骤

1.创建托管服务

托管服务需实现 IHostedService 接口或继承 BackgroundService 类(推荐后者,因为它简化了实现)。

方式一:继承 BackgroundService

  1. MyBackgroundService.cs
    using HostedService.Data;
    using Microsoft.EntityFrameworkCore;namespace HostedService.Service
    {public class MyBackgroundService : BackgroundService{private readonly ILogger<MyBackgroundService> _logger;public MyBackgroundService(ILogger<MyBackgroundService> logger, IServiceScopeFactory scopeFactory){_logger = logger;}protected override async Task ExecuteAsync(CancellationToken stoppingToken){_logger.LogInformation("后台服务启动成功");while (!stoppingToken.IsCancellationRequested){_logger.LogInformation("开始导出数据。。。");//处理数据导出_logger.LogInformation("导出数据成功。。。");}}}
    }
    

方式二:直接实现 IHostedService

  1. MyHostedService.cs
    using Microsoft.Extensions.Hosting;
    using Microsoft.Extensions.Logging;
    using System.Threading;
    using System.Threading.Tasks;public class MyHostedService : IHostedService
    {private readonly ILogger<MyHostedService> _logger;private Timer _timer;public MyHostedService(ILogger<MyHostedService> logger){_logger = logger;}public Task StartAsync(CancellationToken cancellationToken){_logger.LogInformation("托管服务已启动。");_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));return Task.CompletedTask;}private void DoWork(object state){_logger.LogInformation("执行定时任务...");}public Task StopAsync(CancellationToken cancellationToken){_logger.LogInformation("托管服务已停止。");_timer?.Dispose();return Task.CompletedTask;}
    }
    

2.注册托管服务

  1. 在 Program.cs 中,通过 AddHostedService 将服务注册到依赖注入容器:
builder.Services.AddHostedService<MyBackgroundService>();
// 或
builder.Services.AddHostedService<MyHostedService>();

3.处理作用域服务

  1. 若托管服务需要访问作用域服务(如 DbContext),需通过 IServiceScopeFactory 创建作用域:
    
    using HostedService.Data;
    using Microsoft.EntityFrameworkCore;namespace HostedService.Service
    {public class MyBackgroundService : BackgroundService{private readonly ILogger<MyBackgroundService> _logger;private readonly IServiceScope _scope;public MyBackgroundService(ILogger<MyBackgroundService> logger, IServiceScopeFactory scopeFactory){_logger = logger;_scope = scopeFactory.CreateScope();}public override void Dispose(){this._scope.Dispose();base.Dispose();}protected override async Task ExecuteAsync(CancellationToken stoppingToken){var db=_scope.ServiceProvider.GetRequiredService<MyDbContext>();_logger.LogInformation("后台服务启动成功");while (!stoppingToken.IsCancellationRequested){_logger.LogInformation("开始导出数据。。。");//使用db操作数据库并导出long count=await db.Users.CountAsync();await File.WriteAllTextAsync("d:/Hosted.txt",count.ToString());await Task.Delay(5000);_logger.LogInformation("导出数据成功。。。");}}}
    }
    

4.使用定时器(System.Threading.Timer)

  1. 托管服务通常结合定时器实现周期性任务:使用 BackgroundService + PeriodicTimer
    
    using HostedService.Data;
    using Microsoft.EntityFrameworkCore;namespace HostedService.Service
    {public class MyBackgroundService : BackgroundService{private readonly ILogger<MyBackgroundService> _logger;private readonly IServiceScope _scope;private PeriodicTimer? _timer;public MyBackgroundService(ILogger<MyBackgroundService> logger, IServiceScopeFactory scopeFactory){_logger = logger;_scope = scopeFactory.CreateScope();}protected override async Task ExecuteAsync(CancellationToken stoppingToken){_timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); // 每5秒执行一次                                                                 var db = _scope.ServiceProvider.GetRequiredService<MyDbContext>();while (await _timer.WaitForNextTickAsync(stoppingToken)){try{// 执行任务await DoWorkAsync(db);}catch (Exception ex){_logger.LogError(ex, "定时任务执行失败");}}}private async Task DoWorkAsync(MyDbContext db){_logger.LogInformation("后台服务启动成功");            _logger.LogInformation("开始导出数据。。。");long count = await db.Users.CountAsync();await File.WriteAllTextAsync("d:/Hosted.txt", count.ToString());await Task.Delay(5000);_logger.LogInformation("导出数据成功。。。");await Task.CompletedTask;}public override void Dispose(){this._scope.Dispose();base.Dispose();}public override async Task StopAsync(CancellationToken stoppingToken){_timer?.Dispose();await base.StopAsync(stoppingToken);}}
    }
    

5.结合 Quartz.NET 实现复杂调度

  1. 对于复杂的定时任务,可集成第三方库(如 Quartz.NET
  2. 安装必要的Nuget包
    Install-Package Quartz.Extensions.Hosting
    
  3. 示例:
    using HostedService.Data;
    using Microsoft.EntityFrameworkCore;
    using Quartz;
    using static Quartz.Logging.OperationName;namespace HostedService.Service
    {public class QuartzHostedService : IHostedService{private readonly ISchedulerFactory _schedulerFactory;public QuartzHostedService(ISchedulerFactory schedulerFactory){_schedulerFactory = schedulerFactory;}private IScheduler _scheduler;public async Task StartAsync(CancellationToken cancellationToken){_scheduler = await _schedulerFactory.GetScheduler(cancellationToken);var job = JobBuilder.Create<MyJob>().Build();var trigger = TriggerBuilder.Create().StartNow().WithSimpleSchedule(x => x.WithIntervalInSeconds(5).RepeatForever()).Build();await _scheduler.ScheduleJob(job, trigger, cancellationToken);await _scheduler.Start(cancellationToken);}public Task StopAsync(CancellationToken cancellationToken){throw new NotImplementedException();}}public class MyJob : IJob{private readonly IServiceScope _scope;private readonly ILogger<MyJob> _logger;public MyJob(ILogger<MyJob> logger, IServiceScopeFactory scopeFactory){_logger = logger;_scope = scopeFactory.CreateScope();}public async Task Execute(IJobExecutionContext context){var db = _scope.ServiceProvider.GetRequiredService<MyDbContext>();_logger.LogInformation("后台服务启动成功");_logger.LogInformation("开始导出数据。。。");long count = await db.Users.CountAsync();await File.WriteAllTextAsync("d:/Hosted.txt", count.ToString());await Task.Delay(5000);_logger.LogInformation("导出数据成功。。。");await Task.CompletedTask;Console.WriteLine("Quartz 任务执行中...");await Task.CompletedTask;}}
    }
    
  4. Program.cs中添加Quartz注册服务
    // 注册 Quartz
    builder.Services.AddQuartz(q =>
    {// 添加作业和触发器var jobKey = new JobKey("MyJob");q.AddJob<MyJob>(opts => opts.WithIdentity(jobKey));q.AddTrigger(opts => opts.ForJob(jobKey).WithCronSchedule("0/10 * * * * ?"));
    });// 添加托管服务
    builder.Services.AddQuartzHostedService();
    

三、. 注意事项

  • 生命周期:托管服务默认是单例的,避免在构造函数中注入作用域服务。
  • 优雅关闭:正确处理 CancellationToken,确保任务能及时停止。
  • 异步操作:避免在 ExecuteAsync 中使用阻塞操作,优先使用异步方法。
  • 异常处理:捕获并记录异常,防止服务因未处理异常而终止。

总结

  • 托管服务是ASP.NET Core中实现后台任务的推荐方式,适用于:

    • 定时任务(如数据同步、缓存刷新)
    • 消息队列消费
    • 资源监控
    • 其他需要长时间运行的进程

    通过 BackgroundServiceIHostedService,结合依赖注入和异步编程模型,可以轻松构建可靠的后台任务。

http://www.xdnf.cn/news/713521.html

相关文章:

  • Cannot find any provider supporting AES/ECB/PKCS7Padding
  • 智能外呼系统中 NLP 意图理解的工作原理与技术实现
  • 【前端】Vue3 中实现两个组件的动态切换保活
  • 制造企业生产数据分析全解析:5大类数据定义、分析方法与落地指南
  • 【Oracle】DCL语言
  • 【深度学习新浪潮】什么是混合精度分解?
  • Docker常用命令操作指南(一)
  • OPC Client第6讲(wxwidgets):Logger.h日志记录文件(单例模式);登录后的主界面
  • 【HTML/CSS面经】
  • 各国竞争的下一代液晶技术:中国铁电液晶取得重大突破突破
  • python和风api获取天气(JSON Web Token)
  • PostgreSQL如何更新和删除表数据
  • 【达梦数据库】内存使用资源评估
  • 图片压缩工具 | 发布到咸鱼并配置网盘自动发货
  • 通义灵码2.5——基于MCP实现我的12306火车票智能查询小助手
  • 66常用控件_QTableWidget的使用
  • 如何在 Odoo 18 中创建 PDF 报告
  • 【JavaScript 高级】事件循环机制详解
  • 第一个桌面应用程序的创建
  • 实验设计与分析(第6版,Montgomery)第5章析因设计引导5.7节思考题5.2 R语言解题
  • 文科小白学习Linux系统之安全管理
  • QT使用说明
  • matlab天线阵列及GUI框架,可用于相控阵,圆形阵,矩形阵
  • 【C/C++】线程安全初始化:std::call_once详解
  • 数据中心双活架构解决方案
  • 基于大模型的颈椎病全周期预测与治疗方案研究报告
  • 软件开发新技术课设-个人博客系统(一)
  • 【HarmonyOS 5】鸿蒙应用px,vp,fp概念详解
  • VSCode + GD32F407 构建烧录
  • 深度解析 9 大 UI 设计风格