2017-08-24 9 views
0

私は現在AssemblyLoadContext.Default.LoadFromAssemblyPath(path/to/netstandard1.6lib.dll)を使用していますが、ライブラリにはどのようなナゲット依存性を処理するのか不思議でしたか?実行時にNuget依存関係を参照する.NET Standardアセンブリをロードしていますか?

例: ライブラリAは、ライブラリBを動的にロードします。 ライブラリBは、NuGetのRedisに依存します。

ライブラリBは正しくロードされますが、redisクライアントを使用すると、Redisアセンブリが見つからないという厄介なFileNotFoundExceptionが発生します。このシナリオは実際には典型的なモジュールローダータイプのものです。

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クライアントを作成しようとします。そのすべてが爆発します。

実行時にナゲットから第3レベルの依存関係を処理する方法について考えていますか?

+0

あなたはいくつかの情報をここに見つけるかもしれません。https://stackoverflow.com/questions/31859267/load-nuget-dependencies-at-runtime – Rex

+0

これは現在の(どのような。NETのコア/標準の同等の)AppDomainより依存関係を持つ依存関係をロードするのではなく、 –

答えて

1

ロードするにはDLLが必要ですが、AFAIKでは実行時にナゲットパッケージをダウンロードしないようにしてください。遅くなり、ナゲットの起点が利用できない場合はいつでも動作を停止する可能性がありますインターネットに接続していない可能性があります。

あなたのプロジェクトはそのナゲットパッケージに依存しているので、ビルド前にダウンロードされます。

あなたがこのアプローチに興味がないなら、プログラムからNuGet.exeを実行し、必要なDLLを最初にダウンロードさせることができますが、プログラムをダウンロードしている間にプログラムをハングアップさせることができますパッケージファイル。

+0

ライブラリBが構築されると、ナゲットリポジトリがダウンロードされます。したがって、DLLはシステム上に存在します。しかし、ライブラリAがライブラリBを動的にロードすると(ライブラリBが 'Assembly.GetReferencedAssemblies()'でRedisを参照することさえ認識する)、ライブラリBがビルドに使用したDLLの場所を見つけることができません。 ナゲットが問題だとは思わない。 AssemblyLoadContext.Default.LoadFromAssemblyPathはサブ依存関係をロードする方法を知らないと思います。 –

+1

アセンブリには、参照のアセンブリ名に対応するメタデータがありますが、パスはありません。この参照をロードするには、アセンブリを解決するリゾルバが必要です。依存関係dllはLibraryB dllと同じパスにはないので(それは公開されていません)、依存関係へのパスを取得する必要があります。公開されていないので、私はあなたがLibraryB.runtimeconfig.dev.jsonファイルとLibraryB.deps.jsonをロードし、そこにパスを取得する必要があると思います。 –

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); 
    } 
} 
0

アセンブリの依存関係を手動で解決しないでください。

ライブラリライブラリBをロードするときに、依存するすべてのdll-sに.netランタイムがアクセスできることを確認してください。デフォルトでは、あなたのアプリケーションプロセスとGACのワーキングディレクトリをチェックします。 ランタイムのプロービング動作をカスタマイズする場合は、設定ファイルまたはC#コード内で<probing>設定を使用して実行できます。あなたはfuslogツールを使用することができ、依存関係の解決をトラブルシューティングするには

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

私はあなたがこれらのドキュメントを読んで示唆、彼らはあなたがより詳細にどのようにプロービング作品を理解するのに役立つ必要があります。

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

+0

Hmm。これはプロービングの仕組みだと思っていましたが、ライブラリAの作業ディレクトリにライブラリBの依存関係があっても機能しませんでした。私はfuslogを見ていきます、ありがとう! –

関連する問題