public static async Task MetadataApi_GetDownloadUriAsync_Returns_File_Download_Uri_Which_Downloads_Correct_File() { // Arrange MetadataApi target = CreateAuthorizedService(); List <PackageGroup> packages = await target.GetAvailablePackagesAsync(); DataFile dataFile = packages .SelectMany((p) => p.Packages) .First() .Files .First(); // Act Uri result = await target.GetDownloadUriAsync(dataFile.FileName, dataFile.MD5Hash); // Assert Assert.NotNull(result); Assert.True(result.IsAbsoluteUri); string tempPath = Path.Combine(Path.GetTempPath(), dataFile.FileName); try { using (HttpClient client = new HttpClient()) { using (var request = new HttpRequestMessage(HttpMethod.Get, result)) { using ( Stream contentStream = await(await client.SendAsync(request)).Content.ReadAsStreamAsync(), stream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.None, 4096, true)) { await contentStream.CopyToAsync(stream); } } } Assert.True(File.Exists(tempPath)); byte[] hash; using (Stream stream = File.OpenRead(tempPath)) { Assert.Equal(dataFile.Size, stream.Length); using (HashAlgorithm algorithm = MD5.Create()) { hash = algorithm.ComputeHash(stream); } } string hashString = string.Concat(hash.Select((p) => p.ToString("x2", CultureInfo.InvariantCulture))); Assert.Equal(dataFile.MD5Hash, hashString); } finally { if (File.Exists(tempPath)) { File.Delete(tempPath); } } }
/// <summary> /// Downloads the specified file from the specified package group as an asynchronous operation. /// </summary> /// <param name="service">The Metadata API to use to get the download URI.</param> /// <param name="fileStore">The file store to register the download with if successfully downloaded.</param> /// <param name="group">The package group to download the file from.</param> /// <param name="file">The data file to download.</param> /// <param name="downloadRootPath">The root path to download data to.</param> /// <param name="verifyDownloads">Whether to verify file downloads.</param> /// <param name="cancellationToken">The cancellation token to use to cancel any downloads.</param> /// <returns> /// A <see cref="Task"/> representing the asynchronous operation. /// </returns> private static async Task DownloadFileAsync( IMetadataApi service, IFileStore fileStore, PackageGroup group, DataFile file, string downloadRootPath, bool verifyDownloads, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return; } Console.WriteLine("File name: {0}", file.FileName); Console.WriteLine("File hash: {0}", file.MD5Hash); Console.WriteLine("File size: {0:N0}", file.Size); // Query the URIs to download the file from Uri uri = await service.GetDownloadUriAsync(file.FileName, file.MD5Hash); if (uri == null) { Console.WriteLine("File '{0}' is not available for download at this time.", file.FileName); Console.WriteLine(); return; } Console.WriteLine("File URI: {0}", uri); Console.WriteLine(); // Create the path to the directory to download the file to string directoryPath = Path.Combine( downloadRootPath, group.PackageGroupCode, group.Vintage); string filePath = Path.GetFullPath(Path.Combine(directoryPath, file.FileName)); // Create the directory if it doesn't already exist if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } // Download the file Console.WriteLine("Downloading '{0}' ({1}) to '{2}'...", file.FileName, file.MD5Hash, filePath); using (HttpClient client = new HttpClient()) { using (HttpResponseMessage response = await client.GetAsync(uri, cancellationToken)) { response.EnsureSuccessStatusCode(); using (Stream stream = await response.Content.ReadAsStreamAsync()) { using (Stream fileStream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) { // Ensure any existing file is overwritten fileStream.SetLength(0L); await stream.CopyToAsync(fileStream, 4096, cancellationToken); } } } } // Validate the download is correct, if configured. // Don't register the file in the file store as the file download became corrupted somehow. if (!verifyDownloads || VerifyDownload(filePath, file.MD5Hash)) { // Register the file with the file store so further invocations // of the application don't unnecessarily download the file again fileStore.RegisterFile(file.MD5Hash, filePath); } }