加载在运行时引用nuget依赖项的.NET Standard程序集?

时间:2017-08-24 17:54:27

标签: c# .net .net-core .net-standard

我目前正在使用1,并对如何处理库可能具有的任何nuget依赖项感到好奇?

例如: 库A动态加载库B. 图书馆B依赖于NuGet的Redis。

库B正确加载,但在使用redis客户端时 - 我们得到一个令人讨厌的FileNotFoundException抱怨无法找到redis程序集。该场景实际上是典型的模块加载器类型。

AssemblyLoadContext.Default.LoadFromAssemblyPath(path/to/netstandard1.6lib.dll)

当Activator创建实例时,扩展程序的构造函数会尝试创建一个新的redis客户端 - 而这一切都会爆炸。

关于如何在运行时从nuget处理第三级依赖关系的任何想法?

3 个答案:

答案 0 :(得分:1)

DLL必须在那里加载它们,AFAIK你不应该在运行时下载nugget包,因为它会很慢,并且它可以在块金来源不可用的任何时候停止工作,或者更可能,你没有互联网连接。

因此,让您的项目依赖于该块包,并在构建之前下载它。

如果你对这种方法不感兴趣,那么我想你可以尝试从你的程序中执行NuGet.exe并让它首先下载所需的DLL,但这会让你的程序在下载程序包时挂断文件。

答案 1 :(得分:0)

我最终需要做的是在项目的csproj文件中添加:<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

然后调整我的模块加载器代码以迭代所有DLL并加载它们,然后尝试通过激活器从我的程序集中调用构造函数。

public void LoadExtensions()
{
    IConfigurationSection[] extensionConfigurations = _config.GetSections(EXTENSION_CONFIGURATION_KEY).ToArray();
    if (extensionConfigurations.Length == 0)
        return;

    HashSet<IExtension> extensions = new HashSet<IExtension>();
    foreach (IConfigurationSection extensionConfiguration in extensionConfigurations)
    {
        string name = extensionConfiguration.Key;
        string path = _config.Get($"{extensionConfiguration.Path}:path");

        _logger.Debug($"Loading extension: {name}");

        if (string.IsNullOrEmpty(path) || !File.Exists(path))
            throw new ConfigurationItemMissingException($"{extensionConfiguration.Path}:path");

        LoadAssembly(path, name);
    }

    foreach (var extensionType in _extensionTypes)
    {
        IExtension extension = Activator.CreateInstance(extensionType.Key.AsType(), extensionType.Value, _dependencyUtility) as IExtension;
        if (extension == null)
            throw new InvalidExtensionException(extensionType.Value, extensionType.Key.AssemblyQualifiedName);

        extensions.Add(extension);
    }

    Extensions = extensions;
}

private void LoadAssembly(string path, string name)
{
    FileInfo[] dlls = new DirectoryInfo(Path.GetDirectoryName(path)).GetFiles("*.dll");

    foreach (FileInfo dll in dlls)
    {
        Assembly asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(dll.FullName);

        _logger.Info($"Loading assembly: {asm.FullName}");

        TypeInfo type = asm.DefinedTypes.FirstOrDefault(x => x.ImplementedInterfaces.Contains(typeof(IExtension)) && !x.IsAbstract);

        if (type == null)
            continue;

        _extensionTypes.Add(type, name);
    }
}

答案 2 :(得分:-1)

您不应手动解决程序集依赖关系。

只需确保在动态加载 Library B 时,.net运行时即可访问所有相关的dll-s。默认情况下,它会检查您的应用进程和GAC的工作目录。 如果要自定义运行时的探测行为,可以使用配置文件中的<probing>设置或C#代码中的设置来执行此操作。

我建议你阅读这些文档,它们应该帮助你理解探究如何更详细地运作:

https://docs.microsoft.com/en-us/dotnet/framework/deployment/how-the-runtime-locates-assemblies

https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/specify-assembly-location

要对依赖项解决方案进行问题排查,您可以使用 fuslog 工具:

https://docs.microsoft.com/en-us/dotnet/framework/tools/fuslogvw-exe-assembly-binding-log-viewer