Myth.Commons
4.0.1-preview.2
See the version list below for details.
dotnet add package Myth.Commons --version 4.0.1-preview.2
NuGet\Install-Package Myth.Commons -Version 4.0.1-preview.2
<PackageReference Include="Myth.Commons" Version="4.0.1-preview.2" />
<PackageVersion Include="Myth.Commons" Version="4.0.1-preview.2" />
<PackageReference Include="Myth.Commons" />
paket add Myth.Commons --version 4.0.1-preview.2
#r "nuget: Myth.Commons, 4.0.1-preview.2"
#:package Myth.Commons@4.0.1-preview.2
#addin nuget:?package=Myth.Commons&version=4.0.1-preview.2&prerelease
#tool nuget:?package=Myth.Commons&version=4.0.1-preview.2&prerelease
<img style="float: right;" src="myth-commons-logo.jpg" alt="drawing" width="250"/>
Myth.Commons
Myth.Commons is a foundational .NET library providing essential utilities and patterns for building robust, maintainable enterprise applications. It offers JSON serialization, string manipulation, DDD building blocks, and centralized service provider management for cross-library dependency resolution.
Features
- JSON Extensions: Flexible serialization/deserialization with configurable settings
- String Utilities: Rich set of string manipulation methods
- URL Extensions: URL encoding helpers
- Value Objects: DDD base class for implementing value objects with structural equality
- Constants: Type-safe constants using SmartEnum pattern
- Service Provider Management: Global service provider for cross-library dependency resolution
- Scoped Services: Pattern for executing operations within automatic service scopes
- Pagination Support: Value objects and interfaces for paginated results
- Collection Extensions: Helper methods for working with enumerables
Installation
dotnet add package Myth.Commons
Table of Contents
- JSON Extensions
- String Extensions
- URL Extensions
- Value Objects
- Constants
- Service Provider Management
- Scoped Services
- Pagination
- Collection Extensions
JSON Extensions
Powerful JSON serialization and deserialization with System.Text.Json, featuring global configuration, custom converters, and flexible naming strategies.
Basic Usage
using Myth.Extensions;
// Serialize to JSON
var user = new User { Id = 1, Name = "John Doe", Email = "john@example.com" };
var json = user.ToJson();
// {"id":1,"name":"John Doe","email":"john@example.com"}
// Deserialize from JSON
var userObj = json.FromJson<User>();
Global Configuration
Configure JSON settings globally for your entire application:
JsonExtensions.Configure( settings => settings
.UseCaseStrategy( CaseStrategy.SnakeCase )
.IgnoreNull()
.Minify()
);
var json = user.ToJson();
// {"id":1,"name":"John Doe","email":"john@example.com"}
Per-Operation Configuration
Override global settings for specific operations:
// Use snake_case for this operation only
var json = user.ToJson( settings => settings
.UseCaseStrategy( CaseStrategy.SnakeCase )
);
// {"id":1,"name":"john doe","email":"john@example.com"}
// Minify JSON output
var compactJson = user.ToJson( settings => settings.Minify() );
// Ignore null values
var jsonWithoutNulls = user.ToJson( settings => settings.IgnoreNull() );
Interface to Concrete Type Converters
Handle interfaces and abstract types during serialization/deserialization:
// Using generic converter
var json = user.ToJson( settings => settings
.UseInterfaceConverter<IAddress, Address>()
);
// Using non-generic converter
var json = user.ToJson( settings => settings
.UseInterfaceConverter( typeof( IAddress ), typeof( Address ) )
);
Custom JSON Converters
Add custom System.Text.Json converters:
var json = user.ToJson( settings => settings
.UseCustomConverter( new CustomDateTimeConverter() )
);
Advanced JSON Settings
Access underlying JsonSerializerOptions for fine-grained control:
var json = user.ToJson( settings => {
settings.IgnoreNull().Minify();
settings.OtherSettings = options => {
options.MaxDepth = 64;
options.NumberHandling = JsonNumberHandling.AllowReadingFromString;
};
} );
Case Strategies
Two naming conventions are supported:
public enum CaseStrategy {
CamelCase, // myAwesomeProperty
SnakeCase // my_awesome_property
}
Dynamic Object Support
Deserialize to dynamic objects:
var json = "{\"name\":\"John\",\"age\":30}";
dynamic obj = json.FromJson<object>();
Console.WriteLine( obj.name ); // John
Exception Handling
All JSON operations throw JsonParsingException on failure:
try {
var obj = invalidJson.FromJson<User>();
} catch ( JsonParsingException ex ) {
Console.WriteLine( $"JSON parsing failed: {ex.Message}" );
Console.WriteLine( $"Inner exception: {ex.InnerException?.Message}" );
}
String Extensions
Rich set of utilities for string manipulation and analysis.
using Myth.Extensions;
// Remove text
var result = "Hello World".Remove( "World" ); // "Hello "
// Minify (remove all whitespace)
var minified = "Hello World\n\t".Minify(); // "HelloWorld"
// Change case of first letter
var lower = "Hello".ToFirstLower(); // "hello"
var upper = "hello".ToFirstUpper(); // "Hello"
// Extract text between characters
var text = "The 'quick' brown fox";
var extracted = text.GetStringBetween( '\'' ); // "quick"
// Find words
var sentence = "The quick brown fox";
var word = sentence.GetWordThatContains( "qui" ); // "quick"
var before = sentence.GetWordBefore( "brown" ); // "quick"
var after = sentence.GetWordAfter( "quick" ); // "brown"
// Search operations
var hasAny = "Hello World".ContainsAnyOf( "Hi", "Hello", "Hey" ); // true
var startsWithAny = "Hello World".StartsWithAnyOf( "Hi", "Hello" ); // true
URL Extensions
Encode objects for URL usage:
using Myth.Extensions;
var text = "Hello World";
var encoded = text.EncodeAsUrl(); // "Hello+World"
var flag = true;
var encodedFlag = flag.EncodeAsUrl(); // true (as boolean)
Value Objects
Base class for implementing Domain-Driven Design value objects with structural equality.
using Myth.ValueObjects;
public class Address : ValueObject {
public string Street { get; }
public string City { get; }
public string ZipCode { get; }
public Address( string street, string city, string zipCode ) {
Street = street;
City = city;
ZipCode = zipCode;
}
protected override IEnumerable<object> GetAtomicValues() {
yield return Street;
yield return City;
yield return ZipCode;
}
}
// Value objects are compared by their values, not reference
var address1 = new Address( "123 Main St", "Springfield", "12345" );
var address2 = new Address( "123 Main St", "Springfield", "12345" );
var address3 = new Address( "456 Oak Ave", "Springfield", "12345" );
Console.WriteLine( address1 == address2 ); // true (same values)
Console.WriteLine( address1 == address3 ); // false (different values)
// Clone value objects
var clone = address1.Clone();
Value Object Benefits
- Immutability: Encourages immutable design patterns
- Equality by Value: Automatically handles equality comparison based on properties
- DDD Alignment: Perfect for domain modeling and tactical DDD patterns
- Type Safety: Prevents primitive obsession
Constants
Type-safe constants using Ardalis.SmartEnum pattern.
using Myth.ValueObjects;
public class OrderStatus : Constant<OrderStatus, string> {
public static readonly OrderStatus Pending = new( nameof( Pending ), "PENDING" );
public static readonly OrderStatus Processing = new( nameof( Processing ), "PROCESSING" );
public static readonly OrderStatus Completed = new( nameof( Completed ), "COMPLETED" );
public static readonly OrderStatus Cancelled = new( nameof( Cancelled ), "CANCELLED" );
private OrderStatus( string name, string value ) : base( name, value ) { }
}
// Usage
var status = OrderStatus.Pending;
string statusValue = status; // Implicit conversion to "PENDING"
// Get from value
var status2 = OrderStatus.FromValue( "PROCESSING" ); // OrderStatus.Processing
// Get from name
var status3 = OrderStatus.FromName( "Completed" ); // OrderStatus.Completed
// List all options
var options = OrderStatus.GetOptions();
// "(Pending): PENDING | (Processing): PROCESSING | (Completed): COMPLETED | (Cancelled): CANCELLED"
// Switch on constants (exhaustive)
var message = status switch {
var s when s == OrderStatus.Pending => "Order is pending",
var s when s == OrderStatus.Processing => "Order is being processed",
var s when s == OrderStatus.Completed => "Order is completed",
var s when s == OrderStatus.Cancelled => "Order was cancelled",
_ => throw new InvalidOperationException()
};
Constant Benefits
- Type Safety: Compile-time safety instead of magic strings/numbers
- IntelliSense Support: IDE autocomplete for all values
- Pattern Matching: Works beautifully with C# switch expressions
- Listing: Easy enumeration of all values
- Extensibility: Add methods and properties to constants
Service Provider Management
Global service provider management enables cross-library dependency resolution without coupling libraries together.
ASP.NET Core Applications
Use BuildApp() instead of Build() to automatically initialize the global service provider:
var builder = WebApplication.CreateBuilder( args );
builder.Services.AddFlow();
builder.Services.AddGuard();
builder.Services.AddFlowActions( config => { ... } );
var app = builder.BuildApp(); // Instead of builder.Build()
app.UseGuard();
app.Run();
Console Applications / Background Services
Use the global service provider for non-web applications:
var services = new ServiceCollection();
services.AddFlow();
services.AddGuard();
services.AddMyServices();
var serviceProvider = services.BuildServiceProvider();
MythServiceProvider.Initialize( serviceProvider );
// Now all libraries can resolve dependencies
var pipeline = Pipeline.Start( context );
Accessing Global Service Provider
using Myth.ServiceProvider;
// Check if initialized
if ( MythServiceProvider.IsInitialized ) {
var provider = MythServiceProvider.Current;
}
// Get or throw if not initialized
var requiredProvider = MythServiceProvider.GetRequired();
// Get with fallback
var provider = MythServiceProvider.GetOrFallback( localServiceProvider );
// Try initialize (first-wins pattern)
var initialized = MythServiceProvider.TryInitialize( serviceProvider );
// Force initialize (overwrites existing)
MythServiceProvider.Initialize( serviceProvider );
External Library Integration
External libraries can access registered services:
public class ThirdPartyLibrary {
public void DoSomething() {
var provider = ServiceCollectionExtensions.GetGlobalProvider();
var validator = provider?.GetService<IValidator>();
if ( validator != null ) {
// Use Myth libraries without direct coupling
}
}
}
Testing Support
Reset the global provider for isolated unit tests:
[Fact]
public void TestWithCleanProvider() {
MythServiceProvider.Reset();
var services = new ServiceCollection();
// ... configure test services
var provider = services.BuildServiceProvider();
MythServiceProvider.Initialize( provider );
// Run test
}
Scoped Services
Pattern for executing operations within automatic service scopes, perfect for transient handlers accessing scoped dependencies like repositories with DbContext.
Setup
Register the scoped service provider pattern once in your application:
var builder = WebApplication.CreateBuilder( args );
builder.Services.AddScopedServiceProvider();
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
builder.Services.AddDbContext<AppDbContext>();
var app = builder.BuildApp();
Usage in Handlers
public class CreateOrderHandler : ICommandHandler<CreateOrderCommand> {
private readonly IScopedService<IOrderRepository> _repository;
private readonly IScopedService<IEmailService> _emailService;
public CreateOrderHandler(
IScopedService<IOrderRepository> repository,
IScopedService<IEmailService> emailService ) {
_repository = repository;
_emailService = emailService;
}
public async Task<CommandResult> HandleAsync(
CreateOrderCommand command,
CancellationToken ct ) {
// Execute with automatic scope management
var order = await _repository.ExecuteAsync( repo =>
repo.CreateAsync( command.OrderData, ct )
);
// Execute void operations
await _emailService.ExecuteAsync( email =>
email.SendOrderConfirmationAsync( order.Id, ct )
);
return CommandResult.Success();
}
}
Synchronous Operations
// With return value
var result = _scopedService.Execute( service =>
service.GetData()
);
// Void operation
_scopedService.Execute( service =>
service.ProcessData()
);
Asynchronous Operations
// With return value
var result = await _scopedService.ExecuteAsync( service =>
service.GetDataAsync()
);
// Void operation
await _scopedService.ExecuteAsync( service =>
service.ProcessDataAsync()
);
Benefits
- Automatic Scope Management: No manual scope creation or disposal
- Lifetime Safety: Access scoped services from transient contexts safely
- Clean API: Strongly-typed, fluent interface
- Proper Disposal: Handles both sync and async disposal correctly
- DDD Alignment: Perfect for CQRS handlers accessing repositories
Pagination
Value objects and interfaces for implementing paginated results.
Pagination Value Object
using Myth.ValueObjects;
// Default pagination (page 1, size 10)
var pagination = Pagination.Default;
// Custom pagination
var customPagination = new Pagination( pageNumber: 2, pageSize: 20 );
// Get all items (single page)
var allItems = Pagination.All;
// ASP.NET Core automatic binding
[HttpGet]
public IActionResult GetOrders( [FromQuery] Pagination pagination ) {
// Automatically binds from query string: ?$pagenumber=2&$pagesize=20
}
Paginated Results
using Myth.Interfaces.Results;
using Myth.Models.Results;
// Create paginated result
var items = await repository.GetOrdersAsync( pagination );
var total = await repository.GetTotalCountAsync();
var totalPages = ( int )Math.Ceiling( ( double )total / pagination.PageSize );
var result = new Paginated<Order>(
pageNumber: pagination.PageNumber,
pageSize: pagination.PageSize,
totalItems: total,
totalPages: totalPages,
items: items
);
// Access properties
Console.WriteLine( $"Page {result.PageNumber} of {result.TotalPages}" );
Console.WriteLine( $"Showing {result.Items.Count()} of {result.TotalItems} items" );
// Return in API
return Ok( result );
IPaginated Interface
Implement custom paginated types:
public class CustomPaginatedResult<T> : IPaginated<T> {
public int PageNumber { get; set; }
public int PageSize { get; set; }
public int TotalPages { get; set; }
public int TotalItems { get; set; }
public IEnumerable<T> Items { get; set; }
// Add custom properties
public bool HasNextPage => PageNumber < TotalPages;
public bool HasPreviousPage => PageNumber > 1;
}
Collection Extensions
Helper methods for working with collections.
using Myth.Extensions;
var items = new[] { "apple", "banana", "cherry" };
// Join with separator
var result = items.ToStringWithSeparator( ", " );
// "apple, banana, cherry"
// Custom separator
var result2 = items.ToStringWithSeparator( " | " );
// "apple | banana | cherry"
// Default separator (", ")
var result3 = items.ToStringWithSeparator();
// "apple, banana, cherry"
Architecture Patterns
Domain-Driven Design
Myth.Commons provides essential DDD building blocks:
- Value Objects: Implement domain value objects with structural equality
- Constants: Type-safe domain constants and enumerations
- Pagination: Domain model for paginated queries
// Value Object for Money
public class Money : ValueObject {
public decimal Amount { get; }
public string Currency { get; }
public Money( decimal amount, string currency ) {
Amount = amount;
Currency = currency;
}
protected override IEnumerable<object> GetAtomicValues() {
yield return Amount;
yield return Currency;
}
public Money Add( Money other ) {
if ( Currency != other.Currency )
throw new InvalidOperationException( "Cannot add money with different currencies" );
return new Money( Amount + other.Amount, Currency );
}
}
// Type-safe constants
public class Currency : Constant<Currency, string> {
public static readonly Currency USD = new( nameof( USD ), "USD" );
public static readonly Currency EUR = new( nameof( EUR ), "EUR" );
public static readonly Currency BRL = new( nameof( BRL ), "BRL" );
private Currency( string name, string value ) : base( name, value ) { }
}
CQRS Integration
Perfect for CQRS patterns with scoped service management:
public class GetOrdersQueryHandler : IQueryHandler<GetOrdersQuery, IPaginated<Order>> {
private readonly IScopedService<IOrderRepository> _repository;
public GetOrdersQueryHandler( IScopedService<IOrderRepository> repository ) {
_repository = repository;
}
public async Task<QueryResult<IPaginated<Order>>> HandleAsync(
GetOrdersQuery query,
CancellationToken ct ) {
var result = await _repository.ExecuteAsync( async repo => {
var items = await repo.GetOrdersAsync( query.Pagination, ct );
var total = await repo.GetTotalCountAsync( ct );
return new Paginated<Order>(
query.Pagination.PageNumber,
query.Pagination.PageSize,
total,
( int )Math.Ceiling( ( double )total / query.Pagination.PageSize ),
items
);
} );
return QueryResult<IPaginated<Order>>.Success( result );
}
}
Clean Architecture
Supports Clean Architecture principles:
- Infrastructure Independence: JSON serialization without external dependencies
- Framework Independence: Works with any .NET application type
- Testability: Easy to mock and test with clear interfaces
- Separation of Concerns: Each utility focused on single responsibility
Best Practices
JSON Serialization
- Configure global JSON settings once at application startup
- Use per-operation settings only when needed
- Handle
JsonParsingExceptionfor robust error handling - Use interface converters for polymorphic types
Value Objects
- Make value objects immutable
- Override
GetAtomicValues()to include all properties that define equality - Consider validation in constructor
- Use for domain concepts, not just data transfer
Constants
- Use for domain-specific enumerations
- Prefer constants over magic strings/numbers
- Add domain methods to constant classes
- Use with pattern matching for exhaustive checks
Service Provider
- Initialize global provider once at application startup
- Use
BuildApp()for ASP.NET Core applications - Use
TryInitialize()for library code (first-wins pattern) - Reset provider in tests for isolation
Scoped Services
- Register
AddScopedServiceProvider()once per application - Use for accessing scoped dependencies from transient contexts
- Perfect for CQRS handlers and background services
- Automatic disposal - no manual scope management needed
Dependencies
- Ardalis.SmartEnum 8.0.0 - For type-safe constants
- Microsoft.Extensions.DependencyInjection 8.0.0 - For DI support
- System.Text.Json 8.0.5 - For JSON operations
Requirements
- .NET 8.0 or later
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the Apache License 2.0 - see the LICENSE for details.
Support
For issues, questions, or contributions, please visit the GitLab repository.
| 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 (13)
Showing the top 5 NuGet packages that depend on Myth.Commons:
| Package | Downloads |
|---|---|
|
Harpy.Domain
Basis for the domain layer of the Harpy Framework |
|
|
Myth.Specification
Query specification pattern for encapsulating business rules in readable, composable, and testable specifications. Supports filtering, sorting, pagination, and conditional logic for clean query construction. |
|
|
Myth.Repository
Generic repository pattern interfaces with async support, specification integration, and pagination. Provides read/write separation, CRUD operations, and extensible repository contracts for clean data access architecture. |
|
|
Myth.Rest
Fluent REST client with circuit breaker, retry policies, certificate support, and object pooling. Provides resilient HTTP communication with configurable error handling and response mapping. |
|
|
Harpy.Presentation
Basis for the presentation layer of the Harpy Framework |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.1-preview.8 | 0 | 11/22/2025 |
| 4.0.1-preview.7 | 0 | 11/22/2025 |
| 4.0.1-preview.6 | 0 | 11/22/2025 |
| 4.0.1-preview.5 | 0 | 11/21/2025 |
| 4.0.1-preview.4 | 0 | 11/21/2025 |
| 4.0.1-preview.3 | 16 | 11/21/2025 |
| 4.0.1-preview.2 | 46 | 11/21/2025 |
| 4.0.1-preview.1 | 57 | 11/21/2025 |
| 4.0.0 | 206 | 11/20/2025 |
| 4.0.0-preview.3 | 173 | 11/19/2025 |
| 4.0.0-preview.2 | 83 | 11/15/2025 |
| 4.0.0-preview.1 | 105 | 11/15/2025 |
| 3.10.0 | 307 | 11/15/2025 |
| 3.0.5-preview.15 | 145 | 11/14/2025 |
| 3.0.5-preview.14 | 217 | 11/12/2025 |
| 3.0.5-preview.13 | 221 | 11/12/2025 |
| 3.0.5-preview.12 | 229 | 11/11/2025 |
| 3.0.5-preview.11 | 226 | 11/11/2025 |
| 3.0.5-preview.10 | 221 | 11/11/2025 |
| 3.0.5-preview.9 | 220 | 11/10/2025 |
| 3.0.5-preview.8 | 96 | 11/8/2025 |
| 3.0.5-preview.7 | 89 | 11/8/2025 |
| 3.0.5-preview.6 | 86 | 11/8/2025 |
| 3.0.5-preview.5 | 87 | 11/8/2025 |
| 3.0.5-preview.4 | 65 | 11/7/2025 |
| 3.0.5-preview.3 | 135 | 11/4/2025 |
| 3.0.5-preview.2 | 140 | 11/4/2025 |
| 3.0.5-preview.1 | 139 | 11/4/2025 |
| 3.0.4 | 366 | 11/3/2025 |
| 3.0.4-preview.19 | 73 | 11/2/2025 |
| 3.0.4-preview.17 | 69 | 11/1/2025 |
| 3.0.4-preview.16 | 71 | 11/1/2025 |
| 3.0.4-preview.15 | 65 | 10/31/2025 |
| 3.0.4-preview.14 | 134 | 10/31/2025 |
| 3.0.4-preview.13 | 130 | 10/30/2025 |
| 3.0.4-preview.12 | 124 | 10/23/2025 |
| 3.0.4-preview.11 | 123 | 10/23/2025 |
| 3.0.4-preview.10 | 120 | 10/23/2025 |
| 3.0.4-preview.9 | 117 | 10/23/2025 |
| 3.0.4-preview.8 | 116 | 10/22/2025 |
| 3.0.4-preview.6 | 116 | 10/21/2025 |
| 3.0.4-preview.5 | 117 | 10/21/2025 |
| 3.0.4-preview.4 | 121 | 10/20/2025 |
| 3.0.4-preview.3 | 119 | 10/20/2025 |
| 3.0.4-preview.2 | 42 | 10/18/2025 |
| 3.0.4-preview.1 | 122 | 10/7/2025 |
| 3.0.3 | 285 | 8/30/2025 |
| 3.0.2 | 179 | 8/23/2025 |
| 3.0.2-preview.4 | 128 | 8/21/2025 |
| 3.0.2-preview.3 | 100 | 8/16/2025 |
| 3.0.2-preview.1 | 77 | 5/23/2025 |
| 3.0.1 | 4,133 | 3/12/2025 |
| 3.0.1-preview.2 | 145 | 3/11/2025 |
| 3.0.1-preview.1 | 92 | 2/5/2025 |
| 3.0.0.2-preview | 202 | 12/10/2024 |
| 3.0.0.1-preview | 209 | 6/29/2024 |
| 3.0.0 | 4,646 | 12/10/2024 |
| 3.0.0-preview | 215 | 6/28/2024 |
| 2.0.0.16 | 16,202 | 12/15/2023 |
| 2.0.0.15 | 367 | 12/15/2023 |
| 2.0.0.11 | 5,585 | 8/11/2022 |
| 2.0.0.10 | 3,033 | 7/20/2022 |
| 2.0.0.9 | 3,126 | 7/15/2022 |
| 2.0.0.8 | 3,146 | 7/12/2022 |
| 2.0.0.7 | 3,064 | 6/20/2022 |
| 2.0.0.6 | 3,176 | 5/23/2022 |
| 2.0.0.5 | 3,162 | 5/18/2022 |
| 2.0.0 | 3,274 | 2/17/2022 |
| 1.0.0.8 | 2,605 | 12/8/2020 |
| 1.0.0.8-stage-02 | 1,186 | 12/7/2020 |
| 1.0.0.8-stage-01 | 1,446 | 9/25/2020 |
| 1.0.0.7 | 3,863 | 7/28/2020 |
| 1.0.0.7-stage-03 | 1,229 | 7/28/2020 |
| 1.0.0.7-stage-02 | 1,113 | 7/23/2020 |
| 1.0.0.7-stage-01 | 1,066 | 7/21/2020 |
| 1.0.0.6 | 2,393 | 6/28/2020 |
| 1.0.0.4 | 2,235 | 6/27/2020 |
| 1.0.0.3 | 587 | 6/27/2020 |
| 1.0.0.2 | 5,284 | 6/25/2020 |
| 1.0.0.1 | 1,016 | 6/25/2020 |
| 1.0.0 | 590 | 6/25/2020 |