Async Error-Handling in BackgroundWorker - multithreading

How does one get a meaningful BackgroundWorker.Error when DoWork must call a delegate that might throw an exeption?
I'm implementing a static MsgBox class that exposes various ways of conveying custom messages to the user (using a custom message form).
One of the exposed methods, ShowProgress, instantiates a ProgressMessageBoxForm (derived from the custom MessageBoxForm) which displays a progress bar while some background operation is happening (letting user cancel the operation all the while). If running a background task on a modal form sounds awkward, consider a signature like this:
public static DialogResult ShowProgress(string title, string message, _
Action<AsyncProgressArgs> progressAction)
The idea is to encapsulate a background worker that delegates its "work" to any provided method (/handler), while allowing that method to "talk" back and report progress and cancellation... and ideally error status. Whether the form is modal or not has no relevance in this context, the ability to display progress of a running task in a progress bar on a cancellable modal form that also automatically closes unless a checkbox is un-checked so as to remain visible and displaying a success status upon completion, is a required feature.
Here's the AsyncProgressArgs class in question:
public class AsyncProgressArgs
{
private readonly Action<int, string> _update;
private readonly BackgroundWorker _worker;
private readonly DoWorkEventArgs _workEventArgs;
public AsyncProgressArgs(Action<int, string> updateProgress, BackgroundWorker worker, DoWorkEventArgs e)
{
_update = updateProgress;
_worker = worker;
_workEventArgs = e;
}
/// <summary>
/// Reports progress to underlying <see cref="BackgroundWorker"/>.
/// Increments <see cref="ProgressBar"/> value by specified <see cref="int"/> amount and
/// updates the progress <see cref="Label"/> with specified <see cref="string"/> caption.
/// </summary>
public Action<int, string> UpdateProgress { get { return _update; } }
/// <summary>
/// Verifies whether asynchronous action is pending cancellation,
/// in which case asynchronous operation gets cancelled.
/// </summary>
public void CheckCancelled()
{
_workEventArgs.Cancel = _worker.CancellationPending;
}
}
The BackgroundWorker's DoWork event handler then invokes the method that was passed to the custom messagebox
protected virtual void worker_DoWork(object sender, DoWorkEventArgs e)
{
// *** If RunWorkerCompletedEventArgs.Error caught exceptions,
// then this try/catch block wouldn't be needed:
// try
// {
_startHandler(this, new AsyncProgressArgs(UpdateProgressAsync, _worker, e));
// }
// catch(Exception exception)
// {
// if (MsgBox.Show(exception) == DialogResult.Retry)
// {
// BeginWork(_startHandler);
// }
// else
// {
// Hide();
// }
// }
}
Given a method such as this:
private void AsyncProgressAction(AsyncProgressArgs e)
{
// do some work:
Thread.Sleep(200);
// increment progress bar value and change status message:
e.UpdateProgress(10, "Operation #1 completed.");
// see if cancellation was requested:
e.CheckCancelled();
// do some work:
Thread.Sleep(500);
// increment progress bar value and change status message:
e.UpdateProgress(30, "Operation #2 completed.");
// see if cancellation was requested:
e.CheckCancelled();
// ...
// throw new Exception("This should be caught by the BackgroundWorker");
}
The calling code can look like this:
MsgBox.ShowProgress("Async Test", "Please wait while operation completes.", _
AsyncProgressAction);
Everything works as expected (the progress bar moves, the process can be cancelled), until an exception gets thrown in the action method. Normally the BackgroundWorker would catch it and store it in its Error property, but here this doesn't happen.
Thus, the code in the passed action method needs to handle its own exceptions and if it doesn't, it remains unhandled and the program dies a horrible death.
The question is, is it possible to have such a construct and still somehow be able to have a meaningful Error property when the process completes? I want to be able to Throw new Exception() anywhere in the action method and have it handled in the encapsulated worker.
Side note, I resorted to BackgroundWorker because with Task I couldn't get the progress bar to move until all the work was done, and I'd like to avoid dealing with Thread object instances directly.
EDIT
This is a non-issue, the compiled app does not blow up. Actually, I got confused by the debugger breaking on the exception being thrown in the delegate method. As pointed out in the comments below, execution/debugging can continue afterwards, and whatever error-handling logic is intended to run, will run. I was expecting BackgroundWorker to somehow catch the exception and the debugger to keep going, but it turns out the exception is caught and still the debugger breaks.
I should have read this before: Unhandled exceptions in BackgroundWorker

