AppDomain 未处理的异常

Posted

技术标签:

【中文标题】AppDomain 未处理的异常【英文标题】:AppDomain unhandled exceptions 【发布时间】:2013-03-22 11:31:46 【问题描述】:

有很多主题涵盖了这个问题。不过我还是有问题。

我将程序集加载到新的AppDomain 中,如下所示:

public void Run()

    //There's the problem.
    //As Panos Rontogiannis mentioned the thread is created in default AppDomain
    new Thread(RunApp).Start();


private void RunApp()
    try
    
        AppDomain.CreateDomain("domain name").ExecuteAssembly("path to assembly");
    
    catch (Exception _e)
    
        MessageBox.Show("Unhandled Exception.\n" + _e);
    

在加载程序集的 Main 方法中,我将处理程序订阅到 UnhandledException 事件:

AppDomain.CurrentDomain.UnhandledException += handleException;

处理程序本身:

public static void handleException(object a_s, UnhandledExceptionEventArgs a_args)

    var _e = (Exception)a_args.ExceptionObject;
    //Static loger class method
    Loger.WriteError(_e.GetType().ToString(), _e.Message, "default solution");

但是,无论在加载的程序集中哪里抛出异常,处理程序都不会参与其中。我只在默认的AppDomain(第一个try catch)中捕获异常。

【问题讨论】:

【参考方案1】:

很可能,您无法处理新AppDomain 中的异常的原因是它不是从在该AppDomain 中创建的线程中抛出的。从AppDomain.UnhandledException 上的文档来看,这并不是很直接。有趣的部分如下:

只有当线程的整个堆栈都有 在没有找到适用的异常处理程序的情况下展开,因此 可以引发事件的第一个位置是在应用程序域中 线程起源。

现在,如果执行抛出代码的线程是在您的主AppDomain 中创建的(就像控制台应用程序的主线程),那么您应该在主AppDomain 中添加一个处理程序。请注意,如果抛出的异常类型未在主 AppDomain 中加载,.NET 的程序集加载器将尝试从应用程序的基本目录和探测路径加载它。如果这些与子 AppDomain 不同,则程序集将不会被解析并会引发(其他)异常。

【讨论】:

你是对的。 ExecuteAssembly 在默认 AppDomain 中创建的新 Thread 中调用。但是处理新 AppDomain 中加载的组件中的异常是至关重要的。 @Wazelin 通过处理它,您的意思是简单地记录它。对于未处理的异常,您无能为力。如果从子 AppDomain 中创建的线程抛出未处理的异常,则 AppDomain 注定要失败,应用程序也注定要失败。如果您想将您的应用程序与其他代码隔离开来,则需要使用不同的进程。【参考方案2】:

发生这种情况的原因有很多。 http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx 的事件文档详细介绍了这种复杂性如果似乎没有任何内容适用,您能否发布重现代码?

【讨论】:

恕我直言这个答案应该是评论【参考方案3】:

我的猜测是在处理异常时未调用处理程序。即通过上面的 trycatch。

【讨论】:

【参考方案4】:

我真的不明白为什么处理程序没有被调用。

我最终在加载程序集的 Main 方法中使用了 FirstChanceException 而不是 UnhandledException。像这样:

AppDomain.CurrentDomain.FirstChanceException +=
    (obj, e) => Loger.WriteError(
        e.Exception.ToString(),
        e.Exception.Message,
        "default solution"
    );

【讨论】:

它可能适合您的事业,但我对此表示怀疑。第一次机会异常事件与未捕获的异常相同。简而言之,无论引发的每个异常是否最终都未被代码处理(捕获块而没有重新抛出),您都会收到此事件。 好吧,因为我只将它用于记录目的,我认为没关系。异常会被记录下来,如果存在,处理程序会继续工作。 是的,但请记住,某些代码(甚至在 .net 框架本身中)在内部使用异常,这些代码不会浮出水面,并且可能会用“虚假”异常掩盖您的日志记录。当然,您的里程可能会有所不同。 感谢您的警告。我还没想过。【参考方案5】:

这是一个迟到的回复,但如果你问我这似乎工作正常(VS2012/.NET 4.5),当然需要在调用 ExecuteAssembly 之前注册异常处理程序:(我有一个导致访问的子进程通过写入空引用(不安全代码)来强制崩溃并触发以下 HandleException 的违规行为:

public static void HandleException(object a_s, UnhandledExceptionEventArgs a_args)

    var _e = (Exception)a_args.ExceptionObject;
    Console.WriteLine(_e.GetType().ToString(), _e.Message, "default solution");


public void StarProcessWithinAppDomain(string fileName)

    try
    
        // New appdoamin / check exception isolation level 
        AppDomain sandBox = AppDomain.CreateDomain("sandBox");
        try
        
            AppDomain.CurrentDomain.UnhandledException += HandleException;
            sandBox.ExecuteAssembly(fileName);
        
        catch (Exception ex)
        
            Console.WriteLine("An error occurred (inner) within AppDomain, executing \"0\":" + "\n" + ex.Message, fileName);
        
        finally
        
            AppDomain.Unload(sandBox); 
        
    
    catch (Exception ex)
    
        Console.WriteLine("An error occurred within AppDomain, executing \"0\":" + "\n" + ex.Message, fileName);
    

【讨论】:

【参考方案6】:
    FirstChanceException 着火了。 任何catch 块都会被执行。 如果块中没有catch 块或throw,则UnhandledException 触发

您的catch 块可确保UnhandledException 不会触发。

【讨论】:

以上是关于AppDomain 未处理的异常的主要内容,如果未能解决你的问题,请参考以下文章

当我加载的另一个 AppDomain 引发未处理的异常时,我可以隔离我当前的 AppDomain 以防被拆除吗?

是否可以防止子 AppDomain 中的未处理异常导致主进程崩溃?

AppDomain.UnhandledException 自动重新抛出已处理的异常

Appdomain.Load(AssemblyName) 引发文件未找到异常

AppDomain.AssemblyLoad 事件捕获事件处理程序中引发的所有异常

沙盒 AppDomain 跨程序集异常处理