web-dev-qa-db-ja.com

異なるAppDomainでのアセンブリのロード/アンロード

実行時にロードされたアセンブリでメソッドを実行する必要があります。ここで、メソッド呼び出しの後に、ロードされたアセンブリをアンロードしたいと思います。ライブラリをアンロードできるように、新しいAppDomainが必要であることはわかっています。しかし、ここで問題が発生します。

ロードするアセンブリは、私のプラグインフレームワークのプラグインです。エントリポイントはまったくありません。私が知っているのは、特定のインターフェイスを実装するいくつかのタイプが含まれていることだけです。古い非AppDomainコードは次のようになります(少し短縮されています)。

try
{
    string path = Path.GetFullPath("C:\library.dll");
    AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    Assembly asm = Assembly.LoadFrom(path);
    Type[] types = asm.GetExportedTypes();
    foreach (Type t in types)
    {
        if ((t.GetInterface("IStarter") != null) && !t.IsAbstract)
        {
            object tempObj = Activator.CreateInstance(t);
            MethodInfo info = t.GetMethod("GetParameters");
            if (info != null)
            {
                return info.Invoke(tempObj, null) as string;
            }
        }
    }
}
catch (Exception ex)
{
    MessageBox.Show(String.Format("Damn '{0}'.", ex.Message), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    if (args.Name.StartsWith("MyProject.View,"))
    {
        string path = Path.GetFullPath("C:\view.dll"));
        return Assembly.LoadFrom(path);
    }
    return null;
}

今、私はそれらを独自のAppDomainにロードしたいと思います。

try
{
    string path = Path.GetFullPath("C:\library.dll");
    AppDomain domain = AppDomain.CreateDomain("TempDomain");
    domain.AssemblyResolve += CurrentDomain_AssemblyResolve;  // 1. Exception here!!
    domain.ExecuteAssembly(path);  // 2. Exception here!!
    domain.CreateInstanceFrom(...);  // 3. I have NO clue, how the type is named.
    domain.Load(...);  // 4. I have NO clue, how the Assembly is named.
    domain.DoCallBack(...); // 5. Exception here!!
    // ...
}
catch (Exception ex)
{
    MessageBox.Show(String.Format("Damn '{0}'.", ex.Message), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

ご覧のとおり、私は5つのケースに入れました。

  1. イベントハンドラーを設定すると、アセンブリ(管理コンソール(mmc.exe)SnapIn。が見つからない/読み込まれない)という例外が発生します。

  2. ExecuteAssemblyはエントリポイントを検出しません(まあ、何もありません)。

  3. 型がどのように命名されているのか私にはわかりません。インターフェイスでロードする方法は?

  4. 3.と同様です。アセンブリの名前を取得するにはどうすればよいですか?

  5. 1と同じエラー。

問題はどういうわけか管理コンソールであるか、私が間違っていることの手がかりがまったくないと思います。どんな助けでもありがたいです。

更新1

投稿されたプロキシソリューションを使用してみました。

AppDomain domain = AppDomain.CreateDomain("TempDomain");
InstanceProxy proxy = domain.CreateInstanceAndUnwrap(Assembly.GetAssembly(
    typeof(InstanceProxy)).FullName, typeof(InstanceProxy).ToString()) as InstanceProxy;
if (proxy != null)
{
    proxy.LoadAssembly(path);
}
AppDomain.Unload(domain);

public class InstanceProxy : MarshalByRefObject
{
    public void LoadAssembly(string path)
    {
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
        Assembly asm = Assembly.LoadFrom(path);
        Type[] types = asm.GetExportedTypes();
        // ...see above...
    }
}

これも機能しません。プロキシオブジェクトを作成しようとすると、例外が発生します。

ファイルまたはアセンブリ 'MyProject.SnapIn、Version = 1.0.0.0、Culture = neutral、PublicKeyToken = null'またはその依存関係の1つを読み込めませんでした。システムは、指定されたファイルを見つけることができません。

エラーメッセージ内のファイルは、mmc(SnapIn)にロードされたファイルです。このエラーを修正する方法はありますか? AppDomain.AssemblyResolveは呼び出されません(古いドメインでも新しいドメインでも)。

更新2

AppDomainSetupを使用してソリューションを試しました。現在、例外は次のように変更されています。

ファイルまたはアセンブリ 'file:/// C:/Development/MyProject/bin/SnapIn/MyProject.SnapIn.DLL'またはその依存関係の1つを読み込めませんでした。指定されたアセンブリ名またはコードベースが無効でした。 (HRESULTからの例外:0x80131047)

何か案が?

22
Scoregraphic

これを試して:

namespace SeperateAppDomainTest
{
    class Program
    {
        static void Main(string[] args)
        {
            LoadAssembly();
        }

        public static void LoadAssembly()
        {
            string pathToDll = Assembly.GetExecutingAssembly().CodeBase;
            AppDomainSetup domainSetup = new AppDomainSetup { PrivateBinPath = pathToDll };
            var newDomain = AppDomain.CreateDomain("FooBar", null, domainSetup);
            ProxyClass c = (ProxyClass)(newDomain.CreateInstanceFromAndUnwrap(pathToDll, typeof(ProxyClass).FullName));
            Console.WriteLine(c == null);

            Console.ReadKey(true);
        }
    }

    public class ProxyClass : MarshalByRefObject { }
14
BFree

この前の答えを見てください: Windows Mobile(.NET CF)上の別のAppDomainにアセンブリをロードする方法? 。その答えは、新しいAppDomainコンテキストで実行されるプロキシクラスを作成するため、初期化を完全に制御できます。

Start()メソッドをServiceApplicationProxyクラスに作成し、proxy.Start()を使用してホストから通常どおり呼び出すことができます。

1
Rubens Farias

https://msdn.Microsoft.com/en-us/library/3c4f1xde%28v=vs.110%29.aspx

それを指定します

typeNameタイプ:System.String

_The fully qualified name of the requested type, including the namespace but not the Assembly, as returned by the Type.FullName
_

プロパティ。

したがって、typeof(InstanceProxy).ToString()を使用する代わりに、完全修飾名で呼び出してみてください_"<<Namespace>>.InstanceProxy"_

以下のように

_InstanceProxy proxy = domain.CreateInstanceAndUnwrap(path, "<<Namespace>>.InstanceProxy") as InstanceProxy;
_
0
Khavasi