//************************************************************** // 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; try { XmlNode filelist = _manifest.GetElementsByTagName("FilesToDownload")[0]; XmlNodeList files = null; if (filelist != null && filelist.HasChildNodes) { files = filelist.ChildNodes; } if (files != null) { _filesToDownload = new string[files.Count]; for (int i = 0; i <= files.Count; i++) { _filesToDownload[i] = files[i].InnerText; } } }catch {} }
//************************************************************** // 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()); } else //otherwise do the check ourselves { //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()); } else //If versioning is not enabled, check the files themselves { 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 (OnUpdateDetected != null) { foreach (UpdateDetectedEventHandler UC in OnUpdateDetected.GetInvocationList()) { UpdateDetectedEventArgs ud = new UpdateDetectedEventArgs(); ud.UpdateDetected = retValue; EventControl.BeginInvoke(UC, new object[] { this, ud }); } } return(retValue); }
//************************************************************** // 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 = 0; //if we have a known set of files-to-download, get it from that. otherwise, deep copy the directory - krishna - jun05 if (AppMan.Manifest.State.FilesToDownload != null && AppMan.Manifest.State.FilesToDownload.Length != 0) // { //raise the progress event before starting first download. if (OnDownloadProgress != null) { //currentState represents the percent done. DownloadEventArgs.CurrentState = 0; DownloadEventArgs.CurrentFile = 1; DownloadEventArgs.TotalFiles = AppMan.Manifest.State.FilesToDownload.Length; OnDownloadProgress(this, DownloadEventArgs); } for (int i = 0; i < AppMan.Manifest.State.FilesToDownload.Length; i++) { string file = AppMan.Manifest.State.FilesToDownload[i]; string url = AppMan.Manifest.State.DownloadSource; string destinationtempDir = AppMan.Manifest.State.DownloadDestination; Debug.WriteLine("URL = " + url); if (!url.EndsWith("/")) { url += "/"; } url += file; Debug.WriteLine("URL after = " + url); //make sure the path has a \ at the end MakeValidPath(destinationtempDir); //If the directory doesn't exist, create it first if (!Directory.Exists(destinationtempDir)) { Directory.CreateDirectory(destinationtempDir); } //copy file to temp location, not to the main place. file = destinationtempDir + file; Debug.WriteLine("File temp path= " + file); WebFileLoader.UpdateFile(url, file); //raise the event UpdateCount++; if (OnDownloadProgress != null) { //currentState represents the percent done. if (i < AppMan.Manifest.State.FilesToDownload.Length) { DownloadEventArgs.CurrentFile = i + 1; } else { DownloadEventArgs.CurrentFile = i; } //total files is already set in the code above. //set the percentage done,below. DownloadEventArgs.CurrentState = (100 * UpdateCount / AppMan.Manifest.State.FilesToDownload.Length); OnDownloadProgress(this, DownloadEventArgs); } } } else { 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); }