/// <summary> /// The actual functionality to download with optional hash verification /// subclasses that wish to return the contents of the downloaded file /// or do something else with it can override this instead of RunWithReturn. /// If you do, you must call RaiseOnStart()/RaiseOnEnd() /// </summary> /// <param name="success"></param> /// <returns></returns> protected virtual string RunDownload(bool success) { Exception exception = null; var attempts = 0; bool result = false; do { if (Token.IsCancellationRequested) { break; } exception = null; try { Logger.Trace($"Download of {Url} to {Destination} Attempt {attempts + 1} of {RetryCount + 1}"); using (var destinationStream = fileSystem.OpenWrite(Destination, FileMode.Append)) { result = Utils.Download(Logger, Url, destinationStream, (value, total) => { UpdateProgress(value, total); return(!Token.IsCancellationRequested); }); } if (result && ValidationHash != null) { var md5 = fileSystem.CalculateFileMD5(TargetDirectory); result = md5.Equals(ValidationHash, StringComparison.CurrentCultureIgnoreCase); if (!result) { Logger.Warning($"Downloaded MD5 {md5} does not match {ValidationHash}. Deleting {TargetDirectory}."); fileSystem.FileDelete(TargetDirectory); } else { Logger.Trace($"Download confirmed {md5}"); break; } } } catch (Exception ex) { exception = ex; } } while (attempts++ < RetryCount); if (!result) { Token.ThrowIfCancellationRequested(); throw new DownloadException("Error downloading file", exception); } return(Destination); }