Rumrunner0.BackToReality.SharedExtensions 0.10.2

Prefix Reserved
dotnet add package Rumrunner0.BackToReality.SharedExtensions --version 0.10.2
                    
NuGet\Install-Package Rumrunner0.BackToReality.SharedExtensions -Version 0.10.2
                    
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="Rumrunner0.BackToReality.SharedExtensions" Version="0.10.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Rumrunner0.BackToReality.SharedExtensions" Version="0.10.2" />
                    
Directory.Packages.props
<PackageReference Include="Rumrunner0.BackToReality.SharedExtensions" />
                    
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 Rumrunner0.BackToReality.SharedExtensions --version 0.10.2
                    
#r "nuget: Rumrunner0.BackToReality.SharedExtensions, 0.10.2"
                    
#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 Rumrunner0.BackToReality.SharedExtensions@0.10.2
                    
#: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=Rumrunner0.BackToReality.SharedExtensions&version=0.10.2
                    
Install as a Cake Addin
#tool nuget:?package=Rumrunner0.BackToReality.SharedExtensions&version=0.10.2
                    
Install as a Cake Tool

back-to-reality-shared-extensions

General-purpose toolkit of utilities and extensions for everyday .NET code.

This repository contains the Rumrunner0.BackToReality.SharedExtensions class library and Rumrunner0.BackToReality.SharedExtensions.Tests test project. All the content in the repository is an original work created as a personal project to keep reusable everyday utilities in one place.

License Nuget

Description

The Rumrunner0.BackToReality.SharedExtensions is a general-purpose class library of utilities and extension methods for everyday .NET code. It covers collections, cryptography, disposal, environment variables, exception guards and inspection, strings and object shaping, JSON serialization defaults, task awaiting, time truncation, and value objects. The library targets .NET 9, has no dependencies outside the base class library, enables nullable reference types with [NotNull] and [NotNullWhen] annotations on checks and guards, and ships strong-named with XML documentation and a symbol package.

The Rumrunner0.BackToReality.SharedExtensions.Tests is an xunit test project covering the behavior of the library.

Installation

To install the package, use the following command:

$ dotnet add package Rumrunner0.BackToReality.SharedExtensions

Usage

All types live under the Rumrunner0.BackToReality.SharedExtensions namespace. Each feature area below is a sub-namespace, for example Rumrunner0.BackToReality.SharedExtensions.Collections.

Collections

Counting predicates for IEnumerable<T> that stop enumerating as soon as the answer is known:

  • None(), Some(), Many() for the common cases.
  • Exactly(n), AtLeast(n), MoreThan(n), LessThan(n) for explicit bounds.
  • IsNullOrEmpty() and IsNotNullAndNotEmpty(), annotated so the compiler narrows nullability after the check.
using Rumrunner0.BackToReality.SharedExtensions.Collections;

var ready = requests.AtLeast(2) && requests.LessThan(100); // Never enumerates more than needed.

Helpers for lists and other collections:

  • Add(items) overloads that accept sequences, which also allows mixing single items and sequences in a collection initializer.
  • AddNonNulls(items) adds only the non-null values; ArrayExtensions.CreateFromNonNulls(items) builds an array the same way.
  • AddAndReturn(item) and AddAndReturnCollection(item) add an item and return the item or the collection.
  • RemoveFirst(), RemoveLast(), RemoveFromStart(end), RemoveToEnd(start), RemoveBetween(start, end) remove list ranges by inclusive indexes and return the list for chaining.
  • First() and Last() for IReadOnlyList<T> without LINQ.
  • Deconstruct2() through Deconstruct8() unpack a list into a value tuple.
  • StringJoin(separator) joins items into a string (the default separator is a space).
  • Cycle(ct) loops over a collection endlessly until the token is canceled or the collection becomes empty.
  • HashSetFactory.ReferenceEquality<T>() creates a HashSet<T> that compares items by reference.
IEnumerable<string> lines = ReadLines();
var merged = new List<string> { "header", lines, "footer" }; // Add(items) in an initializer.

var (host, port) = "localhost:8080".Split(':').Deconstruct2();

Cryptography

AES-256-GCM encryption of strings. The nonce, the authentication tag, and the ciphertext are packed into a single Base64 blob (nonce|tag|cipher), so one string carries everything needed for decryption. UTF-8 handling is strict (ill-formed input throws instead of being silently replaced), and transient copies of the key and the plaintext are zeroed after use.

using Rumrunner0.BackToReality.SharedExtensions.Cryptography;

var key = AesGcmSymmetricEncryption.GenerateKey();           // Base64-encoded 256-bit key.
var blob = AesGcmSymmetricEncryption.Encrypt("secret", key); // Base64 blob: nonce|tag|cipher.
var text = AesGcmSymmetricEncryption.Decrypt(blob, key);     // "secret".

CryptographicOperationExtensions.FixedTimeEquals(left, right) compares two strings without exiting early on the first mismatch, for values like tokens or password hashes.

Disposing

DisposableGroup treats several disposables as one. Disposal runs in reverse order to mirror nested using blocks, happens once even with concurrent calls, and never stops halfway: exceptions from individual items are collected into DisposalExceptions instead of being thrown. The group also implements IReadOnlyList<IDisposable>, so the items stay accessible until disposal.

using Rumrunner0.BackToReality.SharedExtensions.Disposing;

using var resources = new DisposableGroup([connection, transaction, reader]);

Environment

Readers for environment variables that must be present. A missing or empty variable produces an InvalidOperationException that names the variable; numbers are parsed with the invariant culture.

