Могут ли необработанные исключения в Дочерние домены приложений не могут привести к сбою основного процесса?

Я пишу небольшую библиотеку плагинов, которая использует домены приложений для изоляции плагинов с помощью .Net framework 4.0. Следовательно, код, который входит в каждый плагин, находится вне моего контроля. Когда в одном из плагинов возникает необработанное исключение, я заметил, что результаты являются смешанными. Они заключаются в следующем:

Когда необработанное исключение возникает в основном потоке подключаемого модуля, основное подключаемое приложение, вызывающее метод выполнения подключаемого модуля, способно уловить и обработать его чисто. Никаких проблем нет. Однако

  1. , если подключаемый модуль запускает цикл сообщений для приложения на основе WinForms в методе подключаемого модуля Execute, и в приложении WinForm (т.е. в форме) возникает необработанное исключение, тогда подключаемое приложение может перехватить исключение только в том случае, если оно запущено. изнутри отладчика Visual Studio. В противном случае (при вызове вне VS) основное подключаемое приложение вылетает вместе с подключаемыми модулями.

  2. Если необработанное исключение выбрасывается в отдельном потоке, порожденном методом Execute подключаемого модуля, то подключаемое приложение не имеет шанса перехватить исключение и сбой.

Я создал простой проект VS 2010 для моделирования этого поведения по ссылке ниже. http://www.mediafire.com/file/1af3q7tzl68cx1p/PluginExceptionTest.zip

В нем основной метод в подключаемом приложении выглядит так

namespace PluginExceptionTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Press enter to load plugin");
            Console.ReadLine();

            Assembly entryAsm = Assembly.GetEntryAssembly();
            string assemblyFileName = Path.Combine(Path.GetDirectoryName(entryAsm.Location), "EvilPlugin.exe");


            AppDomainSetup domainSetup = new AppDomainSetup();
            AppDomain domain = AppDomain.CreateDomain("PluginDomain", null, domainSetup);
            PluginBase plugin = (PluginBase)domain.CreateInstanceFromAndUnwrap(assemblyFileName, "EvilPlugin.Plugin");

            Console.WriteLine("Plugin Loaded.");

            //SCENARIO 1: WinForms based plugin
            Console.WriteLine("Press Enter to execute winforms plugin. (Remember to click on the button in the form to raise exception)");
            Console.ReadLine();

            try
            {
                plugin.ExecuteWinApp();
            }
            catch (Exception)
            {
                //The exception is caught and this gets executed only when running in visual studio debugger. Else application exits. Why?
                Console.WriteLine("WinForms plugin exception caught. However same does not happen when run out of visual studio debugger. WHY?");
            }

            //SCENARIO 2: WinForms based plugin
            Console.WriteLine("Press Enter to execute threading plugin, wait for 3 seconds and the app will exit. How to prevent app from exiting due to this?");
            Console.ReadLine();
            try
            {
                plugin.ExecuteThread();
            }
            catch (Exception)
            {
                //This never gets executed as the exception is never caught. Application exits. Why?
                Console.WriteLine("WinForms plugin exception caught");
            }

            Console.ReadLine();
        }
    }
}

Это код для проекта подключаемого модуля. Он наследуется от класса PluginBase в проекте подключаемого приложения выше.

namespace EvilPlugin
{
    public class Plugin:PluginBase
    {
        public Plugin():base()
        {

        }

        public override void ExecuteWinApp()
        {            
            Application.Run(new Form1());            
        }

        public override void ExecuteThread()
        {
            Thread t = new Thread(new ThreadStart(RaiseEx));           
            t.Start();
        }

        private void RaiseEx()
        {
            Thread.Sleep(3000);
            throw new Exception("Another Evil Exception in a seperate thread");
        }
    }
}

Наконец, это код из формы в подключаемом модуле

namespace EvilPlugin
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnException_Click(object sender, EventArgs e)
        {
            throw new Exception("Evil Exception");
        }
    }
}

Как я могу предотвратить выход из основного процесса из-за двух упомянутых сценариев (1 и 2) над?

Заранее спасибо.

8
задан Harindaka 29 June 2011 в 12:46
поделиться