简体   繁体   English

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

[英]Loading an .NET Standard assembly which references a nuget dependency at runtime?

I'm currently using AssemblyLoadContext.Default.LoadFromAssemblyPath(path/to/netstandard1.6lib.dll) and was curious about how to handle any nuget dependencies that library may have? 我目前正在使用AssemblyLoadContext.Default.LoadFromAssemblyPath(path/to/netstandard1.6lib.dll)并对如何处理库可能具有的任何nuget依赖项感到好奇?

For example: Library A dynamically loads Library B. Library B depends on Redis from NuGet. 例如:库A动态加载库B。库B依赖于NuGet中的Redis。

Library B loads correctly, but upon using the redis client -- we get a nasty FileNotFoundException complaining that the redis assembly cannot be found. 库B正确加载,但是在使用Redis客户端时-我们收到一个讨厌的FileNotFoundException,抱怨找不到redis程序集。 The scenario is really a typical module-loader type thing. 该场景确实是典型的模块加载器类型的事情。

Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
if (assembly == null)
    throw new InvalidExtensionException(name, path);

TypeInfo type = assembly.DefinedTypes.FirstOrDefault(x => x.ImplementedInterfaces.Contains(typeof(IExtension)));
if (type == null)
    throw new InvalidExtensionException(name, path);

IExtension extension = Activator.CreateInstance(type.AsType(), name, _dependencyUtility) as IExtension;
if (extension == null)
    throw new InvalidExtensionException(name, path);

extensions.Add(extension);

When Activator creates the instance, the extension's constructor attempts to make a new redis client -- and it all blows up. 当Activator创建实例时,扩展程序的构造函数尝试创建一个新的redis客户端-一切都破灭了。

Any thoughts on how to handle 3rd level dependencies from nuget at runtime? 关于如何在运行时处理来自nuget的第三级依赖项的任何想法?

DLLs must be there in order to load them, AFAIK you shouldn't download nugget packages on the run, because it will be slow, and it can stop working at any time that the nugget origin is not available or, more probably, that you don't have internet connection. 必须加载DLL才能加载它们,AFAIK您不应该在运行时下载块包,因为它运行缓慢,并且在没有任何块源或很可能是在任何时候都可能停止工作没有互联网连接。

So make your project depend on that nugget package, and it will be download before building. 因此,使您的项目依赖于该块软件包,并且在构建之前将其下载。

If you're not interested on this approach, then I suppose you could try to execute NuGet.exe from your program and make it download the required DLL first, but this will make your program to hang up while it's downloading the package files. 如果您对这种方法不感兴趣,那么我想您可以尝试从程序中执行NuGet.exe并使其首先下载所需的DLL,但这会使您的程序在下载程序包文件时挂断。

What I ended up needing to do is add this in my project's csproj file: <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> 我最终需要做的就是将其添加到项目的csproj文件中: <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

Then adjust my module loader code to iterate through all of the DLLs and load them as well all before attempting to calling the constructor from my assembly via activator. 然后调整我的模块加载器代码以遍历所有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);
    }
}

You should not manually resolve assembly dependencies. 您不应该手动解决程序集依赖性。

Just make sure that when you load your Library B dynamically all the dependent dll-s are reachable by the .net runtime. 只要确保在动态加载库B时,.net运行时就可以访问所有依赖的dll。 By default, it will check the Working Directory of your app process and GAC. 默认情况下,它将检查您的应用程序进程和GAC的工作目录。 If you want to customize runtime's probing behavior you can do it with <probing> setting in your config file or from within C# code. 如果要自定义运行时的探测行为,可以使用配置文件中的<probing>设置或从C#代码中进行设置。

I suggest you reading these docs, they should help you understand how probing works in greater details: 我建议您阅读这些文档,它们应该可以帮助您更详细地了解探测的工作原理:

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

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

To troubleshoot the dependency resolution you can use fuslog tool: 要解决依赖关系解析,可以使用fuslog工具:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 .NET标准Nuget参考 - .NET Standard Nuget References 引用较旧版本的nuget依赖项的C#库会导致程序集反射失败 - C# library which references older version of nuget dependency causes assembly reflection to fail ASP.NET:由Nuget引起的.NET Framework /标准/核DLL冲突。 “你必须添加对程序集System.Runtime的引用......” - ASP.NET: .NET Framework/Standard/Core DLL collisions, caused by Nuget. “You must add a reference to assembly System.Runtime…” 无法为 NET Standard 加载 NuGet 包的文件或程序集异常 NET 5/6 - could not load file or assembly exception NET 5/6 of NuGet package for NET Standard 使用 blazor 加载外部 .NET Standard 2.0 程序集 - Loading an external .NET Standard 2.0 assembly with blazor 依赖注入和程序集引用 - Dependency Injection and assembly references 通过 nuget 与手动参考在 .NET 标准中使用 .NET 框架程序集时的不同错误 - Different errors when using .NET framework assembly in .NET standard via nuget vs manual reference 混合使用.Net Standard 和.Net Framework 时,如何自动部署隐藏的NuGet 依赖项的C# DLL? - How to deploy C# DLL of hidden NuGet dependency automatically when mixing .Net Standard and .Net Framework? 根据.NET标准编译.NET Framework项目时,为什么缺少此NuGet依赖项? - Why is this NuGet dependency missing when compiling .NET Framework project depending on .NET Standard? 在运行时加载2个版本的程序集 - Loading 2 versions of assembly at runtime
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM