preferred way of exiting a command line program - part 2 - c#

I tried to edit this question: What's the preferred way of exiting a command line program?
But my edit was rejected. I'm not allowed to comment, hence I'll take the risk of duplicating the question.
The original question was "What is the best way to exit a command line program". The best way is obviously to return from Main(), but what if I want to exit from an event handler like Console.CancelKeyPress or a Timer?
Is the only way to exit "far away" from Main(), like in an event handler, the Environment.Exit() method? It's possibly unsafe because Environment.Exit() will not clean up.
Example code:
class Program
{
static void Main(string[] args)
{
Timer t = new Timer(4000);
t.Elapsed += t_Elapsed;
t.Start();
while (true)
{
System.Threading.Thread.Sleep(1000);
}
}
static void t_Elapsed(object sender, ElapsedEventArgs e)
{
// I want to exit here
}
}

Providing your program is single-threaded, you can throw a custom exception, and catch it no soner than in the Main() method. That gives you plenty of opportunities to perform any cleanup (e.g. in finally blocks) to achieve graceful exit. Like this:
public class ExitProgramException : Exception { }
public void SomeNestedStuff()
{
...
if (...) throw new ExitProgramException();
...
}
public void Main()
{
try
{
...
SomeNestedStuff();
...
}
catch (ExitProgramException)
{
Console.WriteLine("Bye!");
}
}
However, if your program is multi-threaded, then you will need to implement some more complex graceful exit mechanism, depending on the specifics of your business logic.

Related

Need to implement "Scan" method in dll (non blocking)

Sorry for the title, i didn't find it easy to resume.
My issue is that I need to implement a c# dll that implements a 'scan' method, but this scan, when invoked, must not block the main thread of the application using the dll. Moreover, it is a duty that after the scan resolves it rises an Event.
So my issue (in the deep) is that i'm not so experienced at c#, and after very hard investigation i've come up with some solutions but i'm not very sure if they are the "right" procedures.
In the dll i've come up with:
public class Reader
{
public delegate void ReaderEventHandler(Object sender, AlertEventArgs e);
public void Scan(String ReaderName)
{
AlertEventArgs alertEventArgs = new AlertEventArgs();
alertEventArgs.uuiData = null;
//Code with blocking scan function here
if (ScanFinnished)
{
alertEventArgs.uuiData = "Scan Finnished!";
}
alertEventArgs.cardStateData = readerState[0].eventState;
ReaderEvent(new object(), alertEventArgs);
}
public event ReaderEventHandler ReaderEvent;
}
public class AlertEventArgs : EventArgs
{
#region AlertEventArgs Properties
private string _uui = null;
private uint cardState = 0;
#endregion
#region Get/Set Properties
public string uuiData
{
get { return _uui; }
set { _uui = value; }
}
public uint cardStateData
{
get { return cardState; }
set { cardState = value; }
}
#endregion
}
While in the main app I do:
Reader reader;
Task polling;
String SelectedReader = "Some_Reader";
private void bButton_Click(object sender, EventArgs e)
{
reader = new Reader();
reader.ReaderEvent += new Reader.ReaderEventHandler(reader_EventChanged);
polling = Task.Factory.StartNew(() => reader.Scan(SelectedReader));
}
void reader_EventChanged(object sender, AlertEventArgs e)
{
MessageBox.Show(e.uuiData + " Estado: " + e.cardStateData.ToString("X"));
reader.Dispose();
}
So here, it works fine but i don't know if it's the proper way, in addition i'm not able to handle possible Exceptions generated in the dll.
Also tried to use async/await but found it difficult and as I understand it's just a simpler workaround Tasks.
What are the inconvinients of this solution? how can i capture Exceptions (are they in other threads and that's why i cant try/catch them)? Possible concept faults?
When your class sends events, the sender usually is that class, this. Having new object() as sender makes absolutely no sense. Even null would be better but... just use this.
You shouldn't directly raise events as it might result in race conditions. Might not happen easily in your case but it's just a good guideline to follow. So instead of calling ReaderEvent(new object(), alertEventArgs); call RaiseReaderEvent(alertEventArgs); and create method for it.
For example:
private void RaiseReaderEvent(AlertEventArgs args)
{
var myEvent = ReaderEvent; // This prevents race conditions
if (myEvent != null) // remember to check that someone actually subscribes your event
myEvent(this, args); // Sender should be *this*, not some "new object()".
}
Though I personally like a bit more generic approach:
private void Raise<T>(EventHandler<T> oEvent, T args) where T : EventArgs
{
var eventInstance = oEvent;
if (eventInstance != null)
eventInstance(this, args);
}
Which can then be used to raise all events in same class like this:
Raise(ReaderEvent, alertEventArgs);
Since your scan should be non-blocking, you could use tasks, async/await or threads for example. You have chosen Tasks which is perfectly fine.
In every case you must understand that when you are not blocking your application, your application's main thread continues going like a train. Once you jump out of that train, you can't return. You probably should declare a new event "ErrorEvent" that is raised if your scan-procedure catches an exception. Your main application can then subscribe to that event as well, but you still must realize that those events are not (necessarily) coming from the main thread. When not, you won't be able to interact with your GUI directly (I'm assuming you have one due to button click handler). If you are using WinForms, you'll have to invoke all GUI changes when required.
So your UI-thread safe event handler should be something like this:
void reader_EventChanged(object sender, AlertEventArgs e)
{
if (InvokeRequired) // This true for others than UI Thread.
{
Invoke((MethodInvoker)delegate
{
Text = "My new title!";
});
}
else
Text = "My new title!";
}
In WPF there's Dispather that handles similar invoking.

