src/WebJobs.Script/Description/DotNet/PackageAssemblyResolver.cs (101 lines of code) (raw):

// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using Microsoft.Azure.WebJobs.Host; using Newtonsoft.Json.Linq; using NuGet.Frameworks; using NuGet.ProjectModel; namespace Microsoft.Azure.WebJobs.Script.Description { /// <summary> /// Resolves assemblies referenced by NuGet packages used by the function. /// </summary> public sealed class PackageAssemblyResolver { private const string EmptyFolderFileMarker = "_._"; private readonly ImmutableArray<PackageReference> _packages; public PackageAssemblyResolver(string workingDirectory) { _packages = InitializeAssemblyRegistry(workingDirectory); } public ImmutableArray<PackageReference> Packages { get { return _packages; } } public IEnumerable<string> AssemblyReferences { get { return _packages.Aggregate(new List<string>(), (assemblies, p) => { assemblies.AddRange(p.CompileTimeAssemblies.Values); assemblies.AddRange(p.FrameworkAssemblies.Values); return assemblies; }).Distinct(); } } private static ImmutableArray<PackageReference> InitializeAssemblyRegistry(string functionDirectory) { var builder = ImmutableArray<PackageReference>.Empty.ToBuilder(); string fileName = Path.Combine(functionDirectory, DotNetConstants.ProjectLockFileName); if (File.Exists(fileName)) { LockFile lockFile = null; try { var reader = new LockFileFormat(); lockFile = reader.Read(fileName); var target = lockFile.Targets .FirstOrDefault(t => string.Equals(t.TargetFramework.DotNetFrameworkName, FrameworkConstants.CommonFrameworks.NetStandard20.DotNetFrameworkName)); if (target != null) { string nugetCachePath = PackageManager.GetNugetPackagesPath(); // Get all the referenced libraries for the target, excluding the framework references we add by default var libraries = target.Libraries.Where(s => !DotNetConstants.FrameworkReferences.Contains(s.Name)); foreach (var library in libraries) { var package = new PackageReference(library.Name, library.Version.ToFullString()); var assemblies = GetAssembliesList(library.CompileTimeAssemblies, nugetCachePath, package); package.CompileTimeAssemblies.AddRange(assemblies); assemblies = GetAssembliesList(library.RuntimeAssemblies, nugetCachePath, package); package.RuntimeAssemblies.AddRange(assemblies); var frameworkAssemblies = library.FrameworkAssemblies.ToDictionary(a => new AssemblyName(a)); package.FrameworkAssemblies.AddRange(frameworkAssemblies); builder.Add(package); } } } catch (FileFormatException) { return ImmutableArray<PackageReference>.Empty; } } return builder.ToImmutableArray(); } private static IReadOnlyDictionary<AssemblyName, string> GetAssembliesList(IList<LockFileItem> compileTimeAssemblies, string nugetCachePath, PackageReference package) { string packagePath = Path.Combine(nugetCachePath, package.Name, package.Version.ToString()); return compileTimeAssemblies.Select(i => Path.Combine(packagePath, i.Path)) .Where(p => !p.EndsWith(EmptyFolderFileMarker) && File.Exists(p)) .ToDictionary(p => AssemblyName.GetAssemblyName(p), p => new Uri(p).LocalPath); } public bool TryResolveAssembly(string name, out string path) { path = null; var assemblyName = new AssemblyName(name); foreach (var package in _packages) { if (package.RuntimeAssemblies.TryGetValue(assemblyName, out path) || package.FrameworkAssemblies.TryGetValue(assemblyName, out path)) { break; } } return path != null; } } }