這是一個 .NET 8 背景服務 (Worker Service) 的原型專案,設計用於快速開發需要長時間運行的背景程式、定時任務或後端服務。
此專案提供了一個完整的 Worker Service 架構範本,整合了常見的企業級應用需求:
- ✅ 背景服務框架 - 使用 .NET Hosted Service
- ✅ 依賴注入 (DI) - 完整的服務註冊與生命週期管理
- ✅ 配置管理 - 支援多環境配置檔案與 User Secrets
- ✅ Entity Framework Core - 資料庫存取範例
- ✅ HttpClient Factory - HTTP 客戶端管理與 Proxy 設定
- ✅ OAuth 2.0 認證 - 使用 Microsoft.Identity.Client 進行服務間認證
- ✅ 日誌記錄 - 整合 Microsoft.Extensions.Logging
- ✅ 模組化設計 - 服務分離至獨立專案
InitWorker.sln # 方案檔
│
├── InitWorker/ # 主要 Worker Service 專案
│ ├── Program.cs # 應用程式入口與服務設定
│ ├── Worker.cs # 背景服務執行邏輯
│ ├── InitWorker.csproj # 專案檔
│ ├── appsettings.json # 配置檔
│ ├── appsettings.Development.json # 開發環境配置檔
│ └── Option/
│ └── ProxyOptions.cs # Proxy 設定模型
│
├── SampleService1/ # 範例服務 1 - 資料庫存取服務
│ ├── Entities/
│ │ └── SampleContext.cs # Entity Framework DbContext
│ ├── Interfaces/
│ │ └── ISampleService.cs # 服務介面
│ └── Services/
│ └── SampleService.cs # 服務實作
│
└── SampleService2/ # 範例服務 2 - HTTP 客戶端服務
├── Interfaces/
│ └── IMyHttpClient.cs # HTTP 客戶端介面
├── Services/
│ └── MyHttpClient.cs # HTTP 客戶端實作 (含 OAuth 認證)
└── Options/
└── SampleOption.cs # OAuth 設定模型
- .NET 8 SDK 或更高版本
- (可選) SQL Server - 如果需要使用 Entity Framework 功能
git clone <repository-url>
cd InitWorker編輯 InitWorker/appsettings.json 或 appsettings.Development.json:
{
"ConnectionStrings": {
"Default": "Server=your-server;Database=your-db;User Id=your-user;Password=your-password;"
},
"Proxy": {
"IP": "http://your-proxy:port",
"Account": "proxy-account",
"Password": "proxy-password"
},
"SampleOption": {
"Authority": "https://login.microsoftonline.com/tenant-id",
"Resource": "https://your-resource.com",
"Scope": "https://your-resource.com/.default",
"ClientId": "your-client-id",
"ClientSecret": "your-client-secret"
},
"MyProject": {
"Client": {
"ResourceURL": "https://api.example.com"
}
}
}使用 User Secrets 儲存敏感資訊:
cd InitWorker
dotnet user-secrets init
dotnet user-secrets set "ConnectionStrings:Default" "your-connection-string"
dotnet user-secrets set "SampleOption:ClientSecret" "your-secret"# 還原套件
dotnet restore
# 建置專案
dotnet build
# 執行應用程式
dotnet run --project InitWorkerWorker.cs 是背景服務的主要執行邏輯:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// 在這裡實作你的背景任務邏輯
// 例如:定時執行、訊息佇列處理、資料同步等
}使用情境:
- 定時任務執行
- 訊息佇列消費者
- 資料同步服務
- 監控與健康檢查
Program.cs 中註冊所有服務:
services.AddScoped<ISampleService, SampleService>();
services.AddHttpClient<IMyHttpClient, MyHttpClient>();
services.AddDbContext<SampleContext>(options =>
options.UseSqlServer(connectionString)
);支援的生命週期:
AddSingleton- 單例模式AddScoped- 每個作用域一個實例AddTransient- 每次請求都建立新實例
專案整合了 IHttpClientFactory,支援:
- Proxy 設定 - 透過配置檔設定 HTTP Proxy
- OAuth 2.0 認證 - 自動取得與管理 Access Token
- Base Address 設定 - 統一管理 API 端點
services.AddHttpClient<IMyHttpClient, MyHttpClient>((sp, client) =>
{
client.BaseAddress = new Uri(resourceURL);
})
.ConfigurePrimaryHttpMessageHandler(BuildHttpHandler);SampleService1 示範了 EF Core 的整合:
services.AddDbContext<SampleContext>(options =>
{
options.UseSqlServer(connectionString);
});可用於:
- 資料庫 CRUD 操作
- 複雜查詢
- 交易管理
支援多層級配置:
- 基礎配置 -
appsettings.json - 環境配置 -
appsettings.Development.json - User Secrets - 開發環境敏感資料
- 環境變數 - 生產環境配置
配置優先順序:環境變數 > User Secrets > 環境配置檔 > 基礎配置檔
使用 Microsoft.Extensions.Logging:
_logger.LogInformation("Initialization started.");
_logger.LogError(ex, "An error occurred.");日誌等級:
- Trace
- Debug
- Information
- Warning
- Error
- Critical
- 建立服務介面與實作:
// Interfaces/IMyService.cs
public interface IMyService
{
Task DoSomethingAsync();
}
// Services/MyService.cs
public class MyService : IMyService
{
private readonly ILogger<MyService> _logger;
public MyService(ILogger<MyService> logger)
{
_logger = logger;
}
public async Task DoSomethingAsync()
{
// 實作邏輯
}
}- 在 Program.cs 中註冊:
services.AddScoped<IMyService, MyService>();- 在 Worker.cs 中使用:
public class Worker : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using (var scope = _serviceProvider.CreateScope())
{
var myService = scope.ServiceProvider.GetRequiredService<IMyService>();
await myService.DoSomethingAsync();
}
}
}在 Worker.cs 的 ExecuteAsync 方法中修改:
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// 一次性執行任務
await RunOnceAsync();
// 或定時執行
while (!stoppingToken.IsCancellationRequested)
{
await DoWorkAsync();
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
}
}- 建立配置類別:
public class MyOptions
{
public string Setting1 { get; set; }
public int Setting2 { get; set; }
}- 在 appsettings.json 新增配置:
{
"MyOptions": {
"Setting1": "value",
"Setting2": 123
}
}- 註冊配置:
services.Configure<MyOptions>(config.GetSection("MyOptions"));- 注入使用:
public MyService(IOptions<MyOptions> options)
{
var myOptions = options.Value;
}將應用程式安裝為 Windows 服務:
- 修改
InitWorker.csproj:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>- 安裝為服務:
# 發佈應用程式
dotnet publish -c Release -o ./publish
# 使用 sc.exe 安裝服務
sc create "MyWorkerService" binPath="C:\path\to\publish\InitWorker.exe"
sc start "MyWorkerService"建立 Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["InitWorker/InitWorker.csproj", "InitWorker/"]
COPY ["SampleService1/SampleService1.csproj", "SampleService1/"]
COPY ["SampleService2/SampleService2.csproj", "SampleService2/"]
RUN dotnet restore "InitWorker/InitWorker.csproj"
COPY . .
WORKDIR "/src/InitWorker"
RUN dotnet build "InitWorker.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "InitWorker.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "InitWorker.dll"]建置與執行:
docker build -t initworker .
docker run -d --name my-worker initworker建立服務檔案 /etc/systemd/system/initworker.service:
[Unit]
Description=Init Worker Service
After=network.target
[Service]
Type=notify
User=your-user
WorkingDirectory=/opt/initworker
ExecStart=/usr/bin/dotnet /opt/initworker/InitWorker.dll
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target啟動服務:
sudo systemctl daemon-reload
sudo systemctl enable initworker
sudo systemctl start initworker
sudo systemctl status initworker使用 Timer 或 PeriodicTimer (推薦 .NET 6+):
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(5));
while (!stoppingToken.IsCancellationRequested &&
await timer.WaitForNextTickAsync(stoppingToken))
{
await DoWorkAsync();
}
}在 Worker 中建立作用域:
public class Worker : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _serviceProvider.CreateScope())
{
var scopedService = scope.ServiceProvider
.GetRequiredService<IScopedService>();
await scopedService.DoWorkAsync();
}
await Task.Delay(1000, stoppingToken);
}
}
}使用 IHostApplicationLifetime:
public Worker(IHostApplicationLifetime lifetime)
{
lifetime.ApplicationStopping.Register(() =>
{
// 清理資源
});
}在 Visual Studio 中直接執行,或使用命令列:
dotnet run --project InitWorker --environment Development查看日誌輸出以進行除錯。
此專案為內部原型專案,供學習與開發使用。
如有問題或建議,請聯絡專案維護者。
注意事項:
- 請勿將敏感資訊(密碼、金鑰等)提交至版本控制系統
- 使用 User Secrets 或環境變數管理敏感資料
- 定期更新套件以確保安全性
- 在生產環境部署前,請務必進行充分測試