I should have read this before: Unhandled exceptions in BackgroundWorker.
This is a very, very long question with lots of context for a simple non-issue: the VS debugger stops and misleadingly says "Exception was unhandled by user code" as it would for an unhandled exception... when it actually means "BackgroundWorker task has thrown an exception and the debugger is letting you know about it because otherwise you would think the BackgroundWorker is swallowing it."
The exception can be F5'd / ignored to resume execution, the exception does end up in RunWorkerCompletedEventArgs.Error as expected, and the deployed app does not blow up in the user's face.
Posting this answer to remove this question from the (overflowing?) stack of unanswered questions...

Related

I am running a javafx program and I am getting an IllegalStateException in a situation where I would expect usual Thread interference

tl:dr at the bottom. I am taking a Java course on Udemy and our instructor is demonstrating a situation where background threads can interfere with each other and crash the program. In this case pushing either of the two buttons initiates a method that starts a background Thread, waits, then updates a label. He explains it something along the lines as the threads overwriting each other causing the program to crash with an IllegalStateException. What I don't understand is Threads overwriting each other is not uncommon and just makes the program behave in ways not intended and doesn't usually completely crash the program.
In this case the threads are both trying to change the label to the same String.
Why is this throwing an IllegalStateException instead of just causing the usual interference? After all more than one thread trying to update an object doesn't necessarily crash the program.
tl:dr Why does more than one thread modifying a Label object throw an IllegalStateException in this case but in other multi-threaded programs you just get the usual thread interference? The method of interest is the onButtonClicked() method.
I have tried catching the IllegalStateException to see if I can call Thread.currentThread().getName() but the catch block(both of them actually) seem to get ignored.
public class Controller {
#FXML
private TextField nameField;
#FXML
private Button helloButton;
#FXML
private Button byeButton;
#FXML
private CheckBox ourCheckBox;
#FXML
private Label ourLabel;
#FXML
public void initialize() {
helloButton.setDisable(true);
byeButton.setDisable(true);
}
#FXML
public void onButtonClicked(ActionEvent event) {
if (event.getSource().equals(helloButton)) {
System.out.println("hello, " + nameField.getText());
} else if (event.getSource().equals(byeButton)) {
System.out.println("Bye, " + nameField.getText());
}
Runnable task = new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
ourLabel.setText("We did something");
} catch (InterruptedException e) {
System.out.println("Interuppted Exception " + e.getMessage());
} catch (IllegalStateException e) {
System.out.println("Illegal State Exception: " + e.getMessage() + " "
+ Thread.currentThread().getName());
}
}
};
new Thread(task).start();
if (ourCheckBox.isSelected()) {
nameField.clear();
byeButton.setDisable(true);
helloButton.setDisable(true);
}
}
#FXML
public void handleKeyReleased() {
String text = nameField.getText();
boolean disableButtons = text.isEmpty() || text.trim().isEmpty();
byeButton.setDisable(disableButtons);
helloButton.setDisable(disableButtons);
}
#FXML
public void handleChange() {
System.out.println("The checkbox is " +
(ourCheckBox.isSelected() ? "checked" : "not checked"));
}
}
Updating active scene graph elements (such as label text) in your own threads has the potential to cause a race condition (please read and understand the Software section of the link) in the internal state of the JavaFX system. The results of which are unpredictable and a corruption or ”crash” of the JavaFX system cannot be ruled out. Perhaps nothing bad will happen, but perhaps something bad will.
Some calls to JavaFX APIs will detect when potential race condition may occur (when they are being invoked by a thread which is not the JavaFX thread), and fail fast by throwing an IllegalStateException. Other JavaFX APIs may not bother to check the calling thread and may not throw an IllegalStateException, thus allowing the potential race condition to occur. Either way, the users calling code is wrong, it should not be trying to modify the active scene graph off of the JavaFX application thread.
JavaFX code which manipulates the active scene graph (elements or properties of elements currently being displayed in a rendered scene) is only ever expected to occur on a single thread (the JavaFX application thread). In that way a race condition cannot occur.
If you want to feedback information from another thread to the UI, then you can either use the Platform.runLater API, which will execute a piece of code at some time in the future on the JavaFX thread, or make use of utilities in the javafx.concurrent package.

Method setText() must be called from the UI Thread, currently inferred thread is worker thread

