簡體   English   中英

加載在運行時引用nuget依賴項的.NET Standard程序集?

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

我目前正在使用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客戶端-一切都破滅了。

關於如何在運行時處理來自nuget的第三級依賴項的任何想法?

必須加載DLL才能加載它們,AFAIK您不應該在運行時下載塊包,因為它運行緩慢,並且在沒有任何塊源或很可能是在任何時候都可能停止工作沒有互聯網連接。

因此,使您的項目依賴於該塊軟件包,並且在構建之前將其下載。

如果您對這種方法不感興趣,那么我想您可以嘗試從程序中執行NuGet.exe並使其首先下載所需的DLL,但這會使您的程序在下載程序包文件時掛斷。

我最終需要做的就是將其添加到項目的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);
    }
}

您不應該手動解決程序集依賴性。

只要確保在動態加載庫B時,.net運行時就可以訪問所有依賴的dll。 默認情況下,它將檢查您的應用程序進程和GAC的工作目錄。 如果要自定義運行時的探測行為,可以使用配置文件中的<probing>設置或從C#代碼中進行設置。

我建議您閱讀這些文檔,它們應該可以幫助您更詳細地了解探測的工作原理:

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

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

要解決依賴關系解析,可以使用fuslog工具:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM