VB6-to-.NET 10 migration of the legacy store synchronization receiver.
A self-contained Windows desktop application that imports product-master sync packages and posts inter-store inventory transfers. Built as a behavior-preserving replacement for the legacy VB6 TaskUpdateTransfer application.
TaskMonitor watches C:\DL-SYNCH for incoming packages and processes them:
| Package Type | File Pattern | Action |
|---|---|---|
| Product Sync | N SynProducts.rar |
Upserts products, barcodes, departments, vendors, users, and home-store quantities into the target SQL Server database |
| Store Transfer | N Itemtrans.rar |
Posts received inventory transfers: updates QuantityOnHand, writes audit trail records, validates destination store routing |
Product packages always complete before any transfer package is processed.
TaskMonitorModern.sln
├── TaskMonitor.Domain/ — Core models, settings, sync value objects
├── TaskMonitor.Application/ — Services, interfaces, orchestration
│ ├── Services/ — SyncExportService, SyncImportService,
│ │ SyncProcessingService, SyncSchedulerService,
│ │ TransferPostingService, SyncPackageNameService
│ └── Abstractions/ — 16 interfaces (repository, file, settings)
├── TaskMonitor.Infrastructure/ — SQL Server, file I/O, archive, settings
│ ├── Persistence/ — DbOperationExecutor (retry), SQL builders,
│ │ repositories, connection factories
│ ├── Files/ — File staging, archive extraction, package discovery
│ └── Settings/ — JSON settings store with atomic writes
├── TaskMonitor.Desktop/ — WPF UI, ViewModels, composition root
│ ├── ViewModels/ — MainViewModel orchestrates focused SettingsViewModel,
│ │ ActivityPanelViewModel, diagnostics, scheduler, sync
│ └── Composition/ — Microsoft.Extensions.DependencyInjection (AppCompositionRoot)
└── TaskMonitor.Tests/ — 41 console-based self-tests + ops CLI
└── TaskMonitor.Tests.Unit/ — 18 xUnit tests (CI-discoverable)
- Target: .NET 10 (net10.0-windows)
- UI: WPF + Windows Forms interop
- Database: SQL Server via
Microsoft.Data.SqlClient7.0.2 - Archives: Standard ZIP (
.rarextension retained for legacy compatibility) - ~4,745 lines of C#, clean architecture, interface-driven design
- Windows x64
- .NET 10 SDK (for building from source)
- SQL Server (SQL Server 2022 or compatible)
dotnet build TaskMonitorModern.sln --configuration Releasedotnet run --no-build --configuration Release --project TaskMonitor.Tests/TaskMonitor.Tests.csproj
# CI-discoverable unit tests
dotnet test --configuration Release --project TaskMonitor.Tests.Unit/TaskMonitor.Tests.Unit.csprojdotnet publish TaskMonitor.Desktop/TaskMonitor.Desktop.csproj \
--configuration Release \
--runtime win-x64 \
--self-contained true \
--output artifacts/publish/TaskMonitor-win-x64The published output is a fully self-contained ~180 MB directory — copy it anywhere, no .NET runtime required. appsettings.json is included in the publish output; review and adjust it for the target environment before first run.
All settings live in appsettings.json alongside the executable.
Quick DB setup on a new machine: run
Set-DbCredentials.ps1to set the server, database, and authentication without hand-editing JSON. See the script's-?help for examples (Windows auth, SQL login, and runtime password viaTASKMONITOR_DB_PASSWORD).
| Setting | Default | Description |
|---|---|---|
Mode |
"Recording" |
"Database" to write to SQL Server |
ActivationApproved |
false |
Must be true before Database mode starts |
Mode is also editable from the UI. The Settings window has an Application Mode selector (
Recording/Database) with an explanatory note. Changing it writes toappsettings.jsonand takes effect after an application restart.
| Setting | Default | Description |
|---|---|---|
TaskMonitor.SyncBehaviour |
"ExecuteSync" |
"CreateSync", "ExecuteSync", or "Both" |
TaskMonitor.IntervalTime |
"30" |
Scheduler interval amount |
TaskMonitor.IntervalType |
"Minutely" |
"Minutely" or "Hourly" |
DisableCreateSync |
false |
Suppress outgoing package creation |
DisableExecuteSync |
false |
Suppress incoming sync processing |
DisableTransferProcessing |
false |
Product sync only, hold transfers |
LocalStoreId |
0 |
Receiving store ID for destination routing |
RequireDestinationStoreRouting |
true |
Reject transfers addressed to other stores |
- WPF incoming polling: Every 30 seconds (hardcoded) — fires while the app window is open
- Scheduler polling: Configurable via
IntervalTime/IntervalType
"Database": {
"Server": "HPWIN11",
"DatabaseName": "PVSQLDBN",
"UseIntegratedSecurity": true,
"UserName": "",
"Password": "",
"Encrypt": true,
"TrustServerCertificate": false
}Database passwords are never persisted to disk — the Settings window always saves an
empty password, and any plaintext value already in appsettings.json is ignored on save.
Authentication options:
- Windows Integrated Security (
UseIntegratedSecurity: true, preferred on domain-joined machines). On a workgroup machine the SQL client must negotiate Kerberos, which fails with "Cannot generate SSPI context" — use SQL authentication instead. - SQL authentication (
UseIntegratedSecurity: false+UserName): supply the password at runtime through theTASKMONITOR_DB_PASSWORDenvironment variable (checked at process/user/machine scope), or setPasswordtemporarily in the file (it is cleared on the next save).Set-DbCredentials.ps1automates this.
- Activation gate: Database mode blocked until
ActivationApprovedistrue— prevents accidental writes during setup - Non-blocking startup validation: The database schema check runs at startup but never bricks the UI — any mismatch is surfaced as an error row in Diagnostics, so the Settings window stays usable and connection problems can be fixed in-app
- SQL transient retry: 3 retries with exponential backoff (500ms → 1s → 2s) for deadlocks, timeouts, and connection drops
- SHA-256 fingerprinting: Identical packages are quarantined, never double-posted
- Atomic settings writes: Write-then-rename with
FileOptions.WriteThrough - Destination routing: Rejects transfers not addressed to this store
- Product sync: Upserts via
IF EXISTS … UPDATE … ELSE INSERT— idempotent, re-runnable - Transfer posting: Single transaction per package — audit header + product QOH update + audit trail for each item line
- Duplicate detection: SHA-256 fingerprint receipts prevent replay attacks
- Quarantine: Duplicate packages moved to
Quarantinefolder - Monthly archiving: Completed packages archived to
Archive\Mth-MM-yyyy
Create Sync generates sequentially numbered SynProducts.rar packages:
- Sequence: 1 → 2 → … → 99 → wraps to 1
- Increment tracked in
LastSyncIncrementsetting - Collision avoidance: if the cloud upload system is down and packages accumulate in
UL-SYNCH, the next available sequence number is used and the increment is synced back
Only error/failure entries are written to tblServerLog:
Download Folder Error— missing required foldersPackage Processing Failed— sync or transfer failureDuplicate Package— SHA-256 match quarantinedTransfer Processing Deferred— product sync failure blocks transfers
Informational noise (folder paths, routine processing, row counts) is excluded by design — if the log is quiet, processing is healthy.
C:\DL-SYNCH\ — Incoming sync directory
├── _work\ — Isolated extraction workspace
├── Archive\ — Completed product packages (by month)
├── Failed\ — Packages that failed processing
├── Processed\ — Fingerprint receipts + completed transfer packages
├── Quarantine\ — Duplicate packages
└── Logs\ — Log files (auto-cleaned, 30-day retention)
C:\UL-SYNCH\ — Outgoing sync directory (Create Sync packages)
- Review
appsettings.json— server, database, store ID, sync behavior - Set
ActivationApprovedtofalseduring initial setup - Run Diagnostics from the UI — confirm zero errors
- Set
ActivationApprovedtotrue - Restart the application
- The scheduler starts with the "Start" button or via
--start-schedulerflag
| Flag | Action |
|---|---|
--execute-sync |
Run one sync cycle and exit |
--create-sync |
Create one product sync package and exit |
--start-scheduler |
Start the scheduler on launch |
- 59 automated tests — 41 self-tests (all passing) covering sync, transfer, archive, XML, settings, SQL builders, and polling, plus an 18-test xUnit suite (
TaskMonitor.Tests.Unit) that runs under any standard test runner for CI - Clean architecture (Domain → Application → Infrastructure → Desktop)
- Interface-driven design with dependency injection (
Microsoft.Extensions.DependencyInjection) - No static mutable state
SqlOperationvalue objects for testable SQL generationRecording*test doubles for all repositories
Proprietary. Built for Park View Drugs, Trinidad.