Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 加载在运行时引用nuget依赖项的.NET标准程序集?_C#_.net_.net Core_.net Standard - Fatal编程技术网

C# 加载在运行时引用nuget依赖项的.NET标准程序集?

C# 加载在运行时引用nuget依赖项的.NET标准程序集?,c#,.net,.net-core,.net-standard,C#,.net,.net Core,.net Standard,我目前使用的是AssemblyLoadContext.Default.LoadFromAssemblyPath(path/to/netstandard1.6lib.dll),我想知道如何处理库中可能存在的任何nuget依赖项 例如: 库A动态加载库B。 库B依赖于NuGet的Redis 库B正确加载,但在使用redis客户端时——我们收到一个令人讨厌的FileNotFoundException,抱怨找不到redis程序集。该场景实际上是典型的模块加载程序类型 Assembly assembly

我目前使用的是
AssemblyLoadContext.Default.LoadFromAssemblyPath(path/to/netstandard1.6lib.dll)
,我想知道如何处理库中可能存在的任何nuget依赖项

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

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

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);
当Activator创建实例时,扩展的构造函数试图创建一个新的redis客户机——结果一切都失败了


关于如何在运行时处理nugget的三级依赖关系,您有什么想法吗?

DLL必须在那里才能加载它们,否则您不应该在运行时下载nugget软件包,因为这样会很慢,并且它可以在nugget源不可用或您没有internet连接的任何时候停止工作

因此,让您的项目依赖于nugget包,它将在构建之前下载


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

我最后需要做的是在我的项目的csproj文件中添加这个:
true

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

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);
    }
}
public void LoadExtensions()
{
IConfigurationSection[]扩展配置=_config.GetSections(扩展配置键).ToArray();
if(extensionConfigurations.Length==0)
返回;
HashSet extensions=新的HashSet();
foreach(扩展配置中的IConfigurationSection扩展配置)
{
字符串名称=extensionConfiguration.Key;
字符串路径=_config.Get($“{extensionConfiguration.path}:path”);
_Debug($“加载扩展:{name}”);
if(string.IsNullOrEmpty(path)| |!File.Exists(path))
抛出新的ConfigurationItemMissingException($“{extensionConfiguration.Path}:Path”);
LoadAssembly(路径、名称);
}
foreach(扩展类型中的变量扩展类型)
{
IExtension extension=Activator.CreateInstance(extensionType.Key.AsType(),extensionType.Value,_dependencyUtility)作为IExtension;
if(扩展==null)
抛出新的InvalidExtensionException(extensionType.Value、extensionType.Key.AssemblyQualifiedName);
扩展。添加(扩展);
}
扩展=扩展;
}
专用void加载程序集(字符串路径、字符串名称)
{
FileInfo[]dlls=newdirectoryinfo(Path.GetDirectoryName(Path)).GetFiles(“*.dll”);
foreach(dll中的FileInfo dll)
{
Assembly asm=AssemblyLoadContext.Default.LoadFromAssemblyPath(dll.FullName);
_Info($“正在加载程序集:{asm.FullName}”);
TypeInfo type=asm.DefinedTypes.FirstOrDefault(x=>x.ImplementedInterfaces.Contains(typeof(IExtension))&&&!x.isastract);
if(type==null)
继续;
_extensionTypes.Add(类型、名称);
}
}

您不应该手动解析程序集依赖项

只要确保在动态加载库B时,.net运行时可以访问所有依赖的dll-s。默认情况下,它将检查应用程序进程和GAC的工作目录。 如果您想自定义运行时的探测行为,可以使用配置文件中的
设置或从C#code中进行设置

我建议您阅读这些文档,它们将帮助您更详细地了解探测工作原理:

要解决依赖项解析问题,可以使用fuslog工具:


您可能会在此处找到一些信息,这似乎更多地是关于在当前(无论.NET核心/标准等效物是什么)AppDomain中加载nuget软件包,而不是加载具有更多依赖项的依赖项。嗯,nuget存储库是在构建库B时下载的。因此,DLL存在于系统上。但是,当库A动态加载库B时(它甚至识别出库B引用了
Assembly.getReferenceAssemblys()
)中的Redis),它找不到库B用来构建的DLL的位置。我不认为nuget是个问题。我认为AssemblyLoadContext.Default.LoadFromAssemblyPath不知道如何加载子依赖项。程序集具有与引用的程序集名称相对应的元数据,但没有路径。要加载此引用,您需要一个解析程序,它将解析程序集。由于依赖项dll与LibraryB dll不在同一路径中(未发布),因此需要获取依赖项的路径。由于尚未发布,我认为您需要加载LibraryB.runtimeconfig.dev.json文件和LibraryB.deps.json,并在那里获取路径。我想这就是探测的工作原理——但是在库A的工作目录中有库B的依赖项是不起作用的。我来看看fuslog,谢谢!