diff --git a/Samples/Shared/SdkResolverNetCoreApp.cs b/Samples/Shared/SdkResolverNetCoreApp.cs index a7670e8..ce631c2 100644 --- a/Samples/Shared/SdkResolverNetCoreApp.cs +++ b/Samples/Shared/SdkResolverNetCoreApp.cs @@ -11,13 +11,14 @@ namespace Genetec.Dap.CodeSamples; using System.Linq; using System.Reflection; using System.Runtime.Loader; +using System.Text.Json; using Microsoft.Win32; using System.Collections.Concurrent; public static class SdkResolver { private static string s_probingPath; - private static AssemblyDependencyResolver s_dependencyResolver; + private static Dictionary s_packageAssemblyPaths; private static readonly ConcurrentDictionary> s_loaders = new(StringComparer.OrdinalIgnoreCase); public static void Initialize() @@ -27,12 +28,87 @@ public static void Initialize() if (string.IsNullOrEmpty(s_probingPath)) throw new InvalidOperationException("SDK probing path could not be found."); - var sdkDll = Path.Combine(s_probingPath, "Genetec.Sdk.dll"); - s_dependencyResolver = File.Exists(sdkDll) ? new AssemblyDependencyResolver(sdkDll) : null; + s_packageAssemblyPaths = BuildPackageAssemblyIndex(s_probingPath); AssemblyLoadContext.Default.Resolving += OnAssemblyResolve; } + private static Dictionary BuildPackageAssemblyIndex(string probingPath) + { + var index = new Dictionary(StringComparer.OrdinalIgnoreCase); + + var nugetCache = Environment.GetEnvironmentVariable("NUGET_PACKAGES"); + if (string.IsNullOrWhiteSpace(nugetCache)) + nugetCache = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".nuget", "packages"); + + bool hasNugetCache = Directory.Exists(nugetCache); + + foreach (var depsFile in Directory.EnumerateFiles(probingPath, "*.deps.json")) + { + try + { + using var stream = File.OpenRead(depsFile); + using var doc = JsonDocument.Parse(stream); + + if (!doc.RootElement.TryGetProperty("targets", out var targets)) + continue; + + foreach (var target in targets.EnumerateObject()) + { + foreach (var package in target.Value.EnumerateObject()) + { + if (!package.Value.TryGetProperty("runtime", out var runtime)) + continue; + + foreach (var runtimeEntry in runtime.EnumerateObject()) + { + var runtimeName = runtimeEntry.Name; + + if (Path.IsPathRooted(runtimeName)) + continue; + + var dllName = Path.GetFileNameWithoutExtension(Path.GetFileName(runtimeName)); + if (index.ContainsKey(dllName)) + continue; + + // Check if DLL is already in the SDK folder + var localPath = Path.Combine(probingPath, Path.GetFileName(runtimeName)); + if (File.Exists(localPath)) + { + index[dllName] = localPath; + continue; + } + + // Try to find in NuGet cache + if (hasNugetCache) + { + var packageParts = package.Name.Split('/'); + if (packageParts.Length == 2) + { + var packagePath = Path.Combine(nugetCache, packageParts[0].ToLowerInvariant(), packageParts[1], runtimeName); + if (File.Exists(packagePath)) + { + index[dllName] = packagePath; + } + } + } + } + } + } + } + catch (JsonException) + { + // Skip malformed deps.json files + } + catch (IOException) + { + // Skip files that cannot be read + } + } + + return index; + } + private static Assembly OnAssemblyResolve(AssemblyLoadContext context, AssemblyName assemblyName) { string key = assemblyName.FullName ?? assemblyName.Name; @@ -54,10 +130,21 @@ private static Assembly OnAssemblyResolve(AssemblyLoadContext context, AssemblyN private static Assembly LoadAssembly(AssemblyLoadContext context, AssemblyName assemblyName) { - // 1) Try AssemblyDependencyResolver - var path = s_dependencyResolver.ResolveAssemblyToPath(assemblyName); - if (!string.IsNullOrEmpty(path) && File.Exists(path)) - return context.LoadFromAssemblyPath(path); + if (s_packageAssemblyPaths == null) + return null; + + // 1) Try the package assembly index (built from all .deps.json files) + if (s_packageAssemblyPaths.TryGetValue(assemblyName.Name, out var resolvedPath) && File.Exists(resolvedPath)) + { + try + { + return context.LoadFromAssemblyPath(resolvedPath); + } + catch (BadImageFormatException) + { + // Fall through to next resolution strategy + } + } // 2) Try direct probing folder if (!string.IsNullOrEmpty(s_probingPath)) @@ -68,7 +155,7 @@ private static Assembly LoadAssembly(AssemblyLoadContext context, AssemblyName a { return context.LoadFromAssemblyPath(candidate); } - catch (Exception) + catch (BadImageFormatException) { // Ignore and try next candidate } @@ -134,4 +221,4 @@ private static string GetProbingPath() } } -#endif \ No newline at end of file +#endif