Bir WinForms uygulamasındaki tüm 'işlenmemiş' istisnaları yakalayan bir şeyi nasıl yapabilirim?


87

Şimdiye kadar, sadece etrafında bir try / catch bloğu koymak Application.Runiçinde Program.csprograma giriş noktasına. Bu, Hata Ayıklama modunda tüm istisnaları yeterince iyi yakalar, ancak programı hata ayıklama modu olmadan çalıştırdığımda, istisnalar artık işlenmiyor. İşlenmemiş istisna kutusunu alıyorum.

Bunun olmasını istemiyorum. Hata ayıklama olmayan modda çalışırken tüm istisnaların yakalanmasını istiyorum. Programın birden çok iş parçacığı vardır ve tercihen bunlardan gelen tüm istisnalar aynı işleyici tarafından yakalanır; DB'de istisnaları kaydetmek istiyorum. Bunun nasıl yapılacağı konusunda herhangi bir tavsiyesi olan var mı?

Yanıtlar:


112

ThreadException belgelerinden örneğe bir göz atın :

public static void Main(string[] args)
{
   // Add the event handler for handling UI thread exceptions to the event.
    Application.ThreadException += new     
  ThreadExceptionEventHandler(ErrorHandlerForm.Form1_UIThreadException);

  // Set the unhandled exception mode to force all Windows Forms errors
  // to go through our handler.
  Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

  // Add the event handler for handling non-UI thread exceptions to the event. 
  AppDomain.CurrentDomain.UnhandledException += new       
  UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}

Ayrıca, hata ayıklamayı kolaylaştırdığı için, hata ayıklama sırasında istisnaları yakalamamak isteyebilirsiniz. Bu bir şekilde bir hack'tir, ancak bunun için yukarıdaki kodu etrafına sarabilirsiniz

 if (!AppDomain.CurrentDomain.FriendlyName.EndsWith("vshost.exe")) { ... }

Hata ayıklama sırasında istisnaların yakalanmasını önlemek için.


1
Bir arka plan işçisi yaptım ve dowork olay işleyicisinde kasıtlı olarak bir boş referans istisnasına neden oldum. Ancak, bunları ayarlamasına rağmen AppDomain.CurrentDomain.UnhandledException tarafından yakalanmadı: Application.ThreadException + = new System.Threading.ThreadExceptionEventHandler (Application_ThreadException); Application.SetUnhandledExceptionMode (UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException + = new UnhandledExceptionEventHandler (CurrentDomain_UnhandledException);
Isaac Bolinger

4
@IsaacB, arka plan çalışanı istisnaları kendisi yakalar. RunWorkerCompleted'deki istisnayı RunCompletedEventArgs.Error özelliğine bakarak bile kontrol edebilirsiniz.
Can Gencer

1
Ek iş parçacıkları için özel durum işlemeyi, bunu ana formunuzun OnLoad'a ekleyerek test edebilirsiniz. new Thread (() => {throw new Exception ();}). Start ();
Can Gencer

Ne yazık ki UnhandledException'ın işlenmesi, uygulamanın sonlandırılmasını durdurmaz :(
Nazar Grynko

7
FriendlyName.EndsWith hack yerine, daha temiz olan Debugger.IsAttached deneyin.
moltenform

27

NET 4'te, belirli istisnalar artık varsayılan olarak yakalanmamaktadır; bunlar, AccessViolationException gibi yürütülebilir dosyanın (muhtemelen ölümcül) bozuk bir durumunu gösteren istisnalar olma eğilimindedir.

[HandleProcessCorruptedStateExceptions] etiketini ana yönteminizin önünde kullanmayı deneyin, örn.

using System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions

[HandleProcessCorruptedStateExceptions]
public static int Main()
{
    try
    {
        // Catch any exceptions leaking out of the program
        CallMainProgramLoop();
    }
    catch (Exception e) // We could be catching anything here
    {
        System.Console.WriteLine(e.Message);
        return 1;
    }
    return 0;
  } 

Ben kullanabilir miyim AppDomain.CurrentDomain.UnhandledExceptionve Application.ThreadExceptionçok ile [HandleProcessCorruptedStateExceptions]etiketiyle?
Kiquenet 01

18

Güzel bir örnek http://www.csharp-examples.net/catching-unhandled-exceptions/ adresinde bulunabilir. Temel olarak ana dilinizi şu şekilde değiştirin:

static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
        Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

        Application.Run(new Form1());
    }

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        MessageBox.Show(e.Exception.Message, "Unhandled Thread Exception");
    }

    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        MessageBox.Show((e.ExceptionObject as Exception).Message, "Unhandled UI Exception");
    }

9

Bunun için NBug kitaplığını kullanabilirsiniz . Bunun gibi minimum kurulumla:

NBug.Settings.Destination1 = "Type=Mail;From=me@mycompany.com;To=bugtracker@mycompany.com;SmtpServer=smtp.mycompany.com;";
AppDomain.CurrentDomain.UnhandledException += NBug.Handler.UnhandledException;
Application.ThreadException += NBug.Handler.ThreadException;

İstemcilere dağıtıldığında bile uygulamanızdaki tüm işlenmemiş hatalar hakkında bilgi toplamaya başlayabilirsiniz. Bir 3. taraf kitaplığı kullanmak istemiyorsanız, aşağıdaki etkinliklere eklemelisiniz:

// These two should come before enabling visual styles or running the application
AppDomain.CurrentDomain.UnhandledException += ...
Application.ThreadException += ...
...
Application.Run(new Form1());

1
Rica ederim. Başka sorularınız varsa ( nbusy.com/forum/f11 ) NBug proje tartışma forumunu kullanın veya burada [nbug] etiketini kullanın.
Teoman Soygul

Elbette, UnhandledException olayına "normal" bir olay işleyicisine de abone olabilirsiniz. Bkz msdn.microsoft.com/en-us/library/...
neo2862

Win7 + VS10'daki çocuklar, bu olaylara abone olursam abonelik çalışmaz, bunun yerine normal Windows Vista / 7 iletişim kutusu açılır Check Online for a SolutionVeya Close the Program.. vb. Ancak abone DEĞİLSEM, normal genel .NET İşlenmemiş İstisnası alırım Pencere. Bu, Hem Sürüm hem de Hata Ayıklama sürümlerinde olur, ayrıca Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);hiçbir şeyi değiştirmez ayarını denedi .
gideon

@giddy, istisnaları hallettikten sonra Environment.Exit (1) ile uygulamadan çıkmalısınız; hata penceresinin görüntülenmesini istemiyorsanız.
Teoman Soygul

Cevabınız için @Teo teşekkürler. Kendi hata formumun görünmesini ve ardından uygulamanın çıkmasını istiyorum. Ancak olay aboneliği asla çalışmaz, istisnalarla karşılaştığında sadece genel Win Vista / 7 iletişim kutusunu gösterir. Ancak, genel .NET işlenmemiş istisna iletişimine abone olmazsam belirir!
gideon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.