Worker Service后台服务启动成功但未执行业务代码问题排查
问题诊断与修复方案
你的Worker Service作为Windows服务运行时未执行业务代码,主要由以下几个关键问题导致,逐一修复即可解决:
1. 核心问题点
- ExecuteAsync方法错误包装异步逻辑:用
Task.Run包裹异步任务后直接返回,导致后台服务无法正确跟踪任务执行; - DbContext未通过依赖注入管理:手动
new TemperatureDbContext未加载配置且生命周期不正确; - Program中缺少必要服务注册:未注册DbContext和HttpClientFactory,导致配置读取异常、资源泄漏;
- Windows服务中无法使用Console输出:
Console.WriteLine在服务环境下无输出,无法排查问题; - HttpClient重复创建导致资源泄漏:每次请求都新建HttpClient,会耗尽Socket资源;
- 时间戳冗余处理:
ToString后再ParseExact完全没必要,浪费性能。
2. 修复后的代码
Program.cs(完善服务注册)
using Microsoft.EntityFrameworkCore; using TemperatureService.Entities; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace TemperatureService { public class Program { static async Task Main(string[] args) { var host = Host.CreateDefaultBuilder(args) .ConfigureServices((context, services) => { // 注册DbContext,从配置读取连接字符串 services.AddDbContext<TemperatureDbContext>(options => options.UseSqlServer(context.Configuration.GetConnectionString("TemperatureDb"))); // 注册HttpClient工厂,避免资源泄漏 services.AddHttpClient(); // 注册后台服务 services.AddHostedService<Worker>(); }) .UseWindowsService() .Build(); await host.RunAsync(); } } }
Worker.cs(修正逻辑与依赖注入)
using TemperatureService.Entities; using Newtonsoft.Json.Linq; using Microsoft.Extensions.Logging; using System.Net.Http; namespace TemperatureService { public class Worker : BackgroundService { private readonly ILogger<Worker> _logger; private readonly TemperatureDbContext _dbContext; private readonly IHttpClientFactory _httpClientFactory; private const string _apiUrl = "http://10.10.30.249/state"; private const string _sensorIp = "10.10.30.249"; // 通过构造函数注入所有依赖 public Worker(ILogger<Worker> logger, TemperatureDbContext dbContext, IHttpClientFactory httpClientFactory) { _logger = logger; _dbContext = dbContext; _httpClientFactory = httpClientFactory; } // 直接实现异步逻辑,无需Task.Run包装 protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation("Temperature service started at: {Time}", DateTimeOffset.Now); while (!stoppingToken.IsCancellationRequested) { try { // 使用HttpClient工厂创建客户端 var httpClient = _httpClientFactory.CreateClient(); var json = await GetTemperatureAsync(httpClient, _apiUrl, stoppingToken); var responseJson = JObject.Parse(json); var sensorsArray = responseJson["multiSensor"]["sensors"]; _logger.LogDebug("Received sensor data: {Sensors}", sensorsArray); // 直接使用当前时间,无需冗余转换 var timestamp = DateTime.UtcNow; // 建议用UtcNow避免时区问题 var sensorData = new TemperatureSensorData { Value = (double)sensorsArray[0]["value"] / 100, Trend = (int)sensorsArray[0]["trend"], State = (int)sensorsArray[0]["state"], ElapsedTimeS = (int)sensorsArray[0]["elapsedTimeS"], TimeStamp = timestamp, IpAddress = _sensorIp }; _dbContext.Temperatures.Add(sensorData); await _dbContext.SaveChangesAsync(stoppingToken); _logger.LogInformation("Saved sensor data at: {Time}", timestamp); await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken); } catch (Exception ex) { _logger.LogError(ex, "Error processing temperature data"); // 出错后延迟再重试,避免频繁报错 await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken); } } _logger.LogInformation("Temperature service stopped at: {Time}", DateTimeOffset.Now); } private async Task<string> GetTemperatureAsync(HttpClient httpClient, string url, CancellationToken cancellationToken) { var response = await httpClient.GetAsync(url, cancellationToken); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(cancellationToken); } } }
3. 额外配置说明
- appsettings.json中添加连接字符串:
{ "ConnectionStrings": { "TemperatureDb": "Server=你的数据库地址;Database=TemperatureDb;Trusted_Connection=True;TrustServerCertificate=True;" } }
- 查看服务日志:可以通过Windows事件查看器(事件查看器 -> 应用程序和服务日志 -> .NET Runtime)查看ILogger输出的日志,方便排查问题。
内容的提问来源于stack exchange,提问作者Tommy
相关产品推荐
相关产品推荐

