You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 7 Worker Service作为Windows服务运行异常求助

Windows服务模式下.NET 7 Worker Service代理功能失效问题排查与修复

我基于.NET 7.0开发了一个C# Worker Service程序,使用Titanium Web Proxy监听所有入站GET请求,并将请求的URI和URL保存到Log.txt文件中。程序直接运行时功能正常,但发布为Windows服务后,通过sc start命令启动服务,服务显示运行但实际功能完全不生效。

原始代码

Program.cs

using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Extensions.Hosting;
using Serilog.Extensions.Logging;

namespace WorkerService5
{
    public class Program
    {
        static async Task Main(string[] args)
        {
            IHost host = Host.CreateDefaultBuilder(args)
                .ConfigureServices(services =>
                {
                    services.AddHostedService<Worker>();
                })
                .UseWindowsService()
                .UseSerilog()
                .Build();

            await host.RunAsync();
        }
    }
}

Worker.cs

using System.Net;
using Titanium.Web.Proxy;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models;
using Serilog;
using Microsoft.Extensions.Hosting;

namespace WorkerService5
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private readonly IHostApplicationLifetime _hostApplicationLifetime;

        public Worker(ILogger<Worker> logger, IHostApplicationLifetime hostApplicationLifetime)
        {
            _logger = logger;
            _hostApplicationLifetime = hostApplicationLifetime;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken) => Task.Run(async () =>
        {
            try
            {
                var proxyServer = new ProxyServer(userTrustRootCertificate: false);

                proxyServer.BeforeRequest += OnRequest;

                var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true);

                proxyServer.AddEndPoint(explicitEndPoint);

                proxyServer.Start();

                foreach (var endPoint in proxyServer.ProxyEndPoints)
                    _logger.LogInformation("Listening on '{0}' endpoint at Ip {1} and port: {2} ",
                        endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);

                proxyServer.SetAsSystemHttpProxy(explicitEndPoint);

                // Console.ReadLine();

                stoppingToken.Register(() =>
                {
                    proxyServer.BeforeRequest -= OnRequest;
                    proxyServer.Stop();
                });

                await Task.Delay(Timeout.Infinite, stoppingToken);
            }

            catch (Exception)
            {
                throw;
            }

        });

        private async Task OnRequest(object sender, SessionEventArgs e)
        {
            var filePath = @"E:\LogiusService\Logs\log.txt";

            Log.Logger = new LoggerConfiguration()
                .WriteTo.File(filePath, rollingInterval: RollingInterval.Day, shared: true)
                .CreateLogger();

            string requestedUrl = e.HttpClient.Request.Host;
            Console.WriteLine("Requested URL: " + requestedUrl);
            Log.Information($"Requested URL: " + requestedUrl);

            string requestedUri = e.HttpClient.Request.RequestUri.AbsoluteUri;
            Console.WriteLine("Requested URI: " + requestedUri);
            Log.Information($"Requested URI: " + requestedUri);
        }
    }
}

问题根源

  1. 权限不足:Windows服务默认以低权限账户运行,无修改系统代理、读写日志目录的权限
  2. Serilog重复初始化:每次请求时重新创建Log.Logger,导致日志写入异常且效率低下
  3. 异步逻辑混乱:ExecuteAsync嵌套Task.Run,破坏服务生命周期管理
  4. 系统代理设置失败:SetAsSystemHttpProxy需要管理员权限,普通服务账户无法执行

修复方案

1. 修正Serilog全局配置(Program.cs)

将Serilog初始化提前绑定到Host,避免重复创建:

using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;

namespace WorkerService5
{
    public class Program
    {
        static async Task Main(string[] args)
        {
            // 全局配置Serilog
            Log.Logger = new LoggerConfiguration()
                .WriteTo.File(@"E:\LogiusService\Logs\log.txt", rollingInterval: RollingInterval.Day, shared: true)
                .CreateLogger();

            try
            {
                IHost host = Host.CreateDefaultBuilder(args)
                    .ConfigureServices(services =>
                    {
                        services.AddHostedService<Worker>();
                    })
                    .UseWindowsService()
                    .UseSerilog() // 集成到Host日志系统
                    .Build();

                await host.RunAsync();
            }
            finally
            {
                Log.CloseAndFlush(); // 确保日志写入完成
            }
        }
    }
}

2. 重构Worker异步逻辑与权限处理(Worker.cs)

移除冗余嵌套、修复代理生命周期、添加错误日志:

using System.Net;
using Titanium.Web.Proxy;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Models;
using Serilog;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace WorkerService5
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;
        private ProxyServer? _proxyServer;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            try
            {
                _proxyServer = new ProxyServer(userTrustRootCertificate: false);
                _proxyServer.BeforeRequest += OnRequest;

                var explicitEndPoint = new ExplicitProxyEndPoint(IPAddress.Any, 8000, true);
                _proxyServer.AddEndPoint(explicitEndPoint);

                _proxyServer.Start();

                foreach (var endPoint in _proxyServer.ProxyEndPoints)
                    _logger.LogInformation("Listening on '{0}' endpoint at Ip {1} and port: {2} ",
                        endPoint.GetType().Name, endPoint.IpAddress, endPoint.Port);

                // 若不需要全局代理则注释此行,避免权限问题
                // _proxyServer.SetAsSystemHttpProxy(explicitEndPoint);

                stoppingToken.Register(() =>
                {
                    if (_proxyServer != null)
                    {
                        _proxyServer.BeforeRequest -= OnRequest;
                        _proxyServer.Stop();
                    }
                });

                await Task.Delay(Timeout.Infinite, stoppingToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Proxy service encountered critical error");
                throw; // 让服务管理器感知到错误
            }
        }

        private async Task OnRequest(object sender, SessionEventArgs e)
        {
            if (e.HttpClient.Request.Method == "GET")
            {
                string requestedUrl = e.HttpClient.Request.Host;
                Log.Information($"Requested URL: {requestedUrl}");

                string requestedUri = e.HttpClient.Request.RequestUri.AbsoluteUri;
                Log.Information($"Requested URI: {requestedUri}");
            }
            await Task.CompletedTask;
        }
    }
}

3. 服务部署权限配置

  • 创建服务时指定管理员账户:
    sc create ProxyWorkerService binPath= "C:\发布路径\WorkerService5.exe" obj= "DOMAIN\管理员账户" password= "账户密码" start= auto
    
  • 确保E:\LogiusService\Logs目录存在,且服务账户拥有读写权限
  • 若不需要全局代理,直接注释SetAsSystemHttpProxy代码

验证步骤

  1. 重新发布程序
  2. 执行sc start ProxyWorkerService启动服务
  3. 通过http://localhost:8000发送GET请求,检查日志文件是否正常记录
  4. 查看Windows事件查看器的应用程序日志,排查潜在错误

内容的提问来源于stack exchange,提问作者Tomasz Florczyk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 21:15:34