无法在netcoreapp中加载具有特定于平台的dll的NuGet dll

时间:2017-09-05 20:07:12

标签: c# nuget .net-standard

我无法使用netcoreapp中提供的ICompilationAssemblyResolver从它的nuget包中加载System.Data.Client dll。大会解决的大部分是从here借来的,并且大部分都很有效。它看起来像这样:

internal sealed class AssemblyResolver : IDisposable
{
    private readonly ICompilationAssemblyResolver assemblyResolver;
    private readonly DependencyContext dependencyContext;
    private readonly AssemblyLoadContext loadContext;

    public AssemblyResolver(string path)
    {
        this.Assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
        this.dependencyContext = DependencyContext.Load(this.Assembly);

        this.assemblyResolver = new CompositeCompilationAssemblyResolver(new ICompilationAssemblyResolver[]
        {
            new AppBaseCompilationAssemblyResolver(Path.GetDirectoryName(path)),
            new ReferenceAssemblyPathResolver(),
            new PackageCompilationAssemblyResolver()
        });

        this.loadContext = AssemblyLoadContext.GetLoadContext(this.Assembly);
        this.loadContext.Resolving += OnResolving;
    }

    public Assembly Assembly { get; }

    public void Dispose()
    {
        this.loadContext.Resolving -= this.OnResolving;
    }

    private Assembly OnResolving(AssemblyLoadContext context, AssemblyName name)
    {
        bool NamesMatch(RuntimeLibrary runtime)
        {
            return string.Equals(runtime.Name, name.Name, StringComparison.OrdinalIgnoreCase);
        }

        RuntimeLibrary library =
        this.dependencyContext.RuntimeLibraries.FirstOrDefault(NamesMatch);
        if (library != null)
        {
            var wrapper = new CompilationLibrary(
                library.Type,
                library.Name,
                library.Version,
                library.Hash,
                library.RuntimeAssemblyGroups.SelectMany(g => g.AssetPaths),
                library.Dependencies,
                library.Serviceable);

            var assemblies = new List<string>();
            this.assemblyResolver.TryResolveAssemblyPaths(wrapper, assemblies);
            if (assemblies.Count > 0)
            {
                return this.loadContext.LoadFromAssemblyPath(assemblies[0]);
            }
        }

        return null;
    }
}

但是我无法加载引用System.Data.Client @ 4.3.1的dll,因为在运行时我收到错误消息:

Exception has occurred: CLR/System.IO.FileNotFoundException
An unhandled exception of type 'System.IO.FileNotFoundException' 
occurred in System.Private.CoreLib.ni.dll: 'Could not load file or 
assembly 'System.Data.SqlClient, Version=4.1.0.0, Culture=neutral, 
PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.'

我不确定为什么在我指定4.3.0时尝试加载4.1.0但我认为这有点像红鲱鱼。我怀疑PackageCompilationAssemblyResolver只在lib文件夹下查看,而且有问题的包没有netstandard。但它有一个特定的运行时:

Contents of System.Data.SqlClient

有了这些信息,我创建了一个令人难以置信的原始AssemblyLoader,它在nuget包的runtimes文件夹下查找,我能够加载dll并按照我的预期运行我的程序。

using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.DotNet.PlatformAbstractions;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.DependencyModel.Resolution;

namespace Loader
{
    public class CrudeCompilationAssemblyResolver : ICompilationAssemblyResolver
    {
        private readonly string[] _nugetPackageDirectories;

        public CrudeCompilationAssemblyResolver()
        {
            var basePath = Environment.GetEnvironmentVariable("HOME");
            var defaultPath = Path.Combine(basePath, ".nuget", "packages");
            _nugetPackageDirectories = new [] { defaultPath };
        }

        public bool TryResolveAssemblyPaths(CompilationLibrary library, List<string> assemblies)
        {
            if (_nugetPackageDirectories == null || _nugetPackageDirectories.Length == 0 || !string.Equals(library.Type, "package", StringComparison.OrdinalIgnoreCase))
            {
                return false;
            }

            foreach (var directory in _nugetPackageDirectories)
            {
                string packagePath;

                var fullPath = Path.Combine(directory, library.Name, library.Version, "runtimes", "unix", "lib", "netstandard1.3", $"{library.Name}.dll");
                if (File.Exists(fullPath))
                {
                    assemblies.AddRange(new[] { fullPath });
                    return true;
                }
            }

            return false;        
        }
    }
}

我的问题是:是否有更好的/官方认可的方式从nuget包加载这个麻烦的组件?或者我是否需要使原油装载机的原油少得多?

完整的回购在这里:CustomAssemblyResolver

0 个答案:

没有答案