我正在尝试使用Akka.net构建文件下载Actor。它应在下载完成时发送消息,同时报告下载进度。
在.NET中,有支持使用多个事件进行异步操作的类。例如,WebClient.DownloadFileAsync有两个事件:DownloadProgressChanged和DownloadFileCompleted。
最好使用基于任务的异步版本并使用.PipeTo扩展方法。但是,我看不出如何使用公开两个事件的异步方法。就像WebClient.DownloadFileAsync这种情况一样。即使使用WebClient.DownloadFileTaskAsync,您仍然需要使用事件处理程序处理DownloadProgressChanged。
我发现唯一的方法是在创建我的actor时连接两个事件处理程序。然后,在处理程序中,我将消息发送到Self和Sender。为此,我必须从事件处理程序内部引用actor的某些私有字段。这让我感觉不对,但我找不到其他出路。
是否有更安全的方法在Actor中使用多个事件处理程序?
目前,我的解决方案看起来像这样(_client是在actor的构造函数中创建的WebClient实例):
当下载开始时,会设置一些字段。此外,我确保自己处于一种状态,即进一步的
在.NET中,有支持使用多个事件进行异步操作的类。例如,WebClient.DownloadFileAsync有两个事件:DownloadProgressChanged和DownloadFileCompleted。
最好使用基于任务的异步版本并使用.PipeTo扩展方法。但是,我看不出如何使用公开两个事件的异步方法。就像WebClient.DownloadFileAsync这种情况一样。即使使用WebClient.DownloadFileTaskAsync,您仍然需要使用事件处理程序处理DownloadProgressChanged。
我发现唯一的方法是在创建我的actor时连接两个事件处理程序。然后,在处理程序中,我将消息发送到Self和Sender。为此,我必须从事件处理程序内部引用actor的某些私有字段。这让我感觉不对,但我找不到其他出路。
是否有更安全的方法在Actor中使用多个事件处理程序?
目前,我的解决方案看起来像这样(_client是在actor的构造函数中创建的WebClient实例):
public void HandleStartDownload(StartDownload message)
{
_self = Self;
_downloadRequestor = Sender;
_uri = message.Uri;
_guid = message.Guid;
_tempPath = Path.GetTempFileName();
_client.DownloadFileAsync(_uri, _tempPath);
}
private void Client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
var completedMessage = new DownloadCompletedInternal(_guid, _tempPath);
_downloadRequestor.Tell(completedMessage);
_self.Tell(completedMessage);
}
private void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
var progressedMessage = new DownloadProgressed(_guid, e.ProgressPercentage);
_downloadRequestor.Tell(progressedMessage);
_self.Tell(progressedMessage);
}
当下载开始时,会设置一些字段。此外,我确保自己处于一种状态,即进一步的
StartDownload
消息被存储,直到Self接收到DownloadCompleted
消息为止: public void Ready()
{
Receive<StartDownload>(message => {
HandleStartDownload(message);
Become(Downloading);
});
}
public void Downloading()
{
Receive<StartDownload>(message => {
Stash.Stash();
});
Receive<DownloadCompleted>(message => {
Become(Ready);
Stash.UnstashAll();
});
}
供参考,这里是整个Actor的代码,但我认为重要内容直接在这篇文章中: https://gist.github.com/AaronLenoir/4ce5480ecea580d5d283c5d08e8e71b5