Vollständige Implementierung des EngineeringSync-Middleware-Tools: - Windows Service (Kestrel :5050) mit FileSystemWatcher + SignalR - WPF Tray-App mit PendingChanges- und Projektverwaltungs-Fenster - Setup-Wizard (8-Schritte-Installer) - SQLite/EF Core Datenschicht (WAL-Modus) - SHA-256-basiertes Debouncing (2s Fenster) - Backup-System mit konfigurierbarer Aufbewahrung Bugfixes & Verbesserungen: - BUG-1: AppDbContext OnConfiguring invertierte Bedingung behoben - BUG-2: Event-Handler-Leak in TrayApp (Fenster-Singleton-Pattern) - BUG-3: ProjectConfigChanged SignalR-Signal in allen CRUD-Endpoints - BUG-5: Rename-Sync löscht alte Datei im Simulations-Ordner - BUG-6: Doppeltes Dispose von SignalR verhindert - BUG-7: Registry-Deinstallation nur EngineeringSync-Eintrag entfernt - S1: Path-Traversal-Schutz via SafeCombine() im SyncManager - E1: FSW Buffer 64KB + automatischer Re-Scan bei Overflow - E2: Retry-Logik (3x) für gesperrte Dateien mit exponentiellem Backoff - E4: Channel.Writer.TryComplete() beim Shutdown - C2: HubMethodNames-Konstanten statt Magic Strings - E3: Pagination in Changes-API (page/pageSize Query-Parameter) - A1: Fire-and-Forget mit try/catch + Logging Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
9.0 KiB
Project Context: Engineering-to-Simulation Sync Tool ("EngineeringSync")
You are an expert C# / .NET 10 developer. Build a middleware tool that bridges mechanical engineering (CAD) and simulation (Process Simulate).
Problem: Engineers save files to a shared folder. Immediate overwrites in the simulation folder cause data corruption for the simulator. This tool watches the engineering folder, records changes, and notifies the simulation engineer via a WPF System Tray App. The simulation engineer reviews changes, selects what to sync, and triggers a controlled copy.
Tech Stack
- Framework: .NET 10
- Service: Worker Service (Windows Service) + ASP.NET Core Minimal API + SignalR
- Client: WPF (.NET 10-Windows) with
H.NotifyIcon.Wpf - Database: SQLite via EF Core 10 (WAL mode for concurrency)
- File Watching:
System.IO.FileSystemWatcher+System.Threading.Channels(debouncing) - UI Pattern: MVVM with
CommunityToolkit.Mvvm
Phase 1: Solution Initialization
Create solution structure via .NET CLI:
EngineeringSync.sln
├── EngineeringSync.Domain (Class Library, net10.0) – Entities, Enums, Interfaces
├── EngineeringSync.Infrastructure (Class Library, net10.0) – EF Core, AppDbContext, Migrations
├── EngineeringSync.Service (Worker Service, net10.0) – Kestrel :5050, SignalR, Watcher
└── EngineeringSync.TrayApp (WPF App, net10.0-windows) – System tray + all UI windows
Dependency direction (strict one-way):
Infrastructure→DomainService→Domain+InfrastructureTrayApp→Domain(for shared DTOs/Enums only)
NuGet Packages:
| Project | Packages |
|---|---|
| Domain | (none – pure POCOs) |
| Infrastructure | Microsoft.EntityFrameworkCore.Sqlite, Microsoft.EntityFrameworkCore.Design |
| Service | Microsoft.Extensions.Hosting.WindowsServices, Microsoft.AspNetCore.SignalR |
| TrayApp | H.NotifyIcon.Wpf, Microsoft.AspNetCore.SignalR.Client, CommunityToolkit.Mvvm |
Phase 2: Domain & Database Modeling
Domain Entities (EngineeringSync.Domain)
ProjectConfig – A watched project (persisted in DB, managed via UI):
Id(Guid, PK)Name(string) – Display name, e.g. "Hauptprojekt Karosserie"EngineeringPath(string) – Source folder the watcher monitorsSimulationPath(string) – Target folder for controlled syncFileExtensions(string) – Comma-separated, e.g. ".jt,.cojt,.xml"IsActive(bool) – Enable/disable watching without deletingCreatedAt(DateTime)
FileRevision – Tracks known file state for change detection:
Id(Guid, PK)ProjectId(Guid, FK → ProjectConfig)RelativePath(string)FileHash(string) – SHA-256Size(long)LastModified(DateTime)
PendingChange – A detected change awaiting user action:
Id(Guid, PK)ProjectId(Guid, FK → ProjectConfig)RelativePath(string)ChangeType(Enum: Created, Modified, Renamed, Deleted)OldRelativePath(string?) – Only for RenamedStatus(Enum: Pending, Synced, Ignored)CreatedAt(DateTime)SyncedAt(DateTime?)
Infrastructure (EngineeringSync.Infrastructure)
AppDbContextwithDbSet<ProjectConfig>,DbSet<FileRevision>,DbSet<PendingChange>- SQLite connection string with
Mode=ReadWriteCreateand WAL pragma - Auto-migration at service startup via
context.Database.Migrate() - Unique index on
(ProjectId, RelativePath)forFileRevision
Phase 3: The Windows Service (Core Logic)
3.1 Project Management API (CRUD)
New endpoints for managing projects from the TrayApp UI:
GET /api/projects– List all ProjectConfigPOST /api/projects– Create new ProjectConfig (validates paths exist)PUT /api/projects/{id}– Update ProjectConfig (restarts watcher for that project)DELETE /api/projects/{id}– Delete ProjectConfig + associated changes
When a ProjectConfig is created or updated with IsActive = true, the WatcherService must dynamically start/stop the corresponding FileSystemWatcher.
3.2 FileSystemWatcher & Debouncing (WatcherService)
BackgroundServicethat manages oneFileSystemWatcherper activeProjectConfig- Listen to:
Created,Changed,Renamed,Deleted - Filter by
ProjectConfig.FileExtensions - Debouncing pipeline:
- Push raw
FileSystemEventArgsinto aChannel<FileEvent>(unbounded) - Consumer reads from channel, groups events by
(ProjectId, RelativePath)within a 2000ms sliding window - After window closes, compute SHA-256 hash of file
- Compare hash against latest
FileRevisionfor that path - If hash differs (or file is new): write
FileRevision+PendingChangeto DB - Broadcast via SignalR
- Push raw
- Renamed: Record old + new path, update
FileRevision.RelativePath - Deleted: Record as
ChangeType.Deleted, removeFileRevision
3.3 Minimal API & SignalR Hub
Host Kestrel on http://localhost:5050:
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/projects |
List all projects |
| POST | /api/projects |
Create project |
| PUT | /api/projects/{id} |
Update project |
| DELETE | /api/projects/{id} |
Delete project |
| GET | /api/changes/{projectId} |
Pending changes for project |
| GET | /api/changes/{projectId}/history |
Synced/ignored changes (last 100) |
| POST | /api/sync |
Sync selected PendingChange IDs |
| POST | /api/ignore |
Ignore selected PendingChange IDs |
SignalR Hub (NotificationHub at /notifications):
ReceiveChangeNotification(projectId, projectName, count)– Fired when new PendingChanges are persistedProjectConfigChanged()– Fired when a project is created/updated/deleted
3.4 Sync Logic (SyncManager)
When POST /api/sync is called with a list of PendingChange IDs:
- Load PendingChange + ProjectConfig from DB
- Verify source file exists at
EngineeringPath / RelativePath - If target already exists in
SimulationPath:- Rename to
{filename}_{timestamp:yyyyMMdd_HHmmss}.bak(timestamped to prevent overwriting previous backups)
- Rename to
- Copy source → target (create subdirectories as needed)
- Mark PendingChange as
Status = Synced, setSyncedAt - For
ChangeType.Deleted: Delete target file (after backup), mark Synced - Return result summary (success count, errors)
Phase 4: The WPF Tray App
4.1 System Tray Setup
H.NotifyIcon.Wpf: headless startup (no main window)- Tray icon context menu:
- "Änderungen anzeigen" → Opens PendingChangesWindow
- "Projekte verwalten" → Opens ProjectManagementWindow
- "Beenden" → Graceful shutdown
4.2 SignalR Client
- Connect to
http://localhost:5050/notificationson startup - Auto-reconnect with exponential backoff
- On
ReceiveChangeNotification: Show balloon tip "Neue Engineering-Daten für Projekt [Name] verfügbar. Klicken zum Überprüfen." - On
ProjectConfigChanged: Refresh project list in any open window
4.3 Project Management Window (NEW)
A WPF Window (MVVM) for managing watched projects:
- ListView showing all ProjectConfig entries (Name, EngineeringPath, SimulationPath, Active-Status)
- "Neues Projekt" button → Opens inline form or dialog:
- Name (TextBox)
- Engineering-Pfad (TextBox + FolderBrowserDialog via Button)
- Simulations-Pfad (TextBox + FolderBrowserDialog via Button)
- Dateiendungen (TextBox, comma-separated, default: ".jt,.cojt,.xml")
- Aktiv (CheckBox)
- "Bearbeiten" / "Löschen" buttons per row
- All CRUD calls go to
POST/PUT/DELETE /api/projects - Path validation: Check that folders exist before saving
4.4 Pending Changes Window
- MVVM with
DataGrid - Project selector (ComboBox) at top → fetches from
GET /api/projects - Columns: Datei, Änderungstyp, Zeitstempel, Auswahl (CheckBox)
- "Ausgewählte synchronisieren" →
POST /api/sync - "Ausgewählte ignorieren" →
POST /api/ignore - "Alle synchronisieren" / "Alle ignorieren" convenience buttons
- Auto-refresh when SignalR notification arrives for the selected project
Phase 5: Build Order & Execution
Build step-by-step, verify each phase compiles before proceeding:
- Phase 1 – Solution scaffolding via
dotnetCLI. Verifydotnet buildsucceeds. - Phase 2 – Domain entities + EF Core DbContext + initial migration. Verify migration applies.
- Phase 3.1 – Project CRUD API endpoints. Test with manual HTTP requests.
- Phase 3.2 – WatcherService with Channel debouncing. Test with file drops.
- Phase 3.3 – SignalR hub + remaining API endpoints.
- Phase 3.4 – SyncManager copy logic.
- Phase 4.1+4.2 – TrayApp shell with SignalR client.
- Phase 4.3 – Project Management Window (path configuration UI).
- Phase 4.4 – Pending Changes Window.
Use CommunityToolkit.Mvvm for [ObservableProperty], [RelayCommand] source generators in all ViewModels.
Ensure all code compiles under .NET 10. Use clean architecture and dependency injection throughout.