| File: DependencyContextLoader.cs | Web Access |
| Project: src\runtime\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; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; namespace Microsoft.Extensions.DependencyModel { public class DependencyContextLoader { private const string DepsJsonExtension = ".deps.json"; private readonly string? _entryPointDepsLocation; private readonly IEnumerable<string> _nonEntryPointDepsPaths; private readonly IFileSystem _fileSystem; private readonly Func<IDependencyContextReader> _jsonReaderFactory; public DependencyContextLoader() : this( DependencyContextPaths.Current.Application, DependencyContextPaths.Current.NonApplicationPaths, FileSystemWrapper.Default, () => new DependencyContextJsonReader()) { } internal DependencyContextLoader( string? entryPointDepsLocation, IEnumerable<string> nonEntryPointDepsPaths, IFileSystem fileSystem, Func<IDependencyContextReader> jsonReaderFactory) { _entryPointDepsLocation = entryPointDepsLocation; _nonEntryPointDepsPaths = nonEntryPointDepsPaths; _fileSystem = fileSystem; _jsonReaderFactory = jsonReaderFactory; } public static DependencyContextLoader Default { get; } = new(); private static bool IsEntryAssembly(Assembly assembly) { return assembly.Equals(Assembly.GetEntryAssembly()); } private static Stream? GetResourceStream(Assembly assembly, string name) { return assembly.GetManifestResourceStream(name); } [RequiresAssemblyFiles("DependencyContext for an assembly from a application published as single-file is not supported. The method will return null. Make sure the calling code can handle this case.")] public DependencyContext? Load(Assembly assembly) { ArgumentNullException.ThrowIfNull(assembly); DependencyContext? context = null; using (IDependencyContextReader reader = _jsonReaderFactory()) { if (IsEntryAssembly(assembly)) { context = LoadEntryAssemblyContext(reader); } context ??= LoadAssemblyContext(assembly, reader); if (context != null) { foreach (string extraPath in _nonEntryPointDepsPaths) { DependencyContext? extraContext = LoadContext(reader, extraPath); if (extraContext != null) { context = context.Merge(extraContext); } } } } return context; } private DependencyContext? LoadEntryAssemblyContext(IDependencyContextReader reader) { return LoadContext(reader, _entryPointDepsLocation); } private DependencyContext? LoadContext(IDependencyContextReader reader, string? location) { if (!string.IsNullOrEmpty(location)) { Debug.Assert(_fileSystem.File.Exists(location)); using (Stream stream = _fileSystem.File.OpenRead(location)) { return reader.Read(stream); } } return null; } [RequiresAssemblyFiles("DependencyContext for an assembly from a application published as single-file is not supported. The method will return null. Make sure the calling code can handle this case.")] private DependencyContext? LoadAssemblyContext(Assembly assembly, IDependencyContextReader reader) { using (Stream? stream = GetResourceStream(assembly, assembly.GetName().Name + DepsJsonExtension)) { if (stream != null) { return reader.Read(stream); } } string? depsJsonFile = GetDepsJsonPath(assembly); if (!string.IsNullOrEmpty(depsJsonFile)) { using (Stream stream = _fileSystem.File.OpenRead(depsJsonFile)) { return reader.Read(stream); } } return null; } [RequiresAssemblyFiles("The use of DependencyContextLoader is not supported when publishing as single-file")] private string? GetDepsJsonPath(Assembly assembly) { // Assemblies loaded in memory (e.g. single file) return empty string from Location. // In these cases, don't try probing next to the assembly. string assemblyLocation = assembly.Location; if (string.IsNullOrEmpty(assemblyLocation)) { return null; } string depsJsonFile = Path.ChangeExtension(assemblyLocation, DepsJsonExtension); bool depsJsonFileExists = _fileSystem.File.Exists(depsJsonFile); if (!depsJsonFileExists) { // in some cases (like .NET Framework shadow copy) the Assembly Location // and CodeBase will be different, so also try the CodeBase string? assemblyCodeBase = GetNormalizedCodeBasePath(assembly); if (!string.IsNullOrEmpty(assemblyCodeBase) && assemblyLocation != assemblyCodeBase) { depsJsonFile = Path.ChangeExtension(assemblyCodeBase, DepsJsonExtension); depsJsonFileExists = _fileSystem.File.Exists(depsJsonFile); } } return depsJsonFileExists ? depsJsonFile : null; } [RequiresAssemblyFiles] private static string? GetNormalizedCodeBasePath(Assembly assembly) { #pragma warning disable SYSLIB0012 // CodeBase is obsolete if (Uri.TryCreate(assembly.CodeBase, UriKind.Absolute, out Uri? codeBase) #pragma warning restore SYSLIB0012 // CodeBase is obsolete && codeBase.IsFile) { return codeBase.LocalPath; } else { return null; } } } }