/// <summary> /// Run the tally for the specified quest. /// </summary> /// <param name="quest">The quest to scan.</param> /// <param name="token">Cancellation token.</param> public async Task RunAsync(IQuest quest, CancellationToken token) { if (quest == null) { throw new ArgumentNullException(nameof(quest)); } try { TallyIsRunning = true; TallyResults = string.Empty; // Mark the quest as one that we will listen for changes from. quest.PropertyChanged -= Quest_PropertyChanged; quest.PropertyChanged += Quest_PropertyChanged; voteCounter.ResetUserDefinedTasks(quest.DisplayName); using (var forumReader = serviceProvider.GetRequiredService <ForumReader>()) { try { forumReader.StatusChanged += ForumReader_StatusChanged; var(threadTitles, posts) = await forumReader.ReadQuestAsync(quest, token).ConfigureAwait(false); voteCounter.SetThreadTitles(threadTitles); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); await TallyPosts(posts, quest, token).ConfigureAwait(false); stopwatch.Stop(); logger.LogDebug($"Time to process posts: {stopwatch.ElapsedMilliseconds} ms."); } finally { forumReader.StatusChanged -= ForumReader_StatusChanged; } } } catch (InvalidOperationException e) { TallyResults += $"\n{e.Message}"; return; } catch (OperationCanceledException) { throw; } catch (Exception) { //VoteCounter.Instance.Quest = null; throw; } finally { TallyIsRunning = false; // Free memory used by loading pages as soon as we're done: GC.Collect(); } await UpdateResults(token).ConfigureAwait(false); }