エクステンションロード機構
概要
エクステンション単位で異なるバージョンのライブラリを利用可能
Next Design では、エクステンション単位で異なる領域にライブラリをロードします。 これにより、エクステンションごとに同一ライブラリの異なるバージョンを利用できます。
狙い
- エクステンションでは、複数のエクステンションで異なるバージョンの同じライブラリを利用できます。
エクステンションAでは System.Text.Json
のバージョン 4.7.1
を利用し、別のエクステンションBでは System.Text.Json
の新しいバージョン 5.0.2
を利用できます。この場合、それぞれ、エクステンションAはバージョン 4.7.1
のAPIを、エクステンションBはバージョン 5.0.2
のAPIを利用します。
- エクステンションでは、Next Design 本体が参照するライブラリより新しいバージョンのライブラリを利用できます。
エクステンションでは、Next Design 本体が参照する Microsoft.WindowsAPICodePack
より新しいバージョンのライブラリを利用できます。
エクステンションで参照するライブラリのバージョンが Next Design 本体に同梱のライブラリのバージョン以下の場合、エクステンション側の該当ライブラリをロードすることはせず、Next Design 本体側でロード済みのライブラリが利用されます。
これは、以下の理由によるものです。
- ライブラリロード領域のために確保するメモリサイズを抑制する
- Next Design 本体側の動作を保証する
- Next Design 本体とエクステンション間のデータ交換によるインタフェース不整合を抑制する
エクステンションの依存ライブラリの解決方法
Next Design では、エクステンションの依存ライブラリの配置場所を解決する際に、アセンブリメタデータの記述ファイル(*.deps.jsonファイル)を利用します。
また、依存するライブラリがネイティブライブラリの場合であっても正しく認識できます。
狙い
- アセンブリメタデータの記述により、依存ライブラリの配置構成をエクステンション側でカスタマイズできます。
- 依存ライブラリを NuGet パッケージ管理機能を用いて解決している場合、アセンブリメタデータの記述ファイル(*.deps.jsonファイル)はビルド時に自動生成されます。
- そのため、エクステンションでは、依存ライブラリを NuGet パッケージ管理機能を用いて解決することを推奨します。
- ネイティブライブラリに依存するエクステンションを配布できます。
- アセンブリメタデータの記述ファイル(*.deps.jsonファイル)を利用することでネイティブライブラリに依存するエクステンションを配置できます。
- また、OS や CPU の違いにより"依存するネイティブライブラリが異なる"場合においても、エクステンションの実行時に解決するため、例えば、
win-x64
向けとwin-x86
向けのネイティブライブラリを1つのエクステンションに同梱できます。
複数のエクステンションから参照されるライブラリにおける静的変数の扱い
Next Design では、エクステンション単位で異なる領域にライブラリをロードします。これに伴い、静的変数は次のように扱われます。
- エクステンションごとに異なるメモリ管理となるため、複数のエクステンション間で静的変数(クラス変数など)が共有されません。
- そのためエクステンション間での情報の共有に静的変数を利用できません。
例えば、あるエクステンションで以下のようなクラス変数を定義しても、別のエクステンションからは_SomeDictionaryの値を参照できません。
public class SomeClass
{
private static IDictionary<string, object> _SomeDictionary = new Dictionary<string, object>();
}
共有ライブラリについて
共有ライブラリの概要
Next Design では、Next Design 本体が参照するライブラリより新しいバージョンのライブラリをエクステンションで利用できるようにするため、エクステンション単位で異なる領域にライブ ラリをロードします。 しかしながら、ライブラリによっては異なる領域にロードされることによって動作に影響を及ぼす可能性があります。 共有ライブラリはそのようなライブラリを同一領域にロードして動作への影響を回避するための仕組みです。
- エクステンションが参照するライブラリを共有ライブラリに指定すると他エクステンションと共有されます。 これにより、他エクステンションで管理されているオブジェクトを受け渡しできます。
- エクステンションごとに異なるバージョンのライブラリが共有ライブラリに指定された場合、最も新しいバージョンのライブラリがロードされて共有されます。 これにより、機能改善やバグフィクスが自動的に適用されます。
Next Design に同梱されるライブラリより新しいバージョンをエクステンションで利用したい場合は、そのライブラリを共有ライブラリに指定しないでください。
共有ライブラリのロード
Next Designは、有効なすべてのエクステンション1のマニフェストをライフサイクルに関係なく走査して、共有ライブラリとして指定されているライブラリを決定します。この時、それぞれのエクステンションに同じライブラリの異なるバージョンが共有ライブラリとして指定されている場合は、それらのライブラリのうちで最も新しいファイルバージョンのライブラリがロード対象となります。
この仕組みにより、古いバージョンのライブラリが配置されているエクステンションであっても、他のエクステンションフォルダに配置された最新のライブラリを利用することになります。
また、カルチャ(リソース)については、Next Design 本体のカルチャに対してリソースライブラリをロードします2。この際、共有ライブラリとしてロード対象となったライブラリと同じフォルダのja
、en
などのサブフォルダを探索します。
- エクステンションの共有ライブラリは、エクステンションの実行フォルダ以下のフォルダから探索します。
ただし、次の条件に該当するフォルダ(およびそのサブフォルダ)は探索対象から除外します。- フォルダ名が"."から始まるフォルダ
- フォルダ内に実行ファイル(*.exe)が含まれるフォルダ
共有ライブラリの制約事項
- ネイティブライブラリを共有ライブラリに指定することはできません。共有ライブラリには、ネイティブライブラリが含まれないように構成してください。
- Next Design本体が参照するライブラリは共有ライブラリに指定できません。Next Design本体が参照するライブラリを共有ライブラリに指定しないようにマニフェストを定義してください。
共有ライブラリの注意事項
同じライブラリを共有ライブラリに指定しているエクステンションと、共有ライブラリに指定していないエクステンションが混在する場合、どのエクステンションでも共有ライブラリが使用されます。
この機構は、古いバージョンのライブラリが配置されたエクステンションに対しても、バグフィックスや最新機能が利用できます。
一方で、該当ライブラリで下位互換性が保証されていない場合には、エクステンションで実行時エラーが発生することがあります。
エクステンションで参照するライブラリを共有ライブラリに指定しなかった場合は非共有ライブラリとしてロードされます。ライブラリを共有ライブラリに指定した場合はそのライブラリに加えて、そのライブラリが参照するライブラリもすべて共有ライブラリとしてロードされます。
そして、非共有ライブラリと共有ライブラリが同じライブラリを参照する場合は、同じライブラリが別々のメモリ管理下に二重にロードされた状態になります。
この状態では、同じライブラリで定義されている同じ型であっても、他方のメモリ管理下では見つからないといった実行時エラーが発生する可能性があります。
WPF を利用しているエクステンションをはじめ、このようなライブラリを参照するエクステンションでは、該当するライブラリをすべて共有ライブラリに指定してください。
エクステンション開発・保守時の注意点
エクステンションが参照するライブラリが非共有ライブラリの場合、エクステンション実行時に参照するライブラリのバージョンは、次のルールに従って決定されます。
エクステンション同梱(A) | Next Design 本 体同梱(B) | ライブラリバージョンの新旧 | 参照するバージョン |
---|---|---|---|
同梱している | - | - | (A) |
- | 同梱している | - | (B) |
同梱している | 同梱している | (A)の方が(B)より新しい | (A) |
同梱している | 同梱している | (A)と(B)が同じ、または、 (B)の方が(A)より新しい | (B) |
エクステンション間の共有ライブラリの場合、各エクステンションに同梱されているライブラリの中で最も新しいバージョンが参照されます。
また、Next Design 本体に同梱されているライブラリを共有ライブラリに指定することはできません。
上記ルールを理解の上、エクステンションの開発と保守では次の点にご注意ください。
開発では、対象とする Next Design のバージョンや共有ライブラリを参照する他エクステンションと組み合わせたうえで、エクステンションが正しく動作することを確認してください。
保守では、次の変化に合わせてエクステンション実行時に参照するライブラリのバージョンを確認し、そのバージョンと組み合わせてエクステンションが正しく動作することを確認してください。
- Next Design 本体がバージョンアップされて本体に同梱されているライブラリやそのバージョンが変更された
- 他エクステンションで共有ライブラリの指定が変更された
- 他エクステンションで共有ライブラリに指定されていたライブラリのバージョンが変更された
エクステンション配布手順と注意事項
エクステンション配布時は、下記内容に従って配布すべきファイルを構成してください。
エクステンションフォルダ構成
Next Design では、エクステンションの配布用フォルダに、マニフェストファイル、エクステンション本体ライブラリ、依存ライブラリに加えて、アセンブリメタデータの記述ファイル(*.deps.jsonファイル)を配置します。
{エクステンションフォルダ}/
manifest.json
{エクステンション本体ライブラリ名}.dll
{エクステンション本体ライブラリ名}.deps.json
{エクステンション依存ライブラリ名}.dll
・・・
アセンブリメタデータの記述ファイル
dotnet build でエクステンションをビルドすると、ビルド結果の出力フォルダに自動的に作成されます。詳しくは以下を参照してください。
- エクステンションの配布時には、生成された
*.deps.jsonファイル
をエクステンションフォルダに配置してください。 - 配置されていない場合は、エクステンションが依存するライブラリのロードに失敗する場合があります。
依存ライブラリの収集
dotnet publish でエクステンションの依存ライブラリを出力フォルダに収集できます。詳しくは以下を参照してください。
- dotnet publish は、すべての依存ライブラリが収集されます。
- エクステンションが、Next Design 本体も参照するライブラリを利用する場合、そのライブラリが本体より新しいバージョンでなければ、エクステンション配布時のパッケージから取り除いてパッケージサイズを縮小できます。
国際化対応リソースDLLの配置
DLL方式のエクステンションでは、C# 標準のローカライズが利用できます。
- エクステンション(およびその依存ライブラリ)が文字列リソースを用いた国際化対応を行っている場合、出力フォルダに言語単位のリソース情報を含むライブラリ(*.resources.dll)が生成されます。
- エクステンションの配布時には、それらライブラリをフォルダ構成と共にエクステンションフォルダに配置してください。
{エクステンションフォルダ}/
en/
{エクステンション本体ライブラリ名}.resources.dll
fr/
{エクステンション本体ライブラリ名}.resources.dll
manifest.json
{エクステンション本体ライブラリ名}.dll
{エクステンション本体ライブラリ名}.deps.json
{エクステンション依存ライブラリ名}.dll
・・・
ネイティブライブラリの配置
Next Design では、エクステンションにネイティブライブラリを利用できます。
- エクステンション(およびその依存ライ ブラリ)がネイティブライブラリに依存する場合、出力フォルダにランタイム環境ごとのネイティブライブラリが出力されます。
- エクステンションの配布時には、それらライブラリをフォルダ構成と共にエクステンションフォルダに配置してください。
{エクステンションフォルダ}/
runtimes/
win-x64/
{ネイティブライブラリ名}.dll
win-x86/
{ネイティブライブラリ名}.dll
manifest.json
{エクステンション本体ライブラリ名}.dll
{エクステンション本体ライブラリ名}.deps.json
{エクステンション依存ライブラリ名}.dll
・・・
制限事項
Next Design 本体が参照するライブラリとの競合
Next Design 本体が参照するライブラリより古いバージョンのライブラリはロードされません。本体が参照する新しいバージョンのライブラリが利用されます。 そのため、エクステンションが、Next Design の exe と同じフォルダにあるライブラリと同じで古いバージョンのライブラリを利用するとき、それらのライブラリ間で下位互換性が保証されていない場合はエクステンションの活性化に失敗、または実行時にエラーとなります。
- 例えば、古い
Next Design.Core
でビルドされたエクステンションで、新しいNext Design.Core
では廃止されたインタフェースを参照していた場合、新しい Next Design では、該当インタフェースを解決できないためエラーとなります。
ネイティブライブラリを参照するエクステンションの制約
.NET の制限により、ネイティブライブラリの配置場所を解決できない場合があります。
- NativeLibrary.Load() によってネイティブライブラリのロードが要求された場合、エクステンションロード機構では解決できま せん。
- そのため、ネイティブライブラリを上記のメソッドでロードしている場合は該当のライブラリがNativeLibrary.Load()でロードできる場所に配置されている必要があります。
現時点で判明している上記制限に該当するネイティブライブラリ
- EFCoreで利用されているSQLiteのネイティブライブラリ(e_sqlite3.dll)が該当します。
- Next Design では上記制限を緩和するため、EFCore 3.1系のネイティブライブラリを同梱しています。
- そのため、EFCore 3.1系以外のバージョンに依存するエクステンションの動作は保証されません。
一時的なアセンブリファイル生成に対する制約
実行時に一時的なアセンブリファイルの生成を必要とする機能をエクステンションで利用した場合、エクステンションロード機構がそれらのアセンブリファイルの格納先を特定できないため、エクステンションが正常に動作しない場合があります。 利用する機能についての開発元からの情報に従って、一時的なアセンブリファイルの生成を回避するような実装方法を選択してください。