23

実行時に読み込まれたアセンブリでメソッドを実行する必要があります。メソッド呼び出しの後に、ロードされたアセンブリをアンロードしたいと思います。ライブラリをアンロードできるように、新しい 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) のスナップイン) が見つからない、または読み込まれないという例外が発生します。

  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 (スナップイン) にロードされたものです。このエラーを修正する方法はありますか? AppDomain.AssemblyResolve は呼び出されません (古いドメインでも新しいドメインでも)。

更新 2

私はAppDomainSetupで解決策を試しました。現在、例外は次のように変更されています。

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

何か案が?

4

3 に答える 3

15

これを試して:

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 { }
于 2010-01-25T14:35:15.670 に答える
1

この以前の回答を見てください: How to load an assembly into different AppDomain on Windows Mobile (.NET CF) ? . その答えは、新しい AppDomain コンテキストで実行されるプロキシ クラスを作成するため、初期化を完全に制御できます。

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

于 2010-01-25T13:59:22.827 に答える