SamSoft.Common 1.4.0

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

SamSoft.Common

SamSoft.Common is a .NET class library that centralizes reusable building blocks for application code: a Result model with structured errors, an optional Maybe<T> type, and many extension methods for strings, collections, dates, binary data, and cryptography.

Target framework .NET 8.0
Language C# (nullable reference types enabled)
License MIT (see PackageLicenseExpression in SamSoft.Common.csproj)
Package readme This file is packed as the NuGet readme (PackageReadmeFile)

Table of contents

  1. Why use this library
  2. Installation
  3. Repository layout
  4. Namespaces and API reference
  5. Behavior notes and pitfalls
  6. Security (cryptography)
  7. Build, test, and package
  8. Versioning and releases
  9. Contributing

Why use this library

  • Predictable error handling — Model failures with Result / Error instead of scattering try/catch for control flow.
  • Optional valuesMaybe<T> for presence/absence without overloading null semantics everywhere.
  • Less boilerplate — Extensions for common string, collection, and date operations used across services and UI layers.
  • Single dependency surface — One package instead of copying helpers into each solution.

Installation

Project reference (source / monorepo)

<ItemGroup>
  <ProjectReference Include="..\SamSoft.Common\SamSoft.Common.csproj" />
</ItemGroup>

NuGet (when the package is published)

dotnet add package SamSoft.Common

Ensure the consuming project targets .NET 8 or higher (or a compatible TFM that can reference net8.0 libraries).


Repository layout

SamSoft.Common/
├── SamSoft.Common/           # Main library (net8.0)
│   ├── Enums/                # CurrencyCodes, CurrencyCodeExtension
│   ├── ExtensionMethods/     # String, enumerable, date, crypto, etc.
│   ├── OptionObject/         # Maybe<T>, MaybeExtensions
│   ├── Results/              # Result, Result<T>, Error, ResultExtensions
│   └── TokenResponse.cs
├── SamSoft.Common.Tests/     # Unit tests (xUnit.net v3)
├── SamSoft.Common.sln
└── README.md                 # This file (also packed for NuGet)

Namespaces and API reference

SamSoft.Common.Results

Type Purpose
Result Discriminated success/failure without a value. IsSuccess / IsFailure, Error on failure.
Result<TValue> Success carries Value; on failure Value is default. Implicit conversion from T to success.
Error Record: Code, Message, ErrorType, optional Metadata (IReadOnlyDictionary<string, object?>?). Static helpers: Failure, Validation (with optional metadata), NotFound, Conflict, Problem, Create(Exception). Error.None, Error.NullValue. Implicit conversions to string (code) and Result.
ErrorType Failure, Validation, NotFound, Conflict, Problem, None.
ResultExtensions Ensure, Map (sync and Task), Map on Task<Result>bool, sync/async Bind, Combine, TryCatch, Tap, sync/async Match, FirstFailure.

Result factories

  • Result.Success(), Result.Success<T>(T value)
  • Result.Failure(Error), Result.Failure<T>(Error)
  • Result.Create<T>(T? value, Error) / Result.Create<T>(T value) (reference types)
  • Result.FirstFailureOrSuccess(params Result[] results)

Error.Metadata (field validation and extras)

Optional bag for field-level validation messages, correlation IDs, or other structured details. Prefer string keys (property names) and values such as string, string[], or numbers.

var error = Error.Validation(
    "User.Validation",
    "One or more validation errors occurred.",
    new Dictionary<string, object?>
    {
        ["Email"] = new[] { "Email is required.", "Email is invalid." },
        ["Age"] = new[] { "Age must be at least 18." },
        ["CorrelationId"] = "abc-123"
    });

Result result = error; // implicit conversion to failure Result
// result.Error.Metadata!["Email"] → string[]

Factories that omit metadata leave Metadata as null.


SamSoft.Common.OptionObject

Type Purpose
Maybe<T> HasValue / HasNoValue, Value (throws if none), None, From(T?), implicit TMaybe<T>. GetValueOrDefault(), GetValueOrDefault(T), TryGetValue(out T). Equals / GetHashCode.
MaybeExtensions Bind (async), Match on Task<Maybe<T>>.

SamSoft.Common (root)

Type Purpose
TokenResponse Obsolete — define auth-specific types in your application layer. Primary constructor: token, expiry, isSuperAdmin, refreshToken, tenantId, isAdmin.

SamSoft.Common.Enums

