RLC.TaskChaining 0.1.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package RLC.TaskChaining --version 0.1.1
                    
NuGet\Install-Package RLC.TaskChaining -Version 0.1.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="RLC.TaskChaining" Version="0.1.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RLC.TaskChaining" Version="0.1.1" />
                    
Directory.Packages.props
<PackageReference Include="RLC.TaskChaining" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add RLC.TaskChaining --version 0.1.1
                    
#r "nuget: RLC.TaskChaining, 0.1.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package RLC.TaskChaining@0.1.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=RLC.TaskChaining&version=0.1.1
                    
Install as a Cake Addin
#tool nuget:?package=RLC.TaskChaining&version=0.1.1
                    
Install as a Cake Tool

RLC.TaskChaining

Monadic-style chaining for C# Tasks.

Rationale

Asynchronous code (particularly in C#) typically relies on using the async/await feature introduced in C# 5.0. This has a lot of benefits, but it unfortunately tends to push code into an imperative style. This library aims to make writing asychronous functional code easier, cleaner, and less error-prone using extensions to System.Threading.Tasks.

Installation

Install RLC.TaskChaining as a NuGet package via an IDE package manager or using the command-line instructions at nuget.org.

API

Chaining

Then

Once a Task<T> has been created, successive operations can be chained using the Then method.

HttpClient client;  // Assuming this is coming from an HttpClientFactory or injected or whatever

Task.FromResult("https://www.google.com")  // Task<string>
  .Then(client.GetAsync)                   // Task<HttpResponseMessage>
  .Then(response => response.StatusCode);  // Task<System.Net.HttpStatusCode>
Catch

When a Task<T> enters a faulted state, the Catch method can be used to return the Task<T> to a non-faulted state.

HttpClient client;  // Assuming this is coming from an HttpClientFactory or injected or whatever

Task.FromResult("not-a-url")              // Task<string>
  .Then(client.GetAsync)                  // Task<HttpResponseMessage> but FAULTED
  .Catch(exception => exception.Message)  // Task<string> and NOT FAULTED
  .Then(message => message.Length)        // Task<int>

Note that it's entirely possible for a Catch method to cause the Task<T> to remain in a faulted state, e.g. if you only wanted to recover into a non-faulted state if a particular exception type occurred.

HttpClient client;  // Assuming this is coming from an HttpClientFactory or injected or whatever

Task.FromResult("not-a-url")          // Task<string>
  .Then(client.GetAsync)              // Task<HttpResponseMessage> but FAULTED
  .Catch(exception => exception is NullReferenceException
    ? exception.Message
    : Task.FromException(exception))  // Task<string> but STILL FAULTED if anything other than NullReferenceException occurred
  .Then(message => message.Length)    // Task<int>
IfFulfilled/IfRejected/Tap

The IfFulfilled and IfRejected methods can be used to perform side effects such as logging when the Promise<T> is in the fulfilled or faulted state, respectively.

HttpClient client;  // Assuming this is coming from an HttpClientFactory or injected or whatever

Promise<string>.Resolve("https://www.google.com/")
  .Then(client.GetAsync)
  .IfFulfilled(response => _logger.LogDebug("Got response {Response}", response)
  .Then(response => response.StatusCode);
HttpClient client;  // Assuming this is coming from an HttpClientFactory or injected or whatever

Promise<string>.Resolve("not-a-url")
  .Then(client.GetAsync)
  .IfRejected(exception => _logger.LogException(exception, "Failed to get URL")
  .Catch(exception => exception.Message)
  .Then(message => message.Length);

The Tap method takes both an onFulfilled and onRejected Action in the event that you want to perform some side effect on both sides of the Promise at a single time.

HttpClient client;  // Assuming this is coming from an HttpClientFactory or injected or whatever

Promise<string>.Resolve(someExternalUrl)
  .Then(client.GetAsync)
  .Tap(
    response => _logger.LogDebug("Got response {Response}", response),
    exception => _logger.LogException(exception, "Failed to get URL")
  )

Static Methods

There are some convenience methods on TaskExtras that are useful when transitioning between the fulfilled and faulted states.

RejectIf

RejectIf can be used to transition into a faulted state based on some Predicate<T>.

Task.FromResult(1)
  .Then(TaskExtras.RejectIf(
    value => value % 2 == 0,
    value => new Exception($"{nameof(value)} was not even")
  ));
ResolveIf

ResolveIf can be used to transition from a faulted state to a fulfilled state based on some Predicate<Exception>.

Task.FromException<int>(new ArgumentException())
  .Catch(TaskExtras.ResolveIf(
    exception => exception is ArgumentException,
    exception => exception.Message.Length
  ))
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.20.0 890 7/8/2025
2.19.2 2,074 3/27/2025
2.19.0 308 3/6/2025
2.18.5 1,435 11/25/2024
2.18.4 189 11/22/2024
2.18.3 184 11/22/2024
2.18.2 195 11/22/2024
2.18.1 1,127 7/26/2024
2.16.1 2,106 4/20/2024
2.16.0 974 12/18/2023
2.15.0 2,312 11/1/2023
2.14.0 2,166 5/14/2023
2.13.0 591 5/12/2023
2.12.0 554 5/12/2023
2.11.0 9,416 3/12/2023
2.10.0 872 12/29/2022
2.9.0 916 9/22/2022
2.8.0 849 9/21/2022
2.7.0 1,137 6/18/2022
2.6.0 895 6/17/2022
2.5.0 879 6/16/2022
2.4.0 947 6/10/2022
2.3.0 891 6/9/2022
2.2.0 866 5/20/2022
2.1.2 890 5/17/2022
2.1.1 916 5/13/2022
2.1.0 854 5/13/2022
2.0.0 866 5/1/2022
1.0.0 880 4/26/2022
0.3.1 836 4/26/2022
0.3.0 852 4/26/2022
0.2.0 903 4/24/2022
0.1.1 879 4/18/2022
0.1.0 942 4/18/2022