#nullable enable using System; using System.Collections.Generic; using System.Reflection; using T3.Core.Logging; namespace T3.Core.Diagnostics; /// /// Registers a hook on that logs the missing /// assembly name and its requester before the CLR throws . /// The handler returns null — it does not attempt to recover, only to enrich the /// log trail. Captured by Sentry breadcrumbs, so the next crash report carries the context. /// Fires only on resolution failure; zero cost on the happy path. /// public static class AssemblyLoadDiagnostics { private static bool _installed; private static readonly object _gate = new(); private static readonly HashSet _alreadyLogged = new(StringComparer.OrdinalIgnoreCase); /// Idempotent. Call as early as possible in Main. public static void Install() { lock (_gate) { if (_installed) return; AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve; _installed = true; } } private static Assembly? OnAssemblyResolve(object? sender, ResolveEventArgs args) { var assemblyName = args.Name ?? ""; // Satellite resource assemblies (Culture=en-US etc.) aren't always deployed; // the runtime falls back to the neutral culture transparently. Not an error. try { var parsedName = new AssemblyName(assemblyName); if (!string.IsNullOrEmpty(parsedName.CultureName)) return null; // Pre-generated XmlSerializer assemblies (e.g. 'Lib.XmlSerializers') are an // opt-in build artifact we don't produce; the runtime emits the serializer at // runtime instead. The probe always fails here — expected, not a broken install. if (parsedName.Name?.EndsWith(".XmlSerializers", StringComparison.OrdinalIgnoreCase) == true) return null; } catch { /* malformed name — fall through to log */ } var requester = args.RequestingAssembly?.GetName().Name ?? ""; // Log each missing assembly once per session. lock (_gate) { if (!_alreadyLogged.Add(assemblyName)) return null; } Log.Warning( $"AssemblyResolve failed: '{assemblyName}' (requested by '{requester}'). " + "This usually indicates a missing or corrupt TiXL install file — " + "antivirus quarantine, partial install, or manual deletion are the common causes. " + "Reinstalling TiXL is recommended."); return null; } }