I'm making a project in Android Studio, and somewhere i've to use AsyncTask, but when i try to setText in a try catch i got the error: "Method setText() must be called from the UI Thread, currently inferred thread is worker"
What to do?
Here's some prints of my code:
onCreate and onClick
Validate user on AsyncTask
That error is expected if you're trying to update any UI components on a separate thread. I have myself a helper function that I use to run specific things back on the UI thread, here's the important bits:
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(new Runnable() {
#Override
public void run() {
txt_Error.setText("Sorry!! Incorrect Username or Password");
}
});
The error says you can't call txt_Error.setText() method there because the AsyncTask DoInBackGround runs in the background, in other words, the txt_Error.setText() method can just be called from the IU thread.
What you can do is to call this method publishProgress(2 parameter); in the DoInBackground and add this method onProgressUpdate(2 parameter) in the AsyncTask pressing ALT + O.
The onProgressUpdate(2 parameter) method runs in the Main Thread or IU Thread, so every time you call publishProgress(2 parameter); in the DoInBackground the onProgressUpdate() is triggered.
Another important thing is, the publishProgress(2 parameter); method send and onProgressUpdate(2 parameter) method recive the second parameter you established at the beginning private class validateUserTask extends AsyncTask <1 parameter, 2 parameter, 3 parameter>.
Example:
new AsyncTask<Integer,String,Void>(){
#Override
protected Void doInBackground(Integer... integers) {
*can call this method wherever you want here*
publishProgress(string);
return null;
}
#Override
protected void onProgressUpdate(final String... values) {
text.setText(values[0]);
}
}.execute();
Note: I just did the AsyncTask in a method... (easier)

New Thread doesn't open scene [duplicate]

