Write a Updater Application Block Wrapper Class and include the PostProcessor in it. Previously I showed you the C# code for a UAB Wrapper Class, that is reusable in any Sel-Updating application.
Since you probably will have multiple DLLs and EXEs in an application of any size or complexity, you probably will not want to have to download assemlys that have not changed. For example, the Microsoft Application Block files (8) have to be deployed to the client in order for the Self-Updating application to update itself. Obviously, you do not want to have to download those files each time your application is updated, since they do not change. Some of your own application files probably will not change very often and you only want to download those files that have changed.
This article will give you the C# Code for a PostProcessor Class that is called from the UAB Wrapper Class, in the StartNewVersion method of the Wrapper Class.
Several things must be accomplished in this PostProcessor. They are listed in the order that they will be performed.
That's about all there is to the PostProcessor for my test app. You can add anything that your application might need, after it is downloaded, but before it can be restarted.
I have added a call to the PostProcessor to the UAB Wrapper Class, if the application has requested that the PostProcessor be called. That code has been extracted from the UAB Wrapper and shown in Figure 1.
Figure 1 - Modifications to the UAB Wrapper Class To Call the PostProcessor.
| /// <summary> /// If PostProcessor is required, call that DLL to move the files /// that were not updated. /// Finally, start AppStart.exe and dispose of this application. /// AppStart.exe will start the new version. /// /// private bool StartNewDownloadedVersion( ServerApplicationInfo server ) { try { if (server==null) { this.CantStart("server info is null"); return false; } // if PostProcessor is called for, run it if(RunPostProcessor) { InfoPro.UABWrapper.PostProcessor pp = new PostProcessor(ExeName); bool ok = pp.CopyFilesNotUpdated(); if (!ok) {return false;} } XmlDocument doc = new XmlDocument(); // load config file to get base dir doc.Load( AppDomain.CurrentDomain.SetupInformation.ConfigurationFile); // get the base dir string baseDir = doc.SelectSingleNode( "configuration/appUpdater/UpdaterConfiguration/application/client/baseDir") .InnerText; if (baseDir.Length==0) { throw(new Exception("baseDir is empty")); } string newDir = Path.Combine( baseDir, "AppStart.exe" ); ProcessStartInfo process = new ProcessStartInfo( newDir ); process.WorkingDirectory = Path.Combine( newDir , server.AvailableVersion ); // launch new version (actually, launch AppStart.exe // which HAS pointer to new version ) Process.Start( process ); // tell updater to stop CurrentDomain_ProcessExit( null, null ); // leave this app Environment.Exit( 0 ); // control should not reach here, but it satifies the compiler return true; } catch(System.Exception ex) { // add your code here this.NewVersionStartFailed(ex, new EventArgs()); return false; } } |
| using System; using System.IO; using System.Text.RegularExpressions; using System.Collections; using System.Configuration; using System.Diagnostics; namespace UABWrapper { /// <summary> /// This class handles the post processing of files. /// Since we may not want to transfer all files, /// because all files were not updated, this object /// is called after the files are downloaded by the /// downcompleted event to check the list of files /// in the current executing folder against the /// new version folder. It will copy any files from /// the current that do not exist in the new. It /// must verify that there is a a new folder (in case /// the validation or download failed and the UAB /// deleted all of the files). /// The assumption is that the Root folder, where /// AppStart resides, contains version folders as: /// c:\AppRoot /// c:\Approot\1.0.0.0 /// c:\AppRoot\2.0.0.0 /// AppStart.exe.config always points to the latest /// version folder. /// public class PostProcessor { public PostProcessor(string appName) { AppName = appName; } #region Class Level Variables private string _AppName; private string _ThisExePath; private string _NewVersionPath; private UABWrapper.XMLConfigurationHandler xCH; #endregion #region Public Properties public string AppName { get {return _AppName;} set {_AppName = value;} } public string ThisExePath { get{return _ThisExePath;} set{_ThisExePath = value;} } public string NewVersionPath { get{return _NewVersionPath;} set{_NewVersionPath = value;} } #endregion #region Public Methods /// <summary> /// Make a list of files in the new directory and copy /// any missing files from the old directory. /// /// <returns>true if successful public bool CopyFilesNotUpdated() { ArrayList missingFiles = GetMissingFilePaths(AppName); return CopyFileList(missingFiles); } #endregion #region Private Methods /// <summary> /// Copy the list of files from the old directory /// to the new version path /// /// private bool CopyFileList(ArrayList missingFiles) { for (int i =0; i<missingFiles.Count; i++)<BR> { string oldFile = Path.Combine(ThisExePath,missingFiles[i].ToString()); string newFile = Path.Combine(NewVersionPath,Path.GetFileName( missingFiles[i].ToString())); try { File.Copy(oldFile,newFile); } catch { return false; } } return true; } #endregion /// <summary> /// This method will return an arraylist of files that were /// in the current version folder, but are not in the new /// version folder. /// /// /// <returns>ArrayList of missing files private ArrayList GetMissingFilePaths(string exeName) { // first we get the path to the appStart.exe.config // it has already been modified by the upadter to point // to the new exe path. xCH = new XMLConfigurationHandler(""); string appStartConfig = xCH.GetSingleNode( "configuration/appUpdater/UpdaterConfiguration/application/client/xmlFile"); xCH = new XMLConfigurationHandler(appStartConfig); string newVersionAppPath = xCH.GetSingleNode( "configuration/appStart/ClientApplicationInfo/appFolderName"); NewVersionPath = newVersionAppPath; // the currently executing assembly is found by calling GetApppath string myPath = Path.GetDirectoryName(GetAppPath()); ThisExePath = myPath; string[] oldFiles = GetCurrentVersionFileList(myPath); string[] newFiles = GetNewVersionFileList(newVersionAppPath); ArrayList deltaFiles=GetFilesToCopy(oldFiles, newFiles); return deltaFiles; } /// <summary> /// Loop thru oldFiles array with inner loop to /// go thru the newFiles array. If a file exists /// in the oldFiles and is not in newFiles, add to /// arraylist which is returned. /// /// /// /// <returns>arraylist of files that need copying private ArrayList GetFilesToCopy(string[] oldFiles, string[] newFiles) { ArrayList al = new ArrayList(); foreach(string oldFile in oldFiles) { bool found=false; string oldFN = Path.GetFileName(oldFile); string newFN=string.Empty; foreach(string newFile in newFiles) { newFN = Path.GetFileName(newFile); if (oldFN.ToLower() == newFN.ToLower()) { found=true; break; } } if(!found) {al.Add(oldFile);} } return al; } /// <summary> /// Return the path to the new version of my app. /// /// <returns> private string GetPathToNewVersion() { string s=null; return s; } /// <summary> /// Return list of files from new directory /// /// /// <returns> private string[] GetNewVersionFileList(string newVersionPath ) { string[] newList = Directory.GetFiles(newVersionPath); return newList; } /// <summary> /// Return array of files from current version /// /// <returns> private string[] GetCurrentVersionFileList(string currVersionPath) { string[] currList = Directory.GetFiles(currVersionPath); return currList; } private string GetAppPath() { return System.Reflection.Assembly.GetExecutingAssembly().Location; } #endregion } } |