0

私が開発しているプラ​​グイン (PLUGIN と呼びましょう) は、それが作成されたメイン ソフトウェア (PARENT と呼びましょう) から 2 つのアセンブリ ファイルを使用しています。PARENT が新しいバージョンに更新されるとすぐに (そして、週に数回発生します)、再コンパイルを強制することなく、PLUGIN が依存関係の新しいバージョンを動的にロードするようにします。

PARENT はプラグインをソース コード ファイルとしてロードし、ジャスト イン タイムでコンパイルします。コードを DLL に入れたいので、Loader.cs ファイルはリフレクションを介して DLL から関数を呼び出します。

以下は、Loader.cs のコードです。

// error handling removed for better readability

public Loader()
{   
    assembly = Assembly.LoadFile(dllPath);
    type = assembly.GetType("PLUGIN.PLUGINStarter");
    instance = Activator.CreateInstance(type);
}

public override void Dispose()
{
    type.InvokeMember("Dispose", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, instance, null);
    base.Dispose();
}

public override void OnButtonPress()
{   
    type.InvokeMember("ShowForm", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, instance, null);
}

PLUGIN 名前空間の PLUGINStarter クラスは次のようになります。

class PLUGINStarter
{
    private PLUGIN plugin = null;

    /// <summary>
    /// This is loading PARENT.exe and PARENTSomeOtherFile.dll dependencies.
    /// </summary>
    public PLUGINStarter()
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, eventArgs) =>
        {
            var fullAssemblyName = new AssemblyName(eventArgs.Name);              

            // this is not executed when PARENT version changes
            MessageBox.Show(fullAssemblyName.Name, "Loading assembly...");

            if (fullAssemblyName.Name.Equals("PARENT"))
            {
                // AppDomain.CurrentDomain.FriendlyName will handle the case where PARENT.exe is re-named
                var found = Assembly.LoadFile(Path.Combine(Environment.CurrentDirectory, AppDomain.CurrentDomain.FriendlyName));
                return found;
            }
            else if (fullAssemblyName.Name.Equals("PARENTSomeOtherFile"))
            {
                var found = Assembly.LoadFile(Path.Combine(Environment.CurrentDirectory, "PARENTSomeOtherFile.dll"));
                return found;
            }
            else
            {
                return null;
            }
        };

        Initialize();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private void Initialize() 
    {
        // the PARENT's assemblies are referenced in the PLUGIN class
        plugin = new PLUGIN();
    }

    public void ShowForm()
    {
        plugin.ShowForm();
    }

    public void Dispose()
    {
        plugin.Dispose();
    }
}

PARENT が新しいバージョンに更新されると、イベントは発生しません。なんで?

編集#1

明確にするために:PARENTは、PARENTからのアセンブリ(および主にPARENT.exe自体)に依存するPLUGIN.dllをロードするLoader.csをロードします(ジャストインタイムでコンパイルします)。

編集#2

PARENT ソフトウェアは手動で更新されます。ユーザーは、インターネット (製品の Web サイト) からダウンロードします。次に、ユーザーは PLUGIN.dll を PARENT の「Plugins」ディレクトリにコピーします。

次に、Loader.cs で次の例外をキャッチできます。

[07:55:19.822 D] [PLUGIN] Loading DLL 'C:\PNT\PARENTNew\Plugins\PLUGIN\PLUGIN.dll'.
[07:55:19.826 D] [PLUGIN] Exception loading assembly 'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileLoadException: Could not load file or assembly 'PARENT, Version=6.2.8113.191, Culture=neutral, PublicKeyToken=21a554ab5c01ae50' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
   at PLUGIN.PLUGINStarter..ctor()
   --- End of inner exception stack trace ---
   at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
   at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
   at System.Activator.CreateInstance(Type type, Boolean nonPublic)
   at System.Activator.CreateInstance(Type type)
   at PLUGINLoader.Loader..ctor() in c:\PNT\PARENTNew\Plugins\PLUGIN\Loader.cs:line 42'.

編集#3

Is it possible to replace a reference to a strong named assembly with a "weak" reference? で説明されているように、これは可能だと思いますか? しかし、何らかの奇妙な理由で、私のアプリケーションでは失敗します。

編集#4

PLUGINStarter を削除し、アセンブリ解決コードを Loader.cs のコンストラクターに移動することで問題を解決しました。アセンブリのバージョンが間違っていても、すべてがうまく解決するようになりました。

4

2 に答える 2