< Summary

Information
Class: DotNetApiDiff.AssemblyLoading.IsolatedAssemblyLoadContext
Assembly: DotNetApiDiff
File(s): /home/runner/work/dotnet-api-diff/dotnet-api-diff/src/DotNetApiDiff/AssemblyLoading/IsolatedAssemblyLoadContext.cs
Line coverage
62%
Covered lines: 42
Uncovered lines: 25
Coverable lines: 67
Total lines: 143
Line coverage: 62.6%
Branch coverage
63%
Covered branches: 24
Total branches: 38
Branch coverage: 63.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)50%22100%
.ctor(...)100%11100%
get_AdditionalSearchPaths()100%11100%
AddSearchPath(...)100%88100%
Load(...)64.28%331454.16%
LoadUnmanagedDll(...)42.85%531441.66%

File(s)

/home/runner/work/dotnet-api-diff/dotnet-api-diff/src/DotNetApiDiff/AssemblyLoading/IsolatedAssemblyLoadContext.cs

#LineLine coverage
 1// Copyright DotNet API Diff Project Contributors - SPDX Identifier: MIT
 2using System.Reflection;
 3using System.Runtime.Loader;
 4using Microsoft.Extensions.Logging;
 5
 6namespace DotNetApiDiff.AssemblyLoading;
 7
 8/// <summary>
 9/// Custom assembly load context that provides isolation for loaded assemblies
 10/// </summary>
 11public class IsolatedAssemblyLoadContext : AssemblyLoadContext
 12{
 13    private readonly string _assemblyDirectory;
 14    private readonly AssemblyDependencyResolver _resolver;
 15    private readonly string _mainAssemblyPath;
 16    private readonly ILogger? _logger;
 17
 18    /// <summary>
 19    /// Creates a new isolated assembly load context
 20    /// </summary>
 21    /// <param name="assemblyPath">Path to the main assembly</param>
 22    public IsolatedAssemblyLoadContext(string assemblyPath)
 3723        : base(isCollectible: true)
 3724    {
 3725        _mainAssemblyPath = assemblyPath;
 3726        _assemblyDirectory = Path.GetDirectoryName(assemblyPath) ?? string.Empty;
 3727        _resolver = new AssemblyDependencyResolver(assemblyPath);
 3728        _logger = null;
 3729    }
 30
 31    /// <summary>
 32    /// Creates a new isolated assembly load context
 33    /// </summary>
 34    /// <param name="assemblyPath">Path to the main assembly</param>
 35    /// <param name="logger">Logger for diagnostic information</param>
 36    public IsolatedAssemblyLoadContext(string assemblyPath, ILogger logger)
 2737        : this(assemblyPath)
 2738    {
 2739        _logger = logger;
 2740    }
 41
 42    /// <summary>
 43    /// Additional search paths for assemblies
 44    /// </summary>
 35845    public List<string> AdditionalSearchPaths { get; } = new List<string>();
 46
 47    /// <summary>
 48    /// Adds an additional search path for assemblies
 49    /// </summary>
 50    /// <param name="path">Path to search for assemblies</param>
 51    public void AddSearchPath(string path)
 16552    {
 16553        if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !AdditionalSearchPaths.Contains(path))
 15654        {
 15655            AdditionalSearchPaths.Add(path);
 15656            _logger?.LogDebug("Added search path: {Path}", path);
 15657        }
 16558    }
 59
 60    /// <summary>
 61    /// Loads an assembly with the given name
 62    /// </summary>
 63    /// <param name="assemblyName">The assembly name to load</param>
 64    /// <returns>The loaded assembly or null if not found</returns>
 65    protected override System.Reflection.Assembly? Load(AssemblyName assemblyName)
 866    {
 67        try
 868        {
 869            _logger?.LogDebug("Attempting to resolve assembly: {AssemblyName}", assemblyName.FullName);
 70
 71            // First, try to resolve using the dependency resolver
 872            string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
 873            if (assemblyPath != null)
 374            {
 375                _logger?.LogDebug("Resolved assembly {AssemblyName} to path: {Path}", assemblyName.FullName, assemblyPat
 376                return LoadFromAssemblyPath(assemblyPath);
 77            }
 78
 79            // Next, try to find the assembly in the same directory
 580            string potentialPath = Path.Combine(_assemblyDirectory, $"{assemblyName.Name}.dll");
 581            if (File.Exists(potentialPath))
 082            {
 083                _logger?.LogDebug("Found assembly {AssemblyName} in directory: {Path}", assemblyName.FullName, potential
 084                return LoadFromAssemblyPath(potentialPath);
 85            }
 86
 87            // If we can't resolve it, return null to let the runtime handle it
 588            _logger?.LogDebug("Could not resolve assembly: {AssemblyName}", assemblyName.FullName);
 589            return null;
 90        }
 091        catch (Exception ex)
 092        {
 093            _logger?.LogWarning(
 094                ex,
 095                "Error resolving assembly {AssemblyName} for {MainAssembly}",
 096                assemblyName.FullName,
 097                _mainAssemblyPath);
 098            throw;
 99        }
 8100    }
 101
 102    /// <summary>
 103    /// Loads a native library with the given name
 104    /// </summary>
 105    /// <param name="libName">The library name to load</param>
 106    /// <returns>The loaded library handle or IntPtr.Zero if not found</returns>
 107    protected override IntPtr LoadUnmanagedDll(string libName)
 3108    {
 109        try
 3110        {
 3111            _logger?.LogDebug("Attempting to resolve native library: {LibName}", libName);
 112
 113            // First, try to resolve using the dependency resolver
 3114            string? libraryPath = _resolver.ResolveUnmanagedDllToPath(libName);
 3115            if (libraryPath != null)
 0116            {
 0117                _logger?.LogDebug("Resolved native library {LibName} to path: {Path}", libName, libraryPath);
 0118                return LoadUnmanagedDllFromPath(libraryPath);
 119            }
 120
 121            // Next, try to find the library in the same directory
 3122            string potentialPath = Path.Combine(_assemblyDirectory, libName);
 3123            if (File.Exists(potentialPath))
 0124            {
 0125                _logger?.LogDebug("Found native library {LibName} in directory: {Path}", libName, potentialPath);
 0126                return LoadUnmanagedDllFromPath(potentialPath);
 127            }
 128
 129            // If we can't resolve it, return IntPtr.Zero to let the runtime handle it
 3130            _logger?.LogDebug("Could not resolve native library: {LibName}", libName);
 3131            return IntPtr.Zero;
 132        }
 0133        catch (Exception ex)
 0134        {
 0135            _logger?.LogWarning(
 0136                ex,
 0137                "Error resolving native library {LibName} for {MainAssembly}",
 0138                libName,
 0139                _mainAssemblyPath);
 0140            throw;
 141        }
 3142    }
 143}