Har*_*aka 8 .net crash process appdomain unhandled-exception
我正在编写一个小插件库,它使用app域来隔离使用.Net framework 4.0的插件.因此,每个插件中的代码都不受我的控制.当其中一个插件出现未处理的异常时,我发现结果是混合包.它们如下.
当未处理的异常被插入到插件的主线程中时,调用插件的execute方法的主要可插拔应用程序能够清楚地捕获并处理它.没有问题.然而,
如果插件在插件的Execute方法中启动基于WinForms的应用程序的消息循环,并且在WinForm应用程序中抛出未处理的异常(即在表单中),那么可插拔应用程序只能在Visual Studio调试器内部运行时捕获异常.否则(在VS外部调用时)主插件应用程序与插件一起崩溃.
如果在插件的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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是插件项目的代码.它继承自上面的可插入应用程序项目中的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");
}
}
}
Run Code Online (Sandbox Code Playgroud)
最后,这是插件中Form的代码
namespace EvilPlugin
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnException_Click(object sender, EventArgs e)
{
throw new Exception("Evil Exception");
}
}
}
Run Code Online (Sandbox Code Playgroud)
如何防止主进程因上述两种情况(1和2)而退出?
提前致谢.
用于处理 WinForms 异常。您可以在 PluginBase 类中为此类 ThreadException 设置“陷阱”:
public abstract class PluginBase:MarshalByRefObject
{
protected PluginBase()
{
System.Windows.Forms.Application.ThreadException +=
(o, args) =>
{
throw new Exception("UntrappedThread Exception:" + args.Exception);
};
}
public abstract void ExecuteWinApp();
public abstract void ExecuteThread();
}
Run Code Online (Sandbox Code Playgroud)
默认情况下,它将显示“异常窗口”。但如果提供的话,将到达此处理程序。
至于从其他线程捕获异常。不可能。您能做的最好的事情就是收到有关抛出异常的通知。
AppDomain domain = AppDomain.CreateDomain("PluginDomain", null, domainSetup);
domain.UnhandledException +=
(o, eventArgs) =>
{
Console.WriteLine("Exception was caught from other AppDomain: " + eventArgs.ExceptionObject);
Console.WriteLine("CLR is terminating?: " + eventArgs.IsTerminating);
};
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2525 次 |
| 最近记录: |