そもそもAssemblyLoadContextとは
プラグインを用意して後から機能を足したいという場合にアセンブリを動的に読み込ませたい場合があると思います。
.NET FrameworkではAppDomainを分けて別々にロードすることができましたが、.Net CoreではAssemblyLoadContextが別であれば別アセンブリとして認識されるようになっており、AssemblyLoadContextを分けることで本体アプリが参照しているライブラリと同じものを利用するがバージョンが違うといった場合に読み込めないエラーを回避できます。
背景
私のプロジェクトでも後からプラグインとして機能を差し込めるように動的に読み込む口を用意していたのですが、読み込ませるプラグイン同士で連携するような構想が出てきたためにAssemblyLoadContextが分かれているのに同じ参照をさせたい。困ったぞということがありました。
もう少し詳細な困りごとを説明すると、各プラグインで提供するサービスを実装する上で必要となる本体のサービスはDI登録されているため、DIより取得するような仕組みを構築していたのですが、各プラグイン同士で定義されたサービスも連携させるために各プラグイン同士も参照させて取得したいケースが発生しました。
結論から言えば、開発者側が仕込むプラグインのことをモジュールを呼んでいるのですが、モジュールを読み込む場合のAssemblyLoadContextは分けずにデフォルトのAssemblyLoadContextにすべて読み込ませて、外部利用者向けのプラグインはAssemblyLoadContextを分ける方式で動的読み込みの仕組みを2つに分けて実現する方針が良さそうでした。
外部利用者向けのプラグインの話は一旦先送りとして、今まで分けていたモジュールのAssemblyLoadContextを1つに統合した場合に発生した問題があります。
問題
AssemblyLoadContextをデフォルトの1つとしてすべてのモジュールを読み込み、アプリケーションを起動した際に以下のようなエラーが発生しました。
System.IO.FileNotFoundException: 'Could not load file or assembly "**読み込んだモジュール**".resources.dll'. 指定されたファイルが見つかりません。'
解決法
以下の記事の手法を試したところ解消しました。
Workaround is to specify en-US in a Directory.Build.props. I guess [assembly: NeutralResourcesLanguage("en-US")] would work as well.
csprojに"<NeutralLanguage>ja-JP</NeutralLanguage>"を指定することが必要でした。
なぜこれが原因であったのか、ちょっと調べましたがよくわからなかったので私の想像ですが、Assembly.LoadFrom(path) を使用して読み込む際にCurrentCultureは特に設定していなかったので何も設定されていないかen-USあたりが設定され、カルチャ情報を取得しにいく際にエラーが出ていた?上記の対応でカルチャ情報が揃うことになり、解消された?
解決はしましたが、原因についてはちょっと納得していないためまた今度調査してみようと思います。