8

I'm interested in any common routine/procedures/methods that you might use in you Program.cs when creating a .NET project. For instance I commonly use the following code in my desktop applications to allow easy upgrades, single instance execution and friendly and simple reporting of uncaught system application errors.


    using System;
    using System.Diagnostics;
    using System.Threading;
    using System.Windows.Forms;

    namespace NameoftheAssembly
    {
        internal static class Program
        {
            /// <summary>
            /// The main entry point for the application. Modified to check for another running instance on the same computer and to catch and report any errors not explicitly checked for.
            /// </summary>
            [STAThread]
            private static void Main()
            {
                //for upgrading and installing newer versions
                string[] arguments = Environment.GetCommandLineArgs();
                if (arguments.GetUpperBound(0) > 0)
                {
                    foreach (string argument in arguments)
                    {
                        if (argument.Split('=')[0].ToLower().Equals("/u"))
                        {
                            string guid = argument.Split('=')[1];
                            string path = Environment.GetFolderPath(Environment.SpecialFolder.System);
                            var si = new ProcessStartInfo(path + "\\msiexec.exe", "/x" + guid);
                            Process.Start(si);
                            Application.Exit();
                        }
                    }
                    //end of upgrade
                }
                else
                {
                    bool onlyInstance = false;
                    var mutex = new Mutex(true, Application.ProductName, out onlyInstance);
                    if (!onlyInstance)
                    {
                        MessageBox.Show("Another copy of this running");
                        return;
                    }
                    AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
                    Application.ThreadException += ApplicationThreadException;
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    Application.Run(new Form1());
                }
            }

            private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
            {
                try
                {
                    var ex = (Exception) e.ExceptionObject;
                    MessageBox.Show("Whoops! Please contact the developers with the following"
                                    + " information:\n\n" + ex.Message + ex.StackTrace,
                                    " Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                }
                catch (Exception)
                {
                    //do nothing - Another Exception! Wow not a good thing.
                }
                finally
                {
                    Application.Exit();
                }
            }

            public static void ApplicationThreadException(object sender, ThreadExceptionEventArgs e)
            {
                try
                {
                    MessageBox.Show("Whoops! Please contact the developers with the following"
                                    + " information:\n\n" + e.Exception.Message + e.Exception.StackTrace,
                                    " Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                }
                catch (Exception)
                {
                    //do nothing - Another Exception! Wow not a good thing.
                }
            }
        }
    }

I find these routines to be very helpful. What methods have you found helpful in Program.cs?

Rick
  • 648
  • 1
  • 11
  • 25
  • I find it pretty terrible that you are just dropping any additional exceptions on the floor. – John Gietzen Nov 03 '09 at 14:48
  • 3
    I don't think he's dropping additional exceptions on the floor. The only exceptions that he ignoring are the ones caused when he actually display an error message to the user, i.e the call to MessageBox.Show(). – Matt Warren Nov 03 '09 at 15:09

5 Answers5

5

I try to avoid putting anything significant in the Program.cs file. Anything that I write for a simple Console app could someday be moved to a class library, and so I'll build a separate class for the actual program logic.

That said, there is some generic code that I use over and over. The main thing is using the Trace class to handle the console output, so I don't have to change any important code in the app itself to redirect things to a log file or somewhere else later when the inevitable transition to class library or gui app occurs:

using System;
using System.Diagnostics;

public static void Main(string[] args)
{
    Trace.Listeners.Add(new ConsoleTraceListener());
    Trace.WriteLine("Program Started - " + DateTime.Now.ToString());Trace.WriteLine("");

    //Call into a separate class or method for the actual program logic
    DoSomething(); //I'll use Trace for output in here rather than Console

    Trace.WriteLine("");Trace.WriteLine("Program Finished - " + DateTime.Now.ToString());

    Console.Write("Press a key to exit...");
    Console.ReadKey(true);
    Console.WriteLine();
}
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
2

For argument parsing, the Novell Options class is the best I've seen (via "Best way to parse command line arguments in C#"). I've also adapted it for interactive console applications, for programs that don't just run and quit.

Here's an example of the Options class:

static void Main(string[] args)
{
    var p = new new OptionSet ()
         .Add ("v|verbose", v=> setVerbose())
         .Add ("h|?|help",  v=> showHelp())
         .Add ("n|name=", v=> showName(v));

    p.Parse (args);
}
Community
  • 1
  • 1
Chris S
  • 64,770
  • 52
  • 221
  • 239
1

I usually have a very small Main function that calls another function (e.g. Start) - that way, if some assembly is missing and Start cannot be JITted, I can catch the TypeLoadException and display a human-readable error message.

Niki
  • 15,662
  • 5
  • 48
  • 74
1

We usually use main for basic command-line parsing, crash handling setup, license checking, and creation of main form (assuming it's a windows application and not a console application).

However, most of that functionality is handled by other objects that main just instantiates and calls.

Jeff Yates
  • 61,417
  • 20
  • 137
  • 189
0

The only code I definitely but into every program is my Exception Handler:

At the start:

#If Not Debug Then
        AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf Me.Application_UnhandledException
        AddHandler Application.ThreadException, AddressOf Me.Application_ThreadException
#End If

Private Sub Application_UnhandledException(ByVal sender As Object, ByVal e As System.UnhandledExceptionEventArgs)
    Me.UnhandledExceptionLog(TryCast(e.ExceptionObject, Exception).Message, New StackTrace(TryCast(e.ExceptionObject, Exception), True), e.ExceptionObject)
End Sub
Private Sub Application_ThreadException(ByVal sender As Object, ByVal e As System.Threading.ThreadExceptionEventArgs)
    Me.UnhandledExceptionLog(e.Exception.Source & Environment.NewLine & e.Exception.Message & Environment.NewLine & e.Exception.StackTrace, New StackTrace(e.Exception, True), e.Exception)
End Sub

Public Sub UnhandledExceptionLog(ByVal message As String, ByVal stack As StackTrace, ByVal ex As Object)
    ' write the exception details to a log and inform the user the he screwed something ;) '
End Sub

This will catch every Exception I missed and will write it to a log of my own (asking the client what the error message stated is actually not the wisest thing...).

Bobby

Bobby
  • 11,419
  • 5
  • 44
  • 69