2016-05-03 4 views
3

Я пытаюсь создать файл скачать актер, используя 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

ответ

2

Я должен обратиться к некоторым частным полям актера изнутри события . Это кажется мне неправильным, но я не вижу другого выхода.

Есть ли более безопасный способ использования нескольких обработчиков событий в актере?

Нет ничего естественного в том, что актер имеет внутреннее состояние и члены, которые являются частью событий, связанных с поднятием состояния, которые обрабатываются внутри актера. Не более, чем это было бы неправильно, если бы вы использовали OO-подход.

Единственная реальная проблема заключается в том, что это внутреннее состояние смешивается между несколькими запросами загрузки файлов, но я думаю, что ваш текущий код звучит.

Возможно, более привлекательный подход может состоять в том, чтобы взглянуть на FileDownloadActor как на одного участника, запустить его, загрузить файл, сообщить результат отправителю и затем убить актера. Запуск актеров - это дешевая операция, и это полностью оборачивает возможность совместного использования внутреннего состояния между несколькими запросами на загрузку.

Если вы, конечно, не нуждаетесь в загрузке очереди, чтобы запускать ее последовательно, как ваш текущий код, - но очередь может управляться другим актером в целом и по-прежнему рассматривать роли загрузки как временные.

+0

Спасибо, я действительно возьму подход одноразового актера. Я сделаю что-то еще, что ставит их в очередь, так как я хочу одну очередь загрузки на хост. – Aaron

Смежные вопросы