Làm cách nào tôi có thể tạo thứ gì đó bắt được tất cả các ngoại lệ 'chưa xử lý' trong ứng dụng WinForms?


85

Cho đến bây giờ, tôi chỉ cần đặt một khối try / catch xung quanh Application.Runtrong Program.csđiểm nhập vào chương trình. Điều này bắt tất cả các ngoại lệ đủ tốt trong chế độ Gỡ lỗi, nhưng khi tôi chạy chương trình mà không có chế độ gỡ lỗi, các ngoại lệ không được xử lý nữa. Tôi nhận được hộp ngoại lệ chưa xử lý.

Tôi không muốn điều này xảy ra. Tôi muốn tất cả các ngoại lệ được bắt khi chạy ở chế độ không gỡ lỗi. Chương trình có nhiều luồng và tốt nhất là tất cả các trường hợp ngoại lệ của chúng đều bị bắt bởi cùng một trình xử lý; Tôi muốn ghi các ngoại lệ trong DB. Có ai có bất kỳ lời khuyên trong cách làm điều này?

Câu trả lời:


110

Hãy xem ví dụ từ tài liệu 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);
}

Bạn cũng có thể muốn không bắt các ngoại lệ khi gỡ lỗi, vì điều này giúp gỡ lỗi dễ dàng hơn. Đó là một phần của một cuộc tấn công, nhưng đối với điều đó, bạn có thể bọc đoạn mã trên với

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

Để ngăn chặn việc bắt các ngoại lệ khi gỡ lỗi.


1
Tôi đã tạo một nhân viên nền và trong trình xử lý sự kiện dowork, tôi đã cố tình gây ra một ngoại lệ tham chiếu rỗng. Tuy nhiên, nó không bị bắt bởi AppDomain.CurrentDomain.UnhandledException mặc dù đã thiết lập những điều này: Application.ThreadException + = new System.Threading.ThreadExceptionEventHandler (Application_ThreadException); Application.SetUnhandledExceptionMode (UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException + = new UnhandledExceptionEventHandler (CurrentDomain_UnhandledException);
Isaac Bolinger

4
@IsaacB, background worker tự bắt các ngoại lệ. Bạn có thể kiểm tra ngoại lệ trong RunWorkerCompleted, ngay cả khi xem thuộc tính RunCompletedEventArgs.Error.
Can Gencer

1
Bạn có thể kiểm tra việc xử lý ngoại lệ cho các luồng bổ sung bằng cách đặt nó vào OnLoad của biểu mẫu chính của bạn. new Thread (() => {ném new Exception ();}). start ();
Can Gencer

Thật không may xử lý UnhandledException sẽ không ngừng ứng dụng từ chấm dứt :(
Nazar Grynko

7
Thay vì hack FriendlyName.EndsWith, hãy thử Debugger.IsAttached, cái này rõ ràng hơn.
moltenform

27

Trong NET 4, một số ngoại lệ nhất định không còn bị bắt theo mặc định; chúng có xu hướng là các ngoại lệ cho biết trạng thái bị hỏng (có thể nghiêm trọng) của tệp thực thi, chẳng hạn như AccessViolationException.

Hãy thử sử dụng thẻ [HandleProcessCorrupStateExceptions] phía trước phương thức chính của bạn, ví dụ:

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

Tôi có thể sử dụng AppDomain.CurrentDomain.UnhandledExceptionvà cả Application.ThreadExceptionvới [HandleProcessCorruptedStateExceptions]thẻ không?
Kiquenet

18

Bạn có thể tìm thấy một ví dụ thú vị tại http://www.csharp-examples.net/catching-unhandled-exceptions/ Về cơ bản, hãy thay đổi chính của bạn thành:

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

Bạn có thể sử dụng thư viện NBug cho việc đó. Với thiết lập tối thiểu như thế này:

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;

Bạn có thể bắt đầu thu thập thông tin về tất cả các lỗi chưa được khắc phục trong ứng dụng của mình, ngay cả khi nó được triển khai cho khách hàng. Nếu bạn không muốn sử dụng thư viện của bên thứ 3, bạn nên đính kèm các sự kiện dưới đây:

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

1
Không có gì. Sử dụng diễn đàn thảo luận về dự án NBug nếu bạn có thêm câu hỏi ( nbusy.com/forum/f11 ) hoặc sử dụng thẻ [nbug] tại đây.
Teoman Soygul

Tất nhiên, bạn cũng có thể đăng ký một trình xử lý sự kiện "thông thường" cho sự kiện UnhandledException. Xem msdn.microsoft.com/en-us/library/…
neo2862

Các bạn trên Win7 + VS10, nếu tôi đăng ký các sự kiện này, đăng ký không chạy, thay vào đó hộp thoại Windows Vista / 7 thông thường sẽ hiển thị Check Online for a SolutionHoặc Close the Program............ ” Cửa sổ. Điều này xảy ra trên cả bản dựng Phát hành và Gỡ lỗi, cũng đã thử cài đặt Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);Không thay đổi bất kỳ điều gì.
gideon

@giddy, sau khi xử lý các trường hợp ngoại lệ, bạn nên thoát ứng dụng với Environment.Exit (1); nếu bạn không muốn cửa sổ lỗi hiển thị.
Teoman Soygul

@Teo cảm ơn bạn đã trả lời. Tôi muốn biểu mẫu lỗi của riêng mình hiển thị và sau đó tôi muốn ứng dụng thoát. Nhưng đăng ký sự kiện không bao giờ chạy, nó chỉ hiển thị hộp thoại chung của Win Vista / 7 khi gặp các trường hợp ngoại lệ. Nhưng nếu tôi không đăng ký, hộp thoại ngoại lệ không được xử lý .NET chung sẽ xuất hiện!
gideon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.