Launching Winform App Using Static Form Variable

I am wondering if using a program level static Form variable to hold a reference to my MainUI form is a safe technique, or am I introducing something that can cause threading or other problems? Specifically, I am concerned about calling instance methods on the static variable from multiple locations within the application. As long as all calls to these instance methods occur within the application thread am I safe?
static class Program
{
static internal MainUI MainUI;
[STAThread]
static void Main()
{
...
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
MainUI = new MainUI();
Application.Run(MainUI);
...
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
...
MainUI.SetBusyState(false);
...
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
...
MainUI.SetBusyState(false);
...
}
The above code accomplishes a couple of things.
First, the application itself has hundreds of different calls to retrieve data over the internet, which often take a couple of seconds to complete. During this time the MainUI needs to be disabled and a wait cursor displayed. Instead of wrapping every call in a try catch block just to properly reset the state of the MainUI in case of an exception, I can depend on the Application_ThreadException and CurrentDomain_UnhandledException handlers where I can reenable the UI using the MainUI.SetBusyState method.
Second, I can create useful instance methods on the MainUI and make them available in a clean fashion to the rest of the application using Program.MainUI. For example, I can use Program.MainUI.SetBusyState in my user controls instead of ((MainUI)this.ParentForm).SetBusyState. But using instance methods like this is my primary concern.
Thanks!
It's pretty legit what you've done there because the app itself will only have one main form that will only be destroyed when the app is closed. If you were doing this with other forms it would be more of an issue.
If you do, however, want to get rid of the static variable you can do this:
[STAThread]
static void Main()
{
MainUI form = new MainUI();
AppDomain.CurrentDomain.UnhandledException += (s,e)=> {
form.SetBusyState(false);
};
Application.ThreadException += (s,e)=> {
form.SetBusyState(false);
};
Application.Run(form);
}

Code improvement: Better alternatives to this pattern?

In a similar question:
What is this pattern called? Soft Lock?
I was asking about the name of the pattern for the code listing below.
public class MyClass
{
public event EventHandler MyEvent;
private bool IsHandlingEvent = false;
public MyClass()
{
MyEvent += new EventHandler(MyClass_MyEvent);
}
void MyClass_MyEvent(object sender, EventArgs e)
{
if (IsHandlingEvent) { return; }
IsHandlingEvent = true;
{
// Code goes here that handles the event, possibly invoking 'MyEvent' again.
// IsHandlingEvent flag is used to avoid redundant processing. What is this
// technique, or pattern called.
// ...
}
IsHandlingEvent = false;
}
}
It seems that most of the conversation was centered around why we should an should not do this, so I think that this question provides a better forum to tackle the problem and address all of the issues. What is the better / proper way to handle this?
There are series of problems with that pattern. If you want to invoke the handler only once, you would do something like this:
protected static object _lockObj = new object();
protected static bool _isHandled = false;
void MyClass_MyEvent(object sender, EventArgs e)
{
if(_isHandled)
return;
lock(_lockObj)
{
if(_isHandled)
return;
_isHandled = true;
MyOtherPossiblyRecursiveMethod(); // Actually does all your work
_isHandled = false;
}
}
void MyOtherPossiblyRecursiveMethod()
{
}
This way, only one thread should be able to access the actual work method.
I will use something like:
using( var sl = new SoftLock() )
{
sl.Execute(()=>{....});
}
the execute will raise the internal boolean to prevent re-entering. In the dispose that flag would be resetted. Execute will call the lambda just if the flag is false. This is to ensure flag go to false even if exception happens ( causing handler never executed ) and maybe is a little better to see. Of course this is not thread safe, as the original code, but this because we are talking about preventing double execution from the same thread.
The original code is a sufficient (and very lightweight) way to prevent recursion in a single-threaded app. So if during your event handling function you could get into code that might be firing the event again you will not enter infinite recursion.
But the code is not sufficient to prevent access from multiple threads, due to the potential for race conditions. If you need to ensure only one thread gets to run this event, then you should use a stronger locking mechanism, like a Mutex or Semaphore.
The following works in single- and multi-threaded scenarios and is exception-safe... also if need be it can be modified to allow for a certain level of reentrancy (for example 3 levels)...
public class MyClass
{
public event EventHandler MyEvent;
private int IsHandlingEvent = 0;
public MyClass()
{
MyEvent += new EventHandler(MyClass_MyEvent);
}
void MyClass_MyEvent(object sender, EventArgs e)
{
// this allows for nesting if needed by comparing for example < 3 or similar
if (Interlocked.Increment (ref IsHandlingEvent) == 1 )
{
try {
}
finally {};
}
Interlocked.Decrement (ref IsHandlingEvent);
}
}

How to avoid error message window

we're having an application on server instance and quite rarely, but we have out of memory exception (program is not leaking, just instance is quite small and it operates with quite big amounts of data).
That would be not a problem, as we monitor processes on that server instance and if some of the processes are not found in process list, alert email is sent.
Now the problem is with this:
That prevents process from disappearing from process list, so we don't get alert email about it's failure. Is it possible to disable this message, that if program fails on something we don't catch, it would close without user interaction?
Assuming Windows Forms, I typically do multiple steps to prevent this message box.
First, I connect several handlers in the Main function:
[STAThread]
private static void Main()
{
Application.ThreadException +=
application_ThreadException;
Application.SetUnhandledExceptionMode(
UnhandledExceptionMode.CatchException);
AppDomain.CurrentDomain.UnhandledException +=
currentDomain_UnhandledException;
Application.Run(new MainForm());
}
Those handlers are being called when an otherwise unhandled exception occurs. I would define them something like:
private static void application_ThreadException(
object sender,
ThreadExceptionEventArgs e)
{
doHandleException(e.Exception);
}
private static void currentDomain_UnhandledException(
object sender,
UnhandledExceptionEventArgs e)
{
doHandleException(e.ExceptionObject as Exception);
}
The actual doHandleException function that is then called does the actual error handling. Usually this is logging the error and notifying the user, giving him the options to continue the application or quit it.
An example from a real-world application looks like:
private static void doHandleException(
Exception e)
{
try
{
Log.Instance.ErrorException(#"Exception.", e);
}
catch (Exception x)
{
Trace.WriteLine(string.Format(
#"Error during exception logging: '{0}'.", x.Message));
}
var form = Form.ActiveForm;
if (form == null)
{
MessageBox.Show(buildMessage(e),
"MyApp", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
MessageBox.Show(form, buildMessage(e),
"MyApp", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
With the helper function:
public static string buildMessage(Exception exception)
{
var result = new StringBuilder();
while (exception != null)
{
result.AppendLine(exception.Message);
result.AppendLine();
exception = exception.InnerException;
}
return result.ToString().Trim();
}
If you are using not Windows Forms but e.g. a Console application or WPF, some handlers are not present, while others are present instead.
The idea stays the same: Subscribe to event handlers that are being called if you have no try...catch around your code blocks.
Personally, I try to have as few of those try...catch blocks as possible (ideally none).
don't know if you can deactivate this - but I think you should not.
Find the bug/problem in your application and handle the problem with a craceful shutdown or by preventing the problem in first case.
Everything else will be a real crude workaround and I don't think your client will be pleased to have such a behavior (after all won't there be data lost? If not this has allways the buggy / not finished touch)
You could put a global try/catch block in your program and exit the program on any unexpected exception.
If using WPF you can try-catch the following two exceptions in your app.xaml.cs. There may be other/complementary exceptions to handle, but this are the two I am usually looking for:
AppDomain.CurrentDomain.UnhandledException - "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. If sufficient information about the state of the application is available, other actions may be undertaken — such as saving program data for later recovery. Caution is advised, because program data can become corrupted when exceptions are not handled."
Dispatcher.UnhandledException - "Occurs when a thread exception is thrown and uncaught during execution of a delegate by way of Invoke or BeginInvoke."
ie:
public partial class App : Application
{
public App()
{
this.Dispatcher.UnhandledException += DispatcherUnhandledException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
}
private void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// log and close gracefully
}
private new void DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
e.Handled = true;
// log and close gracefully
}
}

.NET Global exception handler in console application

Question: I want to define a global exception handler for unhandled exceptions in my console application. In asp.net, one can define one in global.asax, and in windows applications /services, one can define as below
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler);
But how can I define a global exception handler for a console application ?
currentDomain seems not to work (.NET 2.0) ?
Edit:
Argh, stupid mistake.
In VB.NET, one needs to add the "AddHandler" keyword in front of currentDomain, or else one doesn't see the UnhandledException event in IntelliSense...
That's because the VB.NET and C# compilers treat event handling differently.
No, that's the correct way to do it. This worked exactly as it should, something you can work from perhaps:
using System;
class Program {
static void Main(string[] args) {
System.AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionTrapper;
throw new Exception("Kaboom");
}
static void UnhandledExceptionTrapper(object sender, UnhandledExceptionEventArgs e) {
Console.WriteLine(e.ExceptionObject.ToString());
Console.WriteLine("Press Enter to continue");
Console.ReadLine();
Environment.Exit(1);
}
}
Do keep in mind that you cannot catch type and file load exceptions generated by the jitter this way. They happen before your Main() method starts running. Catching those requires delaying the jitter, move the risky code into another method and apply the [MethodImpl(MethodImplOptions.NoInlining)] attribute to it.
If you have a single-threaded application, you can use a simple try/catch in the Main function, however, this does not cover exceptions that may be thrown outside of the Main function, on other threads, for example (as noted in other comments). This code demonstrates how an exception can cause the application to terminate even though you tried to handle it in Main (notice how the program exits gracefully if you press enter and allow the application to exit gracefully before the exception occurs, but if you let it run, it terminates quite unhappily):
static bool exiting = false;
static void Main(string[] args)
{
try
{
System.Threading.Thread demo = new System.Threading.Thread(DemoThread);
demo.Start();
Console.ReadLine();
exiting = true;
}
catch (Exception ex)
{
Console.WriteLine("Caught an exception");
}
}
static void DemoThread()
{
for(int i = 5; i >= 0; i--)
{
Console.Write("24/{0} =", i);
Console.Out.Flush();
Console.WriteLine("{0}", 24 / i);
System.Threading.Thread.Sleep(1000);
if (exiting) return;
}
}
You can receive notification of when another thread throws an exception to perform some clean up before the application exits, but as far as I can tell, you cannot, from a console application, force the application to continue running if you do not handle the exception on the thread from which it is thrown without using some obscure compatibility options to make the application behave like it would have with .NET 1.x. This code demonstrates how the main thread can be notified of exceptions coming from other threads, but will still terminate unhappily:
static bool exiting = false;
static void Main(string[] args)
{
try
{
System.Threading.Thread demo = new System.Threading.Thread(DemoThread);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
demo.Start();
Console.ReadLine();
exiting = true;
}
catch (Exception ex)
{
Console.WriteLine("Caught an exception");
}
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine("Notified of a thread exception... application is terminating.");
}
static void DemoThread()
{
for(int i = 5; i >= 0; i--)
{
Console.Write("24/{0} =", i);
Console.Out.Flush();
Console.WriteLine("{0}", 24 / i);
System.Threading.Thread.Sleep(1000);
if (exiting) return;
}
}
So in my opinion, the cleanest way to handle it in a console application is to ensure that every thread has an exception handler at the root level:
static bool exiting = false;
static void Main(string[] args)
{
try
{
System.Threading.Thread demo = new System.Threading.Thread(DemoThread);
demo.Start();
Console.ReadLine();
exiting = true;
}
catch (Exception ex)
{
Console.WriteLine("Caught an exception");
}
}
static void DemoThread()
{
try
{
for (int i = 5; i >= 0; i--)
{
Console.Write("24/{0} =", i);
Console.Out.Flush();
Console.WriteLine("{0}", 24 / i);
System.Threading.Thread.Sleep(1000);
if (exiting) return;
}
}
catch (Exception ex)
{
Console.WriteLine("Caught an exception on the other thread");
}
}
You also need to handle exceptions from threads:
static void Main(string[] args) {
Application.ThreadException += MYThreadHandler;
}
private void MYThreadHandler(object sender, Threading.ThreadExceptionEventArgs e)
{
Console.WriteLine(e.Exception.StackTrace);
}
Whoop, sorry that was for winforms, for any threads you're using in a console application you will have to enclose in a try/catch block. Background threads that encounter unhandled exceptions do not cause the application to end.
I just inherited an old VB.NET console application and needed to set up a Global Exception Handler. Since this question mentions VB.NET a few times and is tagged with VB.NET, but all the other answers here are in C#, I thought I would add the exact syntax for a VB.NET application as well.
Public Sub Main()
REM Set up Global Unhandled Exception Handler.
AddHandler System.AppDomain.CurrentDomain.UnhandledException, AddressOf MyUnhandledExceptionEvent
REM Do other stuff
End Sub
Public Sub MyUnhandledExceptionEvent(ByVal sender As Object, ByVal e As UnhandledExceptionEventArgs)
REM Log Exception here and do whatever else is needed
End Sub
I used the REM comment marker instead of the single quote here because Stack Overflow seemed to handle the syntax highlighting a bit better with REM.
What you are trying should work according to the MSDN doc's for .Net 2.0. You could also try a try/catch right in main around your entry point for the console app.
static void Main(string[] args)
{
try
{
// Start Working
}
catch (Exception ex)
{
// Output/Log Exception
}
finally
{
// Clean Up If Needed
}
}
And now your catch will handle anything not caught (in the main thread). It can be graceful and even restart where it was if you want, or you can just let the app die and log the exception. You woul add a finally if you wanted to do any clean up. Each thread will require its own high level exception handling similar to the main.
Edited to clarify the point about threads as pointed out by BlueMonkMN and shown in detail in his answer.

Categories