Overview
Cuemon.Extensions.Threading adds four Task and Task<TResult> extension methods that replace ConfigureAwait(true) and ConfigureAwait(false) with named intent. Instead of carrying Boolean flags through asynchronous code, callers can express whether a continuation should return to the captured synchronization context or continue without it.
The package is deliberately small. It complements System.Threading with a narrower surface than Cuemon.Threading, focusing on await configuration for normal task-based code instead of introducing broader looping or coordination primitives.
Key APIs
ContinueWithCapturedContext(this Task task) wraps ConfigureAwait(true) for non-generic tasks so continuation policy is explicit when the caller should resume on the captured synchronization context.
ContinueWithCapturedContext<TResult>(this Task<TResult> task) does the same for result-bearing tasks and keeps the awaited TResult flow unchanged while still naming the continuation choice.
ContinueWithSuppressedContext(this Task task) wraps ConfigureAwait(false) for non-generic tasks, which is the package's direct way to mark library and background code that should not hop back to a captured context.
ContinueWithSuppressedContext<TResult>(this Task<TResult> task) applies the same suppressed-context policy to Task<TResult> so async pipelines can keep their result values while opting out of context capture.
Basic usage
using System.Collections.Generic;
using System.Threading.Tasks;
using Cuemon.Extensions.Threading.Tasks;
using Codebelt.Extensions.Xunit;
using Xunit;
namespace Contoso.Threading.Tests;
public class InvoicePipelineTest : Test
{
public InvoicePipelineTest(ITestOutputHelper output) : base(output)
{
}
[Fact]
public async Task ShouldProcessInvoiceWithExplicitAwaitPolicy()
{
var steps = new List<string>();
var sut = new InvoicePipeline(steps);
var result = await sut.ProcessAsync(42).ContinueWithCapturedContext();
TestOutput.WriteLine(result);
TestOutput.WriteLines(steps);
Assert.Equal("invoice-42:sent", result);
Assert.Equal(new[] { "loaded", "composed", "sent" }, steps);
}
private sealed class InvoicePipeline
{
private readonly List<string> _steps;
public InvoicePipeline(List<string> steps)
{
_steps = steps;
}
public async Task<string> ProcessAsync(int invoiceId)
{
var document = await LoadAsync(invoiceId).ContinueWithSuppressedContext();
var envelope = await ComposeAsync(document).ContinueWithSuppressedContext();
return await SendAsync(envelope).ContinueWithSuppressedContext();
}
private Task<string> LoadAsync(int invoiceId)
{
_steps.Add("loaded");
return Task.FromResult($"invoice-{invoiceId}");
}
private Task<string> ComposeAsync(string document)
{
_steps.Add("composed");
return Task.FromResult($"{document}:ready");
}
private Task<string> SendAsync(string envelope)
{
_steps.Add("sent");
return Task.FromResult(envelope.Replace(":ready", ":sent"));
}
}
}
Use this pattern when a small async workflow should state its continuation policy where each await happens instead of repeating raw ConfigureAwait flags. It matters because the package keeps task-based code readable while preserving the same Task and Task<TResult> behavior that the framework already provides.
Installation
dotnet add package Cuemon.Extensions.Threading
Usage guidance
Use this package when your code already depends on Task-based async flows and you want explicit, named continuation choices at each await site. If raw Task.ConfigureAwait(...) calls are sufficient for your team or you need broader concurrent-loop primitives instead of await-configuration helpers, stay with the framework API or move to Cuemon.Threading.
Family packages
- 🌐Cuemon.AspNetCore
- 🏭Cuemon.AspNetCore.App
- 🌐Cuemon.AspNetCore.Authentication
- 🌐Cuemon.AspNetCore.Mvc
- 🌐Cuemon.AspNetCore.Razor.TagHelpers
- 📦Cuemon.Core
- 🏭Cuemon.Core.App
- 🗄️Cuemon.Data
- 🗄️Cuemon.Data.Integrity
- 🗄️Cuemon.Data.SqlClient
- 🩺Cuemon.Diagnostics
- 🌐Cuemon.Extensions.AspNetCore
- 🌐Cuemon.Extensions.AspNetCore.Authentication
- 🌐Cuemon.Extensions.AspNetCore.Mvc
- 🌐Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json
- 🌐Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml
- 🌐Cuemon.Extensions.AspNetCore.Mvc.RazorPages
- 🌐Cuemon.Extensions.AspNetCore.Text.Json
- 🌐Cuemon.Extensions.AspNetCore.Xml
- 📦Cuemon.Extensions.Collections.Generic
- 📦Cuemon.Extensions.Collections.Specialized
- 📦Cuemon.Extensions.Core
- 🗄️Cuemon.Extensions.Data
- 🗄️Cuemon.Extensions.Data.Integrity
- 📦Cuemon.Extensions.DependencyInjection
- 🩺Cuemon.Extensions.Diagnostics
- 🏗️Cuemon.Extensions.Hosting
- 📦Cuemon.Extensions.IO
- 📦Cuemon.Extensions.Net
- 📦Cuemon.Extensions.Reflection
- 📦Cuemon.Extensions.Runtime.Caching
- 📝Cuemon.Extensions.Text
- 📝Cuemon.Extensions.Text.Json
- 📦Cuemon.Extensions.Xml
- 📦Cuemon.IO
- ⚙️Cuemon.Kernel
- 📦Cuemon.Net
- 📦Cuemon.Resilience
- 📦Cuemon.Runtime.Caching
- 🔐Cuemon.Security.Cryptography
- 📦Cuemon.Threading
- 📦Cuemon.Xml