/// <summary> /// Get all pages in a paginated collection. /// </summary> /// <remarks> /// If <paramref name="progress"/> is non-<see langword="null"/>, the first call to /// <see cref="IProgress{T}.Report"/> will specify the <paramref name="page"/> /// argument. After each task to obtain to the next page of results completes, /// the <see cref="IProgress{T}.Report"/> method will be called again with the /// new page of results. /// <para> /// This method determines that the end of the collection is reached when either of /// the following conditions is true. /// </para> /// <list type="bullet"> /// <item>The <see cref="ReadOnlyCollectionPage{T}.CanHaveNextPage"/> property returns <see langword="false"/>.</item> /// <item>An empty page is reached.</item> /// </list> /// </remarks> /// <typeparam name="T">The type of elements in the collection.</typeparam> /// <param name="page">The first page in the collection.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that the task will observe.</param> /// <param name="progress">An optional callback object to receive progress notifications. If this is <see langword="null"/>, no progress notifications are sent.</param> /// <returns> /// A <see cref="Task"/> object representing the asynchronous operation. When the operation /// completes successfully, the <see cref="Task{TResult}.Result"/> property will contain a /// read-only collection containing the complete set of results from the paginated collection. /// </returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/> is <see langword="null"/>.</exception> public static Task <ReadOnlyCollection <T> > GetAllPagesAsync <T>(this ReadOnlyCollectionPage <T> page, CancellationToken cancellationToken, IProgress <ReadOnlyCollectionPage <T> > progress) { if (page == null) { throw new ArgumentNullException("page"); } List <T> result = new List <T>(); ReadOnlyCollectionPage <T> currentPage = page; Func <bool> condition = () => currentPage != null; Func <Task> body = () => { if (progress != null) { progress.Report(currentPage); } result.AddRange(currentPage); if (currentPage.CanHaveNextPage && currentPage.Count > 0) { return(currentPage.GetNextPageAsync(cancellationToken) .Select(task => currentPage = task.Result)); } else { currentPage = null; return(CompletedTask.Default); } }; return(TaskBlocks.While(condition, body) .Select(_ => result.AsReadOnly())); }
public void TestWhile2_Loop3_NullTaskBody() { AsyncWhileCondition whileCondition = AsyncWhileCondition.True(); WhileBody whileBody = new WhileBody(3, DelegateBehavior.NullTask); // declaring these makes it clear we are testing the correct overload Func <Task <bool> > condition = whileCondition.EvaluateAsync; Func <Task> body = whileBody.ExecuteAsync; Task whileTask = null; try { whileTask = TaskBlocks.While(condition, body); whileTask.Wait(); Assert.Fail("Expected an exception"); } catch (AggregateException ex) { Assert.IsNotNull(whileTask); Assert.AreEqual(TaskStatus.Faulted, whileTask.Status); Assert.AreEqual(1, ex.InnerExceptions.Count); Assert.IsInstanceOfType(ex.InnerExceptions[0], typeof(InvalidOperationException)); Assert.AreEqual(whileBody.MaxExecutions, whileCondition.EvaluateAsyncCount); Assert.AreEqual(whileBody.MaxExecutions, whileCondition.SyncPartEvaluateAsyncCount); Assert.AreEqual(whileBody.MaxExecutions, whileBody.SyncPartExecutionCount); Assert.AreEqual(whileBody.MaxExecutions - 1, whileBody.ExecutionCount); } }
public void TestWhile2_Loop3_SyncFaultedCondition() { AsyncWhileCondition whileCondition = new AsyncWhileCondition(3, DelegateBehavior.SyncFaulted); WhileBody whileBody = new WhileBody(); // declaring these makes it clear we are testing the correct overload Func <Task <bool> > condition = whileCondition.EvaluateAsync; Func <Task> body = whileBody.ExecuteAsync; Task whileTask = null; try { whileTask = TaskBlocks.While(condition, body); whileTask.Wait(); Assert.Fail("Expected an exception"); } catch (AggregateException ex) { Assert.IsNotNull(whileTask); Assert.AreEqual(TaskStatus.Faulted, whileTask.Status); Assert.AreEqual(1, ex.InnerExceptions.Count); Assert.AreSame(whileCondition.ExpectedException, ex.InnerExceptions[0]); Assert.AreEqual(whileCondition.TotalIterations + 1, whileCondition.SyncPartEvaluateAsyncCount); Assert.AreEqual(whileCondition.TotalIterations, whileCondition.EvaluateAsyncCount); Assert.AreEqual(whileCondition.TotalIterations, whileBody.SyncPartExecutionCount); Assert.AreEqual(whileCondition.TotalIterations, whileBody.ExecutionCount); } }
#pragma warning restore 1998 #region WhileAsyncBuildingBlock public Task While() { Stack <int> workList = new Stack <int>(new[] { 3, 5, 7 }); return(TaskBlocks.While( () => HasItemsAsync(workList), () => ProcessWorkItemAsync(workList.Pop()))); }
public void TestWhile2_NullConditionFunction() { // declaring these makes it clear we are testing the correct overload Func <Task <bool> > condition = null; Func <Task> body = new WhileBody().ExecuteAsync; TaskBlocks.While(condition, body); }
public void TestWhile1_Loop3_Success() { WhileCondition whileCondition = new WhileCondition(3); WhileBody whileBody = new WhileBody(); // declaring these makes it clear we are testing the correct overload Func <bool> condition = whileCondition.Evaluate; Func <Task> body = whileBody.ExecuteAsync; Task whileTask = TaskBlocks.While(condition, body); whileTask.Wait(); Assert.AreEqual(whileCondition.TotalIterations + 1, whileCondition.EvaluateCount); Assert.AreEqual(whileCondition.TotalIterations, whileBody.SyncPartExecutionCount); Assert.AreEqual(whileCondition.TotalIterations, whileBody.ExecutionCount); }
public void TestWhile1_NullBodyFunction() { WhileCondition whileCondition = new WhileCondition(0); // declaring these makes it clear we are testing the correct overload Func <bool> condition = whileCondition.Evaluate; Func <Task> body = null; try { TaskBlocks.While(condition, body); } catch { Assert.AreEqual(0, whileCondition.EvaluateCount); throw; } }
protected internal override Task SerializeToStreamAsync(Stream stream, TransportContext context) { // RFC 2046 // // The Content-Type field for multipart entities requires one parameter, // "boundary". The boundary delimiter line is then defined as a line // consisting entirely of two hyphen characters ("-", decimal value 45) // followed by the boundary parameter value from the Content-Type header // field, optional linear whitespace, and a terminating CRLF. // byte[] buffer; var sb = new StringBuilder(); sb.Append('-').Append('-'); sb.Append(boundary); sb.Append('\r').Append('\n'); int i = 0; Func <bool> condition = () => i < nested_content.Count; Func <Task> body = () => { var c = nested_content[i]; foreach (var h in c.Headers) { sb.Append(h.Key); sb.Append(':').Append(' '); foreach (var v in h.Value) { sb.Append(v); } sb.Append('\r').Append('\n'); } sb.Append('\r').Append('\n'); buffer = Encoding.ASCII.GetBytes(sb.ToString()); sb.Length = 0; return(stream.WriteAsync(buffer, 0, buffer.Length) .Then(_ => c.SerializeToStreamAsync(stream, context)) .Select( _ => { if (i != nested_content.Count - 1) { sb.Append('\r').Append('\n'); sb.Append('-').Append('-'); sb.Append(boundary); sb.Append('\r').Append('\n'); } i++; })); }; Func <Task, Task> continuationFunction = task => { sb.Append('\r').Append('\n'); sb.Append('-').Append('-'); sb.Append(boundary); sb.Append('-').Append('-'); sb.Append('\r').Append('\n'); buffer = Encoding.ASCII.GetBytes(sb.ToString()); return(stream.WriteAsync(buffer, 0, buffer.Length)); }; return(TaskBlocks.While(condition, body) .Then(continuationFunction)); }