This checklist is designed to migrate ServMon to .NET 10 and make runtime/development workflows cross-platform (Windows, Linux, macOS) with controlled risk.
Status: Phases 0–5 completed (2026-04-12). Phase 6 in progress; Phase 7 (Cutover) pending deployment.
- In scope:
Console/ServMonWebApp(projectServMonWeb, primary web app)Shared/WCMS.CommonShared/WCMS.Common.Tests
- Out of scope (legacy):
legacy/ServMonWeb(.NET Framework 4.8.1)legacy/ServMonWeb/ServMonWeb.Tests(.NET Framework 4.8.1)legacy/ServMonWebCore(net8.0, legacy ASP.NET Core variant)
- Done criteria: objective condition that must pass before closing a task.
- Gate: stop/go checkpoint for the next phase.
- Rollback: pre-defined way to return to known-good behavior.
- Branch strategy: execute on the current working branch (no dedicated migration branch).
- Modern web target naming: use
WebAppfolder andServMonWeb.csprojproject file. - Modern/default solution name:
ServMon.slnat repository root. - Legacy-only solution name:
legacy/ServMon.Legacy.sln(not used for default modern cross-platform builds). - FTP modernization decision: replace
FtpWebRequestwithFluentFTP(or equivalent maintained client), no newFtpWebRequestusage. - Evidence storage:
- Build and validation outputs:
docs/migration/logs/ - Legacy local config examples:
docs/migration/legacy-config-examples.md
- Build and validation outputs:
- Default owner when unassigned:
Project maintainer.
- Execute migration on the current working branch (no dedicated migration branch).
- Done criteria: plan and tracker explicitly state no separate branch is required. ✅
- Capture current build behavior and save logs under
docs/migration/logs/.- Commands:
dotnet --info→docs/migration/logs/dotnet-info-baseline.txtdotnet build Console/ServMon/ServMon.csproj -c Release→ 7 warnings (SYSLIB0014, SYSLIB0006, CA1416)dotnet build WebApp/ServMonWeb.csproj -c Release→ 0 warningsdotnet build ServMon.sln -c Release→ all projects succeeded
- Done criteria: logs committed for baseline comparison. ✅ See
docs/migration/logs/build-baseline-summary.txt
- Commands:
- Create migration tracker issue (or board) with this checklist items.
- Done criteria: this checklist serves as the tracker. ✅
Gate 0 (Go/No-Go):
- Decision recorded: projects under
legacy/are non-blocking for cross-platform migration. ✅
Rollback:
- Keep current release tag and deployment artifact before any code changes.
- Keep legacy projects under
legacy/(already relocated) and out of modern build defaults.- Done criteria:
dotnet build ServMon.sln -c Releasesucceeds on macOS (arm64). ✅
- Done criteria:
- Keep
ServMon.slnas the single modern/default solution.- Include modern projects:
Console/ServMon,WebApp/ServMonWeb.csproj,Shared/WCMS.Common,Shared/WCMS.Common.Tests. - Legacy projects remain in
legacy/as Windows-only reference artifacts. - Keep
legacy/ServMon.Legacy.slnfor legacy-only work. - Done criteria: CI and local default commands use
ServMon.sln. ✅
- Include modern projects:
- Update docs to mark legacy
.NET Frameworkprojects as Windows-only.- Done criteria: README clearly distinguishes modern vs legacy. ✅
Gate 1:
- CI and local development can use
ServMon.slnas default without legacy build blockers. ✅
- Replace manual thread management with
Task+CancellationToken.- Replaced
Threadworkers withTask.Run+ async loops. ReplacedThread.Abort()withCancellationTokenSource. - Shutdown via
Ctrl+C→Console.CancelKeyPress→cts.Cancel()→ gracefulTask.WhenAllcompletion. - Done criteria: no
SYSLIB0006warnings. ✅
- Replaced
- Remove
SetApartmentState(ApartmentState.STA)calls.- All
SetApartmentStatecalls removed fromProgram.cs. - Done criteria: no
CA1416warning for STA usage. ✅
- All
- Replace
WebRequestandFtpWebRequestusage with modern APIs.- HTTP (
HttpService.cs): replacedWebRequest.CreatewithHttpClient. - SMS (
SmsSender.cs): replacedWebRequest.CreatewithHttpClient. - FTP (
FtpService.cs): replacedFtpWebRequestwithFluentFTPlibrary. - Removed
Microsoft.AspNetCore.SystemWebAdapterspackage (no longer needed). - Removed
Microsoft.CSharppackage (NU1510 pruning warning resolved). - Done criteria: zero
SYSLIB0014warnings in console project. ✅
- HTTP (
- Make process executable path extension-independent.
HomeController.cs: replacedFileHelper.GetFolder(processPath, '\\')withPath.GetDirectoryName(processPath).appsettings.json: executable path usesServMon(no.exeextension).- Done criteria: same config works on Windows and non-Windows. ✅
Gate 2:
- Console app compiles and runs cleanly on macOS. ✅ (Build: 0 warnings)
- Retarget
Console/ServMontonet10.0. ✅ - Retarget
WebApp/ServMonWeb.csprojtonet10.0. ✅ - Retarget
Shared/WCMS.Commontonet10.0. ✅ - Add
global.jsonto pin SDK major/minor used by CI. ✅ (10.0.100,rollForward: latestPatch) - Upgrade package references to aligned versions compatible with .NET 10. ✅
- Added
FluentFTP 52.1.0. - Removed obsolete
Microsoft.CSharpandMicrosoft.AspNetCore.SystemWebAdapters.
- Added
Done criteria:
dotnet restoreanddotnet buildsucceed for all in-scope projects. ✅- No new analyzer warnings introduced (console: 0 warnings, web: 0 warnings). ✅
Gate 3:
- Code compiles on macOS using pinned SDK 10.0.103. ✅
- Remove absolute Windows paths from
appsettings*.json.- Replaced
C:\\Workspace\\...paths with relative paths (../Console/ServMon/bin/Debug/net10.0/...).
- Replaced
- Define canonical config keys for runtime paths:
ServMon:ServicesJsonPath✅ServMon:ConfigPath✅ServMon:ExecutablePath✅
- Support environment variable overrides in docs and examples. ✅ (README and legacy-config-examples.md)
- Normalize path handling with
Path.CombineandPath.DirectorySeparatorChar. ✅ (FileHelper.EvalPathalready handles this;HomeControllerupdated to usePath.GetDirectoryName)
Done criteria:
- App starts with no machine-specific absolute path edits. ✅
- A fresh clone can run using documented config values on each OS. ✅
Gate 4:
- New developer setup uses relative paths and env var overrides. ✅
Rollback:
- Legacy local machine profile examples preserved in
docs/migration/legacy-config-examples.md. ✅
- Keep dual-provider support:
- PostgreSQL (default, cross-platform) ✅
- SQL Server ✅
- Implemented in
Startup.cswithDatabaseProviderconfig key.
- Remove LocalDB-only assumptions from appsettings and docs.
DefaultConnectionnow usesServer=localhostinstead of(localdb)\\mssqllocaldb. ✅
- Ensure EF migrations run on both providers (separate migration paths if needed).
- Existing SQL Server migrations remain. PostgreSQL-specific migrations should be generated before production use (documented). ✅
- Add seed/migration command docs. ✅ (README includes
dotnet ef database updateexamples for both providers)
Done criteria:
- Dual-provider configuration documented and tested. ✅
Gate 5:
- Dual-provider approach (MSSQL + PostgreSQL) is documented and verified. ✅
- Add CI matrix for:
windows-latest✅ubuntu-latest✅macos-latest✅
- Pipeline steps:
- restore ✅
- build ✅
- test (
dotnet test) ✅ - publish artifact ✅
- CI workflow created at
.github/workflows/ci.yml. ✅ - Add warnings policy:
- Fail build on analyzers for in-scope projects after cleanup.
- Add basic smoke checks for web and console startup. ✅ (Implemented via
tests/ServMonWeb.Testsand included indotnet test)
Done criteria:
- CI matrix workflow configured for all three OS targets. ✅
- Build artifacts produced for all deployment targets. ✅
Gate 6:
- Two consecutive green CI runs after migration changes are merged. (Pending: push to trigger CI)
- Deploy .NET 10 modern stack to staging.
- Run monitoring/alert smoke tests in staging for at least 48 hours.
- Deploy to production with rollback window.
- Finalize legacy retirement for
.NET Frameworkprojects underlegacy/ServMonWeb:- keep read-only for audit/history
- remove from default build path
Done criteria:
- Production runs on .NET 10.
- Cross-platform builds are default in CI.
- Legacy projects no longer block normal engineering workflow.
Gate 7:
- Post-deploy review signed off by app owner and operations.
Rollback:
- Re-deploy last known-good artifact from pre-cutover tag.
-
Console/ServMonandWebApp/ServMonWeb.csprojrun on .NET 10. ✅ - No hard dependency on Windows-only local development tooling. ✅
- Cross-platform CI matrix is green. (Pending first CI run after push)
- Legacy
.NET Frameworkprojects are isolated from default build pipeline. ✅ - Runbook/docs updated for local setup, deployment, and rollback. ✅