Tharga.Toolkit.Standard
1.15.20
dotnet add package Tharga.Toolkit.Standard --version 1.15.20
NuGet\Install-Package Tharga.Toolkit.Standard -Version 1.15.20
<PackageReference Include="Tharga.Toolkit.Standard" Version="1.15.20" />
<PackageVersion Include="Tharga.Toolkit.Standard" Version="1.15.20" />
<PackageReference Include="Tharga.Toolkit.Standard" />
paket add Tharga.Toolkit.Standard --version 1.15.20
#r "nuget: Tharga.Toolkit.Standard, 1.15.20"
#:package Tharga.Toolkit.Standard@1.15.20
#addin nuget:?package=Tharga.Toolkit.Standard&version=1.15.20
#tool nuget:?package=Tharga.Toolkit.Standard&version=1.15.20
Tharga.Toolkit.Standard
.NET Standard 2.0 toolkit with utilities for strings, dates, collections, comparisons, timers, and more.
Installation
dotnet add package Tharga.Toolkit.Standard
Features
String Extensions
// Null/empty helpers
string val = "".NullIfEmpty(); // null
bool empty = "".IsNullOrEmpty(); // true
string safe = ((string)null).IfEmpty("fallback"); // "fallback"
// Random strings (cryptographically secure)
var random = StringExtension.GetRandomString(12, 20);
var pin = 6.RandomString(StringExtension.NumericCharacters); // "482917"
// Base64
var encoded = "hello".ToBase64(); // "aGVsbG8="
var decoded = encoded.FromBase64(); // "hello"
// Truncate
var short = "hello world".Truncate(5); // "hello"
Compare
Deep object comparison that returns a list of differences.
var obj1 = new { Name = "Alice", Age = 30 };
var obj2 = new { Name = "Bob", Age = 30 };
var diffs = obj1.Compare(obj2);
foreach (var diff in diffs)
{
Console.WriteLine(diff.Message);
}
// Ignore sort order in collections
var diffs2 = list1.Compare(list2, CompareExtensions.CompareMode.IgnoreSortOrder);
DateTime Extensions
// Local formatting
var dateStr = DateTime.UtcNow.ToLocalDateString(); // "2024-01-15"
var timeStr = DateTime.UtcNow.ToLocalTimeString(); // "14:30:00"
// Duration strings (relative time)
var ago = someDate.ToDurationString(); // "3 hours ago"
var swedish = someDate.ToDurationString(new DurationOptions
{
StringOptions = DurationStringOptionsExtensions.Get(Language.Sv)
}); // "3 timmar sedan"
// TimeSpan formatting
var span = TimeSpan.FromMinutes(45).ToTimeSpanString(); // "45 minutes"
ManagedTimer
Async timer with interval correction, skip detection, and rich events.
var timer = new ManagedTimer(
TimeSpan.FromSeconds(5),
async iteration => { /* your work */ },
autoStart: true
);
timer.BeforeExecuteEvent += (s, e) => { /* can cancel via e.Cancel = true */ };
timer.AfterExecuteEvent += (s, e) => { /* check e.Exception, e.Elapsed */ };
timer.StateChangedEvent += (s, e) => { /* Started, Executing, Waiting, Stopped */ };
timer.Stop();
Enumerable Extensions
var item = items.TakeRandom(); // random element
var shuffled = items.RandomOrder(); // random order
var tail = items.TakeAllButFirst(); // skip first
var init = items.TakeAllButLast(); // skip last
var chunks = items.TakeChunks(10); // split into groups of 10
bool empty = EnumerableExtensions.IsNullOrEmpty(items);
var safe = EnumerableExtensions.EmptyIfNull(items); // never null
Luhn Check Digits
var check = "7992739871".CheckDigit(); // "3"
var full = "7992739871".AppendCheckDigit(); // "79927398713"
bool valid = "79927398713".HasValidCheckDigit(); // true
// Also works with int, long, and IList<int>
int digit = 36155.CheckDigit(); // 0
Password Hasher
PBKDF2-based password hashing.
var hash = PasswordHasher.HashPassword("myPassword");
bool ok = PasswordHasher.VerifyPassword("myPassword", hash); // true
bool bad = PasswordHasher.VerifyPassword("wrong", hash); // false
Collections
// Two-level concurrent dictionary
var dict = new ConcurrentTwoLevelDictionary<string, string, int>();
var (before, after) = dict.AddOrUpdate("users", "alice", 42);
// Observable concurrent dictionary (INotifyCollectionChanged)
var observable = new ObservableConcurrentDictionary<string, int>();
observable.CollectionChanged += (s, e) => { /* react to changes */ };
observable.Add("key", 1);
Semaphore Executor
Key-based async semaphore: same key = sequential, different keys = concurrent.
var executor = new SemaphoreExecutor<string>();
var result = await executor.ExecuteAsync("user-123", async () =>
{
// Only one operation per key at a time
return await ProcessAsync();
});
Claims Extensions
Extract identity, email, and display name from ClaimsPrincipal, ClaimsIdentity, or raw claims.
// Identity extraction (checks sub, oid, nameid, uid, NameIdentifier)
var (identity, type) = principal.GetIdentity();
// Email extraction (checks email, emails, preferred_username, name)
var email = principal.GetEmail();
var domain = principal.GetEmailDomain();
// Display name extraction — tries in order:
// 1. "name" (OIDC) 2. ClaimTypes.Name (WS-Fed) 3. "nickname" (Auth0)
// 4. given_name + family_name 5. ClaimTypes.GivenName + Surname
// 6. preferred_username (non-email) 7. email prefix, title-cased
var displayName = principal.GetDisplayName();
// e.g. "daniel.bohlin@example.com" → "Daniel Bohlin"
// Domain-based role assignment
principal.AddRoleForDomain("Developer", "example.com", "contoso.com");
Other Extensions
// Org number parsing (Swedish format)
if ("556123-4567".TryParseOrgNo(out var orgNo))
Console.WriteLine(orgNo); // "556123-4567"
// Byte size formatting
long bytes = 1536;
Console.WriteLine(bytes.ToReadableByteSize(decimalPlaces: 1)); // "1.5 KB"
// Enum mapping
var target = sourceEnum.MapEnum<TargetEnum, SourceEnum>();
// Exception data helpers
throw new Exception("error")
.AddData("userId", 123)
.AddData("action", "save");
// Smart enum
public class Color : Enumeration
{
public static readonly Color Red = new(1, "Red");
public static readonly Color Blue = new(2, "Blue");
private Color(int id, string name) : base(id, name) { }
}
var all = Enumeration.GetAll<Color>();
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Tharga.Toolkit.Standard:
| Package | Downloads |
|---|---|
|
Tharga.Toolkit
Tools for hashing, claims, API keys, collections, DateTime, Luhn, Compare and more. Includes all features from Tharga.Toolkit.Standard. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.15.20 | 273 | 4/5/2026 |
| 1.15.19 | 454 | 3/25/2026 |
| 1.15.18 | 898 | 1/31/2026 |
| 1.15.16 | 348 | 12/28/2025 |
| 1.15.14 | 215 | 12/20/2025 |
| 1.15.12 | 828 | 12/1/2025 |
| 1.15.10 | 618 | 12/1/2025 |
| 1.15.8 | 529 | 11/30/2025 |
| 1.15.6 | 256 | 11/25/2025 |
| 1.15.4 | 232 | 11/25/2025 |
| 1.15.2 | 992 | 11/11/2025 |
| 1.14.3 | 228 | 11/1/2025 |
| 1.13.26 | 203 | 11/1/2025 |
| 1.13.24 | 265 | 10/31/2025 |
| 1.13.22 | 383 | 10/27/2025 |
| 1.13.20 | 416 | 10/14/2025 |
| 1.13.18 | 235 | 10/13/2025 |
| 1.13.16 | 366 | 8/16/2025 |
| 1.13.14 | 419 | 8/5/2025 |
| 1.13.12 | 725 | 7/22/2025 |