How do I get the Exception that happens in Timer Elapsed event? - c#

I'm working with Windows Forms application and hava a manager class that uses System.Timers.Timer to periodly check data from database.
How do I get the Exception that occurs in timer Elapsed eventhandler delivered into main application? If I'm using the code below, the exception get's "swallowed", and main application never gets it (even if I have handlers for ThreadException and UnHandledException).
// Main Form
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
// Manager class
private System.Timers.Timer _timer;
void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
doSomeDatabaseActions();
}
catch (Exception ex)
{
throw new ApplicationException("How do I get this error back into main thread...", ex);
}
}

If you don't have access to the main thread, you can throw the exception on another, non-timer thread:
catch (Exception exception)
{
ThreadPool.QueueUserWorkItem(
_ => { throw new Exception("Exception on timer.", exception); });
}

Since System.Timers.Timer swallows any exception thrown in the event handler, you will need to marshal the exception to another thread (probably the UI thread). You could do this via Control.Invoke, or by storing error information in a member variable and having the UI thread check this error information after the operation is complete. If non-null, the UI could then throw.
From MSDN:
In the .NET Framework version 2.0 and
earlier, the Timer component catches
and suppresses all exceptions thrown
by event handlers for the Elapsed
event. This behavior is subject to
change in future releases of the .NET
Framework.
Just checked in .NET 4.0, and this behavior has not yet changed.

You can assign the exception to a local variable and check if an exception has been thrown:
// Main Form
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
// Manager class
private System.Timers.Timer _timer;
private exception = null;
void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
//reset the exception in case object is reused.
this.exception = null;
try
{
doSomeDatabaseActions();
}
catch (Exception ex)
{
this.exception = ex;
}
}
/**
* Checks whether the exception object is set.
*/
public bool hasExceptionOccured(){
return (this.exception != null);
}
//The main application will call this to get the exception.
public Exception getException(){
return this.exception;
}

I guess that you want to handle the exception on the main form, this solution is not complete but shows how to do it with an "Action"
using System;
using System.Timers;
public class MainForm
{
public MainForm()
{
var tm = new TestManager(exception =>
{
//do somthing with exception
//note you are still on the timer event thread
});
}
}
public class TestManager
{
private readonly Action<Exception> _onException;
public TestManager(System.Action<System.Exception> onException )
{
_onException = onException;
}
private System.Timers.Timer _timer;
void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
doSomeDatabaseActions();
}
catch (Exception ex)
{
//throw new ApplicationException("How do I get this error back into main thread...", ex);
_onException(ex);
}
}
}

Related

How can I have the main process in a Windows Service repeat upon completion

I want to create a Windows .Net service, using c#, that calls a main process in the service's OnStart event and when that main process completes, I want it to run again automatically, until I manually stop the service. The main process can take several hours to complete and the time to complete varies so I don't want to use a timer. Is it as simple as putting the main process in a while loop or should there be some other controlling mechanism?
Thanks
Building on what #itsme86 said in his comment, in my service OnStart methods, I added a thread and assigned it a method in my code, as follows;
private bool m_isRunning = false;
Thread m_thread;
protected override void OnStart(string[] args)
{
try
{
m_thread = new Thread(StartService);
m_thread.Start();
m_isRunning = true;
}
catch (Exception ex)
{
if (m_logger != null)
{
m_logger.Error(ex, "An exception has occurred in the OnStart method call");
}
throw new Exception(ex.Message);
}
}
In my OnStop method, I added the following code;
protected override void OnStop()
{
try
{
m_isRunning = false;
m_logger.Information("Application stopped.");
m_thread = null;
}
catch (Exception ex)
{
if (m_logger != null)
{
m_logger.Error(ex, "An exception has occurred in the OnStop method call");
}
throw new Exception(ex.Message);
}
}
Then I set up the loop in the StartService method, as shown below;
private void StartService()
{
try
{
InitializeLogger();
m_logger.Information("Application started.");
while (m_isRunning)
{
RunProcess();
}
}
catch (Exception ex)
{
if (m_logger != null)
{
m_logger.Error(ex, "An exception has occurred in the StartService method call");
}
throw new Exception(ex.Message);
}
}
The RunProcess method performs the service duties and when it completes, it fires again due to the while loop in the StartService method.
This all seems to work as I had wanted.

Exception throw behavior

So I have this exception I want to throw if something goes wrong. But it acts strange.
public Calendar LoadCalendar(){
...
if (cal == null)
{
throw new NotImplementedException();
}
_lastPollTime = DateTime.Now;
...
}
I expect this exception to be thrown to wherever LoadCalendar was called. Instead, the program stops at DateTime.Now; because of "NotImplementedException()".
What am I doing wrong? How could I throw it to the end of the method instead?
You need to add a "catch" clause somewhere up the call stack which receives the thrown exception and deals with it somehow.
You could try this in your programs Main function:
static void Main()
{
try
{
// put existing code here
}
catch( Exception e )
{
}
}
Without a catch, the exception has no place to go to and so instead it causes your program to terminate.
These guidlines for working with exceptions might be useful to you: http://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET
Just subscribe DispatcherUnhandledException event in App.xaml.cs Class Constructor and you can handle any application exception in this event.
public partial class App : Application
{
public App()
{
this.DispatcherUnhandledException += App_DispatcherUnhandledException;
}
void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
////Handle your application exception's here by e.Exception.
}
}

