.NET Core WebAPI启动执行Excel导入及每周定时任务问题
.NET Core WebAPI Excel导入SQLite:启动执行与定时任务解决方案
1. 启动时调用Excel导入方法
有两种规范的实现方式:
方式一:Program.cs中手动触发(简单直接)
在Host构建完成后,创建服务作用域并调用业务方法:
var builder = WebApplication.CreateBuilder(args); // 确保接口与实现已正确注册 builder.Services.AddScoped<IDataSourceService, DqcDataService>(); // 其他服务、中间件注册逻辑... var app = builder.Build(); // 启动时执行Excel导入 using (var scope = app.Services.CreateScope()) { var dataSourceService = scope.ServiceProvider.GetRequiredService<IDataSourceService>(); await dataSourceService.ReadFromExcelAsync(); } // 启动WebAPI app.Run();
方式二:使用IHostedService(符合托管服务规范)
创建专门的启动任务服务:
public class StartupImportService : IHostedService { private readonly IServiceProvider _serviceProvider; public StartupImportService(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public async Task StartAsync(CancellationToken cancellationToken) { using (var scope = _serviceProvider.CreateScope()) { var dataSourceService = scope.ServiceProvider.GetRequiredService<IDataSourceService>(); await dataSourceService.ReadFromExcelAsync(); } } public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; }
然后在Program.cs中注册该托管服务:
builder.Services.AddHostedService<StartupImportService>();
2. 服务无法解析的原因与正确注册方式
直接注册DqcDataService虽能临时解决问题,但会丢失依赖注入的解耦优势。之前解析失败通常是以下原因:
- 时机错误:在
builder.Build()完成前就尝试解析服务(此时服务容器尚未初始化完成) - 生命周期不匹配:若
DqcDataService依赖Scoped/Transient类型服务,直接通过根服务提供者获取会报错(根提供者仅支持解析Singleton服务) - 注册遗漏:未添加
builder.Services.AddScoped<IDataSourceService, DqcDataService>()或存在拼写错误
正确做法是保留接口与实现的注册,在需要调用时通过服务作用域获取(如问题1中的两种方式),而非直接注册具体类。
3. 定时任务的正确实现(避免重复代码)
托管服务默认是Singleton生命周期,不能直接注入Scoped类型的IDataSourceService,需在任务执行时动态创建服务作用域。以下是每周定时任务的示例:
实现定时托管服务
public class WeeklyImportService : IHostedService, IDisposable { private readonly IServiceProvider _serviceProvider; private Timer _timer; public WeeklyImportService(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public Task StartAsync(CancellationToken cancellationToken) { // 设置每周日凌晨2点执行(可根据需求调整时间) var now = DateTime.Now; var nextRun = now.AddDays((7 - now.DayOfWeek + DayOfWeek.Sunday) % 7).Date.AddHours(2); if (nextRun <= now) nextRun = nextRun.AddDays(7); var initialDelay = nextRun - now; // 初始化定时器,每周执行一次 _timer = new Timer(ExecuteImport, null, initialDelay, TimeSpan.FromDays(7)); return Task.CompletedTask; } private async void ExecuteImport(object state) { using (var scope = _serviceProvider.CreateScope()) { var dataSourceService = scope.ServiceProvider.GetRequiredService<IDataSourceService>(); await dataSourceService.ReadFromExcelAsync(); } } public Task StopAsync(CancellationToken cancellationToken) { _timer?.Change(Timeout.Infinite, 0); return Task.CompletedTask; } public void Dispose() { _timer?.Dispose(); } }
注册定时服务
在Program.cs中添加:
builder.Services.AddHostedService<WeeklyImportService>();
如果使用第三方定时任务库(如Quartz),核心逻辑一致:在任务执行方法内创建服务作用域,获取IDataSourceService并调用已有方法,完全复用业务代码,无需重复编写。
内容的提问来源于stack exchange,提问作者AoLiGei
相关产品推荐
相关产品推荐

