//************************************************************** // CheckForUpdates() // - Checks for an update // - This is a sync call... normally called by the poller object // on the poller thread. //************************************************************** public bool CheckForUpdates() { Debug.WriteLine("APPMANAGER: Checking for updates."); bool retValue = false; //If the OnCheckForUpdate event the caller is doing the check if (OnCheckForUpdate != null) { retValue = OnCheckForUpdate(this, new EventArgs()); } //otherwise do the check ourselves else //If versioning is enabled check to see if the version file has changed. if (ChangeDetectionMode == ChangeDetectionModes.ServerManifestCheck) { ServerManifest vm = new ServerManifest(); vm.Load(UpdateUrl); retValue = vm.IsServerVersionNewer(GetLatestInstalledVersion()); } //If versioning is not enabled, check the files themselves else { Resource currentResource; foreach (Object r in Manifest.Resources.ResourceList) { currentResource = (Resource)(((DictionaryEntry)r).Value); string url = UpdateUrl + currentResource.Name; string FilePath = currentResource.FilePath; if (WebFileLoader.CheckForFileUpdate(url, FilePath)) { retValue = true; } } } //Fire the OnUpdateDetected Event on the UI thread if (retValue == true) { if (OnUpdateDetected != null) { foreach (UpdateDetectedEventHandler UC in OnUpdateDetected.GetInvocationList()) { EventControl.BeginInvoke(UC, new object[] { this, new EventArgs() }); } } } return(retValue); }
//************************************************************** // Load() //************************************************************** public void Load(string url) { _url = url; String LocalManifestPath = AppDomain.CurrentDomain.BaseDirectory + Path.GetFileName((new Uri(_url)).LocalPath); WebFileLoader.UpdateFile(_url, LocalManifestPath); _manifest = new XmlDocument(); _manifest.Load(LocalManifestPath); ApplicationUrl = _manifest.GetElementsByTagName("ApplicationUrl")[0].InnerText; AvailableVersion = _manifest.GetElementsByTagName("AvailableVersion")[0].InnerText; }
//************************************************************** // CopyDirectory() // Does a deep copy // Returns the number of files copied // If keys is null, validates assemblies copied have been signed // by one of the provided keys. //************************************************************** public static int CopyDirectory(string url, string filePath) { Resource currentResource; int FileCount = 0; string newFilePath; SortedList DirectoryList = WebFileLoader.GetDirectoryContents(url, false); foreach (Object r in DirectoryList) { currentResource = (Resource)(((DictionaryEntry)r).Value); //If the directory doesn't exist, create it first if (!Directory.Exists(filePath)) { Directory.CreateDirectory(filePath); } //If it's a file than copy the file. if (!currentResource.IsFolder) { FileCount++; newFilePath = filePath + currentResource.Name; //only update the file if it doesn't exist or if the one on the server //returned a newer last modtime than the one on disk if (!File.Exists(newFilePath)) { UpdateFile(currentResource.Url, newFilePath); } else if (currentResource.LastModified > LastModFromDisk(newFilePath)) { UpdateFile(currentResource.Url, newFilePath); } } //If it's a folder, download the folder itself. else { newFilePath = filePath + currentResource.Name + "\\"; FileCount += CopyDirectory(currentResource.Url, newFilePath); } } return(FileCount); }
//************************************************************** // UpdateFileList() // - A multi-file UpdateFile //************************************************************** public static void UpdateFileList(SortedList fileList, string sourceUrl, string destPath) { Resource currentResource; //If the directory doesn't exist, create it first if (!Directory.Exists(destPath)) { Directory.CreateDirectory(destPath); } foreach (Object o in fileList) { currentResource = (Resource)(((DictionaryEntry)o).Value); string url = sourceUrl + currentResource.Name; string FilePath = destPath + currentResource.Name; WebFileLoader.UpdateFile(url, FilePath); } }
//************************************************************** // Download() //************************************************************** private void Download() { bool DownloadInProgress = true; int DownloadAttemptCount = 0; int SecondsToSleep = 0; while (DownloadInProgress) { Thread.Sleep(TimeSpan.FromSeconds(SecondsToSleep)); SecondsToSleep = SecondsBetweenDownloadRetry; DownloadAttemptCount++; Trace.WriteLine("APPMANAGER: Attempting to download update from: " + AppMan.Manifest.State.DownloadSource); try { int UpdateCount = WebFileLoader.CopyDirectory(AppMan.Manifest.State.DownloadSource, AppMan.Manifest.State.DownloadDestination); Debug.WriteLine("APPMANAGER: Number of files updated from the server: " + UpdateCount); Debug.WriteLine("APPMANAGER: App update downloaded successfully"); DownloadInProgress = false; } //Things that could go wrong while downloading are pretty much any kind of //network problem, like the client just going offline. However, this can cause //itself to manifest in any number of ways... like exceptions on the stream //objects used to copy the file to disk. catch (WebException e) { Debug.WriteLine("APPMANAGER: Update download failed due to network exception:"); Debug.WriteLine("APPMANAGER: " + e.ToString()); if (DownloadAttemptCount >= DownloadRetryAttempts) { Debug.WriteLine("APPMANAGER: Download attempt has failed 3 times. Aborting Update"); UpdateEventArgs.ErrorMessage = "Download of a new update from '" + AppMan.Manifest.State.DownloadSource + "' failed with the network error: " + e.Message; throw e; } } catch (IOException e) { Debug.WriteLine("APPMANAGER: Update download failed due to file I/O exception:"); Debug.WriteLine("APPMANAGER: " + e.ToString()); if (DownloadAttemptCount >= DownloadRetryAttempts) { Debug.WriteLine("APPMANAGER: Download attempt has failed 3 times. Aborting Update"); UpdateEventArgs.ErrorMessage = "Saving the new update to disk at '" + AppMan.Manifest.State.DownloadDestination + "' failed with the following error: " + e.Message; throw e; } } catch (Exception e) { Debug.WriteLine("APPMANAGER: Update download failed due to the following error: " + e.Message); Debug.WriteLine("APPMANAGER: " + e.ToString()); if (DownloadAttemptCount >= DownloadRetryAttempts) { Debug.WriteLine("APPMANAGER: Download attempt has failed 3 times. Aborting Update"); UpdateEventArgs.ErrorMessage = "Update failed with the following error: '" + e.Message + "'"; throw e; } } } }
//************************************************************** // OnAssemblyResolve() // - This code is what does the auto-download of missing files //************************************************************** private Assembly OnAssemblyResolve(Object sender, ResolveEventArgs args) { //Check to see if the AssemblyLoad in this event is what caused the //event to fire again. If so, the load failed. if (LoadingAssembly == true) { return(null); } LoadingAssembly = true; string[] AssemblyNameParts = args.Name.Split(new Char[] { ',' }, 2); string AssemblyName = AssemblyNameParts[0] + ".dll"; string FilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, AssemblyName); string url; if (ChangeDetectionMode == ChangeDetectionModes.DirectFileCheck) { url = UpdateUrl + AssemblyName; } else { ServerManifest SM = new ServerManifest(); SM.Load(UpdateUrl); url = Path.Combine(SM.ApplicationUrl, AssemblyName); } Debug.WriteLine("APPMANAGER: Auto-downloading assembly: " + AssemblyName + ". From: " + url); try { WebFileLoader.UpdateFile(url, FilePath); } catch (Exception e) { Debug.WriteLine("APPMANAGER: Failed to download the missing assembly from the web server."); Debug.WriteLine("APPMANAGER: " + e.ToString()); if (ShowDefaultUI) { MessageBox.Show("Unable to auto-download the missing parts of the application from:\r\n" + url + "\r\n\r\n" + "Make sure your connected to the network. If the problem persists re-install the application."); } return(null); } Assembly assembly; try { assembly = Assembly.Load(args.Name); } catch (Exception e) { Debug.WriteLine("APPMANAGER: Failed to load the auto-downloaded assembly."); Debug.WriteLine("APPMANAGER: " + e.ToString()); return(null); } finally { LoadingAssembly = false; } return(assembly); }