A global error handler for a class library in C#

Is there a way to catch and handle an exception for all exceptions thrown within any of the methods of a class library?
I can use a try catch construct within each method as in sample code below, but I was looking for a global error handler for a class library. The library could be used by ASP.Net or Winforms apps or another class library.
The benefit would be easier development, and no need to repeatedly do the same thing within each method.
public void RegisterEmployee(int employeeId)
{
try
{
....
}
catch(Exception ex)
{
ABC.Logger.Log(ex);
throw;
}
}
You can subscribe to global event handler like AppDomain.UnhandledException and check the method that throws exception:
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
{
var exceptionObject = unhandledExceptionEventArgs.ExceptionObject as Exception;
if (exceptionObject == null) return;
var assembly = exceptionObject.TargetSite.DeclaringType.Assembly;
if (assembly == //your code)
{
//Do something
}
}

Using MessageBox to show exception information in multithreaded application

Hi I'm working with winform and trying to use MessageBox for exception handling.
The weird thing here is, the MessageBox appears only after the main form ("Form1" in the code below) is closed.
public class Worker {
/* edited (see below)
public void doWork() {
try {
// do something
client.Connect(serverAddress);
stream = client.GetStream();
}
catch(Exception e) {
MessageBox.Show(e.ToString(),
"This will not show up until Form1 is closed");
}
}
*/
}
public class Form1 {
/* edited (see below)
* public void threadProc() {
* Worker worker = new Worker();
* worker.doWork();
* }
*/
void button_Click(object sender, EventArgs e) {
// create a thread that will end up throwing an exception
Thread thread = new Thread(threadProc);
thread.Start();
}
}
What could be a better way to use MessageBox for exception handling?
...So I added some codes for MessageBox-ing in the UI thread, but the problem remains.
public class WorkExceptionArgs : EventArgs {
public Exception e;
public WorkExceptionArgs (Exception e) { this.e = e; }
}
public partial class Worker1 { // renamed (Worker->Worker1)
/* (edited) Now Worker1 doesn't trigger any event (see below)
public event EventHandler<WorkExceptionArgs> workException;
*/
public void doWork() {
try {
// do something
client.Connect(serverAddress);
stream = client.GetStream();
}
catch(Exception e) {
/* (edited) suppose Worker1 never throws any exception (see below)
* // trigger event that will cause MessageBox-ing by UI thread
* workException(this, new WorkExceptionArgs(e));
*/
}
}
}
public partial class Form1 {
public void threadProc() {
Worker1 worker1 = new Worker();
/* (edited) Now Worker1 never throws any exception
* worker.workException += new EventHandler<WorkException>(worker_WorkException);
*/
worker1.doWork();
// (added) After doWork() is done, Form1 creates Worker2
Worker2 w2 = new Worker2(this, this.form2);
w2.workException += new EventHandlerArgs<WorkExceptionArgs>(form2.worker2_WorkException);
w2.doSomeOtherWork();
}
/* public void worker_WorkException(object sender, WorkExceptionArgs eArg) {
* MessageBox.Show(eArg.e.ToString(), "Still not showing");
* } */
Form2 form2 = new Form2(); // (added) At first form2 is hidden (see below)
}
Actually there have been another form and another worker. Once Worker(Worker1) made connection to the server, Form1 hides (.Hide()), Form2 shows (.Show()), and Worker2 starts working with the connection Worker1 made.
public class Worker2 {
Worker2(Worker1 w1, Form2 frm2) { this.w1=w1; this.frm2=frm2; }
public Worker1 w1;
public Form2 frm2;
public event EventHandler<WorkExceptionArgs> workException;
public void doSomeOtherWork() { // do some other, using data in Worker 1.
try { // This will throw an exception
BinaryFormatter formatter = new BinaryFormatter();
MyObj mo = (MyObj)formatter.Deserialize(w1.getStream());
}
catch(Exception e) {
workException(this, new WorkExceptionArgs(e));
}
}
}
public class Form2 {
public Form2(Form1 frm1) { // to switch from frm1 to frm2
InitializeComponent();
this.frm1 = frm1;
}
public Frm1 frm1 {get;set;}
public void worker2_WorkException(object sender, WorkExceptionArgs ea) {
MessageBox.Show(this, ea.e.ToString(), "SHOWS ONLY IF FORM2 IS CLOSED");
}
}
public partial class Form1 {
delegate void switchWindow_Callback();
public void switchWindow() { this.Hide(); form2.Show(); }
public void switchWindowCb(object sender, EventArgs e) {
if(this.InvokeRequired) {
SwitchWindow_Callback hcb = new SwitchWindow_Callback(switchWindow);
this.Invoke(hcb, new object[] {});
}
else { this.switchWindow(); }
}
}
Actually I'll bet the MessageBox is appearing behind the main form, and you just don't see it until you close it.
You'd be much better off letting the UI thread (the one that created and owns Form1) do the MessageBox-ing. You either want to make events, or otherwise have an error callback delegate in your worker class.
However, BackgroundWorker may be worth checking out here rather than trying to roll your own. Assuming it's a fatal exception, you can save and retrieve the error state, and you get an event automatically called when the thread finishes.
You should really be locking down the doWork method so that multiple threads cant access it at the same time, they need to queue.
Look into "Joining Threads". Imagine if you get two exception at the same time. Your app will fall over. Locking down the area of code that will be duplicated repeatedly will form a queue for your threads to access the area of code that handles the exception.
As lc stated, it's quite likely that your message box is appearing behind the main form, and therefore you only see it when the main form is closed.
The model I use to deal with unhandled exceptions in a Windows Forms app looks like this:
// Switch-off the Windows Forms default handler for unhandled exceptions.
// NB From .NET 4 upwards, this won't work if the process state is corrupted.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Setup event handler to intercept an unhandled exception on a UI thread .
// NB The exception will still terminate the application.
// But you can show a MessageBox in the event handler and log the exception.
Application.ThreadException +=
new ThreadExceptionEventHandler(App_UiThreadException);
// Setup event handler to intercept an unhandled exception on a non-UI thread.
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(App_NonUiThreadException);
// Run the application (open main form etc).
The first line says that you want to catch any unhandled exception and deal with it yourself rather than letting the WinForms infrastructure deal with it. Note that from .NET 4 onwards, this setting won't work for an exception that corrupts process state (for example OutOfMemory).
If you have an unhandled exception on a UI thread, the second line will trigger a procedure you create called *App_UiThreadException*. That's where your MesssageBox code should go.
If you have an unhandled exception on a non-UI thread, the last line will trigger a procedure you create called *App_NonUiThreadException*. That's where your MesssageBox code should go.

ServiceBase.Run, why can't I catch it's exceptions, or react to them in some other way?

I'm calling the following from my entry point static main method:
try { ServiceBase.Run(new MonitorSer()); }
catch (Exception ex) { Console.WriteLine(ex.Message + Process.GetCurrentProcess().MainModule.FileName); }
MonitorSer is an instance of:
class MonitorSer : ServiceBase {
and the entry main method is a member of my class:
[RunInstaller(true)]
public class WindowsServiceInstaller : Installer {
I've had good results catching exceptions for debugging but sometimes they seem to find their own way around my traps, as in this case.
I get a windows box flash up telling me I need to install using installutil when what I really want is to find the name of this process and call it again with the -i switch which I have wired up to make it install intself (credit to those here who contributed/recycled that code).
What makes this more frustrating is that if I set breakpoints upto (or on) the call to ServiceBase.Run, it will fail silently and I am left with the blinking console.
UPDATE
static void Install(bool undo, string[] args)
{
try
{
Console.WriteLine(undo ? "uninstalling" : "installing");
using (AssemblyInstaller inst = new AssemblyInstaller(typeof(MonitorSer).Assembly, args))
{
IDictionary state = new Hashtable();
inst.UseNewContext = true;
try
{
if (undo) inst.Uninstall(state);
else
{
inst.Install(state);
inst.Commit(state);
}
}
catch
{
try
{
inst.Rollback(state);
}
catch { }
throw;
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
}
I clumped the entry point here so I could call the above function, I'll try moving that to another class and setting the entry point there, but I know I can make this entry point (that you, Dmitry, deny) work by calling itself with the appropriate argument to install- which only the BaseService class can do- correct me if I am wrong.
[RunInstaller(true)]
public class WindowsServiceInstaller : Installer
Is not your entry point. This will get called once when you install your service using InstallUtil.exe. Entry point can be specified in the project properties and it usually defaults to Program.Main. You should not be starting your service from Installer class.
CLR will let you know of unhandled exceptions if you subscribe to this event:
static void Main() {
...
AppDomain.CurrentDomain.UnhandledException
+= CurrentDomain_UnhandledException;
...
}
private static void CurrentDomain_UnhandledException(
Object sender,
UnhandledExceptionEventArgs e) {
if (e != null && e.ExceptionObject != null) {
// log exception:
}
}
This event provides notification of uncaught exceptions. It allows the
application to log information about the exception before the system
default handler reports the exception to the user and terminates the application
...
Starting with the .NET Framework version 4, this event is not raised
for exceptions that corrupt the state of the process, such as stack
overflows or access violations, unless the event handler is
security-critical and has the
HandleProcessCorruptedStateExceptionsAttribute attribute.
application.
Another place where you might want to log exceptions in windows service (because .NET/SCM will swallow startup exceptions):
protected override void OnStart(String[] args) {
try {
} catch(Exception e) {
// log exception:
throw;
}
}

Categories

Resources