0

サービスがバックグラウンドで継続的に実行され、実行時にプラグイン DLL を追加/削除できるソリューションを開発しています。このサービスは、必要に応じて必要なプラグインをロードし、実行してアンロードします。これはアンロード部分であり、現在私に問題を引き起こしています: 特定のクラスが初めて正常にロードされると (変数 tc)、DLL ファイルが更新されても再ロードされません。クラス/アセンブリ/アプリケーションドメインを適切にアンロードしていないと思うので、この最後のマイルを歩くためのアドバイスをいただければ幸いです。

編集:コードの最近の変更を反映するように投稿を更新し、アンロードが正確に影響を与えない場合を説明します: Linux Ubuntu (Mono 経由) では問題は発生しませんが、Windows 2008 Server では問題が発生します。特定のプラグイン DLL を新しいファイル バージョンに置き換えます。.NET フレームワークがアセンブリをどこかにキャッシュしているようで、再ロードせずに満足しています。DLL ファイル名は変更されませんが、File Version プロパティは異なるため、ランタイムが以前に読み込まれた DLL バージョンと読み込まれているバージョンを比較し、バージョン番号が異なる場合は新しいバージョンを使用することを期待します。別の名前の DLL ファイルからアセンブリをロードするようにコードを少し変更すると、期待どおりに再ロードが行われます。

using System;
using System.Reflection;

namespace TestMonoConsole
{
    public interface ITestClass
    {
        void Talk();
    }
    class MainClass
    {
        public static void Main (string[] args)
        {
            string pluginPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

            string classAssembly = "TestClass";
            string className = "TestMonoConsole.TestClass";
            string command = "";
            do
            {
                try
                {
                    System.AppDomain domain = System.AppDomain.CreateDomain(classAssembly);
                    string pluginAssemblyFile = pluginPath + "/" + classAssembly + ".dll";
                    System.IO.StreamReader reader = new System.IO.StreamReader(pluginAssemblyFile, System.Text.Encoding.GetEncoding(1252), false);
                    byte[] b = new byte[reader.BaseStream.Length];
                    reader.BaseStream.Read(b, 0, System.Convert.ToInt32(reader.BaseStream.Length));
                    domain.Load(b);
                    reader.Close();
                    ITestClass tc = (ITestClass) Activator.CreateInstance(domain, classAssembly, className).Unwrap();
                    tc.Talk();
                    System.AppDomain.Unload(domain);
                }
                catch (System.IO.FileNotFoundException e)
                {
                    Console.WriteLine (String.Format("Error loading plugin: assembly {0} not found", classAssembly));
                }
                command = Console.ReadLine();
            } while (command == "");
        }
    }
}
4

5 に答える 5

2

タイプをホスト ドメインに直接作成しています。http://msdn.microsoft.com/en-us/library/ms224132(v=vs.90).aspxごとに Activator.CreateInstance を使用する場合は、ドメインを指定する必要があります。

于 2012-07-05T19:23:52.723 に答える
0

独自のAppDomain内でプラグインタイプをインスタンス化しています。プラグインフレームワークを数回実装した後、MEF(マネージドエクステンシビリティフレームワーク)をソリューションとして使用することを強くお勧めします。これは、コード分離のこれらの一般的な問題を処理するためです。MEFが必要ない場合、これを行う1つの方法は、アプリドメイン間のコミュニケーターとして機能する「リモートコントロール」クラスを実装することです。セカンダリアプリドメイン内でコードをインスタンス化して実行するリモートクラスのメソッドを呼び出すことができます。

MEFドキュメント

于 2012-07-05T19:31:26.610 に答える
0

この MSDN の記事によると、CLR はデフォルトでシャドウ コピーを使用しません。次の手順に従って有効にすることができます。

  1. AppDomainSetupを作成します。
  2. AppDomainSetup インスタンスで、ShadowCopyFiles を true に設定します。
  3. AppDomainSetup インスタンスで、ShadowCopyFilesDirectories を、実行時に上書きできるようにするアセンブリを含むディレクトリ パスに設定します。これは単に、プラグイン アセンブリが配置されているディレクトリである可能性があります。
  4. AppDomainSetup インスタンスで、必要に応じて他のすべてを設定します。
  5. AppDomainSetup を引数として受け取るAppDomain.CreateAppDomainのオーバーロードの 1 つを使用します。
  6. プラグイン アセンブリを交換してみてください。

CLR (Windows) ではなく Mono で動作するという事実は、デフォルトでシャドウ コピーを有効にするかどうかをCLIが指定していないことを意味する可能性があります。

于 2012-07-13T17:34:50.430 に答える
0

また、このメカニズムを再発明する代わりに、Managed Add-In Framework (MAF、System.AddIn) を利用してこれを行うことができます。クイックスタートについては、こちらをご覧ください。

于 2012-07-05T19:27:31.183 に答える
0

型とアセンブリを AppDomain からアンロードできません。したがって、新しい AppDomain を作成し、型をロードし、すべての作業を行ってから、そのドメインをアンロードする必要があります。

于 2012-07-05T19:30:32.467 に答える