Type Purpose
CurrencyCodes ISO-style numeric currency enum with [Description] metadata; JSON string enum converter.
CurrencyCodeExtension GetCurrencyName(this CurrencyCodes) — resolves description from attributes.

SamSoft.Common.ExtensionMethods (selected groups)

StringExtension

Null-tolerant helpers where applicable: IsNotNullOrEmpty, EqualWithIgnoreCase (ordinal), NotEqual, IsNumeric, ToCamelCase, IsDate, IsValidEmailAddress, IsValidUrl, IsGuid, ToInt (with optional default), ToDecimal, ToDateTime (multiple overloads), IsDateTime, ToBoolean, IsEmailAddress (stricter), IsValidJson, TryParseJson<T>, ToTitleCase, IsArabic, TryGetInt, FormatWithMask (two overloads), IsDateTime with format → (bool, DateTime), IsNumber.

EnumerableExtensions

IsNullOrNotItem, NotNullOrEmpty, Do, ForEach (three overloads: Action, non-generic IEnumerable, Func projection), RemoveAll on ICollection<T>, Count for non-generic IEnumerable, SetValue, IsNullOrEmpty, NotExists (with/without predicate), ForEachAsync, SelectManyRecursive, IsNotNullOrEmpty, ToObservableCollection, ConvertTo, Each, Cache.

PredicateBuilder

And, Or for combining Expression<Func<T, bool>> with parameter rebinding (useful for dynamic LINQ to Entities predicates).

DateTimeExtensionMethods

TryParseTime, IsValidTime (string), ToEgyptLocalTime (Egypt Standard Time / Africa/Cairo), ToDateByLocalTime (obsolete, alias), GetLocalFromUtc, DateOnly/DateTime conversions, Range between dates, BeginOfMonth / EndOfMonth, BeginOfYear / EndOfYear, WithoutMilliseconds, ConvertToUrlFormat, ToDateFromUrlFormat, EndOfDay, IsBetween, ConvertToSqlFormat, GetDateTimeSqlFormat.

EnumExtensionMethods

GetDescription, ToEnum<TEnum>, ToValues<T> (flags-style enumeration; see pitfalls).

GuidGenerator / GuidVersion

Time-based GUID generation (GenerateTimeBasedGuid overloads), GetVersion, GetDateTimeOffset / GetDateTime / GetLocalDateTime / GetUtcDateTime.

TextEncryptDecrypt

Legacy: SsEncrypt, SsDecrypt (obsolete). Secure: SsEncryptSecure, SsDecryptSecure (password, optional PBKDF2 iterations). See Security.

DeepCopyHelper

DeepCopy<T> via System.Text.Json serialize/deserialize (throws if deserialization yields null).

ExceptionExtension

GetInnerExceptionString, ToFullBlownString, GetMostInner, ExceptionJson.

HashCodeByPropertyExtensions

GetHashCodeOnProperties, GetListHashCode.

ByteArrayExtension / GetFileDataFromFileUrl

GetImageUrl, GetMimeType, FromImageUrl (obsolete — use FileData.CreateFromUrl).

FileData

Record FileData(byte[] File, string MimeContentType); CreateFromUrl with MIME allowlist validation.


Behavior notes and pitfalls

Error.Metadata

  • Optional; null when unused.
  • Dictionary equality is by reference on the Error record (contents are not compared deeply).
  • Prefer serializable value types (string, string[], numbers) if you map errors to HTTP/JSON responses — object? can deserialize as JsonElement.

Result<T>.Value on failure

On failure, accessing .Value throws InvalidOperationException. Use TryGetValue, GetValueOrDefault, or Match/Bind instead of reading .Value when the outcome is unknown.

Maybe<T> and value types

HasNoValue is implemented as _value is null. For reference types, null means “none.” For unconstrained value types (e.g. Maybe<int>), there is no distinct “none” separate from default(T); None and 0 are not distinguishable the same way as for references. Prefer Maybe<T?> (e.g. Maybe<int?>) or reference types when you need a clear empty state.

EnumerableExtensions.ForEach and lambdas

There are two ForEach overloads: one takes Action<T>, another Func<T, TResult>. A lambda like x => n += x can bind to the Func overload (because += yields a value). Use a block x => { n += x; } when you intend side effects only.

EnumExtensionMethods.ToValues<T>

Validation (T must be an enum type) runs when the iterator is executed (e.g. foreach, ToList()), not merely when ToValues() is called.

JSON deep copy

DeepCopy<T> depends on System.Text.Json semantics. Polymorphic graphs, cycles, or types that do not round-trip cleanly may fail or throw.

