【问题标题】:How to detect when application terminates?如何检测应用程序何时终止?
【发布时间】:2010-11-25 05:17:15
【问题描述】:

这是对我的initial question 的跟进,我想介绍我的发现并寻求更正、想法和见解。我的发现(或者更确切地说是解释)来自人们对我之前的问题的回答,即阅读 MSDN .NET 3.5 文档和调试 .NET 3.5 代码。我希望这对像我一样想知道如何检测应用程序何时终止的人来说是有价值的。

活动:

  • System.AppDomain.CurrentDomain.ProcessExit:进程退出时引发,例如在默认 AppDomain 之后,其他所有内容都已卸载 [总执行时间仅限于 3 秒!]。对于 WPF,请改用 System.Windows.Application.Exit。对于 Windows 窗体,在 main 方法中运行 Application.Run(...) 之后的代码。

  • System.AppDomain.CurrentDomain.DomainUnload:在卸载默认 AppDomain 以外的 AppDomain 时引发,例如使用单元测试框架(MbUnit 和 TestDriven.NET)运行类时。

  • System.AppDomain.CurrentDomain.UnhandledException: (如果在默认情况下处理AppDomain:) 为任何线程中的任何未处理异常引发,无论线程启动于什么AppDomain。这意味着,这可以用作捕获-all 表示所有未处理的异常。

  • System.Windows.Application.Exit:当 WPF 应用程序(即默认的AppDomain)正常退出时引发。覆盖 System.Windows.Application.OnExit 以利用它。

  • 终结器(C# 中的析构函数):在垃圾收集器释放非托管资源时运行。 [总执行时间有限!]。

事件顺序:

WPF 应用程序:优雅退出

  1. System.Windows.Application.Exit
  2. System.AppDomain.CurrentDomain.ProcessExit
  3. 终结者

WPF 应用程序:未处理的异常

  1. System.AppDomain.CurrentDomain.UnhandledException

在 TestDriven.NET 中运行的 MbUnit:通过测试(优雅退出)

  1. System.AppDomain.CurrentDomain.DomainUnload
  2. 终结者

在 TestDriven.NET 中运行的 MbUnit:测试失败(未处理的异常由 MbUnit 处理)

  1. AppDomain.CurrentDomain.DomainUnload
  2. 终结者

问题:

  • 我的解释/发现是否正确?
  • 你知道我有更多的细节吗 被排除在外了吗?例如。总数是多少 终结器的执行时间?
  • 你知道其他事件吗/ 我知道哪些想法?
  • 存在哪些事件以及它们在其他应用程序中引发的顺序是什么,例如Windows 窗体、Web 服务、ASP.NET 网站等?

【问题讨论】:

    标签: c# .net multithreading appdomain


    【解决方案1】:

    由ssg31415926的问题/答案提示(这个问题有点颠倒),还有Application.SessionEnding,当用户注销或关闭时调用。它在 Exit 事件之前被调用。

    【讨论】:

    • 请注意/仅供参考:这仅在 .NET 3.0+ 中可用,您需要链接 System.Core.dll 才能在 .NET 2.0 中使用它
    【解决方案2】:

    Dispatcher.BeginInvokeShutdown()被调用时,Application.Exit不会被调用。

    【讨论】:

      【解决方案3】:
      1. 终结器执行的默认超时时间为 2 秒。

      【讨论】:

      • 你有那个来源,不是吗?
      【解决方案4】:

      你写:

      System.AppDomain.CurrentDomain.UnhandledException:(如果在默认 AppDomain 中处理:)针对任何线程中的任何未处理异常引发,无论线程在哪个 AppDomain 中启动。这意味着,这可以用作包罗万象的所有未处理的异常。

      我不认为这是正确的。试试下面的代码:

      using System;
      using System.Threading;
      using System.Threading.Tasks;
      
      namespace AppDomainTestingUnhandledException
      {
          class Program
          {
              static void Main(string[] args)
              {
                  AppDomain.CurrentDomain.UnhandledException +=
                      (sender, eventArgs) => Console.WriteLine("Something went wrong! " + args);
      
                  var ad = AppDomain.CreateDomain("Test");
      
                  var service =
                      (RunInAnotherDomain)
                      ad.CreateInstanceAndUnwrap(
                          typeof(RunInAnotherDomain).Assembly.FullName, typeof(RunInAnotherDomain).FullName);
      
                  try
                  {
                      service.Start();
                  }
                  catch (Exception e)
                  {
                      Console.WriteLine("Crash: " + e.Message);
                  }
                  finally
                  {
                      AppDomain.Unload(ad);
                  }
              }
          }
      
          class RunInAnotherDomain : MarshalByRefObject
          {
              public void Start()
              {
                  Task.Run(
                      () =>
                          {
                              Thread.Sleep(1000);
                              Console.WriteLine("Uh oh!");
                              throw new Exception("Oh no!");
                          });
      
                  while (true)
                  {
                      Console.WriteLine("Still running!");
                      Thread.Sleep(300);
                  }
              }
          }
      }
      

      据我所知,UnhandledException 处理程序永远不会被调用,并且线程只会默默地崩溃(或者如果你在调试器中运行它,就会对你唠叨)。

      【讨论】:

      • 我也发现这条线不清楚。也许@user65199 表示 event 是否“在默认 AppDomain 中处理”。显然,如果捕获到异常,则不会引发 UnhandledException 事件。该事件是否仅在默认 AppDomain 中引发,即使对于实际上在另一个 AppDomain 中启动的线程上的未处理异常(与您的示例从默认 AppDomain 开始)?我认为这可能是他的意思,但我不确定这是否是规则。
      【解决方案5】:

      只需在主窗体上添加一个新事件:

      private void frmMain_Load(object sender, EventArgs e)
      {
        Application.ApplicationExit += new EventHandler(this.WhenItStopsDoThis);
      }
      
      private void WhenItStopsDoThis(object sender, EventArgs e)
      {
        //Program ended. Do something here.
      }
      

      【讨论】:

        猜你喜欢
        • 2021-10-24
        • 1970-01-01
        • 1970-01-01
        • 2014-09-11
        • 1970-01-01
        • 2011-09-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多