Code Structure Analysis
Internal Working Document
Note: This is an internal analysis document for comprehensive documentation. Not published on the site.
Executive Summary
XB Homebrew Vault is a .NET 8 + Avalonia 12 MVVM desktop application with ~8-10k LOC across Services, ViewModels, and Views. The architecture is layered (Views → ViewModels → Services → Models) with a predominant “god class” pattern in XboxDeviceService.
Key findings:
- 1 critical god class (XboxDeviceService)
- 14 documented tech debts, potentially 16+ when verified against actual code
- 11
async voidevent handlers (higher than documented 4) - ~82-100
awaitcalls with no.ConfigureAwait(false)in Services - Manual service instantiation in App.axaml.cs (no DI container)
- Generally good error logging in Services, with 14 bare
catch { }blocks
Service Layer Analysis
XboxDeviceService.cs
Metrics:
- Lines of code: 1,207 (actual, vs ~1,038 estimated)
- Public methods/properties: 35
Domain Breakdown (35 methods):
- Connection management: 6
- Package management: 9
- Process management: 2
- Crash dumps: 4
- Network configuration: 4
- System operations (restart, shutdown): 3
- Screenshot: 1
- WebSocket (performance): 1
Responsibilities (Mixed domains):
- Package Management — install, uninstall, launch, list
- Process Management — list, kill, get running title
- Crash Dumps — list, delete, enable/disable crash control
- Network Configuration — get network config, WiFi interfaces/networks
- System Information — get system info, restart, shutdown, screenshot
- Performance Streaming — WebSocket connection for real-time metrics
- Authentication — CSRF token handling, HTTP Basic auth
- SFTP Credentials — SMB password fetch, SSH connection info
Architecture Issues:
- Mixes HTTP REST calls, WebSocket handling, JSON parsing, and logging
- No domain separation → makes testing, navigation, and refactoring difficult
- Tight coupling: ViewModels call all 35 methods directly
Error Handling:
- 2 bare
catch { }blocks (lines 422, 621-623) - ~50+ missing
.ConfigureAwait(false)on await calls - Generally good logging in catch blocks when exceptions are caught
Key Patterns:
// Certificate validation bypass (line 32-33)
ServerCertificateCustomValidationCallback = (_, _, _, _) => true,
// HTTP client recreation on reconfigure (lines 51-68)
// Rationale: BaseAddress freezes after first request in Avalonia/HttpClient
// CSRF token handling via cookie container
// Tokens are managed internally, attached to requests automatically
PackageInstallService.cs
Metrics:
- Well-structured, single responsibility
- Depends on: CacheService, XboxDeviceService
Key Patterns:
- Download + dependency analysis + install orchestration
- Regex-based dependency classification:
DepPattern: Identifies Microsoft, VCLibs, runtime packagesJunkPattern: Filters out certs, PS scripts, diagnosticsInstallerExts:.appx,.msix,.appxbundle,.msixbundle
- Cache-aware: Reuses downloads, validates before install
- Interesting detail: Dependency folder detection (
Dependencies/,deps/,dep/) with case-insensitive matching
SftpService.cs
Metrics:
- Well-implemented, implements
IDisposable✓ - Depends on: SSH.NET (Renci.SshNet)
Key Patterns:
// Connection wrapping in Task.Run for non-blocking UI
public async Task ConnectAsync(string host, int port, string user, string pass)
{
await Task.Run(() => {
// SSH.NET is synchronous, so wrap in Task.Run
_ssh = new SshClient(connInfo);
_ssh.Connect();
_sftp = new SftpClient(connInfo);
_sftp.Connect();
});
}
// Proper resource cleanup
public void Dispose() { /* handles both SSH and SFTP cleanup */ }
Timeouts & Keep-Alive:
- SFTP OperationTimeout: 15 seconds
- KeepAliveInterval: 30 seconds
- Prevents dropped connections during long operations
CatalogApiService.cs
Metrics:
- Single responsibility: fetch + parse catalog
- Cache: 6-hour TTL, persisted to disk
Key Patterns:
// JSON API endpoint (line 20)
const string JsonApiUrl = "https://emulationrevival.github.io/api/catalog.json";
// Cache location
%APPDATA%\XBVault\cache\catalog-api.json
// Fallback strategy: API fails → try stale cache
// Ensures offline functionality
Generated Regex:
[GeneratedRegex(@"microsoft\.|vclibs|\.net\.core|ui\.xaml|windowsappsdk|directx|webview2",
RegexOptions.IgnoreCase | RegexOptions.Compiled)]
Error Handling Issues
Bare catch { } Blocks Found
Total in Services: 14 instances
| File | Line | Context | Severity |
|---|---|---|---|
| XboxDeviceService.cs | 422 | TryParseError() JSON parse |
Medium |
| XboxDeviceService.cs | 1140 | WebSocket close teardown | Low (intentional cleanup) |
| CryptoService.cs | 41 | Decryption failure | Medium |
| AdminHelper.cs | 19 | Elevation check | Low |
| Logger.cs | 125-127 | Logger internal failures | High (error in error logger!) |
| PackageInstallService.cs | 1 | Likely in cleanup paths | TBD |
| SftpService.cs | 2 | SFTP disconnect cleanup | Low (intentional) |
async void Event Handlers - EXPANDED LIST
Total found: 11 instances (vs 4 documented)
| File | Line | Method | Impact |
|---|---|---|---|
| ConnectionWindow.axaml.cs | 37 | OnConnectionCompleted() |
High — connection result handling |
| ErrorDialog.axaml.cs | 60 | OnCopyClick() |
High — error clipboard copy |
| FileExplorerView.axaml.cs | 272 | OnTreeItemExpanded() |
High — file tree expansion |
| FileExplorerView.axaml.cs | 284 | OnBrowseFilesClick() |
High — file browsing |
| FileExplorerView.axaml.cs | 562 | OnDropZoneDrop() |
High — drag-drop file handling |
| LogsView.axaml.cs | 41 | OnCopyClick() |
Medium — logs clipboard copy |
| NetworkInfoWindow.axaml.cs | 15 | OnLoaded() |
High — window initialization |
| SftpInfoWindow.axaml.cs | 23 | OnCopyHostClick() |
Low — simple clipboard ops |
| SftpInfoWindow.axaml.cs | 35 | OnCopyPortClick() |
Low |
| SftpInfoWindow.axaml.cs | 47 | OnCopyUserClick() |
Low |
| SftpInfoWindow.axaml.cs | 59 | OnCopyPasswordClick() |
Low |
Risk: Unhandled exception in any of these crashes the entire process with no recovery.
ConfigureAwait Analysis
Services measured: ~82-100 await calls across Services layer
ConfigureAwait(false) usage: 0 instances found ❌
Impact:
- Each
awaitcaptures the UI synchronization context - In server/service layers, this is unnecessary and reduces throughput
- Potential for deadlocks if UI thread is blocked
Recommendation: Add .ConfigureAwait(false) to all await in:
- XboxDeviceService (~75-80 awaits)
- PackageInstallService (~5 awaits)
- CatalogApiService (~3 awaits)
- SftpService (~4 awaits)
- Other Services as needed
IDisposable Analysis
Missing IDisposable
XboxDeviceService.cs (lines 18-19):
private HttpClient _http;
private HttpClientHandler? _handler;
- Holds disposable resources but does not implement IDisposable
- Manual disposal on reconfigure (lines 61-67), but no cleanup on app exit
- Fragile: Relies on GC finalizer for cleanup
Properly Implemented
✅ SftpService.cs — implements IDisposable, properly disposes SSH and SFTP clients
❌ PerformanceViewModel.cs — holds CancellationTokenSource but does not implement IDisposable
_cts?.Cancel()called, but never_cts?.Dispose()- Resource leak: WaitHandle not released until GC finalizer
Hardcoded Magic Delays
Total instances found: 23 hardcoded Task.Delay() calls
| File | Lines | Values | Purpose |
|---|---|---|---|
| App.axaml.cs | 125 | 2000 | Splash screen duration |
| ConnectionWindow.axaml.cs | 41, 43 | 2000, 1500 | Connection feedback delay |
| RefreshWindow.axaml.cs | 51 | 1500 | Refresh completion delay |
| LogsView.axaml.cs | 58 | 2000 | Log display delay |
| BrowseViewModel.cs | 564 | 3000 | Browse result display |
| UsbPermissionViewModel.cs | 227 | 1000 | USB permission dialog delay |
| RefreshViewModel.cs | 69 | 200 | Refresh status update |
| SettingsViewModel.cs | 77 | 3000 | Settings save feedback |
| XboxDeviceService.cs | 572, 587 | 2000, 3000 | Package manager polling |
| ConnectionViewModel.cs | 105-172 | 300-600 | Animation timing (11 values) |
Recommendation: Extract as named constants in appropriate classes or a TimingConstants class.
Service Composition in App.axaml.cs
Metrics (from agent analysis):
- Total lines: 497
- InitAfterSplashAsync method: 384 lines (single massive method!)
- Services instantiated: 4 (XboxDeviceService, CacheService, PackageInstallService, SftpService)
- Windows/Dialogs wired: 22 dialogs registered dynamically
- Bare catch blocks: 2 (lines 107, 110)
Pattern:
// Manual composition (no DI container)
var xboxService = new XboxDeviceService();
var cacheService = new CacheService();
var installService = new PackageInstallService(cacheService, xboxService);
var sftpService = new SftpService();
// 22 dialog registrations:
dialogCoordinator.Register<ConnectionWindow>(
() => new ConnectionWindow(),
connectionVm => connectionWindow.DataContext = connectionVm);
// ... repeated 22 times
Complexity:
- 384-line
InitAfterSplashAsyncdoes: dialog registration, service initialization, event wiring, splash close - Becomes harder to test and maintain as new features added
ViewModel Patterns
Quick observations:
- Using CommunityToolkit.Mvvm source generators (ObservableProperty, RelayCommand)
- Generally good separation of concerns
Size Analysis (from agent):
- BrowseViewModel: 580 lines (TBD if same as “499 lines” — needs verification)
- 7 main responsibilities: catalog loading, filtering, search, item selection, install orchestration, image thumbnails, selection management
- ❌ Creates CatalogApiService inline (line 40) — not injected
- Issue: Approaching god-class threshold
CatalogApiService Injection Issue:
// In BrowseViewModel constructor
public BrowseViewModel(...)
{
_catalogService = new CatalogApiService(); // PROBLEM: inline creation
}
Consequences:
- Multiple CatalogApiService instances if multiple BrowseVMs created
- Cache not shared properly
- Violates dependency injection pattern
- Tech debt #12
Async/Await Patterns
Current approach in ViewModels:
- Fire-and-forget patterns via
async voidevent handlers - No exception catching → exceptions crash app
ConfigureAwait approach:
- Not used anywhere in codebase
- ViewModels should probably NOT use
.ConfigureAwait(false)(UI updates needed) - Services SHOULD use
.ConfigureAwait(false)(no UI dependency)
Next Steps
- Verify all findings against actual code
- Get method-by-method breakdown from code-analysis agent
- Create decision records for each integration pattern
- Document MVVM patterns in detail
- Create enhancement recommendations for each doc
Document version: 1.0
Last updated: 2026-06-25
Status: In progress (awaiting agent analysis)