I'm trying to understand how threads works in java. This is a simple database request that returns a ResultSet. I'm using JavaFx.
package application;
import java.sql.ResultSet;
import java.sql.SQLException;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
public class Controller{
#FXML
private Button getCourseBtn;
#FXML
private TextField courseId;
#FXML
private Label courseCodeLbl;
private ModelController mController;
private void requestCourseName(){
String courseName = "";
Course c = new Course();
c.setCCode(Integer.valueOf(courseId.getText()));
mController = new ModelController(c);
try {
ResultSet rs = mController.<Course>get();
if(rs.next()){
courseCodeLbl.setText(rs.getString(1));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// return courseName;
}
public void getCourseNameOnClick(){
try {
// courseCodeLbl.setText(requestCourseName());
Thread t = new Thread(new Runnable(){
public void run(){
requestCourseName();
}
}, "Thread A");
t.start();
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This returns an exception:
Exception in thread "Thread A" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread A
How do I correctly implement threading so that every database request is executed in a second thread instead of the main thread?
I've heard of implementing Runnable but then how do I invoke different methods in run method?
Never worked with threading before but I thought it's time for it.
Threading Rules for JavaFX
There are two basic rules for threads and JavaFX:
Any code that modifies or accesses the state of a node that is part of a scene graph must be executed on the JavaFX application thread. Certain other operations (e.g. creating new Stages) are also bound by this rule.
Any code that may take a long time to run should be executed on a background thread (i.e. not on the FX Application Thread).
The reason for the first rule is that, like most UI toolkits, the framework is written without any synchronization on the state of elements of the scene graph. Adding synchronization incurs a performance cost, and this turns out to be a prohibitive cost for UI toolkits. Thus only one thread can safely access this state. Since the UI thread (FX Application Thread for JavaFX) needs to access this state to render the scene, the FX Application Thread is the only thread on which you can access "live" scene graph state. In JavaFX 8 and later, most methods subject to this rule perform checks and throw runtime exceptions if the rule is violated. (This is in contrast to Swing, where you can write "illegal" code and it may appear to run fine, but is in fact prone to random and unpredictable failure at arbitrary time.) This is the cause of the IllegalStateException you are seeing: you are calling courseCodeLbl.setText(...) from a thread other than the FX Application Thread.
The reason for the second rule is that the FX Application Thread, as well as being responsible for processing user events, is also responsible for rendering the scene. Thus if you perform a long-running operation on that thread, the UI will not be rendered until that operation is complete, and will become unresponsive to user events. While this won't generate exceptions or cause corrupt object state (as violating rule 1 will), it (at best) creates a poor user experience.
Thus if you have a long-running operation (such as accessing a database) that needs to update the UI on completion, the basic plan is to perform the long-running operation in a background thread, returning the results of the operation when it is complete, and then schedule an update to the UI on the UI (FX Application) thread. All single-threaded UI toolkits have a mechanism to do this: in JavaFX you can do so by calling Platform.runLater(Runnable r) to execute r.run() on the FX Application Thread. (In Swing, you can call SwingUtilities.invokeLater(Runnable r) to execute r.run() on the AWT event dispatch thread.) JavaFX (see later in this answer) also provides some higher-level API for managing the communication back to the FX Application Thread.
General Good Practices for Multithreading
The best practice for working with multiple threads is to structure code that is to be executed on a "user-defined" thread as an object that is initialized with some fixed state, has a method to perform the operation, and on completion returns an object representing the result. Using immutable objects, in particular, a record, for the initialized state and computation result is highly desirable. The idea here is to eliminate the possibility of any mutable state being visible from multiple threads as far as possible. Accessing data from a database fits this idiom nicely: you can initialize your "worker" object with the parameters for the database access (search terms, etc). Perform the database query and get a result set, use the result set to populate a collection of domain objects, and return the collection at the end.
In some cases it will be necessary to share mutable state between multiple threads. When this absolutely has to be done, you need to carefully synchronize access to that state to avoid observing the state in an inconsistent state (there are other more subtle issues that need to be addressed, such as liveness of the state, etc). The strong recommendation when this is needed is to use a high-level library to manage these complexities for you.
Using the javafx.concurrent API
JavaFX provides a concurrency API that is designed for executing code in a background thread, with API specifically designed for updating the JavaFX UI on completion of (or during) the execution of that code. This API is designed to interact with the java.util.concurrent API, which provides general facilities for writing multithreaded code (but with no UI hooks). The key class in javafx.concurrent is Task, which represents a single, one-off, unit of work intended to be performed on a background thread. This class defines a single abstract method, call(), which takes no parameters, returns a result, and may throw checked exceptions. Task implements Runnable with its run() method simply invoking call(). Task also has a collection of methods which are guaranteed to update state on the FX Application Thread, such as updateProgress(...), updateMessage(...), etc. It defines some observable properties (e.g. state and value): listeners to these properties will be notified of changes on the FX Application Thread. Finally, there are some convenience methods to register handlers (setOnSucceeded(...), setOnFailed(...), etc); any handlers registered via these methods will also be invoked on the FX Application Thread.
So the general formula for retrieving data from a database is:
Create a Task to handle the call to the database.
Initialize the Task with any state that is needed to perform the database call.
Implement the task's call() method to perform the database call, returning the results of the call.
Register a handler with the task to send the results to the UI when it is complete.
Invoke the task on a background thread.
For database access, I strongly recommend encapsulating the actual database code in a separate class that knows nothing about the UI (Data Access Object design pattern). Then just have the task invoke the methods on the data access object.
So you might have a DAO class like this (note there is no UI code here):
public class WidgetDAO {
// In real life, you might want a connection pool here, though for
// desktop applications a single connection often suffices:
private Connection conn ;
public WidgetDAO() throws Exception {
conn = ... ; // initialize connection (or connection pool...)
}
public List<Widget> getWidgetsByType(String type) throws SQLException {
try (PreparedStatement pstmt = conn.prepareStatement("select * from widget where type = ?")) {
pstmt.setString(1, type);
ResultSet rs = pstmt.executeQuery();
List<Widget> widgets = new ArrayList<>();
while (rs.next()) {
Widget widget = new Widget();
widget.setName(rs.getString("name"));
widget.setNumberOfBigRedButtons(rs.getString("btnCount"));
// ...
widgets.add(widget);
}
return widgets ;
}
}
// ...
public void shutdown() throws Exception {
conn.close();
}
}
Retrieving a bunch of widgets might take a long time, so any calls from a UI class (e.g a controller class) should schedule this on a background thread. A controller class might look like this:
public class MyController {
private WidgetDAO widgetAccessor ;
// java.util.concurrent.Executor typically provides a pool of threads...
private Executor exec ;
#FXML
private TextField widgetTypeSearchField ;
#FXML
private TableView<Widget> widgetTable ;
public void initialize() throws Exception {
widgetAccessor = new WidgetDAO();
// create executor that uses daemon threads:
exec = Executors.newCachedThreadPool(runnable -> {
Thread t = new Thread(runnable);
t.setDaemon(true);
return t ;
});
}
// handle search button:
#FXML
public void searchWidgets() {
final String searchString = widgetTypeSearchField.getText();
Task<List<Widget>> widgetSearchTask = new Task<List<Widget>>() {
#Override
public List<Widget> call() throws Exception {
return widgetAccessor.getWidgetsByType(searchString);
}
};
widgetSearchTask.setOnFailed(e -> {
widgetSearchTask.getException().printStackTrace();
// inform user of error...
});
widgetSearchTask.setOnSucceeded(e ->
// Task.getValue() gives the value returned from call()...
widgetTable.getItems().setAll(widgetSearchTask.getValue()));
// run the task using a thread from the thread pool:
exec.execute(widgetSearchTask);
}
// ...
}
Notice how the call to the (potentially) long-running DAO method is wrapped in a Task which is run on a background thread (via the accessor) to prevent blocking the UI (rule 2 above). The update to the UI (widgetTable.setItems(...)) is actually executed back on the FX Application Thread, using the Task's convenience callback method setOnSucceeded(...) (satisfying rule 1).
In your case, the database access you are performing returns a single result, so you might have a method like
public class MyDAO {
private Connection conn ;
// constructor etc...
public Course getCourseByCode(int code) throws SQLException {
try (PreparedStatement pstmt = conn.prepareStatement("select * from course where c_code = ?")) {
pstmt.setInt(1, code);
ResultSet results = pstmt.executeQuery();
if (results.next()) {
Course course = new Course();
course.setName(results.getString("c_name"));
// etc...
return course ;
} else {
// maybe throw an exception if you want to insist course with given code exists
// or consider using Optional<Course>...
return null ;
}
}
}
// ...
}
And then your controller code would look like
final int courseCode = Integer.valueOf(courseId.getText());
Task<Course> courseTask = new Task<Course>() {
#Override
public Course call() throws Exception {
return myDAO.getCourseByCode(courseCode);
}
};
courseTask.setOnSucceeded(e -> {
Course course = courseTask.getCourse();
if (course != null) {
courseCodeLbl.setText(course.getName());
}
});
exec.execute(courseTask);
The API docs for Task have many more examples, including updating the progress property of the task (useful for progress bars..., etc.
Related
JavaFX - Background Thread for SQL Query
Sample for accessing a local database from JavaFX using concurrent tasks for database operations so that the UI remains responsive.
Exception in thread "Thread A" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread A
The exception is trying to tell you that you are trying to access JavaFX scene graph outside the JavaFX application thread. But where ??
courseCodeLbl.setText(rs.getString(1)); // <--- The culprit
If I can't do this how do I use a background thread?
The are different approaches which leads to similar solutions.
Wrap you Scene graph element with Platform.runLater
There easier and most simple way is to wrap the above line in Plaform.runLater, such that it gets executed on JavaFX Application thread.
Platform.runLater(() -> courseCodeLbl.setText(rs.getString(1)));
Use Task
The better approach to go with these scenarios is to use Task, which has specialized methods to send back updates. In the following example, I am using updateMessage to update the message. This property is bind to courseCodeLbl textProperty.
Task<Void> task = new Task<Void>() {
#Override
public Void call() {
String courseName = "";
Course c = new Course();
c.setCCode(Integer.valueOf(courseId.getText()));
mController = new ModelController(c);
try {
ResultSet rs = mController.<Course>get();
if(rs.next()) {
// update message property
updateMessage(rs.getString(1));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
public void getCourseNameOnClick(){
try {
Thread t = new Thread(task);
// To update the label
courseCodeLbl.textProperty.bind(task.messageProperty());
t.setDaemon(true); // Imp! missing in your code
t.start();
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
This has nothing to do with database. JavaFx, like pretty much all GUI libraries, requires that you only use the main UI thread to modify the GUI.
You need to pass the data from the database back to the main UI thread. Use Platform.runLater() to schedule a Runnable to be run in the main UI thread.
public void getCourseNameOnClick(){
new Thread(new Runnable(){
public void run(){
String courseName = requestCourseName();
Platform.runLater(new Runnable(){
courseCodeLbl.setText(courseName)
});
}
}, "Thread A").start();
}
Alternatively, you can use Task.

Is the operation of toggling a button in JavaFX atomic?

A toggle button in a JavaFX operation will be accessed by 2 separate threads.
1.
One thread will be invoked as soon as user clicks (toggles button state) and will
a) do something in the OS
b) check if (a) succeeded
c) exit on success / exit and return toggle button to previous state on failure
2
The other thread will monitor events asynchronous to the previous operation(s) and in case of a particular event it will change the button state.
Do I need to provide synchronization between threads 1 and 2 in terms of locking the button state?
EDIT: The idea proposed by James_D seems reasonable, but I just wanted to propose an alternative (whose effectiveness remains to be proved however).
How about using synchronized code blocks, and using as lock the reference to the particular button, i.e. something like:
// getting the reference to the button
#FXML
private ToggleButton tButtonToBeSynchronized
// Thread1
synchronized(tButtonToBeSynchronized) {
// do stuff with button upon user click
}
// Thread2
synchronized(tButtonToBeSynchronized) {
// poll system every X seconds
// when asynchronous event occurs (not related to UI events)
// update tButtonToBeSynchronized state
}
Would that work in case these are called by different Controller classes? (assuming the reference to the tButtonToBeSynchronized is passed by reference - and not by value by the FXML framework?
Like most UI toolkits, JavaFX assumes a single threaded model. You should only ever access the state of nodes that are part of a scene graph from the FX Application Thread. So, toggling a button is not an atomic operation, and the code you describe is not guaranteed to work as you currently have it set up. In Java 8, it will likely throw a RuntimeException.
JavaFX provides functionality to enable interoperability with background threads. The lowest level of these is Platform.runLater(Runnable r), which executes r on the FX Application Thread. So, your monitor thread (item 2 in your question) should change the state of the toggle button with
Platform.runLater( () -> toggleButton.setSelected(...) );
There is also a javafx.concurrent API. This provides a Task class, among others, which acts as both a Runnable and a java.util.concurrent.FutureTask, and additionally has a collection of callback methods for submitting code to be executed on the FX Application Thread at various points in the Task's lifecycle.
So you should implement item 1 in your question as:
ExecutorService exec = ... ; // e.g. Executors.newCachedThreadPool();
toggleButton.selectedItemProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected) {
Task<Void> task = new Task<Void>() {
#Override
public Void call() throws Exception {
// do something on OS
// throw exception if failed
return null ;
}
};
task.setOnFailed(event -> toggleButton.setSelected(wasSelected));
exec.submit(task);
}
});
If you prefer to return a value indicating success or failure, you can do
Task<Boolean> task = new Task<Boolean>() {
#Override
public Boolean call() {
// do work...
boolean successful = ... ;
return successful ;
}
};
task.setOnSucceeded( event -> {
boolean wasSuccessful = task.getValue();
// ...
});

Exceptions not caught in release build (WinForm desktop app, C#, VS 2010)

I developed a desktop application, it's almost done but still contains some bugs which I'm eliminating.
I use a general [try...catch] block wrapped around my application
[STAThread]
static void Main()
{
try
{
program = new Program();
// ...
}
catch (Exception x)
{
// ...
MessageBox.Show(
message,
Resources.MESSAGEBOX_ERROR_CRASH_Caption,
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
my Program class constructor being:
public Program()
{
// [...]
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// [...]
frmLogon = new Logon();
Application.Run(frmLogon);
}
to ensure that any unhandled exception will bubble all the way up the stack and is at least responded to with some communicative message box.
It works fine when I run the application under Visual Studio (debug mode), but when I deployed it and installed on my PC, it doesn't - that's what I get when the bug (which I've already identified, by the way) causes it to read from a null array
Why? It baffles me really. Why was it "unhandled"? It was my understanding that try...catch should work regardless of whether it's release or debug mode, otherwise what would be the point.
This is kind of old, but if you still need a solution, you need to handle some events, enclosing the entire thing in a try catch won't work. Do something like this:
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AppDomain.CurrentDomain.UnhandledException += ProcessAppException;
Application.ThreadException += ProcessThrException;
Application.Run(new MainForm());
}
private static void ProcessAppException(object sender, UnhandledExceptionEventArgs e)
{
XtraFunctions.LogException((Exception)e.ExceptionObject);
throw (Exception)e.ExceptionObject; //MessageBox in your case.
}
private static void ProcessThrException(object sender, ThreadExceptionEventArgs e)
{
XtraFunctions.LogException(e.Exception);
throw e.Exception; //MessageBox in your case.
}
When an exception isn't caught, it will go through one of those before displaying the exception dialog. So you have the option to override it and display a nice message of your choice.

Resources