TwoRivers.Core 1.1.6

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

TwoRivers.Core

The TwoRivers.Core library provides fundamental utilities, value objects, and extensions used across the TwoRivers Application Framework. This package includes common types for email handling, string manipulation, natural sorting, IP address utilities, and base classes for common patterns.

Installation

You can install the TwoRivers.Core package via NuGet Package Manager Console:

Install-Package TwoRivers.Core

Or via .NET CLI:

dotnet add package TwoRivers.Core

Features

DisposableBase - Safe IAsyncDisposable and IDisposable pattern

Base class for implementing the dispose pattern correctly:

public class MyTestFixture : DisposableBase
{
    private HttpClient? _httpClient;           // IDisposable only
    private DbConnection? _dbConnection;       // IAsyncDisposable

    protected override void Dispose(Boolean disposing)
    {
        if (disposing)
        {
            _httpClient?.Dispose();
            _httpClient = null;
        }

        base.Dispose(disposing);
    }

    protected override async ValueTask DisposeAsyncCore()
    {
        if (_dbConnection is not null)
        {
            await _dbConnection.DisposeAsync().ConfigureAwait(false);
            _dbConnection = null;
        }

        // HttpClient also implements IAsyncDisposable in modern .NET
        if (_httpClient is IAsyncDisposable asyncDisposable)
        {
            await asyncDisposable.DisposeAsync().ConfigureAwait(false);
        }
        else
        {
            _httpClient?.Dispose();
        }

        _httpClient = null;

        await base.DisposeAsyncCore().ConfigureAwait(false);
    }
}

How does a derived class know which dispose to override?

Scenario Override
Async resources (e.g., IAsyncDisposable fields, async streams) DisposeAsyncCore()
Sync-only resources (e.g., IDisposable fields, unmanaged handles) Dispose(Boolean)
Mixed resources Both methods

The key insight: when DisposeAsync() is called, it calls DisposeAsyncCore() first (cleaning managed resources async), then Dispose(false) (cleaning only unmanaged resources). This prevents double-disposal of managed resources.

Value Objects

Email

Strongly-typed email address value object with validation:

using TwoRivers.Emailing;

var email = new Email("user@example.com");
Console.WriteLine(email.Domain);  // "example.com"
Console.WriteLine(email.LocalPart);  // "user"
EmailAddress

Combines display name and email address (compatible with System.Net.Mail.MailAddress):

using TwoRivers.Emailing;

var emailAddress = new EmailAddress("John Doe", "john@example.com");
var mailAddress = (MailAddress)emailAddress;  // Implicit conversion

// Or parse from string
var parsed = new EmailAddress("John Doe <john@example.com>");

NaturalComparer

Compares strings using natural (human-friendly) ordering where numbers are compared numerically:

using TwoRivers;

var files = new[] { "file10.txt", "file2.txt", "file1.txt" };
Array.Sort(files, new NaturalComparer<String>());
// Result: ["file1.txt", "file2.txt", "file10.txt"]

Extension Methods

StringExtensions

Common string manipulation utilities:

using TwoRivers.Extensions;

// Left substring
var text = "Hello World";
var left = text.Left(5);  // "Hello"

// Truncate with ellipsis
var truncated = text.Truncate(8);  // "Hello ..."

// Remove whitespace
var clean = "  lots   of   spaces  ".RemoveWhitespace();  // "lotsofspaces"
IPAddressExtensions

IP address utilities:

using TwoRivers.Extensions;
using System.Net;

var ip = IPAddress.Parse("192.168.1.100");
var network = IPAddress.Parse("192.168.1.0");

if (ip.IsInSameSubnet(network, 24))
{
    Console.WriteLine("Same subnet");
}
MiscExtensions

Miscellaneous extension methods:

using TwoRivers.Extensions;

// Clamp values
var value = 150;
var clamped = value.Clamp(0, 100);  // 100

// Visit exception hierarchy
try
{
    // code
}
catch (Exception ex)
{
    ex.Visit(e => Console.WriteLine($"Exception: {e.Message}"));
}

Comparers

IPAddressComparer

Compares IP addresses for sorting:

using TwoRivers.Net;

var addresses = new[]
{
    IPAddress.Parse("192.168.1.100"),
    IPAddress.Parse("10.0.0.1"),
    IPAddress.Parse("192.168.1.10")
};

Array.Sort(addresses, new IPAddressComparer());
EnumerableComparer

Compares sequences element-by-element:

using TwoRivers;

var comparer = new EnumerableComparer<Int32>();
var list1 = new[] { 1, 2, 3 };
var list2 = new[] { 1, 2, 4 };

var result = comparer.Compare(list1, list2);  // < 0

Reflection Utilities

ReflectionUtils

Extract constants and metadata using reflection:

using TwoRivers.Reflection;

public static class ErrorCodes
{
    public const String NotFound = "NOT_FOUND";
    public const String Unauthorized = "UNAUTHORIZED";
}

// Get all constant values
var codes = ReflectionUtils.GetConstants<String>(typeof(ErrorCodes));
// Returns: ["NOT_FOUND", "UNAUTHORIZED"]

License

This project is licensed under the MIT License. See the LICENSE file for details.

This project is licensed under the MIT License. See the LICENSE file for details.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (7)

Showing the top 5 NuGet packages that depend on TwoRivers.Core:

Package Downloads
ProvisionData.HaloPSA.ApiClient

HaloPSA API Client for .NET providing typed models and client helpers.

TwoRivers.Results

Framework and tools for implementing applications by following best practices in a developer friendly way. Built from commit 4a4908d297d9eb550c65eed6a73acd33dc9c9acc https://github.com/TwoRiversIT/AppFramework/commit/4a4908d297d9eb550c65eed6a73acd33dc9c9acc

TwoRivers.Testing

Framework and tools for implementing applications by following best practices in a developer friendly way. Built from commit 4a4908d297d9eb550c65eed6a73acd33dc9c9acc https://github.com/TwoRiversIT/AppFramework/commit/4a4908d297d9eb550c65eed6a73acd33dc9c9acc

TwoRivers.IdGeneratrion

Framework and tools for implementing applications by following best practices in a developer friendly way. Built from commit 4a4908d297d9eb550c65eed6a73acd33dc9c9acc https://github.com/TwoRiversIT/AppFramework/commit/4a4908d297d9eb550c65eed6a73acd33dc9c9acc

TwoRivers.Security

Framework and tools for implementing applications by following best practices in a developer friendly way. Built from commit 4a4908d297d9eb550c65eed6a73acd33dc9c9acc https://github.com/TwoRiversIT/AppFramework/commit/4a4908d297d9eb550c65eed6a73acd33dc9c9acc

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.6 49 2/26/2026
1.1.5 72 2/25/2026
1.1.4 179 2/22/2026
1.1.3 218 2/22/2026
1.1.2 175 2/22/2026
1.1.1 175 2/22/2026
1.1.0 160 2/22/2026
1.0.0 171 2/17/2026