JoakimAnder.Toolbox
0.3.1
dotnet add package JoakimAnder.Toolbox --version 0.3.1
NuGet\Install-Package JoakimAnder.Toolbox -Version 0.3.1
<PackageReference Include="JoakimAnder.Toolbox" Version="0.3.1" />
<PackageVersion Include="JoakimAnder.Toolbox" Version="0.3.1" />
<PackageReference Include="JoakimAnder.Toolbox" />
paket add JoakimAnder.Toolbox --version 0.3.1
#r "nuget: JoakimAnder.Toolbox, 0.3.1"
#:package JoakimAnder.Toolbox@0.3.1
#addin nuget:?package=JoakimAnder.Toolbox&version=0.3.1
#tool nuget:?package=JoakimAnder.Toolbox&version=0.3.1
JoakimAnder.Toolbox
A collection of helper classes and utilities I've grown tired of copy-pasting between projects.
Installation
dotnet add package JoakimAnder.Toolbox
Requires .NET 10 or later.
What's in the box
ParallelFanout — JoakimAnder.Toolbox.Threading.FanOut
Run several async operations that must all succeed, and cancel the rest the instant one fails — so a long-running sibling isn't left burning time and resources after the outcome is already decided.
using JoakimAnder.Toolbox.Threading;
var (user, orders) = await new FanOut()
.Add(ct => GetUserAsync(ct))
.Add(ct => GetOrdersAsync(ct))
.WhenAll(cancellationToken);
If GetUserAsync throws, the token handed to GetOrdersAsync is cancelled and the original
exception is rethrown unwrapped. Operations are factories (ct => …) so the token can be
threaded into each one. A static FanOut.WhenAll(op1, op2, …) is also available for quick one-liners — both typed
(returning a tuple) and void, for arities 2–8, plus an
IEnumerable<Func<CancellationToken, Task>> overload for dynamic counts.
Result — JoakimAnder.Toolbox.Results.Result<T, TError> / Result<TError>
A typed success/failure container for the boundaries of your code. Producers return values
via implicit conversions; consumers read via Match or TryGetValue — never via loose
Value / Error properties.
using JoakimAnder.Toolbox.Results;
public Task<Result<UserSummary, ApiError>> GetUserSummaryAsync(int id, CancellationToken ct) =>
Result.TryAsync(
async c => new UserSummary(await _users.GetAsync(id, c), await _orders.CountAsync(id, c)),
ex => ex switch
{
KeyNotFoundException k => (ApiError)new ApiError.NotFound(k.Message),
HttpRequestException h => new ApiError.Upstream(nameof(HttpRequestException), h.Message),
_ => new ApiError.Unexpected(ex.Message)
},
ct);
The caller defines ApiError (typically a sealed-record discriminated union) so the
boundary handler can switch on it exhaustively at compile time. Map / MapError /
Bind compose Result-returning calls — sync and async — and Result.Try / ValueOrThrow
provide explicit interop with throwing code (OperationCanceledException is always
rethrown so cancellation stays cancellation).
A void-success variant Result<TError> mirrors the typed one for commands that succeed
without a payload.
See docs/ROADMAP.md for the project roadmap.
DI registration — attributes + source generator
Mark a class with [Singleton], [Scoped], or [Transient] and the generator emits the
IServiceCollection registration for you — no reflection, no hand-maintained AddX lists.
using JoakimAnder.Toolbox.DependencyInjection;
[Singleton(typeof(IClock))] class SystemClock : IClock { }
[Scoped] class OrderService { }
// in Program.cs:
builder.Services.AddAttributedServices();
Omit the service type to register the concrete type itself. Use Group = "..." to emit a
separate AddAttributed<Group>Services() method, and Key = "..." for keyed services. The
attributes are generated into your assembly, so there is no extra runtime dependency.
Web API example — examples/JoakimAnder.Toolbox.Examples.WebApi
A small ASP.NET Core Minimal-API project showing all three Toolbox features
composed in a realistic shape — vertical-slice handlers that return
Result<T, ApiError>, a [Scoped]/[Singleton] service graph wired by the
DI source generator, and a fan-out endpoint (GET /books/{id}/detail) that
fetches author + reviews in parallel via Result.TryAsync(new FanOut().Add(…)).
dotnet run --project examples/JoakimAnder.Toolbox.Examples.WebApi
Use examples/JoakimAnder.Toolbox.Examples.WebApi/WebApi.http (REST Client,
Rider, or VS 2022+ run these in-place) or the auto-generated OpenAPI document
at /openapi/v1.json.
Project structure
src/JoakimAnder.Toolbox— the librarysrc/JoakimAnder.Toolbox.SourceGenerators— source generators, packed into the main NuGettests/— xUnit test projectsexamples/— runnable usage examples
Building locally
dotnet build
dotnet test
Versioning
Versions are derived from git tags via MinVer.
Tag a commit v1.2.3 to release 1.2.3 to NuGet.
License
MIT — see LICENSE.
AI usage
See AI_DISCLOSURE.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.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.