/// <summary> /// Called when a version check operation has been performed sucessfully.s /// </summary> /// <commondoc select='All/Methods/EventRaisers[@Params="+EventArgs"]/*' params='EventName=VersionCheckSuccessful' /> protected virtual void OnVersionCheckSuccessful(VersionCheckSuccessfulEventArgs e) { if (e == null) { throw new ArgumentNullException(); } this.VersionCheckSuccessful?.Invoke(this, e); }
/// <summary> /// Beings connecting to the update server asynchronously and raises either the <see cref="VersionCheckSuccessful" /> /// or <see cref="VersionCheckError" /> event when done. /// </summary> /// <remarks> /// <para> /// The download of the data is performed asynchronously by using a <see cref="BackgroundWorker" /> object. <br /> /// Multiple calls of this method at once can lead in a possible <see cref="NotSupportedException" />, /// because one instance of this class is not able to handle multiple version check operations at the same time. <br /> /// </para> /// <note type="implementnotes"> /// Use the <see cref="IsVersionChecking" /> property to check whether an aynchronous version check operation is /// already in progress before calling this method multiple times. /// </note> /// <note type="implementnotes"> /// Use the <see cref="AbortVersionCheck" /> method to cancel an asynchronous version check operation. /// </note> /// </remarks> /// <exception cref="WebException"> /// Error on connecting to server or downloading data or both <see cref="Update_UpdateInfoPage" /> and /// <see cref="Update_UpdateInfoPageAlt" /> constants contain an invalid URL. /// </exception> /// <exception cref="InvalidOperationException"> /// Another asynchronous version check operation is already in progress by this instance. /// </exception> /// <commondoc select='IDisposable/Methods/All/*' /> /// <seealso cref="VersionCheckSuccessful">VersionCheckSuccessful Event</seealso> /// <seealso cref="VersionCheckError">VersionCheckError Event</seealso> /// <seealso cref="IsVersionChecking">IsVersionChecking Property</seealso> /// <seealso cref="AbortVersionCheck">AbortVersionCheck Method</seealso> public void BeginVersionCheck() { if (this.IsDisposed) { throw new ObjectDisposedException("this"); } if (this.IsVersionChecking) { throw new InvalidOperationException(); } this.currentVersionCheckWorker = new BackgroundWorker(); this.currentVersionCheckWorker.WorkerSupportsCancellation = true; this.currentVersionCheckWorker.DoWork += delegate(object sender, DoWorkEventArgs e) { if (e.Cancel) { return; } var arguments = (Tuple <string[], Version>)e.Argument; string[] urlsToCheck = arguments.Item1; Version currentAppVersion = arguments.Item2; Exception error = null; Version mostRecentVersion = null; string infoMessage = null; string criticalMessage = null; // Work through all available servers to check for a new version. using (WebClient webClient = new WebClient()) { for (int i = 0; i < urlsToCheck.Length; i++) { if (e.Cancel) { return; } try { byte[] data = webClient.DownloadData(string.Format(CultureInfo.InvariantCulture, urlsToCheck[i], currentAppVersion)); using (MemoryStream dataStream = new MemoryStream(data)) { XmlDocument versionCheckData = new XmlDocument(); versionCheckData.Load(dataStream); if (versionCheckData.DocumentElement == null) { throw new FormatException("The update site has returned invalid data."); } XmlNode newestVersionNode = versionCheckData.DocumentElement["NewestVersion"]; XmlNode infoMessageNode = versionCheckData.DocumentElement["InfoMessage"]; XmlNode criticalMessageNode = versionCheckData.DocumentElement["CriticalMessage"]; if ((newestVersionNode == null) || (criticalMessageNode == null)) { throw new FormatException("The update site has returned invalid data."); } Version versionNumberFromThisServer; try { versionNumberFromThisServer = new Version(newestVersionNode.InnerText); } catch (Exception exception) { throw new FormatException("The update site has returned invalid data.", exception); } // Make sure that this server didn't return an older version number than another server. if ((mostRecentVersion != null) && (versionNumberFromThisServer < mostRecentVersion)) { continue; } mostRecentVersion = versionNumberFromThisServer; criticalMessage = criticalMessageNode.InnerText; if (infoMessageNode != null) { infoMessage = infoMessageNode.InnerText; } } } catch (Exception exception) { error = exception; } } } // We don't want to throw an Exception if we got the data we needed from at least one server. if (mostRecentVersion != null) { error = null; } VersionCheckSuccessfulEventArgs successfulResultData = null; if (error == null) { successfulResultData = new VersionCheckSuccessfulEventArgs((currentAppVersion < mostRecentVersion), mostRecentVersion, criticalMessage, infoMessage); } e.Result = new Tuple <Exception, VersionCheckSuccessfulEventArgs>(error, successfulResultData); }; this.currentVersionCheckWorker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) { try { var result = (Tuple <Exception, VersionCheckSuccessfulEventArgs>)e.Result; if (result.Item1 != null) { this.OnVersionCheckError(new ExceptionEventArgs(result.Item1)); } else { this.OnVersionCheckSuccessful(result.Item2); } } finally { if (this.currentVersionCheckWorker != null) { this.currentVersionCheckWorker.Dispose(); this.currentVersionCheckWorker = null; } } }; this.currentVersionCheckWorker.RunWorkerAsync(new Tuple <string[], Version>( new[] { UpdateManager.Update_UpdateInfoPage, UpdateManager.Update_UpdateInfoPageAlt }, (Version)this.Environment.AppVersion.Clone())); }