55502f40dc8b7c769880b10874abc9d0

Hi all i would like someone to show me how to refactor so that it is more maintainable.
Thanks

class Program
    {

        static void Main(string[] args)
        {
            try
            {
                if (args.Length == 0)
                    Import(DateTime.Now);
                else if (args.Length == 1)
                {
                    DateTime dateToImport;
                    bool isValidDate = DateTime.TryParse(args[0], out dateToImport);
                    if (isValidDate)
                    {
                        Import(dateToImport);
                    }
                    else
                        WriteToLogFile(String.Format("The Import date specified was invalid. - {0}", args[0]));
                }
                else if (args.Length == 2)
                {
                    DateTime startDate;
                    DateTime endDate;
                    bool isStartDateValid = DateTime.TryParse(args[0], out startDate);
                    bool isEndDateValid = DateTime.TryParse(args[1], out endDate);

                    if (isStartDateValid && isEndDateValid && (startDate < endDate))
                        Import(startDate, endDate);
                    else
                        WriteToLogFile(String.Format("Invalid Date Range Specified. - Start Date Entered = {0}, End Date Entered = {1}", args[0], args[1]));
                }
            }
            catch (Exception ex)
            {
                WriteToLogFile("Error in Import Process = " + ex.StackTrace);
            }
        }


        private static void Import(DateTime dateToImport)
        {
            DataLayer dl = new DataLayer();
            DataTable dt = dl.GetDataForImport(dateToImport);
            SendToWebService(dt);
        }

        private static void Import(DateTime startDate, DateTime endDate)
        {
            DataLayer dl = new DataLayer();
            DataTable dt = dl.GetDataForImport(startDate, endDate);
            SendToWebService(dt);
        }

        private static void SendToWebService(DataTable dt)
        {
            if (dt == null || dt.Rows.Count == 0)
            {
                WriteToLogFile("Nothing to import");
                return;
            }
            ImportService.ImportService importService = new ImportService.ImportService();
            System.Collections.Generic.List<ImportService.Record> myRecords = new List<ImportService.Record>();
            foreach (DataRow dr in dt.Rows)
                myRecords.Add(DataRowToObject(dr));
            importService.ImportData(myRecords.ToArray());
        }



        private static ImportService.Record DataRowToObject(DataRow myRow)
        {
            ImportService.Record myRecord = new ImportService.Record();

            myRecord.Status = myRow.ItemArray[1].ToString();
            myRecord.FirstName = myRow.ItemArray[3].ToString();
            myRecord.LastName = myRow.ItemArray[4].ToString();
            myRecord.DateLastStatus = Convert.ToDateTime(myRow.ItemArray[13].ToString());
            return myRecord;
        }


        /// <summary>
        /// Write messages to a log file for efficient tracking of the windows service
        /// </summary>
        /// <param name="strMessage"></param>
        public static void WriteToLogFile(string message)
        {
            System.IO.StreamWriter sWriter;
            string ExecutablePath = System.AppDomain.CurrentDomain.BaseDirectory;
            try
            {
                sWriter = new System.IO.StreamWriter(ExecutablePath + "\\logs\\" + "ImportTask_" + DateTime.Now.Month + "_" + DateTime.Now.Day + "_" + DateTime.Now.Year + ".log", true);
                sWriter.WriteLine("Time :" + DateTime.Now.ToShortTimeString() + " -:- " + message);
                sWriter.Flush();
                sWriter.Close();
            }
            catch (Exception ex)
            {
                // If the directory does not exist, then create the logs directory in the directory where
                // the executable resides.
                string strExceptionMessage = ex.Message;
                DirectoryInfo oDir = new DirectoryInfo(ExecutablePath);
                try
                {
                    oDir.CreateSubdirectory("logs");
                    sWriter = new System.IO.StreamWriter(ExecutablePath + "\\logs\\" + "ImportTask_" + DateTime.Now.Month + "_" + DateTime.Now.Day + "_" + DateTime.Now.Year + ".log", true);
                    sWriter.WriteLine("Time :" + DateTime.Now.ToShortTimeString() + " -:- " + message);
                    sWriter.Flush();
                    sWriter.Close();
                }
                catch (Exception dex)
                {
                }
            }
        }
    }

Refactorings

No refactoring yet !

D41d8cd98f00b204e9800998ecf8427e

Anonymous

August 13, 2009, August 13, 2009 18:45, permalink

No rating. Login to rate!

The only real issue here is the fact that everything is a static method. Construct a new Program() from your Main method and do all of your work in an *instance* of Program instead.

class Program
{
    public Program(string[] args) 
    {
        // the stuff that used to be in Main goes here
    }

    static void Main(string[] args)
    {
        Program p = new Program();
    }

    ...
}
D41d8cd98f00b204e9800998ecf8427e

Anonymous

August 13, 2009, August 13, 2009 18:45, permalink

No rating. Login to rate!

That should be new Program(args);

F9a9ba6663645458aa8630157ed5e71e

Ants

August 13, 2009, August 13, 2009 20:32, permalink

No rating. Login to rate!

Actually, there's still a couple other bits that should be fixed:

- Use of magic numbers in lines 75-78 to pick out columns. Use enums or actual column names instead?
- Why not just use myRow[x] instead of myRow.ItemArray[x] in lines 75-78?
- If the column data is already the correct types, why not cast directly to the type instead of calling .ToString()? In particular line 78, why not just cast to DateTime() if it contains a DateTime?
- Note the duplication of code in lines 93-96 and 107-110. Probably should move into a function, and that function should use the using() clause so that there is no need for the explicit Stream.Close().
- Computing the file path for log file in lines 93 and 107 should move into a function, and that function could probably stand to use Path.Combine().

Possible bug:
- On line 90, if you're app is installed under "Program Files", it is very likely that you don't have permissions to create directories and files unless you run elevated. Use Application.LocalUserAppDataPath instead, perhaps?

Consider:
- Use the Trace and the FileLogTraceListener classes perhaps to replace the explicit writes to log file? That way you can also add/create a TraceListener that outputs to the console if you wish.

@Anonymous: I recommend moving all that used to go into Main() into an instance Run(string [] args) method. I subscribe to the idea that constructors do minimal work to get setup, and that actual work be done in methods.

Your refactoring





Format Copy from initial code

or Cancel