如何在指定时间自动调用ASP.NET Core中的[HttpPost]接口
服务器端定时触发HttpPost请求的解决方案
你之前用的代码是WinForms的Timer,这套逻辑在ASP.NET Core服务器环境里根本跑不起来,原因有这几点:
- WinForms的Timer依赖UI线程,服务器端没有这个线程,
Tick事件根本不会触发 - 用
_ran这种全局变量记录执行状态,服务器重启、应用池回收或者多实例部署时,状态直接丢失,没法保证任务只执行一次 - ASP.NET Core是无状态的服务器框架,这种桌面程序的定时逻辑完全不适用
下面给你两种适合服务器端的实现方案:
方案一:用BackgroundService轻量实现
这是ASP.NET Core官方推荐的后台任务方案,结合System.Timers.Timer实现定时检查,同时用持久化方式记录任务执行状态。
1. 创建后台服务类
using Microsoft.Extensions.Hosting; using System.Timers; using System.Runtime.Caching; public class ScheduledPostService : BackgroundService { private Timer _timer; private readonly ILogger<ScheduledPostService> _logger; private readonly HttpClient _httpClient; public ScheduledPostService(ILogger<ScheduledPostService> logger, HttpClient httpClient) { _logger = logger; _httpClient = httpClient; } protected override Task ExecuteAsync(CancellationToken stoppingToken) { // 每分钟检查一次时间(可根据需求调整间隔) _timer = new Timer(60000); _timer.Elapsed += OnTimerElapsed; _timer.Start(); _logger.LogInformation("定时任务服务已启动"); return Task.CompletedTask; } private async void OnTimerElapsed(object sender, ElapsedEventArgs e) { _timer.Stop(); // 先停Timer,避免并发执行 try { var now = DateTime.Now; // 检查是否到11点整,且今日未执行过任务 if (now.Hour == 11 && now.Minute == 0 && !HasJobRunToday()) { _logger.LogInformation("开始执行定时HttpPost请求"); // 替换成你的实际接口地址 var response = await _httpClient.PostAsync("/api/your-target-endpoint", null); if (response.IsSuccessStatusCode) { _logger.LogInformation("HttpPost请求执行成功"); MarkJobAsRunToday(); // 标记今日已执行 } else { _logger.LogError("请求失败,状态码:{Code}", response.StatusCode); } } // 每天7点重置执行标记 else if (now.Hour == 7 && now.Minute == 0) { ResetJobRunMark(); _logger.LogInformation("已重置今日执行标记"); } } catch (Exception ex) { _logger.LogError(ex, "定时任务执行出错"); } finally { _timer.Start(); // 重启Timer } } // 用内存缓存记录执行状态,生产环境建议换成Redis或数据库 private bool HasJobRunToday() { var cacheKey = $"DailyRun_{DateTime.Today:yyyyMMdd}"; return MemoryCache.Default.Get(cacheKey) != null; } private void MarkJobAsRunToday() { var cacheKey = $"DailyRun_{DateTime.Today:yyyyMMdd}"; // 缓存到次日过期 MemoryCache.Default.Set(cacheKey, true, DateTime.Today.AddDays(1)); } private void ResetJobRunMark() { var cacheKey = $"DailyRun_{DateTime.Today:yyyyMMdd}"; MemoryCache.Default.Remove(cacheKey); } public override void Dispose() { _timer?.Dispose(); base.Dispose(); } }
2. 注册服务到Program.cs
var builder = WebApplication.CreateBuilder(args); // 注册HttpClient(避免手动new导致连接泄漏) builder.Services.AddHttpClient(); // 注册后台定时服务 builder.Services.AddHostedService<ScheduledPostService>(); // 其他服务配置... var app = builder.Build(); // 中间件配置... app.Run();
方案二:用Quartz.NET实现复杂定时规则
如果需要更灵活的调度(比如每周一执行、按cron表达式配置),可以用专业的定时任务框架Quartz.NET。
1. 安装NuGet包
Install-Package Quartz Install-Package Quartz.Extensions.Hosting
2. 创建任务类
using Quartz; public class PostRequestJob : IJob { private readonly HttpClient _httpClient; private readonly ILogger<PostRequestJob> _logger; public PostRequestJob(HttpClient httpClient, ILogger<PostRequestJob> logger) { _httpClient = httpClient; _logger = logger; } public async Task Execute(IJobExecutionContext context) { _logger.LogInformation("开始执行Quartz定时HttpPost请求"); var response = await _httpClient.PostAsync("/api/your-target-endpoint", null); if (response.IsSuccessStatusCode) { _logger.LogInformation("请求执行成功"); } else { _logger.LogError("请求失败,状态码:{Code}", response.StatusCode); } } }
3. 配置Quartz到Program.cs
var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpClient(); // 配置Quartz builder.Services.AddQuartz(q => { // 注册任务 var jobId = new JobKey("DailyPostJob"); q.AddJob<PostRequestJob>(opts => opts.WithIdentity(jobId)); // 配置触发器:每天11点执行(cron表达式) q.AddTrigger(opts => opts .ForJob(jobId) .WithIdentity("DailyPostTrigger") .WithCronSchedule("0 0 11 * * ?")); // cron语法:分 时 日 月 周 年(可选) }); // 注册Quartz托管服务 builder.Services.AddQuartzHostedService(opts => opts.WaitForJobsToComplete = true); // 其他配置... var app = builder.Build(); // 中间件配置... app.Run();
注意事项
- 服务器端要注意应用池回收问题,建议配置应用池禁用定期回收,或者用Quartz的持久化功能保存任务状态
- 内存缓存的执行标记在应用重启后会丢失,生产环境一定要用Redis、数据库等分布式存储
- 必须通过依赖注入获取HttpClient,禁止手动实例化,否则会造成TCP连接泄漏
内容的提问来源于stack exchange,提问作者Mustafa Mazin
相关产品推荐
相关产品推荐

