Я пытаюсь создать файл скачать актер, используя Akka.net. Он должен отправлять сообщения о завершении загрузки, а также сообщать о ходе загрузки.Использование обработчиков событий внутри akka.net Актер безопасно
В .NET существуют классы, поддерживающие асинхронные операции с использованием нескольких событий. Например, WebClient.DownloadFileAsync
имеет два события: DownloadProgressChanged
и DownloadFileCompleted
.
Предпочтительно использовать асинхронную версию на основе задач и использовать метод расширения .PipeTo
. Но я не вижу, как это будет работать с асинхронным методом, отображающим два события. Как и в случае с WebClient.DownloadFileAsync
. Даже с WebClient.DownloadFileTaskAsync
вам все равно нужно обработать DownloadProgressChanged
с помощью обработчика событий.
Единственный способ, которым я нашел это, - подключить два обработчика событий при создании моего актера. Затем в обработчиках я посылаю сообщения «Я» и «Отправитель». Для этого я должен обратиться к некоторым частным полям актера изнутри обработчиков событий. Это кажется мне неправильным, но я не вижу другого выхода.
Есть ли более безопасный способ использования нескольких обработчиков событий в актере?
В настоящее время, мое решение выглядит следующим образом (_client является 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);
}
Так что, когда начинается загрузка, некоторые поля установлены. Кроме того, я убедиться, что я Become
состояние, где прятали дальнейшие StartDownload
сообщения, пока 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();
});
}
Для справки, вот весь актер, но я думаю, что важные вещи в этом посте непосредственно: https://gist.github.com/AaronLenoir/4ce5480ecea580d5d283c5d08e8e71b5
Спасибо, я действительно возьму подход одноразового актера. Я сделаю что-то еще, что ставит их в очередь, так как я хочу одну очередь загрузки на хост. – Aaron