0

私はC#を勉強しています。Andrew Troelsen の「C# and the .NET Platform」と Jeffrey Richter の「CLR via C#」の本を読みました。現在、あるディレクトリからアセンブリをロードし、それらを AppDomain にプッシュし、含まれているメソッド (プラグインをサポートするアプリケーション) を実行するアプリケーションを作成しようとしています。これは、共通インターフェイスである DLL です。私はそれを自分のアプリケーションに追加し、プラグインを含むすべての DLL に追加します。MainLib.DLL

namespace MainLib
{
public interface ICommonInterface
{
    void ShowDllName();
}
}

ここにプラグインがあります: PluginWithOutException

namespace PluginWithOutException
{
public class WithOutException : MarshalByRefObject, ICommonInterface
{
    public void ShowDllName()
    {
        MessageBox.Show("PluginWithOutException");
    }

    public WithOutException()
    {

    }
}
}

もう 1 つ: PluginWithException

namespace PluginWithException
{
public class WithException : MarshalByRefObject, ICommonInterface
{
    public void ShowDllName()
    {
        MessageBox.Show("WithException");
        throw new NotImplementedException();
    }
}
}

そして、ここに DLL をロードして別の AppDomain で実行するアプリケーションがあります。

namespace Plug_inApp
{   
class Program
{

    static void Main(string[] args)
    {

        ThreadPool.QueueUserWorkItem(CreateDomainAndLoadAssebly, @"E:\Plugins\PluginWithException.dll");

        Console.ReadKey();
    }
    public static void CreateDomainAndLoadAssebly(object name)
    {
        string assemblyName = (string)name;
        Assembly assemblyToLoad = null;
        AppDomain domain = AppDomain.CreateDomain(string.Format("{0} Domain", assemblyName));
        domain.FirstChanceException += domain_FirstChanceException;

        try
        {
            assemblyToLoad = Assembly.LoadFrom(assemblyName);
        }
        catch (FileNotFoundException)
        {
            MessageBox.Show("Can't find assembly!");
            throw;
        }

        var theClassTypes = from t in assemblyToLoad.GetTypes()
                            where t.IsClass &&
                                  (t.GetInterface("ICommonInterface") != null)
                            select t;
        foreach (Type type in theClassTypes)
        {
            ICommonInterface instance = (ICommonInterface)domain.CreateInstanceFromAndUnwrap(assemblyName, type.FullName);
            instance.ShowDllName();
        }

    }

    static void domain_FirstChanceException(object sender, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e)
    {
        MessageBox.Show(e.Exception.Message);
    }
}
}

別のドメインで実行するinstance.ShowDllName();と (間違っているのでしょうか?)、未処理の例外が実行されているドメインをドロップしますが、デフォルトのドメインは機能します。しかし、私の場合、別のドメインで例外が発生した後、デフォルトのドメインがクラッシュします。私が間違っていることを教えてください。

4

2 に答える 2

4

本当に必要な場合は、これをある程度制御する方法があります。これは、アドインをチーム外で作成できるためです。また、他の人のアドインが原因でアプリケーションがクラッシュするのをできる限り回避しようとしています。

そのため、アプリケーションは例外をスローした AppDomain を削除し、ユーザーに通知して続行します。または、例外がメインの AppDomain から発生した場合は、単に FailFast になります。

App.config には、次のものが必要です。

<configuration>
 <runtime>
  <legacyUnhandledExceptionPolicy enabled="true" />
 </runtime>
</configuration>

これにより、未処理の例外に対する従来の動作に戻り、プロセス全体を強制終了するか、AppDomain のみを強制終了するかを自分で決定できます。

どの AppDomain からどの例外が発生したかを調べるなど、対処すべき他の問題がまだいくつかあります。

もう 1 つの問題は、すべての例外がシリアル化できるわけではないことです。つまり、一部の例外は、AppDomain の境界を超えると SerializationException になります。

アドインは共通の基本クラスを実装しているため、ハンドルされない例外ハンドラーをアドイン自体に配置することで、これらの問題を回避しました。AppDomain.CurrentDomain.UnhandledException次に、andにフックしTaskScheduler.UnobservedTaskExceptionて呼び出しAppDomain.Unload(AppDomain.CurrentDomain)、アドインを終了します。

これは完璧ではありませんが、私たちのプロジェクトではうまく機能します。

于 2013-05-03T13:32:36.987 に答える