DateTimeExtensionMethods.ToEgyptLocalTime

Uses Egypt Standard Time (Windows) or Africa/Cairo (IANA). The obsolete ToDateByLocalTime is an alias. Availability depends on the OS time zone database.

EnumerableExtensions.ForEachAsync

Pass maxDegreeOfParallelism to limit concurrent tasks. The default runs all tasks in parallel via Task.WhenAll.


Security (cryptography)

API Use case
SsEncrypt / SsDecrypt Legacy compatibility only for data encrypted by older versions. Weak by modern standards (fixed IV, MD5-based key material). Do not use for new secrets.
SsEncryptSecure / SsDecryptSecure Preferred for new data: random salt and IV per message, PBKDF2 (SHA-256), AES-CBC. Pass passwords or key material from configuration, vaults, or user input—never embed secrets in source code or commit them to the repository.

Rotate keys and migration strategies if you move from legacy to secure formats.


Build, test, and package

# Restore and compile
dotnet build SamSoft.Common.sln

# Run tests (xUnit.net v3)
dotnet test SamSoft.Common.sln

# Optional: create a NuGet package (produces .nupkg and .snupkg in ./artifacts)
dotnet pack SamSoft.Common/SamSoft.Common.csproj -c Release -o ./artifacts

Publish to NuGet.org (or another feed)

dotnet pack creates two files:

File Purpose
SamSoft.Common.1.4.0.nupkg Main package — upload this first
SamSoft.Common.1.4.0.snupkg Symbol package — upload after the main package exists on the feed

If you upload the .snupkg first (or only upload symbols), NuGet returns:

A package with ID 'SamSoft.Common' and version '1.4.0' does not exist. Please upload the package before uploading its symbols.

Correct order (CLI):

dotnet pack SamSoft.Common/SamSoft.Common.csproj -c Release -o ./artifacts

# 1) Main package first
dotnet nuget push ./artifacts/SamSoft.Common.*.nupkg \
  --source https://api.nuget.org/v3/index.json \
  --api-key YOUR_NUGET_API_KEY \
  --skip-duplicate

# 2) Symbols second (only the .snupkg — do not use *.nupkg here)
dotnet nuget push ./artifacts/SamSoft.Common.*.snupkg \
  --source https://api.nuget.org/v3/index.json \
  --api-key YOUR_NUGET_API_KEY \
  --skip-duplicate

On the nuget.org web UI, upload the .nupkg first, wait until it appears on the site, then upload the .snupkg.

If you do not need separate symbol packages, set <IncludeSymbols>false</IncludeSymbols> in SamSoft.Common.csproj and only publish the .nupkg.

The test project (SamSoft.Common.Tests) targets .NET 8 and uses xUnit.net v3 with broad coverage of public APIs and regression scenarios.


Versioning and releases

  • Assembly and NuGet version are driven by SamSoft.Common.csproj (AssemblyVersion, Version, FileVersion).
  • Bump the version when you publish a new package or introduce breaking API changes (document them for consumers).
  • License acceptance: PackageRequireLicenseAcceptance is set in the project file; consumers may need to acknowledge the MIT license in internal feeds.

Contributing

  1. Keep changes focused and consistent with existing naming and patterns.
  2. Add or update unit tests in SamSoft.Common.Tests for any new or changed behavior.
  3. Update this README when you add public API surface that users depend on.
  4. Do not commit secrets, credentials, or production connection strings.

Additional resources

  • Result pattern (background): the ErrorType enum file references an external talk link in source; see ErrorType.cs in the repository.

For questions or improvements, use your team’s usual code review and issue workflow.

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 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.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on SamSoft.Common:

Package Downloads
SamSoft.Mediator.CQRS

Result-typed CQRS mediator for .NET with pipeline behaviors, FluentValidation, and DI integration.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.4.0 259 8/10/2026
1.3.0 118 8/10/2026
1.2.2 214 4/19/2026
1.2.1 126 4/19/2026 1.2.1 is deprecated because it has critical bugs.
1.2.0 127 4/19/2026 1.2.0 is deprecated because it has critical bugs.
1.1.0 135 4/19/2026 1.1.0 is deprecated because it has critical bugs.
1.0.8 250 6/20/2025
1.0.7 347 6/10/2025
1.0.6 351 6/10/2025
1.0.5 342 6/10/2025
1.0.4 353 6/10/2025
1.0.3 325 6/10/2025
1.0.2 186 5/30/2025
1.0.1 240 5/22/2025
1.0.0 201 5/22/2025