web-dev-qa-db-fra.com

Comment détecter quand l'application se termine?

Ceci fait suite à ma question initiale et je voudrais présenter mes conclusions et demander des corrections, des idées et des idées. Mes découvertes (ou plutôt interprétations) proviennent des réponses des personnes à ma question précédente, à savoir la lecture de la documentation MSDN .NET 3.5 et le débogage du code .NET 3.5. J'espère que cela sera utile à quelqu'un qui se demandait, comme moi, comment détecter le moment où une application se termine.

Événements:

  • System.AppDomain.CurrentDomain.ProcessExit: déclenché à la fin du processus, par ex. après la valeur par défaut AppDomain et que tout le reste a été déchargé [Le temps d'exécution total est limité à 3 secondes seulement!]. Pour WPF, utilisez plutôt System.Windows.Application.Exit. Pour Windows Forms, exécutez le code après Application.Run(...) dans la méthode principale.

  • System.AppDomain.CurrentDomain.DomainUnload: déclenché lorsqu'une AppDomain autre que la valeur par défaut AppDomain est déchargée, par ex. lors de l'exécution de classes avec des frameworks de tests unitaires (MbUnit with TestDriven.NET).

  • System.AppDomain.CurrentDomain.UnhandledException: (si manipulé par défaut AppDomain :) levé pour toute exception non gérée dans un thread, quelle que soit la forme de AppDomain dans laquelle le thread a commencé. Cela signifie que cela peut être utilisé comme attrape-tout pour toutes les exceptions non gérées.

  • System.Windows.Application.Exit: déclenché lorsque l'application WPF (c'est-à-dire la valeur par défaut AppDomain) se ferme normalement. Remplacez System.Windows.Application.OnExit pour en tirer parti.

  • Finalizers (destructeurs en C #): exécutés lorsque le ramasse-miettes libère des ressources non gérées. [Le temps d'exécution total est limité!].

Ordre des événements:

Application WPF: sortie en douceur

  1. System.Windows.Application.Exit
  2. System.AppDomain.CurrentDomain.ProcessExit
  3. Finalizer

Application WPF: exception non gérée

  1. System.AppDomain.CurrentDomain.UnhandledException

MbUnit en cours d'exécution dans TestDriven.NET: test réussi (sortie en douceur)

  1. System.AppDomain.CurrentDomain.DomainUnload
  2. Finalizer

MbUnit s'exécutant dans TestDriven.NET: échec du test (les exceptions non gérées sont gérées par MbUnit)

  1. AppDomain.CurrentDomain.DomainUnload
  2. Finalizer

Questions:

  • Mes interprétations/conclusions sont-elles correctes?
  • Connaissez-vous d'autres détails que j'ai laissés de côté? Par exemple. Quel est le temps total d'exécution pour les finaliseurs?
  • Connaissez-vous d'autres événements/idées dont je suis au courant?
  • Quels événements y at-il et quel ordre sont-ils levés dans d’autres applications, par exemple. Windows Forms, service Web, site Web ASP.NET, etc.?
61
user65199

Invité par la question/réponse de ssg31415926 (cette question est un peu inversée), il y a aussi Application.SessionEnding qui est appelé lorsque l'utilisateur ferme ou ferme la session. Il est appelé avant l'événement de sortie.

7
Ray

Lorsque Dispatcher.BeginInvokeShutdown() est appelé, Application.Exit ne sera pas appelé.

2
FooBarTheLittle

Vous écrivez:

System.AppDomain.CurrentDomain.UnhandledException: (si gérée par défaut par AppDomain :), levée pour toute exception non gérée dans un thread, quelle que soit la méthode utilisée par AppDomain dans le thread. .

Je ne pense pas que cela soit correct. Essayez le code suivant:

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);
            }
        }
    }
}

Autant que je sache, le gestionnaire UnhandledException n'est jamais appelé, et le thread va juste planter en silence (ou vous harceler si vous l'exécutez dans le débogueur).

1
Eyvind
  1. Le délai d'attente par défaut pour l'exécution d'un finaliste est de 2 secondes.
1
unknown

Ajoutez simplement un nouvel événement sur votre formulaire principal:

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.
}
0
Daj Shung