ฉันจะสร้างสิ่งที่จับข้อยกเว้น 'ที่ไม่สามารถจัดการได้' ทั้งหมดในแอปพลิเคชัน WinForms ได้อย่างไร


87

จนถึงตอนนี้ฉันเพิ่งวางบล็อก try / catch ไว้Application.RunในProgram.csจุดเริ่มต้นของโปรแกรม สิ่งนี้จับข้อยกเว้นทั้งหมดได้ดีพอในโหมด Debug แต่เมื่อฉันเรียกใช้โปรแกรมโดยไม่มีโหมดดีบักข้อยกเว้นจะไม่ได้รับการจัดการอีกต่อไป ฉันได้รับกล่องข้อยกเว้นที่ไม่สามารถจัดการได้

ฉันไม่ต้องการให้สิ่งนี้เกิดขึ้น ฉันต้องการให้ตรวจจับข้อยกเว้นทั้งหมดเมื่อทำงานในโหมดไม่แก้ไขข้อบกพร่อง โปรแกรมมีเธรดหลายเธรดและโดยเฉพาะอย่างยิ่งข้อยกเว้นทั้งหมดจะถูกจับโดยตัวจัดการเดียวกัน ฉันต้องการบันทึกข้อยกเว้นในฐานข้อมูล ใครมีคำแนะนำในการทำเช่นนี้หรือไม่?

คำตอบ:


112

ดูตัวอย่างจากเอกสาร ThreadException :

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

นอกจากนี้คุณอาจไม่ต้องการตรวจพบข้อยกเว้นเมื่อทำการดีบักเนื่องจากจะทำให้ง่ายต่อการแก้ไขข้อบกพร่อง มันค่อนข้างจะเป็นการแฮ็ก แต่สำหรับสิ่งนั้นคุณสามารถรวมโค้ดด้านบนไว้ด้วย

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

เพื่อป้องกันการจับข้อยกเว้นเมื่อทำการดีบัก


1
ฉันสร้างคนทำงานเบื้องหลังและในตัวจัดการเหตุการณ์ dowork ฉันตั้งใจทำให้เกิดข้อยกเว้นการอ้างอิงที่เป็นโมฆะ อย่างไรก็ตามมันไม่ได้ถูกจับโดย AppDomain.CurrentDomain.UnhandledException ทั้งๆที่ตั้งค่าเหล่านี้: Application.ThreadException + = new System.Threading.ThreadExceptionEventHandler (Application_ThreadException); Application.SetUnhandledExceptionMode (UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException + = UnhandledExceptionEventHandler ใหม่ (CurrentDomain_UnhandledException);
Isaac Bolinger

4
@IsaacB ผู้ปฏิบัติงานเบื้องหลังจับข้อยกเว้นได้เอง คุณสามารถตรวจสอบข้อยกเว้นใน RunWorkerCompleted ได้โดยดูที่คุณสมบัติ RunCompletedEventArgs.Error
Can Gencer

1
คุณสามารถทดสอบการจัดการข้อยกเว้นสำหรับเธรดเพิ่มเติมได้โดยใส่ลงใน OnLoad ของฟอร์มหลักของคุณ เธรดใหม่ (() => {throw new Exception ();}). start ();
Can Gencer

น่าเสียดายที่การจัดการ UnhandledException จะไม่หยุดการยุติแอปพลิเคชัน :(
Nazar Grynko

7
แทนที่จะเป็น FriendlyName.EndsWith hack ให้ลอง Debugger.IsAttached ซึ่งสะอาดกว่า
หลอมละลาย

27

ใน NET 4 ข้อยกเว้นบางประการจะไม่ถูกจับโดยค่าเริ่มต้นอีกต่อไป สิ่งเหล่านี้มักจะเป็นข้อยกเว้นที่บ่งบอกถึงสถานะที่เสียหาย (อาจถึงแก่ชีวิต) ของไฟล์ปฏิบัติการเช่น AccessViolationException

ลองใช้แท็ก [HandleProcessCorruptedStateExceptions] หน้าวิธีการหลักของคุณเช่น

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

ฉันสามารถใช้AppDomain.CurrentDomain.UnhandledExceptionและApplication.ThreadExceptionเกินไปกับ[HandleProcessCorruptedStateExceptions]แท็ก?
Kiquenet

18

ตัวอย่างที่ดีสามารถพบได้ที่http://www.csharp-examples.net/catching-unhandled-exceptions/ โดยทั่วไปเปลี่ยนหลักของคุณเป็น:

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

คุณสามารถใช้ห้องสมุดNBugได้ ด้วยการตั้งค่าขั้นต่ำเช่นนี้:

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;

คุณสามารถเริ่มรวบรวมข้อมูลเกี่ยวกับจุดบกพร่องที่ไม่ได้จัดการทั้งหมดในแอปพลิเคชันของคุณแม้ว่าจะถูกปรับใช้กับไคลเอนต์ หากคุณไม่ต้องการใช้ไลบรารีของบุคคลที่สามคุณควรแนบกับเหตุการณ์ด้านล่าง:

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

1
ยินดีต้อนรับ ใช้ฟอรัมอภิปรายโครงการ NBug หากคุณมีคำถามเพิ่มเติม ( nbusy.com/forum/f11 ) หรือใช้แท็ก [nbug] ที่นี่
Teoman Soygul

แน่นอนคุณยังสามารถสมัครตัวจัดการเหตุการณ์ "ปกติ" กับเหตุการณ์ UnhandledException ดูmsdn.microsoft.com/en-us/library/…
neo2862

พวกใช้ Win7 + VS10 ถ้าฉันสมัครเข้าร่วมกิจกรรมเหล่านี้การสมัครใช้งานไม่ทำงานแทนกล่องโต้ตอบ Windows Vista / 7 ปกติจะปรากฏขึ้นCheck Online for a SolutionหรือClose the Program.. ฯลฯ แต่ถ้าฉันไม่สมัครสมาชิกฉันจะได้รับข้อยกเว้นทั่วไปของ. NET หน้าต่าง. สิ่งนี้เกิดขึ้นกับทั้งรุ่น Release และ Debug และลองตั้งค่าApplication.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);แล้วไม่เปลี่ยนแปลงอะไรเลย
gideon

@giddy หลังจากจัดการข้อยกเว้นแล้วคุณควรออกจากแอปพลิเคชันด้วย Environment.Exit (1); หากคุณไม่ต้องการให้หน้าต่างแสดงข้อผิดพลาดปรากฏขึ้น
Teoman Soygul

@Teo ขอบคุณสำหรับการตอบกลับของคุณ ฉันต้องการให้แบบฟอร์มข้อผิดพลาดของตัวเองปรากฏขึ้นจากนั้นฉันต้องการให้แอปออก แต่การสมัครรับข้อมูลเหตุการณ์ไม่เคยทำงานเพียงแค่แสดงกล่องโต้ตอบ Win Vista / 7 ทั่วไปเมื่อพบข้อยกเว้น แต่ถ้าฉันไม่สมัครใช้งานกล่องโต้ตอบข้อยกเว้นที่ไม่ได้จัดการ. NET ทั่วไปจะปรากฏขึ้น!
gideon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.