俞晖提到把Main()单独放到一个命名为App的类中,并在Main的开始初始化进行当前应用程序域的异常处理和应用程序的日志记录。
感觉到比较像企业级开发的模式,这些都是与业务无关的设计,但对于一个系统来说,这些是必须的。线程异常的处理保证了系统的健壮性,当然系统健壮性依靠这一点是不够的,还需要更详细的异常处理机制。日志的记录对于系统Release后的Bug修复会有很大的帮助。所以设计一个系统请加上这些处理过程:
using
System;
using SWF = System.Windows.Forms;
using ST = System.Threading;
using T = System.Diagnostics.Trace;
namespace MyAppDemo
{
public class App
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
public static void Main()
{
try
{
// setup generic exception handler
SWF.Application.ThreadException += new ST.ThreadExceptionEventHandler(App.OnAppException);
// setup cleanup routine for normal app shutdown
SWF.Application.ThreadExit += new System.EventHandler(App.OnAppExit);
// when app starts, delete the previous log file (if any)
string logfile = System.AppDomain.CurrentDomain.BaseDirectory + " AppLog.txt " ;
System.IO.TextWriter log = new System.IO.StreamWriter(logfile);
if (Globals.Trace) // then also send trace output to log file?
{
System.Diagnostics.TextWriterTraceListener logger;
logger = new System.Diagnostics.TextWriterTraceListener(log);
System.Diagnostics.Trace.Listeners.Add(logger);
System.Diagnostics.Trace.WriteLine( " App starting: " + DateTime.Now);
}
SWF.Application.Run( new Form1());
}
catch (Exception ex)
{
OnAppException( null , new ST.ThreadExceptionEventArgs(ex));
}
}
/// <summary>
/// Generic exception handler for application.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void OnAppException( object sender, ST.ThreadExceptionEventArgs e)
{
Exception ex;
ex = e.Exception;
// inform user
SWF.MessageBox.Show( " Halting due to error: " + ex.Message, " Bank Customer App " , System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
// log it (the entire exception chain)
T.WriteLine( " Generic Application Exception Handler: " );
while (ex != null )
{
T.WriteLine(ex.GetType().FullName);
T.Indent();
T.WriteLine( " Msg: " + ex.Message);
T.WriteLine( " Trace: " + ex.StackTrace);
T.Unindent();
T.Flush();
ex = ex.InnerException;
} // while
// halt app
T.Close();
SWF.Application.Exit();
}
/// <summary>
/// Called during normal application termination.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void OnAppExit( object sender, System.EventArgs e)
{
T.Close(); // close trace file
}
} // class
} // namespace
using SWF = System.Windows.Forms;
using ST = System.Threading;
using T = System.Diagnostics.Trace;
namespace MyAppDemo
{
public class App
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
public static void Main()
{
try
{
// setup generic exception handler
SWF.Application.ThreadException += new ST.ThreadExceptionEventHandler(App.OnAppException);
// setup cleanup routine for normal app shutdown
SWF.Application.ThreadExit += new System.EventHandler(App.OnAppExit);
// when app starts, delete the previous log file (if any)
string logfile = System.AppDomain.CurrentDomain.BaseDirectory + " AppLog.txt " ;
System.IO.TextWriter log = new System.IO.StreamWriter(logfile);
if (Globals.Trace) // then also send trace output to log file?
{
System.Diagnostics.TextWriterTraceListener logger;
logger = new System.Diagnostics.TextWriterTraceListener(log);
System.Diagnostics.Trace.Listeners.Add(logger);
System.Diagnostics.Trace.WriteLine( " App starting: " + DateTime.Now);
}
SWF.Application.Run( new Form1());
}
catch (Exception ex)
{
OnAppException( null , new ST.ThreadExceptionEventArgs(ex));
}
}
/// <summary>
/// Generic exception handler for application.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void OnAppException( object sender, ST.ThreadExceptionEventArgs e)
{
Exception ex;
ex = e.Exception;
// inform user
SWF.MessageBox.Show( " Halting due to error: " + ex.Message, " Bank Customer App " , System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
// log it (the entire exception chain)
T.WriteLine( " Generic Application Exception Handler: " );
while (ex != null )
{
T.WriteLine(ex.GetType().FullName);
T.Indent();
T.WriteLine( " Msg: " + ex.Message);
T.WriteLine( " Trace: " + ex.StackTrace);
T.Unindent();
T.Flush();
ex = ex.InnerException;
} // while
// halt app
T.Close();
SWF.Application.Exit();
}
/// <summary>
/// Called during normal application termination.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void OnAppExit( object sender, System.EventArgs e)
{
T.Close(); // close trace file
}
} // class
} // namespace
using
System;
using SC = System.Collections;
using CFG = System.Configuration.ConfigurationSettings;
namespace BankCustomerApp
{
public class Globals
{
public static readonly string AppHomeDir;
public static SC.ArrayList Customers;
public static readonly bool Trace;
/// <summary>
/// Constructor to initialize globals (called automatically upon first use of class)
/// </summary>
static Globals()
{
AppHomeDir = System.AppDomain.CurrentDomain.BaseDirectory;
Customers = new SC.ArrayList();
try // to read trace setting
{
Trace = System.Convert.ToBoolean( CFG.AppSettings[ " Tracing " ] );
}
catch
{
Trace = false ;
}
}
} // class
} // namespace
using SC = System.Collections;
using CFG = System.Configuration.ConfigurationSettings;
namespace BankCustomerApp
{
public class Globals
{
public static readonly string AppHomeDir;
public static SC.ArrayList Customers;
public static readonly bool Trace;
/// <summary>
/// Constructor to initialize globals (called automatically upon first use of class)
/// </summary>
static Globals()
{
AppHomeDir = System.AppDomain.CurrentDomain.BaseDirectory;
Customers = new SC.ArrayList();
try // to read trace setting
{
Trace = System.Convert.ToBoolean( CFG.AppSettings[ " Tracing " ] );
}
catch
{
Trace = false ;
}
}
} // class
} // namespace