File: Resolution\ReferenceAssemblyPathResolver.cs
Web Access
Project: src\src\libraries\Microsoft.Extensions.DependencyModel\src\Microsoft.Extensions.DependencyModel.csproj (Microsoft.Extensions.DependencyModel)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
 
namespace Microsoft.Extensions.DependencyModel.Resolution
{
    public class ReferenceAssemblyPathResolver : ICompilationAssemblyResolver
    {
        private readonly IFileSystem _fileSystem;
        private readonly string? _defaultReferenceAssembliesPath;
        private readonly string[] _fallbackSearchPaths;
 
        public ReferenceAssemblyPathResolver()
            : this(FileSystemWrapper.Default, EnvironmentWrapper.Default)
        {
        }
 
        public ReferenceAssemblyPathResolver(string? defaultReferenceAssembliesPath, string[] fallbackSearchPaths)
            : this(FileSystemWrapper.Default, defaultReferenceAssembliesPath, fallbackSearchPaths)
        {
        }
 
        internal ReferenceAssemblyPathResolver(IFileSystem fileSystem, IEnvironment environment)
            : this(fileSystem,
                GetDefaultReferenceAssembliesPath(fileSystem, environment),
                GetFallbackSearchPaths(fileSystem, environment))
        {
        }
 
        internal ReferenceAssemblyPathResolver(IFileSystem fileSystem, string? defaultReferenceAssembliesPath, string[] fallbackSearchPaths)
        {
            ThrowHelper.ThrowIfNull(fileSystem);
            ThrowHelper.ThrowIfNull(fallbackSearchPaths);
 
            _fileSystem = fileSystem;
            _defaultReferenceAssembliesPath = defaultReferenceAssembliesPath;
            _fallbackSearchPaths = fallbackSearchPaths;
        }
 
        public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string>? assemblies)
        {
            ThrowHelper.ThrowIfNull(library);
 
            if (!string.Equals(library.Type, "referenceassembly", StringComparison.OrdinalIgnoreCase))
            {
                return false;
            }
            foreach (string assembly in library.Assemblies)
            {
                if (!TryResolveReferenceAssembly(assembly, out string? fullName))
                {
                    throw new InvalidOperationException(SR.Format(SR.ReferenceAssemblyNotFound, assembly, library.Name));
                }
                assemblies?.Add(fullName);
            }
            return true;
        }
 
        private bool TryResolveReferenceAssembly(string path, [MaybeNullWhen(false)] out string fullPath)
        {
            fullPath = null;
 
            if (_defaultReferenceAssembliesPath != null)
            {
                string relativeToReferenceAssemblies = Path.Combine(_defaultReferenceAssembliesPath, path);
                if (_fileSystem.File.Exists(relativeToReferenceAssemblies))
                {
                    fullPath = relativeToReferenceAssemblies;
                    return true;
                }
            }
 
            string name = Path.GetFileName(path);
 
            foreach (string fallbackPath in _fallbackSearchPaths)
            {
                string fallbackFile = Path.Combine(fallbackPath, name);
                if (_fileSystem.File.Exists(fallbackFile))
                {
                    fullPath = fallbackFile;
                    return true;
                }
            }
 
            return false;
        }
 
        internal static string[] GetFallbackSearchPaths(IFileSystem fileSystem, IEnvironment environment)
        {
            if (!environment.IsWindows())
            {
                return Array.Empty<string>();
            }
 
            string? windir = environment.GetEnvironmentVariable("WINDIR");
            if (windir == null)
            {
                return Array.Empty<string>();
            }
 
            string net20Dir = Path.Combine(windir, "Microsoft.NET", "Framework", "v2.0.50727");
            if (!fileSystem.Directory.Exists(net20Dir))
            {
                return Array.Empty<string>();
            }
 
            return new[] { net20Dir };
        }
 
        internal static string? GetDefaultReferenceAssembliesPath(IFileSystem fileSystem, IEnvironment environment)
        {
            // Allow setting the reference assemblies path via an environment variable
            string? referenceAssembliesPath = DotNetReferenceAssembliesPathResolver.Resolve(environment, fileSystem);
            if (!string.IsNullOrEmpty(referenceAssembliesPath))
            {
                return referenceAssembliesPath;
            }
 
            if (!environment.IsWindows())
            {
                // There is no reference assemblies path outside of windows
                // The environment variable can be used to specify one
                return null;
            }
 
            // References assemblies are in %ProgramFiles(x86)% on
            // 64 bit machines
            string? programFiles = environment.GetEnvironmentVariable("ProgramFiles(x86)");
 
            if (string.IsNullOrEmpty(programFiles))
            {
                // On 32 bit machines they are in %ProgramFiles%
                programFiles = environment.GetEnvironmentVariable("ProgramFiles");
            }
 
            if (string.IsNullOrEmpty(programFiles))
            {
                // Reference assemblies aren't installed
                return null;
            }
 
            return Path.Combine(
                programFiles,
                "Reference Assemblies", "Microsoft", "Framework");
        }
    }
}