public async Task DownloadAsync(Uri address, string directory, string fileName, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); DownloadContext downloadContext = new DownloadContext(); if (!_uriContexts.TryAdd(address, downloadContext)) { throw new ApplicationException("The url is downloading."); } try { using (cancellationToken.Register(CancelAsync)) using (Stream responseStream = await OpenReadTaskAsync(address).ConfigureAwait(false)) { HttpWebResponse response = _uriContexts[address].Response; if (fileName.IsNullOrEmpty()) { fileName = response.GetContentDispositionFileName() ?? Path.GetFileName(response.ResponseUri.AbsolutePath) ?? throw new ArgumentException("fileName"); } string fullPath = Path.Combine(directory, fileName); FileMode fileMode = FileMode.Create; FileInfo file = new FileInfo(fullPath); if (file.Exists) { FileExistsContext fileExistsContext = new FileExistsContext(response.ResponseUri, fullPath) { FileExistsHandling = _defaultFileExistsHandling, }; FileExists?.Invoke(this, new EventArgs <FileExistsContext>(fileExistsContext)); switch (fileExistsContext.FileExistsHandling) { case FileExistsHandling.Ignore: return; case FileExistsHandling.Resume: if (file.Length >= response.ContentLength) { return; } fileMode = FileMode.OpenOrCreate; downloadContext.CurrentFileLength = file.Length; break; case FileExistsHandling.Rename: do { string newFileName = "{0} - New{1}".FormatWith( Path.GetFileNameWithoutExtension(fullPath), Path.GetExtension(fullPath)); fullPath = Path.Combine(directory, newFileName); file = new FileInfo(fullPath); } while (file.Exists); break; } } using (FileStream fileStream = new FileStream(fullPath, fileMode)) { if (downloadContext.CurrentFileLength > 0 && downloadContext.Response.IsRangeSupported()) { fileStream.Seek(downloadContext.CurrentFileLength, SeekOrigin.Begin); } await responseStream.CopyToAsync(fileStream).ConfigureAwait(false); await fileStream.FlushAsync().ConfigureAwait(false); } } } finally { _uriContexts.TryRemove(address, out DownloadContext value); } }