我已经到处寻找.net 4.5中新的Async和Await特性的好的实际示例。我想出了以下代码,用于下载文件列表并限制并发下载数量。如果有最佳实践或提高/优化此代码的方法,我将不胜感激。
我们使用以下语句调用下面的代码。
await this.asyncDownloadManager.DownloadFiles(this.applicationShellViewModel.StartupAudioFiles, this.applicationShellViewModel.SecurityCookie, securityCookieDomain).ConfigureAwait(false);
我们随后使用事件将下载的文件添加到ViewModel中的ObservableCollection(.net 4.5中的新线程安全版本)。
public class AsyncDownloadManager
{
public event EventHandler<DownloadedEventArgs> FileDownloaded;
public async Task DownloadFiles(string[] fileIds, string securityCookieString, string securityCookieDomain)
{
List<Task> allTasks = new List<Task>();
//Limits Concurrent Downloads
SemaphoreSlim throttler = new SemaphoreSlim(initialCount: Properties.Settings.Default.maxConcurrentDownloads);
var urls = CreateUrls(fileIds);
foreach (var url in urls)
{
await throttler.WaitAsync();
allTasks.Add(Task.Run(async () =>
{
try
{
HttpClientHandler httpClientHandler = new HttpClientHandler();
if (!string.IsNullOrEmpty(securityCookieString))
{
Cookie securityCookie;
securityCookie = new Cookie(FormsAuthentication.FormsCookieName, securityCookieString);
securityCookie.Domain = securityCookieDomain;
httpClientHandler.CookieContainer.Add(securityCookie);
}
await DownloadFile(url, httpClientHandler).ConfigureAwait(false);
}
finally
{
throttler.Release();
}
}));
}
await Task.WhenAll(allTasks).ConfigureAwait(false);
}
async Task DownloadFile(string url, HttpClientHandler clientHandler)
{
HttpClient client = new HttpClient(clientHandler);
DownloadedFile downloadedFile = new DownloadedFile();
try
{
HttpResponseMessage responseMessage = await client.GetAsync(url).ConfigureAwait(false);
var byteArray = await responseMessage.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
if (responseMessage.Content.Headers.ContentDisposition != null)
{
downloadedFile.FileName = Path.Combine(Properties.Settings.Default.workingDirectory, responseMessage.Content.Headers.ContentDisposition.FileName);
}
else
{
return;
}
if (!Directory.Exists(Properties.Settings.Default.workingDirectory))
{
Directory.CreateDirectory(Properties.Settings.Default.workingDirectory);
}
using (FileStream filestream = new FileStream(downloadedFile.FileName, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true))
{
await filestream.WriteAsync(byteArray, 0, byteArray.Length);
}
}
catch(Exception ex)
{
return;
}
OnFileDownloaded(downloadedFile);
}
private void OnFileDownloaded(DownloadedFile downloadedFile)
{
if (this.FileDownloaded != null)
{
this.FileDownloaded(this, new DownloadedEventArgs(downloadedFile));
}
}
public class DownloadedEventArgs : EventArgs
{
public DownloadedEventArgs(DownloadedFile downloadedFile)
{
DownloadedFile = downloadedFile;
}
public DownloadedFile DownloadedFile { get; set; }
}
在Svick的建议下,以下是直接问题:
- 将Async / Await嵌入其他Async / Await方法会产生什么影响?(在Async / Await方法中写入文件流到磁盘)
- 每个单独的任务都应该使用一个httpclient还是它们应该共享一个?
- 事件是否是将下载文件引用“发送”到视图模型的好方法? [我也会在codereview发布]