using Rumrunner0.BackToReality.SharedExtensions.Environment;

var connectionString = EnvironmentVariableExtensions.GetRequired("DB_CONNECTION_STRING");
var timeoutSeconds = EnvironmentVariableExtensions.GetRequiredInt("TIMEOUT_SECONDS");

Exceptions

Guard clauses that capture the argument expression automatically and carry nullability attributes, so a failing check reports the right parameter name and a passing one removes the null warnings that follow:

  • ThrowIfNull(value) for classes and ThrowIfNullValue(value) for nullable structs.
  • ThrowIfNullOrEmpty(value) and ThrowIfEmpty(value) for strings and collections.
  • ThrowIfNullOrEmptyOrWhiteSpace(value) and ThrowIfEmptyOrWhiteSpace(value) for strings.
  • ThrowIfAnyNull(collection) for collections that must not contain null items.
  • Throw(message, argumentName) to fail unconditionally.
using Rumrunner0.BackToReality.SharedExtensions.Exceptions;

void Send(Message? message)
{
	ArgumentExceptionExtensions.ThrowIfNull(message); // ArgumentNullException with ParamName "message".
	Deliver(message.Body);                            // No null warning: the guard is annotated with [NotNull].
}

Helpers for inspecting caught exceptions, aware of every branch of an AggregateException:

  • IsOrHasInner<T>() returns the first T found, starting from the exception itself.
  • HasInner<T>() does the same but searches only the inner exceptions.
  • JoinMessages(separator) flattens the messages of the whole chain into one string.
try
{
	await ProcessAsync();
}
catch (Exception e) when (e.IsOrHasInner<TimeoutException>() is not null)
{
	logger.LogWarning("Timed out: {Messages}", e.JoinMessages("; "));
}

Extensions

String helpers:

  • Emptiness checks that narrow nullability: IsNullOrEmpty(), IsEmpty(), IsNullOrEmptyOrWhitespace(), IsEmptyOrWhitespace().
  • IsValidJson() for a quick syntax check.
  • SplitByWhitespace() splits on any whitespace and drops empty entries.
  • ToGuid() and ToGuidOrNull() parse a string into a Guid.
  • TryGetBytesFromBase64String(value, out bytes) decodes Base64 without throwing.
  • Format(values) as an extension form of string.Format.

Object shaping, for keeping a transformation in a single expression:

  • Shape(x => ...) maps an object into another one.
  • Chain(x => ...) runs an action (sync or async) and returns the object.
  • Follow(target) switches the chain to another object.
using Rumrunner0.BackToReality.SharedExtensions.Extensions;

var summary = order
	.Chain(o => logger.LogInformation("Processing {Id}", o.Id))
	.Shape(o => new OrderSummary(o.Id, o.Total));

EmailAddressExtensions.PragmaticRegex() is a source-generated, case-insensitive email pattern meant for practical validation rather than full RFC coverage.

Serialization

JsonSerializerOptionsExtensions.BetterWeb is a shared, read-only JsonSerializerOptions instance: camelCase names, case-insensitive reading, strict number handling, indented output with tabs, \n line endings, no trailing commas. ConfigureBetterWeb() applies the same settings to an instance you own.

using Rumrunner0.BackToReality.SharedExtensions.Serialization;

var json = JsonSerializer.Serialize(order, JsonSerializerOptionsExtensions.BetterWeb);

Tasks

ContinueWithoutContextCapture() is ConfigureAwait(false) under a name that states its effect: the continuation does not marshal back to the captured context. Overloads cover Task, Task<T>, ValueTask, and ValueTask<T>.

using Rumrunner0.BackToReality.SharedExtensions.Tasks;

var payload = await LoadAsync().ContinueWithoutContextCapture();

Time

  • Truncate(resolution) cuts a DateTimeOffset down to the nearest lower multiple of a tick resolution and keeps the offset.
  • TruncatedTimeProvider is a TimeProvider whose GetUtcNow() is truncated to whole microseconds, which keeps timestamps stable when they round-trip through storage with microsecond precision.
using Rumrunner0.BackToReality.SharedExtensions.Time;

var rounded = DateTimeOffset.UtcNow.Truncate(TimeSpan.TicksPerSecond);

Value objects

IValueObject<TSelf, TValue> is a minimal contract for strongly typed wrappers over a single value: a Value property, equality, and a static From factory.

using Rumrunner0.BackToReality.SharedExtensions.ValueObjects;

public readonly record struct UserId(Guid Value) : IValueObject<UserId, Guid>
{
	public static UserId From(Guid value) => new (value);
}

Contributing

If you have any suggestions, ideas, or feedback to enhance the project, please feel free to create an issue. Your collaboration is welcomed to make this project a bit better.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  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.
  • net9.0

    • No dependencies.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on Rumrunner0.BackToReality.SharedExtensions:

Package Downloads
Rumrunner0.BackToReality.Suspicious

Result monad with rich error semantics and traceable context.

Rumrunner0.BackToReality.PasswordHashing

Password hashing implementations with a convenient API.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.10.2 136 8/14/2026
0.10.1 132 7/19/2026
0.10.0 100 7/19/2026
0.10.0-dev.20260718.1 50 7/18/2026
0.9.0 140 6/28/2026
0.8.10 155 5/19/2026
0.8.9 149 1/7/2026
0.8.7 132 1/2/2026
0.8.4 268 12/13/2025
0.8.3 251 12/13/2025
0.8.2 265 12/12/2025
0.8.1 196 12/12/2025
0.8.0 538 12/10/2025
Loading failed