Search code examples
c#ftpwindows-servicesinstallutil

Can't reinstall service


I am trying to create an auto update for an application however I am having a bit of trouble with the updating part. Basically what I have is a windows service that periodically checks for updates and when it finds and update it launches a console application to update itself. The code for the console application is below.

The problem I'm having is that when I uninstall the service and replace the file that drives the service, I get a system.badimageformat exception. Despite reinstalling an identical file. If I uninstall and re-install the file without downloading it and replacing it from FTP there is no issue, but as soon as I change the file it starts giving me exceptions. Does anyone have any ideas on how I can work around this error. I am confident its not a 32 vs 64 bit issue which is what commonly causes this error.

    static void Main(string[] args)
    {
        if (!System.Diagnostics.EventLog.SourceExists("OCR Updater"))
        {
            EventLog.CreateEventSource("OCR Updater", "Application");
        }
        ServiceController sc = new ServiceController("OCR Scheduler", ".");
        if (sc.Status == ServiceControllerStatus.Running)
        {
            sc.Stop();
            sc.WaitForStatus(ServiceControllerStatus.Stopped);
        }

        ProcessStartInfo Uninstallpsi = new ProcessStartInfo();
        Uninstallpsi.Verb = "runas";
        Uninstallpsi.UseShellExecute = false;
        Uninstallpsi.FileName = AppDomain.CurrentDomain.BaseDirectory.ToString() + "installutil.exe";
        Uninstallpsi.Arguments = " /u " + "\"" + AppDomain.CurrentDomain.BaseDirectory.ToString() + "OCR_Scheduler_Service.exe\"";
        Process.Start(Uninstallpsi);

        Console.WriteLine("Sleeping Thread after uninstall");
        System.Threading.Thread.Sleep(10000);


        OCRUpdater program = new OCRUpdater();
        List<string> Files = program.GetFiles();
        foreach (string item in Files)
        {

            if (item.ToString() == "Sqlite" || item.ToString() == "License.xml")
            {
                continue;
            }
            // Get the object used to communicate with the server.
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.mccinnovations.com/OCR_Scheduler/V2Updates/Files/" + item);
            request.Method = WebRequestMethods.Ftp.DownloadFile;

            // This example assumes the FTP site uses anonymous logon.
            request.Credentials = new NetworkCredential("ftp admin", "_Stingray_12");

            FtpWebResponse response = (FtpWebResponse)request.GetResponse();

            Stream responseStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(responseStream);
            string[] temp = reader.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
            reader.Close();
            response.Close();
            string DesktopFile = "";


            try
            {
                DesktopFile = @"C:\Users\hnelson\Desktop\" + item;
                if (File.Exists(DesktopFile))
                {
                    File.Delete(DesktopFile);   
                }
                File.WriteAllLines(DesktopFile, temp);
            }
            catch (Exception ex)
            {

                EventLog.WriteEntry("OCR Updater", "Error in file path" + DesktopFile + ex.Message);
                continue;
            }
            try
            {
                File.Delete(@"C:\Program Files (x86)\MCCi\OCR Scheduler V2\" + item);
                System.Threading.Thread.Sleep(2000);
                File.Copy(DesktopFile, @"C:\Program Files (x86)\MCCi\OCR Scheduler V2\" + item, true);
                File.Delete(DesktopFile);
                EventLog.WriteEntry("OCR Updater", DesktopFile);
            }
            catch (Exception)
            {

                EventLog.WriteEntry("OCR Updater", DesktopFile);
                EventLog.WriteEntry("OCR Updater", "Error in file path " + @"C:\Program Files (x86)\MCCi\OCR Scheduler V2\" + item);
                continue;
            }


        }




        try
        {

            System.Threading.Thread.Sleep(5000);

            ProcessStartInfo psi = new ProcessStartInfo();
            psi.Verb = "runas";
            psi.UseShellExecute = false;
            psi.FileName = AppDomain.CurrentDomain.BaseDirectory.ToString() + "installutil.exe";
            psi.Arguments = " " + "\"" + AppDomain.CurrentDomain.BaseDirectory.ToString() + "OCR_Scheduler_Service.exe\"";
            Process.Start(psi);


        }
        catch (Exception ex)
        {

            EventLog.WriteEntry("OCR Updater", "Could not reinstall service" + ex.Message + ex.InnerException);
        }


        System.Threading.Thread.Sleep(10000);

        Console.WriteLine("Finished resinstalling the service.");


        try
        {



            string[] serviceStartArgs = { "true" };

            sc.Start(serviceStartArgs);
            sc.WaitForStatus(ServiceControllerStatus.Running);

        }
        catch (Exception ex)
        {

            EventLog.WriteEntry("OCR Updater", "Could not start the service after install" + " " + ex.Message + ex.InnerException);
        }

    }

    public List<string> GetFiles()
    {
        // Get the object used to communicate with the server.
        FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.mccinnovations.com/OCR_Scheduler/V2Updates/Files/");
        request.Method = WebRequestMethods.Ftp.ListDirectory;

        // This example assumes the FTP site uses anonymous logon.
        request.Credentials = new NetworkCredential("ftp admin", "_Stingray_12");

        FtpWebResponse response = (FtpWebResponse)request.GetResponse();

        Stream responseStream = response.GetResponseStream();
        StreamReader reader = new StreamReader(responseStream);
        List<string> Files = new List<string>();
        while (reader.EndOfStream == false)
        {
            Files.Add(reader.ReadLine());
        }

        reader.Close();
        response.Close();
        return Files;


    }


}

}


Solution

  • The main problem is that you treat the files as text files:

    string[] temp = reader.ReadToEnd().Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
    ....
    File.WriteAllLines(DesktopFile, temp);
    

    You can use this instead:

    Stream responseStream = response.GetResponseStream();
    
    ...
    
    using (FileStream destStream = File.Create(DesktopFile))
    {
        responseStream.CopyTo(destStream);
    }
    
    responseStream.Close();
    response.Close();
    

    However, this is still not the best solution, since you should use the pattern

    using (X123 x123 = new X123(y))
    {
        // do something with x123
    }
    

    for all classes which support IDisposable.

    In addition, I have some concerns about using Sleep() in so many situations. This is seldom a good idea.