From 83bbe95ab59be5c24f8e0bcb9563256a107d4e13 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 12 Jun 2026 21:06:15 +0200 Subject: [PATCH 1/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor=20cache=20exp?= =?UTF-8?q?iration=20tests=20for=20improved=20readability=20and=20efficien?= =?UTF-8?q?cy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SlimMemoryCacheTest.cs | 77 +++++++++++-------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/test/Cuemon.Runtime.Caching.Tests/SlimMemoryCacheTest.cs b/test/Cuemon.Runtime.Caching.Tests/SlimMemoryCacheTest.cs index af586734..4330f497 100644 --- a/test/Cuemon.Runtime.Caching.Tests/SlimMemoryCacheTest.cs +++ b/test/Cuemon.Runtime.Caching.Tests/SlimMemoryCacheTest.cs @@ -229,37 +229,13 @@ public void Add_ShouldHandleLargeLoadWithoutCollisionUsingDependencyExpirationOf [Fact, Priority(8)] public void Add_VerifyBothLogicalAndActualCacheRemovalUponExpirationForThirtySecondsNamespaceSpecification() { - Thread.Sleep(TimeSpan.FromSeconds(30)); - - AssertNamespaceIsLogicallyExpired(Dependency30Namespace); - AssertNamespaceIsLogicallyExpired(Sliding30Namespace); - AssertNamespaceIsLogicallyExpired(Absolute30Namespace); - - AssertNamespaceIsPhysicallyPresent(Dependency30Namespace); - AssertNamespaceIsPhysicallyPresent(Sliding30Namespace); - AssertNamespaceIsPhysicallyPresent(Absolute30Namespace); - - AssertNamespaceIsPhysicallyRemoved(Dependency30Namespace); - AssertNamespaceIsPhysicallyRemoved(Sliding30Namespace); - AssertNamespaceIsPhysicallyRemoved(Absolute30Namespace); + VerifyBothLogicalAndActualCacheRemovalUponExpiration(Dependency30Namespace, Sliding30Namespace, Absolute30Namespace); } [Fact, Priority(9)] public void Add_VerifyBothLogicalAndActualCacheRemovalUponExpirationForSixtySecondsNamespaceSpecification() { - Thread.Sleep(TimeSpan.FromSeconds(20)); - - AssertNamespaceIsLogicallyExpired(Dependency60Namespace); - AssertNamespaceIsLogicallyExpired(Sliding60Namespace); - AssertNamespaceIsLogicallyExpired(Absolute60Namespace); - - AssertNamespaceIsPhysicallyPresent(Dependency60Namespace); - AssertNamespaceIsPhysicallyPresent(Sliding60Namespace); - AssertNamespaceIsPhysicallyPresent(Absolute60Namespace); - - AssertNamespaceIsPhysicallyRemoved(Dependency60Namespace); - AssertNamespaceIsPhysicallyRemoved(Sliding60Namespace); - AssertNamespaceIsPhysicallyRemoved(Absolute60Namespace); + VerifyBothLogicalAndActualCacheRemovalUponExpiration(Dependency60Namespace, Sliding60Namespace, Absolute60Namespace); } [Fact] @@ -327,24 +303,61 @@ public override void ConfigureServices(IServiceCollection services) services.AddSingleton(); } - private void AssertNamespaceIsPhysicallyRemoved(string ns) + private static void AssertNamespaceIsPhysicallyRemoved(SlimMemoryCache cache, string ns) { - Assert.True(SpinWait.SpinUntil(() => !_cache.Any(pair => pair.Value.Namespace == ns), CleanupTimeout), + Assert.True(SpinWait.SpinUntil(() => !cache.Any(pair => pair.Value.Namespace == ns), CleanupTimeout), $"Cache entries in namespace '{ns}' were not physically removed within {CleanupTimeout}."); } - private void AssertNamespaceIsPhysicallyPresent(string ns) + private static void AssertNamespaceIsPhysicallyPresent(SlimMemoryCache cache, string ns) { - var physicalCount = _cache.Where(pair => pair.Value.Namespace == ns).Count(); + var physicalCount = cache.Where(pair => pair.Value.Namespace == ns).Count(); Assert.True(physicalCount == NumberOfItemsToCache, $"Cache entries in namespace '{ns}' should remain physically present until cleanup. Expected {NumberOfItemsToCache}, actual {physicalCount}."); } - private void AssertNamespaceIsLogicallyExpired(string ns) + private static void AssertNamespaceIsLogicallyExpired(SlimMemoryCache cache, string ns) { - Assert.True(SpinWait.SpinUntil(() => _cache.Count(ns) == 0, CleanupTimeout), + Assert.True(SpinWait.SpinUntil(() => cache.Count(ns) == 0, CleanupTimeout), $"Cache entries in namespace '{ns}' did not logically expire within {CleanupTimeout}."); } + + private static void VerifyBothLogicalAndActualCacheRemovalUponExpiration(string dependencyNs, string slidingNs, string absoluteNs) + { + using (var cache = CreateSlimMemoryCacheForExpirationTest()) + { + var expires = TimeSpan.FromSeconds(1); + var keys = Generate.RangeOf(NumberOfItemsToCache, i => Guid.NewGuid().ToString("N")).ToList(); + + foreach (var key in keys) + { + cache.Add(key, Generate.RandomString(5), new CountdownDependency(expires), dependencyNs); + cache.Add(key, Generate.RandomString(5), expires, slidingNs); + cache.Add(key, Generate.RandomString(5), DateTime.UtcNow.Add(expires), absoluteNs); + } + + AssertNamespaceIsLogicallyExpired(cache, dependencyNs); + AssertNamespaceIsLogicallyExpired(cache, slidingNs); + AssertNamespaceIsLogicallyExpired(cache, absoluteNs); + + AssertNamespaceIsPhysicallyPresent(cache, dependencyNs); + AssertNamespaceIsPhysicallyPresent(cache, slidingNs); + AssertNamespaceIsPhysicallyPresent(cache, absoluteNs); + + AssertNamespaceIsPhysicallyRemoved(cache, dependencyNs); + AssertNamespaceIsPhysicallyRemoved(cache, slidingNs); + AssertNamespaceIsPhysicallyRemoved(cache, absoluteNs); + } + } + + private static SlimMemoryCache CreateSlimMemoryCacheForExpirationTest() + { + return new SlimMemoryCache(o => + { + o.FirstSweep = TimeSpan.FromSeconds(10); + o.SucceedingSweep = TimeSpan.FromSeconds(5); + }); + } } } From 7b246a993e3716898eb6fa75e1b0f6da2dac7ebf Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 12 Jun 2026 21:15:10 +0200 Subject: [PATCH 2/8] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20upgrade=20dependencies?= =?UTF-8?q?=20to=20latest=20patch=20versions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update Docker base image nginx from 1.31.0 to 1.31.1. Upgrade NuGet packages including Codebelt extensions (11.0.9 → 11.1.0, 1.2.6 → 1.3.0), Microsoft.NET.Test.Sdk (18.5.1 → 18.6.0), and runtime packages (net9 and net10 patch updates). --- .docfx/Dockerfile.docfx | 2 +- Directory.Packages.props | 44 ++++++++++++++++++++-------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.docfx/Dockerfile.docfx b/.docfx/Dockerfile.docfx index 1719a33f..23e1b508 100644 --- a/.docfx/Dockerfile.docfx +++ b/.docfx/Dockerfile.docfx @@ -1,4 +1,4 @@ -ARG NGINX_VERSION=1.31.0-alpine +ARG NGINX_VERSION=1.31.1-alpine FROM --platform=$BUILDPLATFORM nginx:${NGINX_VERSION} AS base RUN rm -rf /usr/share/nginx/html/* diff --git a/Directory.Packages.props b/Directory.Packages.props index 1f3d497e..d786b422 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,12 +6,12 @@ - - - - + + + + - + @@ -22,31 +22,31 @@ - + - - - - - + + + + + - + - - - - - + + + + + - - - - - + + + + + From 3ec122f4b1589692a7433c867a6540a7d3e004c1 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Fri, 12 Jun 2026 21:27:16 +0200 Subject: [PATCH 3/8] =?UTF-8?q?=F0=9F=93=9D=20update=20package=20release?= =?UTF-8?q?=20notes=20for=2010.5.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Core.App/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Core/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Data/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .../Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt | 6 ++++++ .../PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.IO/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Kernel/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Net/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Resilience/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Threading/PackageReleaseNotes.txt | 6 ++++++ .nuget/Cuemon.Xml/PackageReleaseNotes.txt | 6 ++++++ 43 files changed, 258 insertions(+) diff --git a/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt index 759a60fb..05d6f9a5 100644 --- a/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt index b112e066..92e420b3 100644 --- a/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt index 9aebd5d2..75e2208a 100644 --- a/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt index 759a60fb..05d6f9a5 100644 --- a/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt index 789d4b29..193c7170 100644 --- a/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt b/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt index 629017c9..167989b0 100644 --- a/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Core/PackageReleaseNotes.txt b/.nuget/Cuemon.Core/PackageReleaseNotes.txt index 5ce59bee..6f083854 100644 --- a/.nuget/Cuemon.Core/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Core/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt b/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt b/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt index 9085517d..ea99abb5 100644 --- a/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Data/PackageReleaseNotes.txt b/.nuget/Cuemon.Data/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Data/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Data/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt b/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt index 759a60fb..05d6f9a5 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt index 4db5cdcb..6cd949d2 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt index 2ffdd27d..b3ddf92e 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt index 759a60fb..05d6f9a5 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt index 05be843e..3158b857 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt index 40cfb512..fce345e2 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt index fac0d15a..9053a7ce 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt index d32dd4e5..3e2823f9 100644 --- a/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10 and .NET 9 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10 and .NET 9 diff --git a/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt index bb342731..63cfd86b 100644 --- a/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt index f9c45f19..9583a0dd 100644 --- a/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt index 0880fcc5..41560fd6 100644 --- a/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt index cb1bbc17..75e0641b 100644 --- a/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt index aca719d1..f96a8820 100644 --- a/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt index 52515e9c..13138d45 100644 --- a/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9, .NET Standard 2.1 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9, .NET Standard 2.1 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt index 1953fe47..7cb8ac97 100644 --- a/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt index 401aa546..6e720d15 100644 --- a/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt index a4073e5f..5c1bbd9d 100644 --- a/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.IO/PackageReleaseNotes.txt b/.nuget/Cuemon.IO/PackageReleaseNotes.txt index 875ea217..9d45d471 100644 --- a/.nuget/Cuemon.IO/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.IO/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Kernel/PackageReleaseNotes.txt b/.nuget/Cuemon.Kernel/PackageReleaseNotes.txt index a47d657d..e16649c0 100644 --- a/.nuget/Cuemon.Kernel/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Kernel/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Net/PackageReleaseNotes.txt b/.nuget/Cuemon.Net/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Net/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Net/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt b/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt b/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt index 7b8b9343..1547aa0f 100644 --- a/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt b/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt index 8f4574dd..db5bd4b3 100644 --- a/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Threading/PackageReleaseNotes.txt b/.nuget/Cuemon.Threading/PackageReleaseNotes.txt index e17e8a95..85d539a5 100644 --- a/.nuget/Cuemon.Threading/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Threading/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 diff --git a/.nuget/Cuemon.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Xml/PackageReleaseNotes.txt index 7d819bda..bf397729 100644 --- a/.nuget/Cuemon.Xml/PackageReleaseNotes.txt +++ b/.nuget/Cuemon.Xml/PackageReleaseNotes.txt @@ -1,3 +1,9 @@ +Version: 10.5.4 +Availability: .NET 10, .NET 9 and .NET Standard 2.0 + +# ALM +- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs) + Version: 10.5.3 Availability: .NET 10, .NET 9 and .NET Standard 2.0 From 585c8acec1bece94e571fd762bcbfe14c6486c0d Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Fri, 19 Jun 2026 15:37:58 +0200 Subject: [PATCH 4/8] =?UTF-8?q?=F0=9F=93=9D=20expand=20api=20documentation?= =?UTF-8?q?=20with=20namespaces=20and=20type=20examples?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enhance the published API documentation with comprehensive namespace guidance, consumer-oriented descriptions, extension member tables, and concrete type-level examples. Improves discoverability and usability of the library's public API across 100+ modified and 570+ new documentation files. --- .../Cuemon.AspNetCore.Authentication.Basic.md | 2 +- ...Cuemon.AspNetCore.Authentication.Digest.md | 2 +- .../Cuemon.AspNetCore.Authentication.Hmac.md | 2 +- .../Cuemon.AspNetCore.Authentication.md | 2 +- .../namespaces/Cuemon.AspNetCore.Builder.md | 2 +- .../Cuemon.AspNetCore.Configuration.md | 2 +- .../Cuemon.AspNetCore.Diagnostics.md | 14 +- .../namespaces/Cuemon.AspNetCore.Hosting.md | 2 +- .../Cuemon.AspNetCore.Http.Headers.md | 10 +- .../Cuemon.AspNetCore.Http.Throttling.md | 2 +- .../api/namespaces/Cuemon.AspNetCore.Http.md | 16 +- .../Cuemon.AspNetCore.Infrastructure.md | 9 + ...Cuemon.AspNetCore.Mvc.Filters.Cacheable.md | 2 +- ...emon.AspNetCore.Mvc.Filters.Diagnostics.md | 2 +- .../Cuemon.AspNetCore.Mvc.Filters.Headers.md | 2 +- ...mon.AspNetCore.Mvc.Filters.ModelBinding.md | 2 +- ...uemon.AspNetCore.Mvc.Filters.Throttling.md | 2 +- .../Cuemon.AspNetCore.Mvc.Filters.md | 2 +- .../Cuemon.AspNetCore.Mvc.Formatters.md | 2 +- .../api/namespaces/Cuemon.AspNetCore.Mvc.md | 2 +- .../Cuemon.AspNetCore.Razor.TagHelpers.md | 2 +- .docfx/api/namespaces/Cuemon.AspNetCore.md | 2 +- .../namespaces/Cuemon.Collections.Generic.md | 10 +- .../Cuemon.Collections.Specialized.md | 8 +- .docfx/api/namespaces/Cuemon.Collections.md | 4 +- .docfx/api/namespaces/Cuemon.Configuration.md | 2 +- .../api/namespaces/Cuemon.Data.Integrity.md | 10 +- .../api/namespaces/Cuemon.Data.SqlClient.md | 2 +- .docfx/api/namespaces/Cuemon.Data.Xml.md | 2 +- .docfx/api/namespaces/Cuemon.Data.md | 9 +- .docfx/api/namespaces/Cuemon.Diagnostics.md | 2 +- ...on.Extensions.AspNetCore.Authentication.md | 7 +- ...mon.Extensions.AspNetCore.Configuration.md | 6 +- ...on.Extensions.AspNetCore.Data.Integrity.md | 4 +- ...uemon.Extensions.AspNetCore.Diagnostics.md | 6 +- .../Cuemon.Extensions.AspNetCore.Hosting.md | 4 +- ...emon.Extensions.AspNetCore.Http.Headers.md | 7 +- ...n.Extensions.AspNetCore.Http.Throttling.md | 6 +- .../Cuemon.Extensions.AspNetCore.Http.md | 7 +- ...Extensions.AspNetCore.Mvc.Configuration.md | 4 +- ...nsions.AspNetCore.Mvc.Filters.Cacheable.md | 7 +- ...ions.AspNetCore.Mvc.Filters.Diagnostics.md | 7 +- ...uemon.Extensions.AspNetCore.Mvc.Filters.md | 5 +- ...ons.AspNetCore.Mvc.Formatters.Text.Json.md | 4 +- ...xtensions.AspNetCore.Mvc.Formatters.Xml.md | 4 +- ...on.Extensions.AspNetCore.Mvc.RazorPages.md | 4 +- ...mon.Extensions.AspNetCore.Mvc.Rendering.md | 6 +- .../Cuemon.Extensions.AspNetCore.Mvc.md | 8 +- ...ensions.AspNetCore.Text.Json.Converters.md | 4 +- ...ensions.AspNetCore.Text.Json.Formatters.md | 4 +- .../Cuemon.Extensions.AspNetCore.Text.Json.md | 15 ++ ...on.Extensions.AspNetCore.Xml.Converters.md | 4 +- ...on.Extensions.AspNetCore.Xml.Formatters.md | 4 +- .../Cuemon.Extensions.AspNetCore.Xml.md | 15 ++ .../Cuemon.Extensions.Collections.Generic.md | 18 +- ...emon.Extensions.Collections.Specialized.md | 4 +- .../Cuemon.Extensions.Data.Integrity.md | 7 +- .../api/namespaces/Cuemon.Extensions.Data.md | 4 +- .../Cuemon.Extensions.DependencyInjection.md | 7 +- .../Cuemon.Extensions.Diagnostics.md | 4 +- .../Cuemon.Extensions.Globalization.md | 19 ++ .../namespaces/Cuemon.Extensions.Hosting.md | 5 +- .docfx/api/namespaces/Cuemon.Extensions.IO.md | 4 +- .../namespaces/Cuemon.Extensions.Net.Http.md | 4 +- .../Cuemon.Extensions.Net.Security.md | 4 +- .../api/namespaces/Cuemon.Extensions.Net.md | 4 +- .../Cuemon.Extensions.Reflection.md | 6 +- .../Cuemon.Extensions.Runtime.Caching.md | 6 +- ...Cuemon.Extensions.Runtime.Serialization.md | 15 ++ .../namespaces/Cuemon.Extensions.Runtime.md | 21 ++ .../Cuemon.Extensions.Text.Json.Converters.md | 6 +- .../Cuemon.Extensions.Text.Json.Formatters.md | 2 +- .../namespaces/Cuemon.Extensions.Text.Json.md | 4 +- .../api/namespaces/Cuemon.Extensions.Text.md | 4 +- .../Cuemon.Extensions.Threading.Tasks.md | 7 +- .../namespaces/Cuemon.Extensions.Xml.Linq.md | 4 +- ...Extensions.Xml.Serialization.Converters.md | 6 +- .../Cuemon.Extensions.Xml.Serialization.md | 4 +- .../api/namespaces/Cuemon.Extensions.Xml.md | 10 +- .docfx/api/namespaces/Cuemon.Extensions.md | 16 +- .docfx/api/namespaces/Cuemon.Globalization.md | 2 +- .docfx/api/namespaces/Cuemon.IO.md | 9 +- .docfx/api/namespaces/Cuemon.Messaging.md | 2 +- .../Cuemon.Net.Collections.Specialized.md | 11 +- .docfx/api/namespaces/Cuemon.Net.Http.md | 2 +- .docfx/api/namespaces/Cuemon.Net.Mail.md | 2 +- .docfx/api/namespaces/Cuemon.Net.md | 9 +- .docfx/api/namespaces/Cuemon.Reflection.md | 12 +- .docfx/api/namespaces/Cuemon.Resilience.md | 2 +- .../api/namespaces/Cuemon.Runtime.Caching.md | 2 +- ...Cuemon.Runtime.Serialization.Converters.md | 2 +- ...Cuemon.Runtime.Serialization.Formatters.md | 2 +- .../Cuemon.Runtime.Serialization.md | 2 +- .docfx/api/namespaces/Cuemon.Runtime.md | 2 +- .../Cuemon.Security.Cryptography.md | 2 +- .docfx/api/namespaces/Cuemon.Security.md | 2 +- .docfx/api/namespaces/Cuemon.Text.md | 11 ++ .docfx/api/namespaces/Cuemon.Threading.md | 2 +- .docfx/api/namespaces/Cuemon.Xml.Linq.md | 8 +- .../Cuemon.Xml.Serialization.Converters.md | 9 +- .../Cuemon.Xml.Serialization.Formatters.md | 2 +- .../namespaces/Cuemon.Xml.Serialization.md | 8 +- .docfx/api/namespaces/Cuemon.Xml.XPath.md | 2 +- .docfx/api/namespaces/Cuemon.Xml.md | 13 +- .docfx/api/namespaces/Cuemon.md | 28 ++- .../System.Runtime.CompilerServices.md | 9 + .docfx/api/types/Cuemon.ActionFactory`1.md | 45 +++++ .docfx/api/types/Cuemon.Alphanumeric.md | 23 +++ ...Cuemon.ArgumentReservedKeywordException.md | 38 ++++ ...entication.AuthenticationHandlerFeature.md | 37 ++++ ...AspNetCore.Authentication.Authenticator.md | 44 +++++ ...thentication.AuthorizationHeaderOptions.md | 32 ++++ ...cation.Basic.BasicAuthenticationHandler.md | 48 +++++ ...ion.Basic.BasicAuthenticationMiddleware.md | 31 +++ ...cation.Basic.BasicAuthenticationOptions.md | 41 ++++ ...Authentication.Basic.BasicAuthenticator.md | 32 ++++ ...tication.Basic.BasicAuthorizationHeader.md | 27 +++ ...n.Basic.BasicAuthorizationHeaderBuilder.md | 26 +++ ...etCore.Authentication.Basic.BasicFields.md | 30 +++ ...tion.Digest.DigestAuthenticationHandler.md | 48 +++++ ...n.Digest.DigestAuthenticationMiddleware.md | 36 ++++ ...tion.Digest.DigestAuthenticationOptions.md | 40 ++++ ...thentication.Digest.DigestAuthenticator.md | 34 ++++ ...cation.Digest.DigestAuthorizationHeader.md | 38 ++++ ...Digest.DigestAuthorizationHeaderBuilder.md | 42 ++++ ...entication.Digest.DigestCryptoAlgorithm.md | 25 +++ ...Core.Authentication.Digest.DigestFields.md | 32 ++++ ...Authentication.Digest.DigestHashFactory.md | 30 +++ ...tication.Hmac.HmacAuthenticationHandler.md | 47 +++++ ...ation.Hmac.HmacAuthenticationMiddleware.md | 36 ++++ ...tication.Hmac.HmacAuthenticationOptions.md | 41 ++++ ...e.Authentication.Hmac.HmacAuthenticator.md | 34 ++++ ...entication.Hmac.HmacAuthorizationHeader.md | 24 +++ ...ion.Hmac.HmacAuthorizationHeaderBuilder.md | 37 ++++ ...pNetCore.Authentication.Hmac.HmacFields.md | 38 ++++ ...tCore.Authentication.MemoryNonceTracker.md | 32 ++++ ...etCore.Authentication.NonceTrackerEntry.md | 24 +++ ...etCore.Builder.MiddlewareBuilderFactory.md | 43 +++++ ...tCore.Configuration.CacheBustingOptions.md | 27 +++ ...tCore.Configuration.DynamicCacheBusting.md | 36 ++++ ...onfiguration.DynamicCacheBustingOptions.md | 31 +++ ...Core.Diagnostics.FaultDescriptorOptions.md | 28 +++ ...ultDescriptorOptionsDecoratorExtensions.md | 32 ++++ ...ore.Diagnostics.HttpExceptionDescriptor.md | 29 +++ ...pExceptionDescriptorDecoratorExtensions.md | 33 ++++ ...pExceptionDescriptorResponseFormatter`1.md | 45 +++++ ....HttpExceptionDescriptorResponseHandler.md | 27 +++ ...iptorResponseHandlerDecoratorExtensions.md | 40 ++++ ...ceptionDescriptorResponseHandlerOptions.md | 30 +++ ...spNetCore.Diagnostics.HttpFaultResolver.md | 33 ++++ ...cs.HttpFaultResolverDecoratorExtensions.md | 40 ++++ ...NetCore.Diagnostics.HttpRequestEvidence.md | 61 ++++++ ...re.Diagnostics.PreferredFaultDescriptor.md | 22 +++ ...mon.AspNetCore.Diagnostics.ServerTiming.md | 26 +++ ...pNetCore.Diagnostics.ServerTimingMetric.md | 54 ++++++ ...Core.Diagnostics.ServerTimingMiddleware.md | 48 +++++ ...NetCore.Diagnostics.ServerTimingOptions.md | 27 +++ ...re.Hosting.HostingEnvironmentMiddleware.md | 43 +++++ ...tCore.Hosting.HostingEnvironmentOptions.md | 29 +++ ...mon.AspNetCore.Http.BadRequestException.md | 26 +++ ...uemon.AspNetCore.Http.ConflictException.md | 52 +++++ ...emon.AspNetCore.Http.ForbiddenException.md | 34 ++++ .../Cuemon.AspNetCore.Http.GoneException.md | 29 +++ ...ttp.HeaderDictionaryDecoratorExtensions.md | 58 ++++++ ...AspNetCore.Http.Headers.ApiKeyException.md | 23 +++ ...e.Http.Headers.ApiKeySentinelMiddleware.md | 42 ++++ ...Core.Http.Headers.ApiKeySentinelOptions.md | 30 +++ ...etCore.Http.Headers.CacheableMiddleware.md | 43 +++++ ...spNetCore.Http.Headers.CacheableOptions.md | 31 +++ ...ders.ChecksumBuilderDecoratorExtensions.md | 27 +++ ...Headers.CorrelationIdentifierMiddleware.md | 50 +++++ ...tp.Headers.CorrelationIdentifierOptions.md | 26 +++ ...NetCore.Http.Headers.ExpiresHeaderValue.md | 31 +++ ...ttp.Headers.RequestIdentifierMiddleware.md | 36 ++++ ...e.Http.Headers.RequestIdentifierOptions.md | 28 +++ ...etCore.Http.Headers.RetryConditionScope.md | 25 +++ ...NetCore.Http.Headers.UserAgentException.md | 23 +++ ...ttp.Headers.UserAgentSentinelMiddleware.md | 45 +++++ ...e.Http.Headers.UserAgentSentinelOptions.md | 32 ++++ ...tCore.Http.Headers.VaryAcceptMiddleware.md | 28 +++ ...ore.Http.HttpContextDecoratorExtensions.md | 65 +++++++ ...ore.Http.HttpRequestDecoratorExtensions.md | 36 ++++ ...re.Http.HttpResponseDecoratorExtensions.md | 36 ++++ ...pStatusCodeExceptionDecoratorExtensions.md | 40 ++++ ...spNetCore.Http.Int32DecoratorExtensions.md | 50 +++++ ...tCore.Http.InternalServerErrorException.md | 25 +++ ...pNetCore.Http.MethodNotAllowedException.md | 25 +++ ....AspNetCore.Http.NotAcceptableException.md | 25 +++ ...uemon.AspNetCore.Http.NotFoundException.md | 37 ++++ ...spNetCore.Http.PayloadTooLargeException.md | 53 ++++++ ...etCore.Http.PreconditionFailedException.md | 26 +++ ...Core.Http.PreconditionRequiredException.md | 27 +++ ...e.Http.Throttling.MemoryThrottlingCache.md | 23 +++ ...spNetCore.Http.Throttling.ThrottleQuota.md | 46 +++++ ...NetCore.Http.Throttling.ThrottleRequest.md | 24 +++ ...ore.Http.Throttling.ThrottlingException.md | 39 ++++ ...Throttling.ThrottlingSentinelMiddleware.md | 40 ++++ ...tp.Throttling.ThrottlingSentinelOptions.md | 56 ++++++ ...spNetCore.Http.TooManyRequestsException.md | 55 ++++++ ...n.AspNetCore.Http.UnauthorizedException.md | 26 +++ ...Core.Http.UnsupportedMediaTypeException.md | 29 +++ .../types/Cuemon.AspNetCore.Mvc.Breadcrumb.md | 47 +++++ .../Cuemon.AspNetCore.Mvc.CacheableFactory.md | 49 +++++ ...Core.Mvc.CacheableObjectResultOptions`1.md | 39 ++++ ...e.Mvc.ContentBasedObjectResultOptions`1.md | 35 ++++ ...spNetCore.Mvc.ExceptionDescriptorResult.md | 35 ++++ ...c.Filters.Cacheable.HttpCacheableFilter.md | 30 +++ ....Filters.Cacheable.HttpCacheableOptions.md | 38 ++++ ...ers.Cacheable.HttpEntityTagHeaderFilter.md | 26 +++ ...rs.Cacheable.HttpEntityTagHeaderOptions.md | 50 +++++ ....Cacheable.HttpLastModifiedHeaderFilter.md | 26 +++ ...Cacheable.HttpLastModifiedHeaderOptions.md | 49 +++++ ...lters.Diagnostics.FaultDescriptorFilter.md | 35 ++++ ...s.Diagnostics.MvcFaultDescriptorOptions.md | 32 ++++ ...lters.Diagnostics.ServerTimingAttribute.md | 57 ++++++ ....Filters.Diagnostics.ServerTimingFilter.md | 51 +++++ ...Filters.Headers.ApiKeySentinelAttribute.md | 38 ++++ ...vc.Filters.Headers.ApiKeySentinelFilter.md | 36 ++++ ...Filters.Headers.UserAgentSentinelFilter.md | 34 ++++ ...delBinding.DisableModelBindingAttribute.md | 37 ++++ ...ers.Throttling.ThrottlingSentinelFilter.md | 34 ++++ ...on.AspNetCore.Mvc.ForbiddenObjectResult.md | 44 +++++ .../Cuemon.AspNetCore.Mvc.ForbiddenResult.md | 27 +++ .../types/Cuemon.AspNetCore.Mvc.GoneResult.md | 24 +++ .../Cuemon.AspNetCore.Mvc.SeeOtherResult.md | 25 +++ ...Core.Mvc.TimeBasedObjectResultOptions`1.md | 35 ++++ ...NetCore.Mvc.TooManyRequestsObjectResult.md | 29 +++ ...on.AspNetCore.Mvc.TooManyRequestsResult.md | 28 +++ ...Core.Razor.TagHelpers.AppImageTagHelper.md | 39 ++++ ...tCore.Razor.TagHelpers.AppLinkTagHelper.md | 41 ++++ ...ore.Razor.TagHelpers.AppScriptTagHelper.md | 39 ++++ ...re.Razor.TagHelpers.AppTagHelperOptions.md | 34 ++++ ...Core.Razor.TagHelpers.CdnImageTagHelper.md | 41 ++++ ...tCore.Razor.TagHelpers.CdnLinkTagHelper.md | 39 ++++ ...ore.Razor.TagHelpers.CdnScriptTagHelper.md | 41 ++++ ...re.Razor.TagHelpers.CdnTagHelperOptions.md | 29 +++ ...Core.Razor.TagHelpers.ProtocolUriScheme.md | 31 +++ .docfx/api/types/Cuemon.AssignmentOperator.md | 26 +++ .../Cuemon.ByteArrayDecoratorExtensions.md | 50 +++++ .docfx/api/types/Cuemon.Calculator.md | 36 ++++ .docfx/api/types/Cuemon.CasingMethod.md | 30 +++ .../types/Cuemon.CharDecoratorExtensions.md | 39 ++++ .../Cuemon.Collections.Generic.Arguments.md | 39 ++++ ...s.Generic.CollectionDecoratorExtensions.md | 30 +++ ...s.Generic.DictionaryDecoratorExtensions.md | 46 +++++ ...mon.Collections.Generic.DynamicComparer.md | 36 ++++ ...ections.Generic.DynamicEqualityComparer.md | 30 +++ ...ctions.Generic.EnumReadOnlyDictionary`1.md | 52 +++++ ...ctions.Generic.EnumerableSizeComparer-1.md | 40 ++++ ...lections.Generic.PaginationEnumerable-1.md | 39 ++++ ...on.Collections.Generic.PaginationList-1.md | 44 +++++ ...n.Collections.Generic.PaginationOptions.md | 64 +++++++ ...ections.Generic.PartitionerCollection-1.md | 47 +++++ ...ections.Generic.PartitionerEnumerable`1.md | 66 +++++++ ...Collections.Generic.ReferenceComparer-1.md | 52 +++++ ...ctions.Generic.StackDecoratorExtensions.md | 7 + ...ecialized.DictionaryDecoratorExtensions.md | 42 ++++ .docfx/api/types/Cuemon.Condition.md | 116 ++++++++++++ .docfx/api/types/Cuemon.Convertible.md | 28 +++ .../Cuemon.ConvertibleConverterDictionary.md | 66 +++++++ .docfx/api/types/Cuemon.ConvertibleOptions.md | 74 ++++++++ .../types/Cuemon.Data.DataManagerOptions.md | 37 ++++ ...emon.Data.DataReaderDecoratorExtensions.md | 52 +++++ .docfx/api/types/Cuemon.Data.DataStatement.md | 69 +++++++ .../types/Cuemon.Data.DataStatementOptions.md | 46 +++++ .docfx/api/types/Cuemon.Data.DataTransfer.md | 49 +++++ .../types/Cuemon.Data.DataTransferColumn.md | 55 ++++++ ...uemon.Data.DataTransferColumnCollection.md | 38 ++++ .../api/types/Cuemon.Data.DataTransferRow.md | 68 +++++++ .../Cuemon.Data.DataTransferRowCollection.md | 46 +++++ .../types/Cuemon.Data.DatabaseDependency.md | 80 ++++++++ .../api/types/Cuemon.Data.DatabaseWatcher.md | 112 +++++++++++ .../Cuemon.Data.DbTypeDecoratorExtensions.md | 37 ++++ .docfx/api/types/Cuemon.Data.DsvDataReader.md | 39 ++++ .../api/types/Cuemon.Data.InOperatorResult.md | 66 +++++++ .../Cuemon.Data.Integrity.CacheValidator.md | 51 +++++ ...on.Data.Integrity.CacheValidatorFactory.md | 45 +++++ .../Cuemon.Data.Integrity.ChecksumBuilder.md | 36 ++++ ...rity.ChecksumBuilderDecoratorExtensions.md | 45 +++++ ...mon.Data.Integrity.DataIntegrityFactory.md | 54 ++++++ ...ata.Integrity.EntityDataIntegrityMethod.md | 47 +++++ ...Integrity.EntityDataIntegrityValidation.md | 47 +++++ .../types/Cuemon.Data.Integrity.EntityInfo.md | 52 +++++ ...emon.Data.Integrity.FileChecksumOptions.md | 49 +++++ ...mon.Data.Integrity.FileIntegrityOptions.md | 57 ++++++ .docfx/api/types/Cuemon.Data.QueryFormat.md | 40 ++++ .docfx/api/types/Cuemon.Data.QueryType.md | 45 +++++ .../Cuemon.Data.SqlClient.SqlDataManager.md | 52 +++++ .../Cuemon.Data.SqlClient.SqlInOperator`1.md | 39 ++++ .../Cuemon.Data.SqlClient.SqlQueryBuilder.md | 98 ++++++++++ .docfx/api/types/Cuemon.Data.TokenBuilder.md | 48 +++++ ...emon.Data.UniqueIndexViolationException.md | 40 ++++ .../types/Cuemon.Data.Xml.XmlDataReader.md | 49 +++++ .docfx/api/types/Cuemon.DataPair.md | 43 +++++ .docfx/api/types/Cuemon.DataPair`1.md | 51 +++++ .docfx/api/types/Cuemon.DateSpan.md | 38 ++++ .../Cuemon.DateTimeDecoratorExtensions.md | 48 +++++ .../api/types/Cuemon.DateTimeFormatPattern.md | 32 ++++ .docfx/api/types/Cuemon.DateTimeRange.md | 58 ++++++ .docfx/api/types/Cuemon.DayPart.md | 36 ++++ .docfx/api/types/Cuemon.Decorator-1.md | 37 ++++ .docfx/api/types/Cuemon.Decorator.md | 31 +++ .../Cuemon.DelegateDecoratorExtensions.md | 39 ++++ .docfx/api/types/Cuemon.DelimitedString.md | 33 ++++ .../types/Cuemon.DelimitedStringOptions.md | 52 +++++ .../types/Cuemon.DelimitedStringOptions`1.md | 36 ++++ ...mon.Diagnostics.AsyncTimeMeasureOptions.md | 36 ++++ .../Cuemon.Diagnostics.ExceptionDescriptor.md | 34 ++++ ...iagnostics.ExceptionDescriptorAttribute.md | 40 ++++ ....Diagnostics.ExceptionDescriptorOptions.md | 47 +++++ .../api/types/Cuemon.Diagnostics.Failure.md | 31 +++ .../types/Cuemon.Diagnostics.FaultResolver.md | 49 +++++ ...mon.Diagnostics.FaultSensitivityDetails.md | 55 ++++++ .../Cuemon.Diagnostics.MemberEvidence.md | 48 +++++ .../Cuemon.Diagnostics.ProfilerOptions.md | 37 ++++ .../types/Cuemon.Diagnostics.TimeMeasure.md | 54 ++++++ .../Cuemon.Diagnostics.TimeMeasureOptions.md | 42 ++++ .../Cuemon.Diagnostics.TimeMeasureProfiler.md | 30 +++ ...uemon.Diagnostics.TimeMeasureProfiler`1.md | 37 ++++ .docfx/api/types/Cuemon.DisposableOptions.md | 51 +++++ .../types/Cuemon.DoubleDecoratorExtensions.md | 42 ++++ .docfx/api/types/Cuemon.EndianOptions.md | 33 ++++ .docfx/api/types/Cuemon.Endianness.md | 30 +++ .docfx/api/types/Cuemon.Eradicate.md | 30 +++ .../api/types/Cuemon.ExceptionCondition`1.md | 53 ++++++ .../Cuemon.ExceptionDecoratorExtensions.md | 36 ++++ .docfx/api/types/Cuemon.ExceptionHandler`1.md | 42 ++++ .docfx/api/types/Cuemon.ExceptionHandler`2.md | 37 ++++ .docfx/api/types/Cuemon.ExceptionInsights.md | 35 ++++ .docfx/api/types/Cuemon.ExceptionInvoker`1.md | 42 ++++ .docfx/api/types/Cuemon.ExceptionInvoker`2.md | 56 ++++++ .../Cuemon.Extensions.ActionExtensions.md | 51 +++++ .../types/Cuemon.Extensions.ActionFactory.md | 30 +++ ...entication.ApplicationBuilderExtensions.md | 75 ++++++++ ...ication.AuthenticationBuilderExtensions.md | 62 ++++++ ...entication.AuthorizationResponseHandler.md | 40 ++++ ...ion.AuthorizationResponseHandlerOptions.md | 27 +++ ...hentication.ServiceCollectionExtensions.md | 37 ++++ ...Core.Configuration.AssemblyCacheBusting.md | 35 ++++ ...nfiguration.AssemblyCacheBustingOptions.md | 35 ++++ ...nfiguration.ServiceCollectionExtensions.md | 47 +++++ ...Data.Integrity.CacheValidatorExtensions.md | 34 ++++ ...ata.Integrity.ChecksumBuilderExtensions.md | 28 +++ ...iagnostics.ApplicationBuilderExtensions.md | 28 +++ ...Diagnostics.ServiceCollectionExtensions.md | 56 ++++++ ...e.Diagnostics.ServiceProviderExtensions.md | 27 +++ ...re.Hosting.ApplicationBuilderExtensions.md | 34 ++++ ...NetCore.Http.HeaderDictionaryExtensions.md | 43 +++++ ...tp.Headers.ApplicationBuilderExtensions.md | 46 +++++ ...ttp.Headers.EntityTagCacheableValidator.md | 35 ++++ ...ttp.Headers.ServiceCollectionExtensions.md | 44 +++++ ...onDescriptorResponseFormatterExtensions.md | 26 +++ ...s.AspNetCore.Http.HttpRequestExtensions.md | 55 ++++++ ....AspNetCore.Http.HttpResponseExtensions.md | 54 ++++++ ...ensions.AspNetCore.Http.Int32Extensions.md | 50 +++++ ...Throttling.ApplicationBuilderExtensions.md | 37 ++++ ....Throttling.ServiceCollectionExtensions.md | 54 ++++++ ...ore.Mvc.CacheableObjectResultExtensions.md | 75 ++++++++ ...le.CacheableAsyncResultFilterExtensions.md | 45 +++++ ...Diagnostics.HttpFaultResolverExtensions.md | 35 ++++ ....Mvc.Filters.FilterCollectionExtensions.md | 45 +++++ ...etCore.Mvc.Filters.MvcBuilderExtensions.md | 67 +++++++ ...xt.Json.JsonSerializationInputFormatter.md | 30 +++ ...t.Json.JsonSerializationMvcOptionsSetup.md | 37 ++++ ...t.Json.JsonSerializationOutputFormatter.md | 30 +++ ...rmatters.Text.Json.MvcBuilderExtensions.md | 36 ++++ ...ters.Text.Json.MvcCoreBuilderExtensions.md | 37 ++++ ...Mvc.Formatters.Xml.MvcBuilderExtensions.md | 33 ++++ ...Formatters.Xml.MvcCoreBuilderExtensions.md | 35 ++++ ...ters.Xml.XmlSerializationInputFormatter.md | 30 +++ ...ers.Xml.XmlSerializationMvcOptionsSetup.md | 33 ++++ ...ers.Xml.XmlSerializationOutputFormatter.md | 30 +++ ...tCore.Mvc.RazorPages.PageBaseExtensions.md | 25 +++ ...Core.Mvc.Rendering.HtmlHelperExtensions.md | 26 +++ ...etCore.Mvc.ViewDataDictionaryExtensions.md | 63 ++++++ ...rters.JsonConverterCollectionExtensions.md | 63 ++++++ ....Formatters.ServiceCollectionExtensions.md | 29 +++ ...AspNetCore.Text.Json.MinimalJsonOptions.md | 46 +++++ ...e.Text.Json.ServiceCollectionExtensions.md | 27 +++ ...e.Xml.Converters.XmlConverterExtensions.md | 46 +++++ ....Formatters.ServiceCollectionExtensions.md | 29 +++ ...NetCore.Xml.ServiceCollectionExtensions.md | 27 +++ .../types/Cuemon.Extensions.ByteExtensions.md | 38 ++++ .../types/Cuemon.Extensions.CharExtensions.md | 32 ++++ ...ollections.Generic.CollectionExtensions.md | 30 +++ ...ollections.Generic.DictionaryExtensions.md | 45 +++++ ...ollections.Generic.EnumerableExtensions.md | 54 ++++++ ...ions.Collections.Generic.ListExtensions.md | 55 ++++++ ...ons.Collections.Generic.QueueExtensions.md | 31 +++ ...ons.Collections.Generic.StackExtensions.md | 34 ++++ ...ctions.Specialized.DictionaryExtensions.md | 47 +++++ ...ecialized.NameValueCollectionExtensions.md | 60 ++++++ ...on.Extensions.Data.DataReaderExtensions.md | 37 ++++ ...Cuemon.Extensions.Data.DbTypeExtensions.md | 36 ++++ ...sions.Data.Integrity.AssemblyExtensions.md | 39 ++++ ...ata.Integrity.ChecksumBuilderExtensions.md | 49 +++++ ...sions.Data.Integrity.DateTimeExtensions.md | 52 +++++ ...sions.Data.Integrity.FileInfoExtensions.md | 49 +++++ ...n.Extensions.Data.QueryFormatExtensions.md | 43 +++++ .../Cuemon.Extensions.DateTimeExtensions.md | 53 ++++++ ...cyInjection.ServiceCollectionExtensions.md | 96 ++++++++++ ...ions.DependencyInjection.ServiceOptions.md | 53 ++++++ ...encyInjection.ServiceProviderExtensions.md | 66 +++++++ ...ions.DependencyInjection.TypeExtensions.md | 44 +++++ ...encyInjection.TypeForwardServiceOptions.md | 73 +++++++ ...s.Diagnostics.FileVersionInfoExtensions.md | 49 +++++ .../Cuemon.Extensions.DoubleExtensions.md | 38 ++++ .../Cuemon.Extensions.ExceptionExtensions.md | 40 ++++ .../types/Cuemon.Extensions.FuncFactory.md | 29 +++ ...ions.Globalization.RegionInfoExtensions.md | 42 ++++ ...obalization.StatisticalRegionExtensions.md | 72 +++++++ .../Cuemon.Extensions.Hosting.Environments.md | 24 +++ ...xtensions.Hosting.HostBuilderExtensions.md | 43 +++++ ...sions.Hosting.HostEnvironmentExtensions.md | 31 +++ ...uemon.Extensions.IO.ByteArrayExtensions.md | 50 +++++ .../Cuemon.Extensions.IO.StreamExtensions.md | 114 +++++++++++ .../Cuemon.Extensions.IO.StringExtensions.md | 38 ++++ ...emon.Extensions.IO.TextReaderExtensions.md | 40 ++++ .../Cuemon.Extensions.IntegerExtensions.md | 35 ++++ ...n.Extensions.MethodDescriptorExtensions.md | 34 ++++ .../Cuemon.Extensions.MutableTupleFactory.md | 31 +++ ...emon.Extensions.Net.ByteArrayExtensions.md | 44 +++++ ...mon.Extensions.Net.DictionaryExtensions.md | 46 +++++ ....Extensions.Net.Http.HttpManagerFactory.md | 36 ++++ ...xtensions.Net.Http.HttpMethodExtensions.md | 43 +++++ ...tensions.Net.Http.SlimHttpClientFactory.md | 44 +++++ ...s.Net.Http.SlimHttpClientFactoryOptions.md | 42 ++++ ...uemon.Extensions.Net.Http.UriExtensions.md | 179 ++++++++++++++++++ ...Extensions.Net.HttpStatusCodeExtensions.md | 46 +++++ ...sions.Net.NameValueCollectionExtensions.md | 46 +++++ ...xtensions.Net.Security.SignedUriOptions.md | 31 +++ ...xtensions.Net.Security.StringExtensions.md | 42 ++++ ...n.Extensions.Net.Security.UriExtensions.md | 31 +++ .../Cuemon.Extensions.Net.StringExtensions.md | 51 +++++ .../Cuemon.Extensions.ObjectExtensions.md | 62 ++++++ ...xtensions.Reflection.AssemblyExtensions.md | 45 +++++ ...ensions.Reflection.MemberInfoExtensions.md | 40 ++++ ...sions.Reflection.PropertyInfoExtensions.md | 40 ++++ ...on.Extensions.Reflection.TypeExtensions.md | 66 +++++++ .../Cuemon.Extensions.RoundOffAccuracy.md | 28 +++ ...ntime.Caching.CacheEnumerableExtensions.md | 31 +++ .../Cuemon.Extensions.Runtime.Hierarchy.md | 38 ++++ ...ns.Runtime.HierarchyDecoratorExtensions.md | 152 +++++++++++++++ ...mon.Extensions.Runtime.HierarchyOptions.md | 54 ++++++ .../Cuemon.Extensions.Runtime.Hierarchy`1.md | 46 +++++ ...ntime.Serialization.HierarchySerializer.md | 43 +++++ .../Cuemon.Extensions.StringExtensions.md | 101 ++++++++++ .../Cuemon.Extensions.TesterFuncFactory.md | 29 +++ ...tensions.Text.EncodingOptionsExtensions.md | 49 +++++ ....Text.Json.Converters.DateTimeConverter.md | 37 ++++ ...Text.Json.Converters.ExceptionConverter.md | 49 +++++ ...rters.JsonConverterCollectionExtensions.md | 64 +++++++ ...ext.Json.Converters.StringEnumConverter.md | 42 ++++ ...son.Converters.StringFlagsEnumConverter.md | 39 ++++ ...erters.TransientFaultExceptionConverter.md | 95 ++++++++++ ...tensions.Text.Json.DynamicJsonConverter.md | 32 ++++ ...ions.Text.Json.Formatters.JsonFormatter.md | 48 +++++ ...xt.Json.Formatters.JsonFormatterOptions.md | 73 +++++++ ...ns.Text.Json.JsonNamingPolicyExtensions.md | 41 ++++ ...xt.Json.JsonSerializerOptionsExtensions.md | 47 +++++ ...tensions.Text.Json.Utf8JsonReaderFunc`1.md | 32 ++++ ...nsions.Text.Json.Utf8JsonWriterAction`1.md | 32 ++++ ...ions.Text.Json.Utf8JsonWriterExtensions.md | 60 ++++++ ...Cuemon.Extensions.Text.StringExtensions.md | 68 +++++++ ...tensions.Threading.Tasks.TaskExtensions.md | 31 +++ .../Cuemon.Extensions.TimeSpanExtensions.md | 33 ++++ .../types/Cuemon.Extensions.TypeExtensions.md | 47 +++++ .../Cuemon.Extensions.VerticalDirection.md | 28 +++ .docfx/api/types/Cuemon.Extensions.Wrapper.md | 32 ++++ .../api/types/Cuemon.Extensions.Wrapper`1.md | 45 +++++ ...emon.Extensions.Xml.ByteArrayExtensions.md | 35 ++++ ...uemon.Extensions.Xml.DateTimeExtensions.md | 46 +++++ ...emon.Extensions.Xml.HierarchyExtensions.md | 57 ++++++ ...on.Extensions.Xml.Linq.StringExtensions.md | 40 ++++ ...ation.Converters.XmlConverterExtensions.md | 67 +++++++ ...lization.XmlSerializerOptionsExtensions.md | 37 ++++ .../Cuemon.Extensions.Xml.StreamExtensions.md | 63 ++++++ .../Cuemon.Extensions.Xml.StringExtensions.md | 46 +++++ .../Cuemon.Extensions.Xml.UriExtensions.md | 48 +++++ .../Cuemon.Extensions.Xml.XmlCopyOptions.md | 63 ++++++ ...emon.Extensions.Xml.XmlReaderExtensions.md | 62 ++++++ ...emon.Extensions.Xml.XmlWriterExtensions.md | 71 +++++++ .docfx/api/types/Cuemon.FormattingOptions.md | 33 ++++ .docfx/api/types/Cuemon.FuncFactory`2.md | 30 +++ .docfx/api/types/Cuemon.Generate.md | 50 +++++ ...mon.Globalization.StatisticalRegionInfo.md | 44 +++++ ...mon.Globalization.StatisticalRegionKind.md | 42 ++++ .../api/types/Cuemon.Globalization.World.md | 35 ++++ .docfx/api/types/Cuemon.GuidFormats.md | 44 +++++ .../types/Cuemon.IO.AsyncDisposableOptions.md | 42 ++++ ...Cuemon.IO.AsyncStreamCompressionOptions.md | 57 ++++++ .../types/Cuemon.IO.AsyncStreamCopyOptions.md | 44 +++++ .../Cuemon.IO.AsyncStreamEncodingOptions.md | 45 +++++ .../Cuemon.IO.AsyncStreamReaderOptions.md | 50 +++++ .../types/Cuemon.IO.BufferWriterOptions.md | 42 ++++ .docfx/api/types/Cuemon.IO.FileInfoOptions.md | 61 ++++++ .../Cuemon.IO.StreamCompressionOptions.md | 52 +++++ .../api/types/Cuemon.IO.StreamCopyOptions.md | 54 ++++++ .../Cuemon.IO.StreamDecoratorExtensions.md | 130 +++++++++++++ .../types/Cuemon.IO.StreamEncodingOptions.md | 63 ++++++ .docfx/api/types/Cuemon.IO.StreamFactory.md | 49 +++++ .../types/Cuemon.IO.StreamReaderOptions.md | 55 ++++++ .../types/Cuemon.IO.StreamWriterOptions.md | 57 ++++++ ...Cuemon.IO.TextReaderDecoratorExtensions.md | 54 ++++++ .../Cuemon.IntegerDecoratorExtensions.md | 39 ++++ .../Cuemon.Messaging.CorrelationToken.md | 32 ++++ .../types/Cuemon.Messaging.RequestToken.md | 30 +++ .docfx/api/types/Cuemon.MutableTuple.md | 32 ++++ .docfx/api/types/Cuemon.MutableTuple`1.md | 24 +++ ...Cuemon.Net.ByteArrayDecoratorExtensions.md | 51 +++++ ....NameValueCollectionDecoratorExtensions.md | 39 ++++ .../types/Cuemon.Net.FieldValueSeparator.md | 33 ++++ ...emon.Net.Http.HttpAuthenticationSchemes.md | 35 ++++ .../types/Cuemon.Net.Http.HttpDependency.md | 52 +++++ .../types/Cuemon.Net.Http.HttpHeaderNames.md | 37 ++++ .../api/types/Cuemon.Net.Http.HttpManager.md | 42 ++++ .../Cuemon.Net.Http.HttpManagerOptions.md | 36 ++++ .../Cuemon.Net.Http.HttpMethodConverter.md | 23 +++ .../api/types/Cuemon.Net.Http.HttpMethods.md | 26 +++ .../Cuemon.Net.Http.HttpRequestOptions.md | 37 ++++ .../api/types/Cuemon.Net.Http.HttpWatcher.md | 30 +++ .../Cuemon.Net.Http.HttpWatcherOptions.md | 36 ++++ .../types/Cuemon.Net.Mail.MailDistributor.md | 33 ++++ .../types/Cuemon.Net.QueryStringCollection.md | 56 ++++++ .../Cuemon.Net.StringDecoratorExtensions.md | 52 +++++ .../types/Cuemon.ObjectDecoratorExtensions.md | 65 +++++++ .../types/Cuemon.ObjectFormattingOptions.md | 40 ++++ .../types/Cuemon.ObjectPortrayalOptions.md | 45 +++++ .docfx/api/types/Cuemon.Patterns.md | 46 +++++ .../Cuemon.Reflection.ActivatorFactory.md | 26 +++ .../Cuemon.Reflection.ActivatorOptions.md | 37 ++++ .../Cuemon.Reflection.AssemblyContext.md | 29 +++ ...uemon.Reflection.AssemblyContextOptions.md | 72 +++++++ ....Reflection.AssemblyDecoratorExtensions.md | 63 ++++++ ...Cuemon.Reflection.ManifestResourceMatch.md | 39 ++++ .../types/Cuemon.Reflection.MemberArgument.md | 51 +++++ ...ction.MemberArgumentDecoratorExtensions.md | 45 +++++ ...eflection.MemberInfoDecoratorExtensions.md | 51 +++++ .../types/Cuemon.Reflection.MemberParser.md | 52 +++++ .../Cuemon.Reflection.MemberReflection.md | 47 +++++ ...emon.Reflection.MemberReflectionOptions.md | 57 ++++++ .../Cuemon.Reflection.MethodBaseOptions.md | 51 +++++ .../Cuemon.Reflection.MethodDescriptor.md | 61 ++++++ ...eflection.MethodInfoDecoratorExtensions.md | 51 +++++ .../Cuemon.Reflection.MethodSignature.md | 37 ++++ .../Cuemon.Reflection.ParameterSignature.md | 34 ++++ ...lection.PropertyInfoDecoratorExtensions.md | 44 +++++ .../Cuemon.Reflection.TypeNameOptions.md | 45 +++++ .../types/Cuemon.Reflection.VersionResult.md | 38 ++++ ...silience.AsyncTransientOperationOptions.md | 44 +++++ .../Cuemon.Resilience.LatencyException.md | 26 +++ ...uemon.Resilience.TransientFaultEvidence.md | 70 +++++++ ...emon.Resilience.TransientFaultException.md | 35 ++++ .../Cuemon.Resilience.TransientOperation.md | 31 +++ ...on.Resilience.TransientOperationOptions.md | 36 ++++ .../Cuemon.Runtime.Caching.CacheEntry.md | 29 +++ ...mon.Runtime.Caching.CacheEntryEventArgs.md | 63 ++++++ ...uemon.Runtime.Caching.CacheInvalidation.md | 35 ++++ .../Cuemon.Runtime.Caching.CachingManager.md | 31 +++ .../Cuemon.Runtime.Caching.SlimMemoryCache.md | 65 +++++++ ....Runtime.Caching.SlimMemoryCacheOptions.md | 34 ++++ .../Cuemon.Runtime.DependencyEventArgs.md | 61 ++++++ .../types/Cuemon.Runtime.FileDependency.md | 41 ++++ .../api/types/Cuemon.Runtime.FileWatcher.md | 41 ++++ ...time.Serialization.Formatters.Formatter.md | 26 +++ .../types/Cuemon.Runtime.WatcherEventArgs.md | 28 +++ .../types/Cuemon.Runtime.WatcherOptions.md | 29 +++ ...Cuemon.Security.Cryptography.AesCryptor.md | 91 +++++++++ ...Security.Cryptography.AesCryptorOptions.md | 77 ++++++++ ...mon.Security.Cryptography.AesKeyOptions.md | 67 +++++++ .../Cuemon.Security.Cryptography.AesSize.md | 48 +++++ ...ecurity.Cryptography.HmacMessageDigest5.md | 64 +++++++ ...y.Cryptography.HmacSecureHashAlgorithm1.md | 29 +++ ...Cryptography.HmacSecureHashAlgorithm256.md | 29 +++ ...Cryptography.HmacSecureHashAlgorithm384.md | 28 +++ ...Cryptography.HmacSecureHashAlgorithm512.md | 29 +++ ...urity.Cryptography.KeyedCryptoAlgorithm.md | 70 +++++++ ....Security.Cryptography.KeyedHashFactory.md | 25 +++ ...on.Security.Cryptography.MessageDigest5.md | 28 +++ .../Cuemon.Security.Cryptography.SHA512256.md | 30 +++ ...urity.Cryptography.SecureHashAlgorithm1.md | 27 +++ ...ity.Cryptography.SecureHashAlgorithm256.md | 29 +++ ...ity.Cryptography.SecureHashAlgorithm384.md | 27 +++ ...ity.Cryptography.SecureHashAlgorithm512.md | 27 +++ ....Cryptography.SecureHashAlgorithm512256.md | 27 +++ ...ity.Cryptography.UnkeyedCryptoAlgorithm.md | 62 ++++++ ...ecurity.Cryptography.UnkeyedHashFactory.md | 28 +++ ...Cuemon.Security.CyclicRedundancyCheck32.md | 38 ++++ ...Cuemon.Security.CyclicRedundancyCheck64.md | 43 +++++ ...Security.CyclicRedundancyCheckAlgorithm.md | 42 ++++ ...n.Security.CyclicRedundancyCheckOptions.md | 41 ++++ .../types/Cuemon.Security.FowlerNollVo1024.md | 37 ++++ .../types/Cuemon.Security.FowlerNollVo128.md | 51 +++++ .../types/Cuemon.Security.FowlerNollVo256.md | 51 +++++ .../types/Cuemon.Security.FowlerNollVo32.md | 45 +++++ .../types/Cuemon.Security.FowlerNollVo512.md | 51 +++++ .../types/Cuemon.Security.FowlerNollVo64.md | 44 +++++ .../Cuemon.Security.FowlerNollVoAlgorithm.md | 38 ++++ .../Cuemon.Security.FowlerNollVoOptions.md | 44 +++++ .../api/types/Cuemon.Security.HashFactory.md | 32 ++++ .../api/types/Cuemon.Security.HashResult.md | 45 +++++ .../Cuemon.Security.NonCryptoAlgorithm.md | 44 +++++ .docfx/api/types/Cuemon.SortOrder.md | 38 ++++ .../types/Cuemon.StringDecoratorExtensions.md | 65 +++++++ .docfx/api/types/Cuemon.StringFactory.md | 45 +++++ .docfx/api/types/Cuemon.StringReplacePair.md | 51 +++++ .docfx/api/types/Cuemon.SuccessfulValue.md | 35 ++++ .docfx/api/types/Cuemon.SuccessfulValue`1.md | 35 ++++ .docfx/api/types/Cuemon.SystemSnapshots.md | 45 +++++ .../api/types/Cuemon.TesterFuncFactory`3.md | 36 ++++ .docfx/api/types/Cuemon.TesterFunc`2.md | 31 +++ .../types/Cuemon.Text.AsyncEncodingOptions.md | 36 ++++ .docfx/api/types/Cuemon.Text.ByteOrderMark.md | 33 ++++ .../api/types/Cuemon.Text.EncodingOptions.md | 43 +++++ .../types/Cuemon.Text.EnumStringOptions.md | 38 ++++ .../Cuemon.Text.FallbackEncodingOptions.md | 35 ++++ .../types/Cuemon.Text.GuidStringOptions.md | 40 ++++ .docfx/api/types/Cuemon.Text.ParserFactory.md | 30 +++ .../api/types/Cuemon.Text.PreambleSequence.md | 34 ++++ ...n.Text.ProtocolRelativeUriStringOptions.md | 38 ++++ .docfx/api/types/Cuemon.Text.Stem.md | 31 +++ .../api/types/Cuemon.Text.UriStringOptions.md | 38 ++++ ...uemon.Threading.AdvancedParallelFactory.md | 24 +++ .../Cuemon.Threading.AsyncActionFactory-1.md | 37 ++++ .../Cuemon.Threading.AsyncActionFactory.md | 34 ++++ .../Cuemon.Threading.AsyncFuncFactory.md | 35 ++++ .../Cuemon.Threading.AsyncFuncFactory`2.md | 49 +++++ .../types/Cuemon.Threading.AsyncOptions.md | 42 ++++ .../types/Cuemon.Threading.AsyncPatterns.md | 43 +++++ .../types/Cuemon.Threading.AsyncRunOptions.md | 44 +++++ ...uemon.Threading.AsyncTaskFactoryOptions.md | 43 +++++ .../Cuemon.Threading.AsyncWorkloadOptions.md | 42 ++++ .docfx/api/types/Cuemon.Threading.Awaiter.md | 36 ++++ .../Cuemon.Threading.ForLoopRuleset`1.md | 40 ++++ .../types/Cuemon.Threading.ParallelFactory.md | 29 +++ .../Cuemon.Threading.RelationalOperator.md | 30 +++ .../types/Cuemon.Threading.TimerFactory.md | 28 +++ .docfx/api/types/Cuemon.TimeRange.md | 41 ++++ .docfx/api/types/Cuemon.TimeUnit.md | 40 ++++ .docfx/api/types/Cuemon.Tweaker.md | 37 ++++ .../api/types/Cuemon.TypeArgumentException.md | 50 +++++ .../Cuemon.TypeArgumentOutOfRangeException.md | 54 ++++++ .../types/Cuemon.TypeDecoratorExtensions.md | 115 +++++++++++ .docfx/api/types/Cuemon.UnsuccessfulValue.md | 38 ++++ .../api/types/Cuemon.UnsuccessfulValue`1.md | 36 ++++ .docfx/api/types/Cuemon.UriScheme.md | 28 +++ .docfx/api/types/Cuemon.Validator.md | 34 ++++ ...Cuemon.Xml.HierarchyDecoratorExtensions.md | 57 ++++++ ...emon.Xml.Linq.StringDecoratorExtensions.md | 60 ++++++ ...lization.Converters.DefaultXmlConverter.md | 39 ++++ ...alization.Converters.ExceptionConverter.md | 89 +++++++++ ...rialization.Converters.FailureConverter.md | 51 +++++ ...verters.XmlConverterDecoratorExtensions.md | 53 ++++++ ...n.Xml.Serialization.DynamicXmlConverter.md | 37 ++++ ...l.Serialization.DynamicXmlConverterCore.md | 99 ++++++++++ ...ml.Serialization.DynamicXmlSerializable.md | 35 ++++ ...l.Serialization.Formatters.XmlFormatter.md | 41 ++++ ...lization.Formatters.XmlFormatterOptions.md | 52 +++++ .../Cuemon.Xml.Serialization.XmlConvert.md | 28 +++ ...on.Xml.Serialization.XmlQualifiedEntity.md | 62 ++++++ .../Cuemon.Xml.Serialization.XmlSerializer.md | 50 +++++ ....Xml.Serialization.XmlSerializerOptions.md | 34 ++++ ...XmlSerializerOptionsDecoratorExtensions.md | 36 ++++ .../Cuemon.Xml.StreamDecoratorExtensions.md | 39 ++++ .../Cuemon.Xml.StringDecoratorExtensions.md | 53 ++++++ .../Cuemon.Xml.XPath.XPathDocumentFactory.md | 26 +++ .../types/Cuemon.Xml.XmlDocumentFactory.md | 28 +++ .../types/Cuemon.Xml.XmlEncodingOptions.md | 57 ++++++ ...Cuemon.Xml.XmlReaderDecoratorExtensions.md | 42 ++++ .../api/types/Cuemon.Xml.XmlStreamFactory.md | 34 ++++ ...Cuemon.Xml.XmlWriterDecoratorExtensions.md | 65 +++++++ ...vices.CallerArgumentExpressionAttribute.md | 36 ++++ 672 files changed, 24769 insertions(+), 175 deletions(-) create mode 100644 .docfx/api/namespaces/Cuemon.AspNetCore.Infrastructure.md create mode 100644 .docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Text.Json.md create mode 100644 .docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Xml.md create mode 100644 .docfx/api/namespaces/Cuemon.Extensions.Globalization.md create mode 100644 .docfx/api/namespaces/Cuemon.Extensions.Runtime.Serialization.md create mode 100644 .docfx/api/namespaces/Cuemon.Extensions.Runtime.md create mode 100644 .docfx/api/namespaces/Cuemon.Text.md create mode 100644 .docfx/api/namespaces/System.Runtime.CompilerServices.md create mode 100644 .docfx/api/types/Cuemon.ActionFactory`1.md create mode 100644 .docfx/api/types/Cuemon.Alphanumeric.md create mode 100644 .docfx/api/types/Cuemon.ArgumentReservedKeywordException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.AuthenticationHandlerFeature.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Authenticator.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.AuthorizationHeaderOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationHandler.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationMiddleware.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticator.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthorizationHeader.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthorizationHeaderBuilder.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicFields.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationHandler.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationMiddleware.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticator.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthorizationHeader.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthorizationHeaderBuilder.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestCryptoAlgorithm.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestFields.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestHashFactory.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationHandler.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationMiddleware.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticator.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthorizationHeader.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthorizationHeaderBuilder.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacFields.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.MemoryNonceTracker.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Authentication.NonceTrackerEntry.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Builder.MiddlewareBuilderFactory.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Configuration.CacheBustingOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Configuration.DynamicCacheBusting.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Configuration.DynamicCacheBustingOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptionsDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptor.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseFormatter`1.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandler.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpFaultResolver.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpFaultResolverDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpRequestEvidence.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.PreferredFaultDescriptor.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTiming.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingMetric.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingMiddleware.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Hosting.HostingEnvironmentMiddleware.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Hosting.HostingEnvironmentOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.BadRequestException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.ConflictException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.ForbiddenException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.GoneException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.HeaderDictionaryDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.ApiKeyException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.ApiKeySentinelMiddleware.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.ApiKeySentinelOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.CacheableMiddleware.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.CacheableOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.ChecksumBuilderDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierMiddleware.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.ExpiresHeaderValue.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.RequestIdentifierMiddleware.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.RequestIdentifierOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.RetryConditionScope.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.UserAgentException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.UserAgentSentinelMiddleware.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.UserAgentSentinelOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Headers.VaryAcceptMiddleware.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.HttpContextDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.HttpRequestDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.HttpResponseDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.HttpStatusCodeExceptionDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Int32DecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.InternalServerErrorException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.MethodNotAllowedException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.NotAcceptableException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.NotFoundException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.PayloadTooLargeException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.PreconditionFailedException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.PreconditionRequiredException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Throttling.MemoryThrottlingCache.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottleQuota.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottleRequest.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelMiddleware.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.TooManyRequestsException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.UnauthorizedException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Http.UnsupportedMediaTypeException.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Breadcrumb.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.CacheableFactory.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.CacheableObjectResultOptions`1.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.ContentBasedObjectResultOptions`1.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.ExceptionDescriptorResult.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpCacheableFilter.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpCacheableOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpEntityTagHeaderFilter.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpEntityTagHeaderOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpLastModifiedHeaderFilter.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpLastModifiedHeaderOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.FaultDescriptorFilter.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.MvcFaultDescriptorOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingAttribute.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingFilter.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Headers.ApiKeySentinelAttribute.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Headers.ApiKeySentinelFilter.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Headers.UserAgentSentinelFilter.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.ModelBinding.DisableModelBindingAttribute.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Throttling.ThrottlingSentinelFilter.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.ForbiddenObjectResult.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.ForbiddenResult.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.GoneResult.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.SeeOtherResult.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.TimeBasedObjectResultOptions`1.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.TooManyRequestsObjectResult.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Mvc.TooManyRequestsResult.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppImageTagHelper.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppLinkTagHelper.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppScriptTagHelper.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppTagHelperOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnImageTagHelper.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnLinkTagHelper.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnScriptTagHelper.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnTagHelperOptions.md create mode 100644 .docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.ProtocolUriScheme.md create mode 100644 .docfx/api/types/Cuemon.AssignmentOperator.md create mode 100644 .docfx/api/types/Cuemon.ByteArrayDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Calculator.md create mode 100644 .docfx/api/types/Cuemon.CasingMethod.md create mode 100644 .docfx/api/types/Cuemon.CharDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.Arguments.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.CollectionDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.DictionaryDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.DynamicComparer.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.DynamicEqualityComparer.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.EnumReadOnlyDictionary`1.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.EnumerableSizeComparer-1.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.PaginationEnumerable-1.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.PaginationList-1.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.PaginationOptions.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.PartitionerCollection-1.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.PartitionerEnumerable`1.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.ReferenceComparer-1.md create mode 100644 .docfx/api/types/Cuemon.Collections.Generic.StackDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Collections.Specialized.DictionaryDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Condition.md create mode 100644 .docfx/api/types/Cuemon.Convertible.md create mode 100644 .docfx/api/types/Cuemon.ConvertibleConverterDictionary.md create mode 100644 .docfx/api/types/Cuemon.ConvertibleOptions.md create mode 100644 .docfx/api/types/Cuemon.Data.DataManagerOptions.md create mode 100644 .docfx/api/types/Cuemon.Data.DataReaderDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Data.DataStatement.md create mode 100644 .docfx/api/types/Cuemon.Data.DataStatementOptions.md create mode 100644 .docfx/api/types/Cuemon.Data.DataTransfer.md create mode 100644 .docfx/api/types/Cuemon.Data.DataTransferColumn.md create mode 100644 .docfx/api/types/Cuemon.Data.DataTransferColumnCollection.md create mode 100644 .docfx/api/types/Cuemon.Data.DataTransferRow.md create mode 100644 .docfx/api/types/Cuemon.Data.DataTransferRowCollection.md create mode 100644 .docfx/api/types/Cuemon.Data.DatabaseDependency.md create mode 100644 .docfx/api/types/Cuemon.Data.DatabaseWatcher.md create mode 100644 .docfx/api/types/Cuemon.Data.DbTypeDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Data.DsvDataReader.md create mode 100644 .docfx/api/types/Cuemon.Data.InOperatorResult.md create mode 100644 .docfx/api/types/Cuemon.Data.Integrity.CacheValidator.md create mode 100644 .docfx/api/types/Cuemon.Data.Integrity.CacheValidatorFactory.md create mode 100644 .docfx/api/types/Cuemon.Data.Integrity.ChecksumBuilder.md create mode 100644 .docfx/api/types/Cuemon.Data.Integrity.ChecksumBuilderDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Data.Integrity.DataIntegrityFactory.md create mode 100644 .docfx/api/types/Cuemon.Data.Integrity.EntityDataIntegrityMethod.md create mode 100644 .docfx/api/types/Cuemon.Data.Integrity.EntityDataIntegrityValidation.md create mode 100644 .docfx/api/types/Cuemon.Data.Integrity.EntityInfo.md create mode 100644 .docfx/api/types/Cuemon.Data.Integrity.FileChecksumOptions.md create mode 100644 .docfx/api/types/Cuemon.Data.Integrity.FileIntegrityOptions.md create mode 100644 .docfx/api/types/Cuemon.Data.QueryFormat.md create mode 100644 .docfx/api/types/Cuemon.Data.QueryType.md create mode 100644 .docfx/api/types/Cuemon.Data.SqlClient.SqlDataManager.md create mode 100644 .docfx/api/types/Cuemon.Data.SqlClient.SqlInOperator`1.md create mode 100644 .docfx/api/types/Cuemon.Data.SqlClient.SqlQueryBuilder.md create mode 100644 .docfx/api/types/Cuemon.Data.TokenBuilder.md create mode 100644 .docfx/api/types/Cuemon.Data.UniqueIndexViolationException.md create mode 100644 .docfx/api/types/Cuemon.Data.Xml.XmlDataReader.md create mode 100644 .docfx/api/types/Cuemon.DataPair.md create mode 100644 .docfx/api/types/Cuemon.DataPair`1.md create mode 100644 .docfx/api/types/Cuemon.DateSpan.md create mode 100644 .docfx/api/types/Cuemon.DateTimeDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.DateTimeFormatPattern.md create mode 100644 .docfx/api/types/Cuemon.DateTimeRange.md create mode 100644 .docfx/api/types/Cuemon.DayPart.md create mode 100644 .docfx/api/types/Cuemon.Decorator-1.md create mode 100644 .docfx/api/types/Cuemon.Decorator.md create mode 100644 .docfx/api/types/Cuemon.DelegateDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.DelimitedString.md create mode 100644 .docfx/api/types/Cuemon.DelimitedStringOptions.md create mode 100644 .docfx/api/types/Cuemon.DelimitedStringOptions`1.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.AsyncTimeMeasureOptions.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.ExceptionDescriptor.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.ExceptionDescriptorAttribute.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.ExceptionDescriptorOptions.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.Failure.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.FaultResolver.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.FaultSensitivityDetails.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.MemberEvidence.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.ProfilerOptions.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.TimeMeasure.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.TimeMeasureOptions.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler.md create mode 100644 .docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler`1.md create mode 100644 .docfx/api/types/Cuemon.DisposableOptions.md create mode 100644 .docfx/api/types/Cuemon.DoubleDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.EndianOptions.md create mode 100644 .docfx/api/types/Cuemon.Endianness.md create mode 100644 .docfx/api/types/Cuemon.Eradicate.md create mode 100644 .docfx/api/types/Cuemon.ExceptionCondition`1.md create mode 100644 .docfx/api/types/Cuemon.ExceptionDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.ExceptionHandler`1.md create mode 100644 .docfx/api/types/Cuemon.ExceptionHandler`2.md create mode 100644 .docfx/api/types/Cuemon.ExceptionInsights.md create mode 100644 .docfx/api/types/Cuemon.ExceptionInvoker`1.md create mode 100644 .docfx/api/types/Cuemon.ExceptionInvoker`2.md create mode 100644 .docfx/api/types/Cuemon.Extensions.ActionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.ActionFactory.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.ApplicationBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthenticationBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandler.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandlerOptions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.ServiceCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Configuration.AssemblyCacheBusting.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Configuration.AssemblyCacheBustingOptions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Configuration.ServiceCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Data.Integrity.CacheValidatorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Data.Integrity.ChecksumBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Diagnostics.ApplicationBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Diagnostics.ServiceCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Diagnostics.ServiceProviderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Hosting.ApplicationBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HeaderDictionaryExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Headers.ApplicationBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Headers.EntityTagCacheableValidator.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Headers.ServiceCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpExceptionDescriptorResponseFormatterExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpRequestExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpResponseExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Int32Extensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Throttling.ApplicationBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Throttling.ServiceCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.CacheableObjectResultExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable.CacheableAsyncResultFilterExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics.HttpFaultResolverExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.FilterCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.MvcBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationInputFormatter.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationMvcOptionsSetup.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationOutputFormatter.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.MvcBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.MvcCoreBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcCoreBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationInputFormatter.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationMvcOptionsSetup.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationOutputFormatter.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.PageBaseExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Rendering.HtmlHelperExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.ViewDataDictionaryExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.Converters.JsonConverterCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.Formatters.ServiceCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.MinimalJsonOptions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.ServiceCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Xml.Converters.XmlConverterExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Xml.Formatters.ServiceCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.AspNetCore.Xml.ServiceCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.ByteExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.CharExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Collections.Generic.CollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Collections.Generic.DictionaryExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Collections.Generic.EnumerableExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Collections.Generic.ListExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Collections.Generic.QueueExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Collections.Generic.StackExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Collections.Specialized.DictionaryExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Collections.Specialized.NameValueCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Data.DataReaderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Data.DbTypeExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Data.Integrity.AssemblyExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Data.Integrity.ChecksumBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Data.Integrity.DateTimeExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Data.Integrity.FileInfoExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Data.QueryFormatExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.DateTimeExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceOptions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceProviderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.DependencyInjection.TypeExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.DependencyInjection.TypeForwardServiceOptions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Diagnostics.FileVersionInfoExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.DoubleExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.ExceptionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.FuncFactory.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Globalization.RegionInfoExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Globalization.StatisticalRegionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Hosting.Environments.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Hosting.HostBuilderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Hosting.HostEnvironmentExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.IO.ByteArrayExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.IO.StreamExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.IO.StringExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.IO.TextReaderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.IntegerExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.MethodDescriptorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.MutableTupleFactory.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.ByteArrayExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.DictionaryExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.Http.HttpManagerFactory.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.Http.HttpMethodExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.Http.SlimHttpClientFactory.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.Http.SlimHttpClientFactoryOptions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.Http.UriExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.HttpStatusCodeExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.NameValueCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.Security.SignedUriOptions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.Security.StringExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.Security.UriExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Net.StringExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.ObjectExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Reflection.AssemblyExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Reflection.MemberInfoExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Reflection.PropertyInfoExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Reflection.TypeExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.RoundOffAccuracy.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Runtime.Hierarchy.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Runtime.HierarchyDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Runtime.HierarchyOptions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Runtime.Hierarchy`1.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Runtime.Serialization.HierarchySerializer.md create mode 100644 .docfx/api/types/Cuemon.Extensions.StringExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.TesterFuncFactory.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.EncodingOptionsExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.Converters.DateTimeConverter.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.Converters.ExceptionConverter.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.Converters.JsonConverterCollectionExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringEnumConverter.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringFlagsEnumConverter.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.Converters.TransientFaultExceptionConverter.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.DynamicJsonConverter.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.Formatters.JsonFormatter.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.Formatters.JsonFormatterOptions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.JsonNamingPolicyExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.JsonSerializerOptionsExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonReaderFunc`1.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonWriterAction`1.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonWriterExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Text.StringExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Threading.Tasks.TaskExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.TimeSpanExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.TypeExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.VerticalDirection.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Wrapper.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Wrapper`1.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Xml.ByteArrayExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Xml.DateTimeExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Xml.HierarchyExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Xml.Linq.StringExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Xml.Serialization.Converters.XmlConverterExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Xml.Serialization.XmlSerializerOptionsExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Xml.StreamExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Xml.StringExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Xml.UriExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Xml.XmlCopyOptions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Xml.XmlReaderExtensions.md create mode 100644 .docfx/api/types/Cuemon.Extensions.Xml.XmlWriterExtensions.md create mode 100644 .docfx/api/types/Cuemon.FormattingOptions.md create mode 100644 .docfx/api/types/Cuemon.FuncFactory`2.md create mode 100644 .docfx/api/types/Cuemon.Generate.md create mode 100644 .docfx/api/types/Cuemon.Globalization.StatisticalRegionInfo.md create mode 100644 .docfx/api/types/Cuemon.Globalization.StatisticalRegionKind.md create mode 100644 .docfx/api/types/Cuemon.Globalization.World.md create mode 100644 .docfx/api/types/Cuemon.GuidFormats.md create mode 100644 .docfx/api/types/Cuemon.IO.AsyncDisposableOptions.md create mode 100644 .docfx/api/types/Cuemon.IO.AsyncStreamCompressionOptions.md create mode 100644 .docfx/api/types/Cuemon.IO.AsyncStreamCopyOptions.md create mode 100644 .docfx/api/types/Cuemon.IO.AsyncStreamEncodingOptions.md create mode 100644 .docfx/api/types/Cuemon.IO.AsyncStreamReaderOptions.md create mode 100644 .docfx/api/types/Cuemon.IO.BufferWriterOptions.md create mode 100644 .docfx/api/types/Cuemon.IO.FileInfoOptions.md create mode 100644 .docfx/api/types/Cuemon.IO.StreamCompressionOptions.md create mode 100644 .docfx/api/types/Cuemon.IO.StreamCopyOptions.md create mode 100644 .docfx/api/types/Cuemon.IO.StreamDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.IO.StreamEncodingOptions.md create mode 100644 .docfx/api/types/Cuemon.IO.StreamFactory.md create mode 100644 .docfx/api/types/Cuemon.IO.StreamReaderOptions.md create mode 100644 .docfx/api/types/Cuemon.IO.StreamWriterOptions.md create mode 100644 .docfx/api/types/Cuemon.IO.TextReaderDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.IntegerDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Messaging.CorrelationToken.md create mode 100644 .docfx/api/types/Cuemon.Messaging.RequestToken.md create mode 100644 .docfx/api/types/Cuemon.MutableTuple.md create mode 100644 .docfx/api/types/Cuemon.MutableTuple`1.md create mode 100644 .docfx/api/types/Cuemon.Net.ByteArrayDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Net.Collections.Specialized.NameValueCollectionDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Net.FieldValueSeparator.md create mode 100644 .docfx/api/types/Cuemon.Net.Http.HttpAuthenticationSchemes.md create mode 100644 .docfx/api/types/Cuemon.Net.Http.HttpDependency.md create mode 100644 .docfx/api/types/Cuemon.Net.Http.HttpHeaderNames.md create mode 100644 .docfx/api/types/Cuemon.Net.Http.HttpManager.md create mode 100644 .docfx/api/types/Cuemon.Net.Http.HttpManagerOptions.md create mode 100644 .docfx/api/types/Cuemon.Net.Http.HttpMethodConverter.md create mode 100644 .docfx/api/types/Cuemon.Net.Http.HttpMethods.md create mode 100644 .docfx/api/types/Cuemon.Net.Http.HttpRequestOptions.md create mode 100644 .docfx/api/types/Cuemon.Net.Http.HttpWatcher.md create mode 100644 .docfx/api/types/Cuemon.Net.Http.HttpWatcherOptions.md create mode 100644 .docfx/api/types/Cuemon.Net.Mail.MailDistributor.md create mode 100644 .docfx/api/types/Cuemon.Net.QueryStringCollection.md create mode 100644 .docfx/api/types/Cuemon.Net.StringDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.ObjectDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.ObjectFormattingOptions.md create mode 100644 .docfx/api/types/Cuemon.ObjectPortrayalOptions.md create mode 100644 .docfx/api/types/Cuemon.Patterns.md create mode 100644 .docfx/api/types/Cuemon.Reflection.ActivatorFactory.md create mode 100644 .docfx/api/types/Cuemon.Reflection.ActivatorOptions.md create mode 100644 .docfx/api/types/Cuemon.Reflection.AssemblyContext.md create mode 100644 .docfx/api/types/Cuemon.Reflection.AssemblyContextOptions.md create mode 100644 .docfx/api/types/Cuemon.Reflection.AssemblyDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Reflection.ManifestResourceMatch.md create mode 100644 .docfx/api/types/Cuemon.Reflection.MemberArgument.md create mode 100644 .docfx/api/types/Cuemon.Reflection.MemberArgumentDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Reflection.MemberInfoDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Reflection.MemberParser.md create mode 100644 .docfx/api/types/Cuemon.Reflection.MemberReflection.md create mode 100644 .docfx/api/types/Cuemon.Reflection.MemberReflectionOptions.md create mode 100644 .docfx/api/types/Cuemon.Reflection.MethodBaseOptions.md create mode 100644 .docfx/api/types/Cuemon.Reflection.MethodDescriptor.md create mode 100644 .docfx/api/types/Cuemon.Reflection.MethodInfoDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Reflection.MethodSignature.md create mode 100644 .docfx/api/types/Cuemon.Reflection.ParameterSignature.md create mode 100644 .docfx/api/types/Cuemon.Reflection.PropertyInfoDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Reflection.TypeNameOptions.md create mode 100644 .docfx/api/types/Cuemon.Reflection.VersionResult.md create mode 100644 .docfx/api/types/Cuemon.Resilience.AsyncTransientOperationOptions.md create mode 100644 .docfx/api/types/Cuemon.Resilience.LatencyException.md create mode 100644 .docfx/api/types/Cuemon.Resilience.TransientFaultEvidence.md create mode 100644 .docfx/api/types/Cuemon.Resilience.TransientFaultException.md create mode 100644 .docfx/api/types/Cuemon.Resilience.TransientOperation.md create mode 100644 .docfx/api/types/Cuemon.Resilience.TransientOperationOptions.md create mode 100644 .docfx/api/types/Cuemon.Runtime.Caching.CacheEntry.md create mode 100644 .docfx/api/types/Cuemon.Runtime.Caching.CacheEntryEventArgs.md create mode 100644 .docfx/api/types/Cuemon.Runtime.Caching.CacheInvalidation.md create mode 100644 .docfx/api/types/Cuemon.Runtime.Caching.CachingManager.md create mode 100644 .docfx/api/types/Cuemon.Runtime.Caching.SlimMemoryCache.md create mode 100644 .docfx/api/types/Cuemon.Runtime.Caching.SlimMemoryCacheOptions.md create mode 100644 .docfx/api/types/Cuemon.Runtime.DependencyEventArgs.md create mode 100644 .docfx/api/types/Cuemon.Runtime.FileDependency.md create mode 100644 .docfx/api/types/Cuemon.Runtime.FileWatcher.md create mode 100644 .docfx/api/types/Cuemon.Runtime.Serialization.Formatters.Formatter.md create mode 100644 .docfx/api/types/Cuemon.Runtime.WatcherEventArgs.md create mode 100644 .docfx/api/types/Cuemon.Runtime.WatcherOptions.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.AesCryptor.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.AesCryptorOptions.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.AesKeyOptions.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.AesSize.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.HmacMessageDigest5.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm1.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm256.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm384.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm512.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.KeyedCryptoAlgorithm.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.KeyedHashFactory.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.MessageDigest5.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.SHA512256.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm1.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm256.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm384.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm512.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm512256.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.UnkeyedCryptoAlgorithm.md create mode 100644 .docfx/api/types/Cuemon.Security.Cryptography.UnkeyedHashFactory.md create mode 100644 .docfx/api/types/Cuemon.Security.CyclicRedundancyCheck32.md create mode 100644 .docfx/api/types/Cuemon.Security.CyclicRedundancyCheck64.md create mode 100644 .docfx/api/types/Cuemon.Security.CyclicRedundancyCheckAlgorithm.md create mode 100644 .docfx/api/types/Cuemon.Security.CyclicRedundancyCheckOptions.md create mode 100644 .docfx/api/types/Cuemon.Security.FowlerNollVo1024.md create mode 100644 .docfx/api/types/Cuemon.Security.FowlerNollVo128.md create mode 100644 .docfx/api/types/Cuemon.Security.FowlerNollVo256.md create mode 100644 .docfx/api/types/Cuemon.Security.FowlerNollVo32.md create mode 100644 .docfx/api/types/Cuemon.Security.FowlerNollVo512.md create mode 100644 .docfx/api/types/Cuemon.Security.FowlerNollVo64.md create mode 100644 .docfx/api/types/Cuemon.Security.FowlerNollVoAlgorithm.md create mode 100644 .docfx/api/types/Cuemon.Security.FowlerNollVoOptions.md create mode 100644 .docfx/api/types/Cuemon.Security.HashFactory.md create mode 100644 .docfx/api/types/Cuemon.Security.HashResult.md create mode 100644 .docfx/api/types/Cuemon.Security.NonCryptoAlgorithm.md create mode 100644 .docfx/api/types/Cuemon.SortOrder.md create mode 100644 .docfx/api/types/Cuemon.StringDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.StringFactory.md create mode 100644 .docfx/api/types/Cuemon.StringReplacePair.md create mode 100644 .docfx/api/types/Cuemon.SuccessfulValue.md create mode 100644 .docfx/api/types/Cuemon.SuccessfulValue`1.md create mode 100644 .docfx/api/types/Cuemon.SystemSnapshots.md create mode 100644 .docfx/api/types/Cuemon.TesterFuncFactory`3.md create mode 100644 .docfx/api/types/Cuemon.TesterFunc`2.md create mode 100644 .docfx/api/types/Cuemon.Text.AsyncEncodingOptions.md create mode 100644 .docfx/api/types/Cuemon.Text.ByteOrderMark.md create mode 100644 .docfx/api/types/Cuemon.Text.EncodingOptions.md create mode 100644 .docfx/api/types/Cuemon.Text.EnumStringOptions.md create mode 100644 .docfx/api/types/Cuemon.Text.FallbackEncodingOptions.md create mode 100644 .docfx/api/types/Cuemon.Text.GuidStringOptions.md create mode 100644 .docfx/api/types/Cuemon.Text.ParserFactory.md create mode 100644 .docfx/api/types/Cuemon.Text.PreambleSequence.md create mode 100644 .docfx/api/types/Cuemon.Text.ProtocolRelativeUriStringOptions.md create mode 100644 .docfx/api/types/Cuemon.Text.Stem.md create mode 100644 .docfx/api/types/Cuemon.Text.UriStringOptions.md create mode 100644 .docfx/api/types/Cuemon.Threading.AdvancedParallelFactory.md create mode 100644 .docfx/api/types/Cuemon.Threading.AsyncActionFactory-1.md create mode 100644 .docfx/api/types/Cuemon.Threading.AsyncActionFactory.md create mode 100644 .docfx/api/types/Cuemon.Threading.AsyncFuncFactory.md create mode 100644 .docfx/api/types/Cuemon.Threading.AsyncFuncFactory`2.md create mode 100644 .docfx/api/types/Cuemon.Threading.AsyncOptions.md create mode 100644 .docfx/api/types/Cuemon.Threading.AsyncPatterns.md create mode 100644 .docfx/api/types/Cuemon.Threading.AsyncRunOptions.md create mode 100644 .docfx/api/types/Cuemon.Threading.AsyncTaskFactoryOptions.md create mode 100644 .docfx/api/types/Cuemon.Threading.AsyncWorkloadOptions.md create mode 100644 .docfx/api/types/Cuemon.Threading.Awaiter.md create mode 100644 .docfx/api/types/Cuemon.Threading.ForLoopRuleset`1.md create mode 100644 .docfx/api/types/Cuemon.Threading.ParallelFactory.md create mode 100644 .docfx/api/types/Cuemon.Threading.RelationalOperator.md create mode 100644 .docfx/api/types/Cuemon.Threading.TimerFactory.md create mode 100644 .docfx/api/types/Cuemon.TimeRange.md create mode 100644 .docfx/api/types/Cuemon.TimeUnit.md create mode 100644 .docfx/api/types/Cuemon.Tweaker.md create mode 100644 .docfx/api/types/Cuemon.TypeArgumentException.md create mode 100644 .docfx/api/types/Cuemon.TypeArgumentOutOfRangeException.md create mode 100644 .docfx/api/types/Cuemon.TypeDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.UnsuccessfulValue.md create mode 100644 .docfx/api/types/Cuemon.UnsuccessfulValue`1.md create mode 100644 .docfx/api/types/Cuemon.UriScheme.md create mode 100644 .docfx/api/types/Cuemon.Validator.md create mode 100644 .docfx/api/types/Cuemon.Xml.HierarchyDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Xml.Linq.StringDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.Converters.DefaultXmlConverter.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.Converters.ExceptionConverter.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.Converters.FailureConverter.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.Converters.XmlConverterDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverter.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverterCore.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlSerializable.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.Formatters.XmlFormatter.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.Formatters.XmlFormatterOptions.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.XmlConvert.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.XmlQualifiedEntity.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.XmlSerializer.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.XmlSerializerOptions.md create mode 100644 .docfx/api/types/Cuemon.Xml.Serialization.XmlSerializerOptionsDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Xml.StreamDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Xml.StringDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Xml.XPath.XPathDocumentFactory.md create mode 100644 .docfx/api/types/Cuemon.Xml.XmlDocumentFactory.md create mode 100644 .docfx/api/types/Cuemon.Xml.XmlEncodingOptions.md create mode 100644 .docfx/api/types/Cuemon.Xml.XmlReaderDecoratorExtensions.md create mode 100644 .docfx/api/types/Cuemon.Xml.XmlStreamFactory.md create mode 100644 .docfx/api/types/Cuemon.Xml.XmlWriterDecoratorExtensions.md create mode 100644 .docfx/api/types/System.Runtime.CompilerServices.CallerArgumentExpressionAttribute.md diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Basic.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Basic.md index 3e100ee2..df04f9ba 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Basic.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Basic.md @@ -2,6 +2,6 @@ uid: Cuemon.AspNetCore.Authentication.Basic summary: *content --- -The `Cuemon.AspNetCore.Authentication.Basic` namespace contains types that enable support for [Basic Authentication Scheme](https://en.wikipedia.org/wiki/Basic_access_authentication). +Implement [Basic Authentication (RFC 7617)](https://en.wikipedia.org/wiki/Basic_access_authentication) in your ASP.NET Core application with middleware and handler types. Use this namespace when you need to validate username and password credentials against a custom store. Start with `BasicAuthenticationHandler` to validate credentials or `BasicAuthenticationMiddleware` for pipeline-based authentication. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] \ No newline at end of file diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Digest.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Digest.md index 1b29d3e7..9297bc46 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Digest.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Digest.md @@ -2,6 +2,6 @@ uid: Cuemon.AspNetCore.Authentication.Digest summary: *content --- -The `Cuemon.AspNetCore.Authentication.Digest` namespace contains types that enable support for [Digest Access Authentication Scheme](https://en.wikipedia.org/wiki/Digest_access_authentication). +Implement [Digest Access Authentication (RFC 7616)](https://en.wikipedia.org/wiki/Digest_access_authentication) in your ASP.NET Core application with middleware, handler, and nonce tracking types. Use this namespace when you need challenge-response authentication that avoids sending passwords in clear text. Start with `DigestAuthenticationHandler` for authentication or `DigestAuthenticationMiddleware` for pipeline integration. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] \ No newline at end of file diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Hmac.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Hmac.md index c4ae6d40..7152c8d9 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Hmac.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Hmac.md @@ -2,6 +2,6 @@ uid: Cuemon.AspNetCore.Authentication.Hmac summary: *content --- -The `Cuemon.AspNetCore.Authentication.Hmac` namespace contains types that enable support for [HMAC Access Authentication Scheme](https://www.okta.com/identity-101/hmac/). Inspired by AWS Signature Version 4 [Authenticating Requests: Using the Authorization Header](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html) and [Signing AWS requests with Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html). +Implement [HMAC-based request signing](https://www.okta.com/identity-101/hmac/) (inspired by [AWS Signature Version 4](https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html) and its [signing process](https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html)) in your ASP.NET Core application. Use this namespace when you need to authenticate requests using a hash-based message authentication code. Start with `HmacAuthenticationHandler` for validating HMAC-signed requests in your authentication pipeline. [!INCLUDE [availability-modern](../../includes/availability-modern.md) \ No newline at end of file diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.md index 559e1174..9a0afa1a 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Authentication.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Authentication summary: *content --- -The `Cuemon.AspNetCore.Authentication` namespace contains types that enable support for authentication using the concept of an Authenticator, AuthorizationHeader and (to tie the knots) an AuthorizationHeaderBuilder. Basic-, Digest Access- and HMAC Authentication is provided out-of-the-box. The namespace is an addition to the `Microsoft.AspNetCore.Authentication` namespace. +Implement Basic, Digest Access, and HMAC authentication in your ASP.NET Core application using authenticators, authorization headers, and header builders. Use this namespace when you need standard HTTP authentication schemes without implementing the protocol details. Start with `AuthorizationHeaderBuilder` for constructing authorization headers or use the built-in handler types for each scheme. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Builder.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Builder.md index cad2ade4..5e027e97 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Builder.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Builder.md @@ -2,6 +2,6 @@ uid: Cuemon.AspNetCore.Builder summary: *content --- -The `Cuemon.AspNetCore.Builder` namespace contains types that supports adding either middleware or configurable middleware types to the application request pipeline. The namespace is an addition to the `Microsoft.AspNetCore.Builder` namespace. +Register middleware — including configurable middleware — in the ASP.NET Core request pipeline using factory types that support typed options and a builder pattern. Use this namespace when you need to add custom middleware to your application pipeline with structured configuration. Start with `MiddlewareBuilderFactory` to create middleware instances with the correct options. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] \ No newline at end of file diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Configuration.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Configuration.md index 68ec55ef..bbd83a17 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Configuration.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Configuration.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Configuration summary: *content --- -The `Cuemon.AspNetCore.Configuration` namespace contains types that provides a way to support a [cache busting strategy](https://www.keycdn.com/support/what-is-cache-busting). +Append versioned query parameters to ASP.NET Core static resources so that clients always receive the latest version of your files without manual cache invalidation. The `Cuemon.AspNetCore.Configuration` namespace implements a [cache busting strategy](https://www.keycdn.com/support/what-is-cache-busting) through types that generate versioned URLs for your static assets. Start with the cache-busting configuration types for your application. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Diagnostics.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Diagnostics.md index b1f8e9d5..f268b8a6 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Diagnostics.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Diagnostics.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Diagnostics summary: *content --- -The `Cuemon.AspNetCore.Diagnostics` namespace contains types that provides a way to support the Server-Timing header for communicating metrics about the request-response cycle to an user agent. The namespace is an addition to the `Microsoft.AspNetCore.Diagnostics` namespace. +Handle HTTP errors and communicate request-response metrics in ASP.NET Core with structured exception descriptors, fault resolvers, and Server-Timing support. Use this namespace when you need consistent error responses, server-timing headers, or structured exception handling in your ASP.NET Core pipeline. Start with `HttpExceptionDescriptor` and `HttpFaultResolver` for mapping exceptions to HTTP error responses. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] @@ -11,4 +11,14 @@ Complements: [Microsoft.AspNetCore.Diagnostics namespace](https://docs.microsoft Related: - [Cuemon.AspNetCore.Mvc.Filters.Diagnostics namespace](/api/aspnet/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.html) 📘 -- [Cuemon.Extensions.AspNetCore.Diagnostics namespace](/api/extensions/aspnet/Cuemon.Extensions.AspNetCore.Diagnostics.html) 📘 \ No newline at end of file +- [Cuemon.Extensions.AspNetCore.Diagnostics namespace](/api/extensions/aspnet/Cuemon.Extensions.AspNetCore.Diagnostics.html) 📘 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|FaultDescriptorOptions|⬇️|`TryResolveHttpExceptionDescriptor`| +|IDecorator|⬇️|`TryResolveHttpExceptionDescriptor`| +|IDecorator|⬇️|`ToProblemDetails`| +|HttpExceptionDescriptorResponseHandler|⬇️|`AddResponseHandler`| +|IDecorator>|⬇️|`AddHttpFaultResolver`| \ No newline at end of file diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Hosting.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Hosting.md index 8438bbb1..47ace6aa 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Hosting.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Hosting.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Hosting summary: *content --- -The `Cuemon.AspNetCore.Hosting` namespace contains types that provides middleware for determining the hosting environment. The namespace is an addition to the `Microsoft.AspNetCore.Hosting` namespace. +Adjust ASP.NET Core middleware behavior based on the current hosting environment (Development, Staging, Production) using dedicated hosting middleware. Use this namespace when you need environment-aware pipeline customization. Start with `HostingEnvironmentMiddleware` and configure it via `HostingEnvironmentOptions`. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Http.Headers.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Http.Headers.md index 2f2c6cc6..a8741da9 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Http.Headers.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Http.Headers.md @@ -2,8 +2,14 @@ uid: Cuemon.AspNetCore.Http.Headers summary: *content --- -The `Cuemon.AspNetCore.Http.Headers` namespace contains types that provides a set of middleware components tied to HTTP headers. The namespace is an addition to the `Microsoft.AspNetCore.Http.Headers` namespace. +Add HTTP caching headers, correlation identifiers, API key protection, and conditional request handling using middleware components for ASP.NET Core. Use this namespace when you need cache validation, request correlation, API key sentinel protection, or ETag/last-modified header support. Start with `CacheableMiddleware` and `CacheableOptions` for HTTP caching scenarios, or `CorrelationIdentifierMiddleware` for correlating requests across services. For API key protection, use `ApiKeySentinelMiddleware`. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] -Complements: [Microsoft.AspNetCore.Http.Headers namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.headers) 🔗 \ No newline at end of file +Complements: [Microsoft.AspNetCore.Http.Headers namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.headers) 🔗 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator|⬇️|`ToEntityTagHeaderValue`| \ No newline at end of file diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Http.Throttling.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Http.Throttling.md index dfd40715..6ab9ffd9 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Http.Throttling.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Http.Throttling.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Http.Throttling summary: *content --- -The `Cuemon.AspNetCore.Http.Throttling` namespace contains types that provides a middleware based throttling mechanism by specifying allowed quota and window duration of HTTP requests tied to a custom context (eg. IP-address, Authorization header, etc.). +Limit HTTP requests in ASP.NET Core using a middleware-based throttling mechanism with configurable quotas and time windows tied to request context (IP address, authorization header, etc.). Use this namespace when you need rate limiting per client or request characteristic. Start with `ThrottlingSentinelMiddleware` and `ThrottlingSentinelOptions` to configure quotas and windows. For custom throttling storage, implement `IThrottlingCache`. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Http.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Http.md index 0f43323f..4f9f24cb 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Http.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Http.md @@ -2,10 +2,22 @@ uid: Cuemon.AspNetCore.Http summary: *content --- -The `Cuemon.AspNetCore.Http` namespace contains types focusing on ways to provide developer friendly exception messages optimized for open- and otherwise public application programming interfaces (API). The namespace is an addition to the `Microsoft.AspNetCore.Http` namespace. +Handle structured HTTP errors, throttling, sentinel validation, and header manipulation in ASP.NET Core applications. Use this namespace when you need status-code exceptions, request throttling, API key validation, or HTTP header utilities. Start with status-code exception classes such as `BadRequestException`, `ForbiddenException`, or `NotFoundException` for standard HTTP error responses, or sentinel middleware like `ApiKeySentinelMiddleware` for request validation. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Microsoft.AspNetCore.Http namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http) 🔗 -Related: [Cuemon.Extensions.AspNetCore.Http namespace](/api/extensions/aspnet/Cuemon.Extensions.AspNetCore.Http.html) 📘 \ No newline at end of file +Related: [Cuemon.Extensions.AspNetCore.Http namespace](/api/extensions/aspnet/Cuemon.Extensions.AspNetCore.Http.html) 📘 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator|⬇️|`InvokeThrottlerSentinelAsync`, `InvokeUserAgentSentinelAsync`, `InvokeApiKeySentinelAsync`, `WriteExceptionDescriptorResponseAsync`| +|IDecorator|⬇️|`IsGetOrHeadMethod`, `IsClientSideResourceCached`| +|IDecorator|⬇️|`AddOrUpdateEntityTagHeader`, `AddOrUpdateLastModifiedHeader`| +|IDecorator|⬇️|`AddResponseHeaders`| +|IDecorator|⬇️|`AddResponseHeaders`| +|IDecorator|⬇️|`AddRange`, `AddOrUpdateHeader`, `AddOrUpdateHeaders`| +|IDecorator|⬇️|`IsInformationStatusCode`, `IsSuccessStatusCode`, `IsRedirectionStatusCode`, `IsNotModifiedStatusCode`, `IsClientErrorStatusCode`, `IsServerErrorStatusCode`| \ No newline at end of file diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Infrastructure.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Infrastructure.md new file mode 100644 index 00000000..c1e38b33 --- /dev/null +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Infrastructure.md @@ -0,0 +1,9 @@ +--- +uid: Cuemon.AspNetCore.Infrastructure +summary: *content +--- +Build ASP.NET Core middleware without writing infrastructure boilerplate from scratch. Use this namespace when you need base types that handle middleware lifecycle, options, and pipeline integration. Start with `ConfigurableMiddlewareCore` for middleware with options, or `MiddlewareCore` for simpler middleware. + +[!INCLUDE [availability-modern](../../includes/availability-modern.md)] + +Complements: [Cuemon.AspNetCore namespace](/api/aspnet/Cuemon.AspNetCore.html) 📘 diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Cacheable.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Cacheable.md index 7eefdc1e..3cfef68d 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Cacheable.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Cacheable.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Mvc.Filters.Cacheable summary: *content --- -The `Cuemon.AspNetCore.Mvc.Filters.Cacheable` namespace contains types that specializes in cache expiration and validation models. The namespace is an addition to the `Microsoft.AspNetCore.Mvc.Filters` namespace. +Enable conditional GET requests and HTTP caching for ASP.NET Core MVC controllers using action filters and result filters backed by ETag and last-modified headers. Use this namespace when you need fine-grained HTTP cache validation. Start with `HttpCacheableFilter` for full cache support, or use `HttpEntityTagHeaderFilter` and `HttpLastModifiedHeaderFilter` individually for ETag-only or last-modified-only scenarios. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.md index bf8255a0..fc77ef61 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Mvc.Filters.Diagnostics summary: *content --- -The `Cuemon.AspNetCore.Mvc.Diagnostics` namespace contains types that provide ways for developers to describe exceptions including evidence to why an operation faulted optimized for open- and otherwise public application programming interfaces (API). The namespace is an addition to the `Microsoft.AspNetCore.Mvc.Filters` namespace. +Capture and describe exceptions with diagnostic evidence in ASP.NET Core API responses using MVC filters that produce structured error responses, server-timing headers, and fault descriptions. Use this namespace when you need consistent API error handling. Start with `FaultDescriptorFilter` or configure `MvcFaultDescriptorOptions`. For server-timing metrics, use `ServerTimingFilter` or the `ServerTimingAttribute`. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Headers.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Headers.md index f7c605bb..080be5d5 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Headers.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Headers.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Mvc.Filters.Headers summary: *content --- -The `Cuemon.AspNetCore.Mvc.Headers` namespace contains types that provide filters explicitly written to different types of HTTP headers. The namespace is an addition to the `Microsoft.AspNetCore.Mvc.Filters` namespace. +Validate incoming HTTP headers before ASP.NET Core MVC controller actions execute using action filters for API key validation and user-agent sentinel checks. Use this namespace when you need HTTP header-based security in your API. Start with `ApiKeySentinelAttribute` or `ApiKeySentinelFilter` for API key protection, or `UserAgentSentinelFilter` for user-agent restrictions. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.ModelBinding.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.ModelBinding.md index 9119e5c9..e42302af 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.ModelBinding.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.ModelBinding.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Mvc.Filters.ModelBinding summary: *content --- -The `Cuemon.AspNetCore.Mvc.ModelBinding` namespace contains types that alters the built-in way of doing model binding. The namespace is an addition to the `Microsoft.AspNetCore.Mvc.ModelBinding` namespace. +Control ASP.NET Core model binding at a granular level by disabling binding for specific properties or parameters. Use this namespace when you need to exclude certain parameters from model binding in your MVC controllers. Start with `DisableModelBindingAttribute` to annotate parameters or properties that should be excluded. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Throttling.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Throttling.md index 29af7762..9cdffb14 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Throttling.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Throttling.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Mvc.Filters.Throttling summary: *content --- -The `Cuemon.AspNetCore.Mvc.Filters.Throttling` namespace contains types that provides filter based throttling mechanism by specifying allowed quota and window duration of HTTP requests tied to a custom context (eg. IP-address, Authorization header, etc.). The namespace is an addition to the `Microsoft.AspNetCore.Mvc.Filters` namespace. +Protect your ASP.NET Core API from excessive requests using MVC action filters for rate limiting with configurable quotas and time windows, scoped to context such as IP address or authorization header. Use this namespace when you need controller-level throttling. Start with `ThrottlingSentinelAttribute` or `ThrottlingSentinelFilter` to apply rate-limiting to your controllers or actions. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.md index a558f2cc..d1814616 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Mvc.Filters summary: *content --- -The `Cuemon.AspNetCore.Mvc.Filters` namespace contains types that supports a generic way of working with built-in interfaces providing ready-to-use class abstractions. The namespace is an addition to the `Microsoft.AspNetCore.Mvc.Filters` namespace. +Write custom ASP.NET Core MVC filters for caching, diagnostics, headers, model binding, and throttling without boilerplate infrastructure code. Use this namespace when you need base classes and abstractions that integrate with the ASP.NET Core filter pipeline. For a custom cache or diagnostic filter, start with `ConfigurableMvcFilterBase`. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Formatters.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Formatters.md index 0890ef99..f0c19c69 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Formatters.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Formatters.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Mvc.Formatters summary: *content --- -The `Cuemon.AspNetCore,Mvc.Formatters` namespace contains types that customizes working with both TextInputFormatter and TextOutputFormatter. The namespace is an addition to the `Microsoft.AspNetCore.Mvc.Formatters` namespace. +Simplify working with raw request and response bodies in ASP.NET Core MVC using configurable input and output formatters, including stream-based formatters. Use this namespace when you need custom serialization or streaming support in your MVC pipeline. Start with `StreamInputFormatter` and `StreamOutputFormatter` for raw stream handling, or extend `ConfigurableInputFormatter` and `ConfigurableOutputFormatter` for custom format processing. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.md index 0e6ad191..11192695 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Mvc.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Mvc summary: *content --- -The `Cuemon.AspNetCore,Mvc` namespace contains types that specializes in cache expiration and validation models and an abundant range of ready-to-use filters in the ASP.NET Core MVC pipeline. The namespace is an addition to the `Microsoft.AspNetCore.Mvc` namespace. +Build HTTP cache-aware MVC results and structured error responses in the ASP.NET Core MVC pipeline using cache expiration models, content-based result types, and exception-handling filters. Use this namespace when you need conditional GET support, ETag/last-modified validation, or consistent API error responses. Start with `CacheableFactory` for building cacheable responses or `ExceptionDescriptorResult` for formatted API errors. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.Razor.TagHelpers.md b/.docfx/api/namespaces/Cuemon.AspNetCore.Razor.TagHelpers.md index a91900c7..5d2f45e4 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.Razor.TagHelpers.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.Razor.TagHelpers.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore.Razor.TagHelpers summary: *content --- -The `Cuemon.AspNetCore.Razor.TagHelpers` namespace contains types that are tailored for tag helper implementations. The namespace is an addition to the `Microsoft.AspNetCore.Razor.TagHelpers` namespace. +Simplify cache-busting, application resource linking, and asset versioning in ASP.NET Core Razor views using tag helpers. Use these tag helpers when you need to serve versioned static assets or generate correct URLs for application resources. Start with `CacheBustingTagHelper` for automatic cache-busting query strings, or `AppLinkTagHelper`, `AppScriptTagHelper`, and `AppImageTagHelper` for application-relative resource URLs. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.AspNetCore.md b/.docfx/api/namespaces/Cuemon.AspNetCore.md index e0ef3931..c0d4cfb9 100644 --- a/.docfx/api/namespaces/Cuemon.AspNetCore.md +++ b/.docfx/api/namespaces/Cuemon.AspNetCore.md @@ -2,7 +2,7 @@ uid: Cuemon.AspNetCore summary: *content --- -The `Cuemon.AspNetCore` namespace contains types focusing on providing means for easier plumber coding in the ASP.NET Core pipeline while serving some concrete implementation of the shell as well. The namespace is an addition to the `Microsoft.AspNetCore` namespace. +Build custom ASP.NET Core middleware, authentication handlers, and pipeline utilities without repetitive plumbing. The `Cuemon.AspNetCore` namespace provides reusable middleware infrastructure, request-scoped services, configuration providers, diagnostics, and HTTP helpers that integrate with the ASP.NET Core request pipeline. Use it when you need production-ready middleware components such as `ConfigurableMiddlewareCore` (for middleware with options) or `RequestScopedService` (for services depending on the current HTTP context). [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.Collections.Generic.md b/.docfx/api/namespaces/Cuemon.Collections.Generic.md index 5dc56073..beab8850 100644 --- a/.docfx/api/namespaces/Cuemon.Collections.Generic.md +++ b/.docfx/api/namespaces/Cuemon.Collections.Generic.md @@ -2,10 +2,18 @@ uid: Cuemon.Collections.Generic summary: *content --- -The `Cuemon.Collections.Generic` namespace contains types that define generic collections that support paging, partitioning, dynamic comparers and some specialized collections such as a read-only enum dictionary and a generic, conditional collection. The namespace is an addition to the `System.Collections.Generic` namespace. +Paginate, partition, and sort data using generic collection types that extend the .NET Base Class Library — including paginated collections, partitioned enumerables, dynamic comparers, a read-only enum dictionary, and a conditional collection. Use these types when you need paging, partitioning, or custom comparison semantics in your data processing. Start with `PaginationEnumerable` or `PaginationList` for paginated results, `PartitionerCollection` or `PartitionerEnumerable` for partitioned processing, or `ConditionalCollection` and `DynamicComparer` for flexible filtering and sorting without custom comparer classes. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [System.Collections.Generic namespace](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic) 🔗 Related: [Cuemon.Extensions.Collections.Generic namespace](/api/extensions/dotnet/Cuemon.Extensions.Collections.Generic.html) 📘 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator>|⬇️|`AddRange`| +|IDecorator>|⬇️|`CopyTo`, `GetValueOrDefault`, `TryGetValueOrFallback`, `ToEnumerable`, `TryAdd`, `AddOrUpdate`, `GetDepthIndex`| +|IDecorator>|⬇️|`TryPop`| diff --git a/.docfx/api/namespaces/Cuemon.Collections.Specialized.md b/.docfx/api/namespaces/Cuemon.Collections.Specialized.md index 63291624..a5942f2c 100644 --- a/.docfx/api/namespaces/Cuemon.Collections.Specialized.md +++ b/.docfx/api/namespaces/Cuemon.Collections.Specialized.md @@ -2,8 +2,14 @@ uid: Cuemon.Collections.Specialized summary: *content --- -The `Cuemon.Collections.Specialized` namespace contains types that define various collections of objects. The namespace is an addition to the `System.Collections.Specialized` namespace. +Convert between `IDictionary` and `NameValueCollection` without writing manual key-value transformation code. Use this namespace when you need to bridge generic dictionaries and legacy name-value collections. Start with the `ToNameValueCollection` extension on `IDecorator>`. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [System.Collections.Specialized namespace](https://docs.microsoft.com/en-us/dotnet/api/system.collections.specialized) 🔗 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator>|⬇️|`ToNameValueCollection`| diff --git a/.docfx/api/namespaces/Cuemon.Collections.md b/.docfx/api/namespaces/Cuemon.Collections.md index d9ad7d5a..361f515e 100644 --- a/.docfx/api/namespaces/Cuemon.Collections.md +++ b/.docfx/api/namespaces/Cuemon.Collections.md @@ -2,7 +2,9 @@ uid: Cuemon.Collections summary: *content --- -The `Cuemon.Collections` namespace contains types that define various collections of objects. The namespace is an addition to the `System.Collections` namespace. +The `Cuemon.Collections` namespace provides specialized collection types — including sorted, bounded, and pageable collections — that extend beyond the standard .NET collection types for more specific data storage needs. + +Use this namespace when you need collection semantics that go beyond `List` or `Dictionary`, such as bounded queues or sorted sets. Start here for foundational collection types. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Configuration.md b/.docfx/api/namespaces/Cuemon.Configuration.md index 240e7624..56046d3c 100644 --- a/.docfx/api/namespaces/Cuemon.Configuration.md +++ b/.docfx/api/namespaces/Cuemon.Configuration.md @@ -2,6 +2,6 @@ uid: Cuemon.Configuration summary: *content --- -The `Cuemon.Configuration` namespace contains types focusing on writing configurable classes to help support adhering to Separation of Concerns (SoC). +The `Cuemon.Configuration` namespace provides a base type and interfaces for building configurable classes that follow Separation of Concerns (SoC). Use `Configurable` or implement `IConfigurable` when your class needs a typed options object that can be validated, cloned, and safely exposed to consumers. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Data.Integrity.md b/.docfx/api/namespaces/Cuemon.Data.Integrity.md index aaeda408..179d8b98 100644 --- a/.docfx/api/namespaces/Cuemon.Data.Integrity.md +++ b/.docfx/api/namespaces/Cuemon.Data.Integrity.md @@ -2,8 +2,14 @@ uid: Cuemon.Data.Integrity summary: *content --- -The `Cuemon.Data.Integrity` namespace contains types that provide ways for developers to determine and maintain integrity of data that is normally associated with an entity/resource. +Compute content-based checksums, manage HTTP cache validation, and track entity metadata for data integrity. Use this namespace when you need content-based caching, integrity checks, or ETag support. Start with `ChecksumBuilder` for checksum computation, or `CacheValidator` and `CacheValidatorFactory` for cache validation workflows. [!INCLUDE [availability-default](../../includes/availability-default.md)] -Related: [Cuemon.Extensions.Data.Integrity namespace](/api/extensions/dotnet/Cuemon.Extensions.Data.Integrity.html) 🔗 +Related: [Cuemon.Extensions.Data.Integrity namespace](/api/extensions/dotnet/Cuemon.Extensions.Data.Integrity.html) 📘 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator|⬇️|`CombineWith`| diff --git a/.docfx/api/namespaces/Cuemon.Data.SqlClient.md b/.docfx/api/namespaces/Cuemon.Data.SqlClient.md index c3f63f86..e8922d09 100644 --- a/.docfx/api/namespaces/Cuemon.Data.SqlClient.md +++ b/.docfx/api/namespaces/Cuemon.Data.SqlClient.md @@ -2,7 +2,7 @@ uid: Cuemon.Data.SqlClient summary: *content --- -The `Cuemon.Data.SqlClient` namespace contains types that provide ways for developers to work with Microsoft SQL Server integrations. The namespace is an addition to the `System.Data.SqlClient` namespace. +Execute commands, manage connections, and work with SQL Server-specific data operations through Cuemon's data abstractions. The `Cuemon.Data.SqlClient` namespace integrates Microsoft SQL Server support into the Cuemon data pipeline. Start with `SqlManager` for command execution or use the types extending `System.Data.SqlClient`. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Data.Xml.md b/.docfx/api/namespaces/Cuemon.Data.Xml.md index 9ac69627..f11537e2 100644 --- a/.docfx/api/namespaces/Cuemon.Data.Xml.md +++ b/.docfx/api/namespaces/Cuemon.Data.Xml.md @@ -2,6 +2,6 @@ uid: Cuemon.Data.Xml summary: *content --- -The `Cuemon.Data.Xml` namespace contains an implementation of the DataReader class that provides a way of reading a forward-only stream of rows from an XML based data source. +Query XML data through a familiar ADO.NET `DbDataReader` interface using a forward-only stream of rows from XML data sources. Use this namespace when you need ADO.NET-style data access over XML content. Start with `XmlDataReader` to read XML data as a tabular result set for XML-driven data access. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Data.md b/.docfx/api/namespaces/Cuemon.Data.md index b21d0134..53852d4f 100644 --- a/.docfx/api/namespaces/Cuemon.Data.md +++ b/.docfx/api/namespaces/Cuemon.Data.md @@ -2,8 +2,15 @@ uid: Cuemon.Data summary: *content --- -The `Cuemon.Data` namespace contains types that provide ways to connect, build and manipulate different data sources. The namespace is an addition to the `System.Data` namespace. +Abstract away ADO.NET plumbing with a higher-level data access layer that includes data readers, data managers, statement builders, and data transfer objects. Use this namespace when you need to connect to data sources, execute commands, and manipulate results without writing raw ADO.NET code. Start with `DataManager` as the main entry point for executing commands, and `DataReader` for wrapping `IDataReader`. For building SQL statements programmatically, use `QueryBuilder`. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [System.Data namespace](https://docs.microsoft.com/en-us/dotnet/api/system.Data) 🔗 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator|⬇️|`ToStream`, `ToEncodedString`, `ToEncodedStringAsync`| +|IDecorator|⬇️|`ToType`| diff --git a/.docfx/api/namespaces/Cuemon.Diagnostics.md b/.docfx/api/namespaces/Cuemon.Diagnostics.md index d9600e93..1f2c87ff 100644 --- a/.docfx/api/namespaces/Cuemon.Diagnostics.md +++ b/.docfx/api/namespaces/Cuemon.Diagnostics.md @@ -2,7 +2,7 @@ uid: Cuemon.Diagnostics summary: *content --- -The Cuemon.Diagnostics namespace contains types that provide ways for developers to describe exceptions including evidence to why an operation faulted. Also includes a flexible, generic and lambda friendly way to perform both synchronous and asynchronous time measuring operations. The namespace is an addition to the System.Diagnostics namespace. +Capture structured exception context for logging and API error responses, or profile synchronous and asynchronous code execution. Use this namespace when you need detailed exception context or performance measurement. Start with `ExceptionDescriptor` for structured error reporting, or `TimeMeasure` / `TimeMeasureProfiler` for lambda-friendly code profiling. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Authentication.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Authentication.md index 59834200..3ba3865d 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Authentication.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Authentication.md @@ -2,15 +2,16 @@ uid: Cuemon.Extensions.AspNetCore.Authentication summary: *content --- -The `Cuemon.Extensions.AspNetCore.Authentication` namespace contains extension methods that complements the `Cuemon.AspNetCore.Authentication` namespace. +Register Basic, Digest, and HMAC authentication middleware in your ASP.NET Core pipeline with a single extension method call. Use this namespace when you need to enable HTTP authentication schemes in your application. Start with `UseBasicAuthentication` on `IApplicationBuilder` for basic auth, `UseDigestAccessAuthentication` for digest auth, or `UseHmacAuthentication` for HMAC auth. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.AspNetCore.Authentication namespace](/api/aspnet/Cuemon.AspNetCore.Authentication.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| |IApplicationBuilder|⬇️|`UseBasicAuthentication`, `UseDigestAccessAuthentication`, `UseHmacAuthentication`| -|IServiceCollection|⬇️|`AddInMemoryDigestAuthenticationNonceTracker`| +|AuthenticationBuilder|⬇️|`AddBasic`, `AddDigestAccess`, `AddHmac`| +|IServiceCollection|⬇️|`AddInMemoryDigestAuthenticationNonceTracker`, `AddAuthorizationResponseHandler`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Configuration.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Configuration.md index c0c993e8..95161189 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Configuration.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Configuration.md @@ -2,14 +2,14 @@ uid: Cuemon.Extensions.AspNetCore.Configuration summary: *content --- -The `Cuemon.Extensions.AspNetCore.Configuration` namespace contains both types and extension methods that complements the `Cuemon.AspNetCore.Configuration` namespace. +Enable cache invalidation based on assembly version changes in ASP.NET Core applications through `IServiceCollection` extension methods. Use `AddAssemblyCacheBusting` or `AddDynamicCacheBusting` to register cache-busting services when you need clients to receive fresh static resources after deployment. Start with `AddAssemblyCacheBusting` for the simplest cache invalidation setup. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.AspNetCore.Configuration namespace](/api/aspnet/Cuemon.AspNetCore.Configuration.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|IServiceCollection|⬇️|`AddAssemblyCacheBusting`, `AddCacheBusting{T}`, `AddDynamicCacheBusting`| +|IServiceCollection|⬇️|`AddAssemblyCacheBusting`, `AddCacheBusting`, `AddDynamicCacheBusting`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Data.Integrity.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Data.Integrity.md index f73d4485..ddb32342 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Data.Integrity.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Data.Integrity.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.AspNetCore.Data.Integrity summary: *content --- -The `Cuemon.Extensions.AspNetCore.Data.Integrity` namespace contains extension methods that complements the `Cuemon.Data.Integrity` namespace. +Bridge data-integrity checksums and cache validation into ASP.NET Core HTTP infrastructure by converting `CacheValidator` and `ChecksumBuilder` instances into HTTP ETag header values. Use this namespace when you need conditional request handling based on content integrity checks. Start with `ToEntityTagHeaderValue` on a `ChecksumBuilder` to produce ETag headers for HTTP cache validation. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.Data.Integrity namespace](/api/dotnet/Cuemon.Data.Integrity.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Diagnostics.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Diagnostics.md index 6f7cb4a6..0f55ed3e 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Diagnostics.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Diagnostics.md @@ -2,16 +2,16 @@ uid: Cuemon.Extensions.AspNetCore.Diagnostics summary: *content --- -The `Cuemon.Extensions.AspNetCore.Diagnostics` namespace contains extension methods that complements the `Cuemon.AspNetCore.Diagnostics` namespace. +Add Server-Timing headers and fault-descriptor exception handling to your ASP.NET Core pipeline. Use this namespace when you need to emit server-timing metrics or provide structured fault responses. Start with `UseServerTiming` on `IApplicationBuilder` for timing headers, or `UseFaultDescriptorExceptionHandler` for structured exception handling. Register services with `AddServerTiming` or `AddFaultDescriptorOptions` on `IServiceCollection`. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.AspNetCore.Diagnostics namespace](https://docs.cuemon.net/api/aspnet/Cuemon.AspNetCore.Diagnostics.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| |IApplicationBuilder|⬇️|`UseServerTiming`, `UseFaultDescriptorExceptionHandler`| -|IServiceCollection|⬇️|`AddServerTiming`, `AddServerTiming{T}`, `AddServerTimingOptions`, `AddFaultDescriptorOptions`, `AddExceptionDescriptorOptions`, `PostConfigureAllExceptionDescriptorOptions`| +|IServiceCollection|⬇️|`AddServerTiming`, `AddServerTiming`, `AddServerTimingOptions`, `AddFaultDescriptorOptions`, `AddExceptionDescriptorOptions`, `PostConfigureAllExceptionDescriptorOptions`| |IServiceProvider|⬇️|`GetExceptionResponseFormatters`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Hosting.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Hosting.md index 301c7d7f..10dd9ec2 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Hosting.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Hosting.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.AspNetCore.Hosting summary: *content --- -The `Cuemon.Extensions.AspNetCore.Hosting` namespace contains extension methods that complements the `Cuemon.AspNetCore.Hosting` namespace. +Bridge ASP.NET Core hosting with Cuemon hosting abstractions by making `IWebHostEnvironment` available through a single extension method. Use this namespace when you need to integrate `Cuemon.AspNetCore.Hosting` middleware with the ASP.NET Core hosting environment. Start with `UseHostingEnvironment` on `IApplicationBuilder` to register the hosting middleware. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.AspNetCore.Hosting namespace](/api/aspnet/Cuemon.AspNetCore.Hosting.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.Headers.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.Headers.md index 3aa2cf51..cf2eb523 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.Headers.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.Headers.md @@ -2,14 +2,15 @@ uid: Cuemon.Extensions.AspNetCore.Http.Headers summary: *content --- -The `Cuemon.Extensions.AspNetCore.Http.Headers` namespace contains extension methods that complements the `Cuemon.AspNetCore.Http.Headers` namespace. +Register correlation identifiers, request identifiers, user-agent sentinel, API-key sentinel, and cache-control middleware on your ASP.NET Core pipeline with single extension method calls. Use this namespace when you need to add request correlation, user-agent validation, API-key protection, or cache-control headers to your pipeline. Start with `UseCorrelationIdentifier` for request tracing or `UseCacheControl` for HTTP cache headers. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.AspNetCore.Http.Headers namespace](/api/aspnet/Cuemon.AspNetCore.Http.Headers.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|IApplicationBuilder|⬇️|`UseCorrelationIdentifier`, `UseRequestIdentifier`, `UseUserAgentSentinel`, `UseApiKeySentinel`, `UseCacheControl`| +|IApplicationBuilder|⬇️|`UseCorrelationIdentifier`, `UseRequestIdentifier`, `UseUserAgentSentinel`, `UseApiKeySentinel`, `UseCacheControl`, `UseVaryAccept`| +|IServiceCollection|⬇️|`AddApiKeySentinelOptions`, `AddUserAgentSentinelOptions`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.Throttling.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.Throttling.md index bf36314f..aae00095 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.Throttling.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.Throttling.md @@ -2,15 +2,15 @@ uid: Cuemon.Extensions.AspNetCore.Http.Throttling summary: *content --- -The `Cuemon.Extensions.AspNetCore.Http.Throttling` namespace contains both types and extension methods that complements the `Cuemon.AspNetCore.Http.Throttling` namespace. Provides an in-memory implementation of a throttling cache for ASP.NET Core. +Configure throttling middleware for your ASP.NET Core application with an in-memory throttling cache. Use this namespace when you need to rate-limit requests based on client characteristics. Start with `UseThrottlingSentinel` on `IApplicationBuilder` to enable rate limiting, or register a cache provider with `AddMemoryThrottlingCache` or `AddThrottlingCache` on `IServiceCollection`. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.AspNetCore.Http.Throttling namespace](/api/aspnet/Cuemon.AspNetCore.Http.Throttling.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| |IApplicationBuilder|⬇️|`UseThrottlingSentinel`| -|IServiceCollection|⬇️|`AddThrottlingCache{T}`, `AddMemoryThrottlingCache`| +|IServiceCollection|⬇️|`AddThrottlingCache`, `AddMemoryThrottlingCache`, `AddThrottlingSentinelOptions`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.md index 6c9436ee..2e6024fe 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.md @@ -2,17 +2,18 @@ uid: Cuemon.Extensions.AspNetCore.Http summary: *content --- -The `Cuemon.Extensions.AspNetCore.Http` namespace contains extension methods that complements the `Cuemon.AspNetCore.Http` namespace while being an addition to the `Microsoft.AspNetCore.Http` namespace. +Manipulate HTTP headers, query HTTP status codes, and write response bodies on ASP.NET Core types without repetitive boilerplate. Use this namespace when you need to check HTTP method semantics on `HttpRequest`, manage ETag and Last-Modified headers on `HttpResponse`, or classify HTTP status codes. Start with `IsGetOrHeadMethod` on `HttpRequest` for method checks, or `AddOrUpdateEntityTagHeader` on `HttpResponse` for cache header management. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.AspNetCore.Http namespace](https://docs.cuemon.net/api/aspnet/Cuemon.AspNetCore.Http.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| |IHeaderDictionary|⬇️|`AddOrUpdateHeaders`, `AddOrUpdateHeader`| -|HttpRequest|⬇️|`IsGetOrHeadMethod`, `IsClientSideResourceCached`| +|HttpRequest|⬇️|`IsGetOrHeadMethod`, `IsClientSideResourceCached`, `AcceptMimeTypesOrderedByQuality`| +|IEnumerable|⬇️|`SelectExceptionDescriptorHandlers`| |HttpResponse|⬇️|`AddOrUpdateEntityTagHeader`, `AddOrUpdateLastModifiedHeader`, `WriteBodyAsync`, `OnStartingInvokeTransformer`| |Int32|⬇️|`IsInformationStatusCode`, `IsSuccessStatusCode`, `IsRedirectionStatusCode`, `IsNotModifiedStatusCode`, `IsClientErrorStatusCode`, `IsServerErrorStatusCode`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Configuration.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Configuration.md index 997ae169..b245a731 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Configuration.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Configuration.md @@ -27,8 +27,8 @@ Complements: [Cuemon.AspNetCore.Configuration namespace](https://docs.cuemon.net [Cuemon.AspNetCore.App (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.App)\ ![NuGet Version](https://img.shields.io/nuget/v/Cuemon.AspNetCore.App?logo=nuget) ![NuGet Preview Version](https://img.shields.io/nuget/vpre/Cuemon.AspNetCore.App?logo=nuget) ![NuGet Downloads](https://img.shields.io/nuget/dt/Cuemon.AspNetCore.App?color=blueviolet&logo=nuget) -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|IServiceCollection|⬇️|`AddCacheBusting{T}`, `AddAssemblyCacheBusting`, `AddDynamicCacheBusting`| \ No newline at end of file +|IServiceCollection|⬇️|`AddCacheBusting`, `AddAssemblyCacheBusting`, `AddDynamicCacheBusting`| \ No newline at end of file diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable.md index e0103119..8ea4f2bf 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable.md @@ -2,14 +2,15 @@ uid: Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable summary: *content --- -The `Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable` namespace contains extension methods that complements the `Cuemon.AspNetCore.Mvc.Filters.Cacheable` namespace. +Add or insert custom cacheable filters and attach ETag or Last-Modified headers to HTTP responses in the ASP.NET Core MVC pipeline. Use this namespace when you need to extend cacheable filters or attach HTTP caching headers to MVC responses. Start with `AddFilter` to register a new cacheable filter or `AddEntityTagHeader` for ETag header support. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.AspNetCore.Mvc.Filters.Cacheable namespace](/api/aspnet/Cuemon.AspNetCore.Mvc.Filters.Cacheable.html) 🔗 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|ICacheableAsyncResultFilter|⬇️|`AddFilter{T}`, `AddFilter{T, TOptions}`, `InsertFilter{T}`, `InsertFilter{T, TOptions}`, `AddEntityTagHeader`, `AddLastModifiedHeader`| \ No newline at end of file +|IList|⬇️|`AddFilter`, `AddFilter`, `InsertFilter`, `InsertFilter`| +|ICacheableAsyncResultFilter|⬇️|`AddEntityTagHeader`, `AddLastModifiedHeader`| \ No newline at end of file diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics.md index 5a2b7f8c..5eedc003 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics.md @@ -2,14 +2,15 @@ uid: Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics summary: *content --- -The `Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics` namespace contains extension methods that complements the `Cuemon.AspNetCore.Mvc.Filters.Diagnostics` namespace. +Register custom fault resolvers for mapping exceptions to HTTP responses in the ASP.NET Core MVC diagnostics pipeline. Use this namespace when you need to extend the error-handling pipeline with custom exception-to-response mappings. Start with `AddHttpFaultResolver` on `HttpFaultResolver` to register a custom fault resolver. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.AspNetCore.Mvc.Filters.Diagnostics namespace](/api/aspnet/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.html) 🔗 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|HttpFaultResolver|⬇️|`AddHttpFaultResolver{T}`| +|HttpFaultResolver|⬇️|`AddHttpFaultResolver`| +|IList|⬇️|`AddHttpFaultResolver`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.md index d208b455..9fdf024d 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.md @@ -2,14 +2,15 @@ uid: Cuemon.Extensions.AspNetCore.Mvc.Filters summary: *content --- -The `Cuemon.Extensions.AspNetCore.Mvc.Filters` namespace contains both types and extension methods that complements the `Cuemon.AspNetCore.Mvc.Filters` namespace while being an addition to `Microsoft.AspNetCore.Mvc.Filters` namespace. +Register ASP.NET Core MVC filters for caching, fault descriptors, server timing, user-agent sentinel, throttling, and API-key sentinel with a single method call. Use this namespace when you need to add HTTP cache validation, structured error handling, server timing, or throttling filters to your MVC filter collection. Start with `AddHttpCacheable` for cache support or `AddFaultDescriptor` for error handling. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.AspNetCore.Mvc.Filters namespace](/api/aspnet/Cuemon.AspNetCore.Mvc.Filters.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| |FilterCollection|⬇️|`AddHttpCacheable`, `AddFaultDescriptor`, `AddServerTiming`, `AddUserAgentSentinel`, `AddThrottlingSentinel`, `AddApiKeySentinel`| +|IMvcBuilder|⬇️|`AddHttpCacheableOptions`, `AddFaultDescriptorOptions`, `AddServerTimingOptions`, `AddUserAgentSentinelOptions`, `AddThrottlingSentinelOptions`, `AddApiKeySentinelOptions`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.md index 982a382a..d525d192 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json summary: *content --- -The `Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json` namespace contains both types and extension methods that complements the `Cuemon.Extensions.Text.Json` namespace while being an addition to the `Microsoft.AspNetCore.Mvc` namespace. Provides JSON formatters for ASP.NET Core based on `System.Text.Json`. +Register JSON formatters for ASP.NET Core MVC based on `System.Text.Json` with a single extension method call. Use this namespace when you need `System.Text.Json` formatters in your MVC pipeline. Start with `AddJsonFormatters` on `IMvcBuilder` or `IMvcCoreBuilder` to enable JSON serialization in your controllers. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.Extensions.Text.Json namespace](/api/extensions/jsonnet/Cuemon.Extensions.Text.Json.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.md index c3738533..f1867352 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml summary: *content --- -The `Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml` namespace contains both types and extension methods that complements the `Cuemon.Extensions.Xml` namespace while being an addition to the `Microsoft.AspNetCore.Mvc` namespace. Provides XML formatters for ASP.NET Core that offers same flexibility as the one provided by the JSON equivalent from Newtonsoft. +Register XML formatters for ASP.NET Core MVC with the same flexibility as the JSON equivalent from Newtonsoft. Use this namespace when you need XML serialization formatters in your MVC pipeline. Start with `AddXmlFormatters` on `IMvcBuilder` or `IMvcCoreBuilder` to enable XML formatters for your controllers. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.Extensions.Xml namespace](/api/extensions/dotnet/Cuemon.Extensions.Xml.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.md index 162d2caf..1c85edd3 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.AspNetCore.Mvc.RazorPages summary: *content --- -The `Cuemon.Extensions.AspNetCore.Mvc.RazorPages` namespace contains extension methods tailored to accompany the types found in `Cuemon.AspNetCore.Razor.TagHelpers` while being an addition to the `Microsoft.AspNetCore.Mvc.RazorPages` namespace. +Access application URLs and CDN URLs from your Razor Pages through convenient extension methods. Use this namespace when you need to resolve application or CDN paths in Razor Pages. Start with `GetAppUrl` on your `PageModel` for application URLs or `GetCdnUrl` for content delivery network paths. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Microsoft.AspNetCore.Mvc.RazorPages](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.razorpages) 🔗 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Rendering.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Rendering.md index 94bd9455..e6af8a76 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Rendering.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Rendering.md @@ -2,14 +2,14 @@ uid: Cuemon.Extensions.AspNetCore.Mvc.Rendering summary: *content --- -The `Cuemon.Extensions.AspNetCore.Mvc.Rendering` namespace contains extension methods that complements the `Microsoft.AspNetCore.Mvc.Rendering` namespace. +Conditionally render HTML content based on the current Razor Page or view type. Use this namespace when you need type-conditional rendering in ASP.NET Core views and pages. Start with `UseWhenPage` to render content only for specific page types, or `UseWhenView` for view-specific content. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Microsoft.AspNetCore.Mvc.Rendering namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.rendering) 🔗 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|IHtmlHelper|⬇️|`UseWhenPage{T}`, `UseWhenView{T}`| +|IHtmlHelper|⬇️|`UseWhenPage`, `UseWhenView`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.md index 578d5dc1..e33e4d84 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.md @@ -2,15 +2,15 @@ uid: Cuemon.Extensions.AspNetCore.Mvc summary: *content --- -The `Cuemon.Extensions.AspNetCore.Mvc` namespace contains both types and extension methods that complements the `Cuemon.AspNetCore.Mvc` namespace while being an addition to `Microsoft.AspNetCore.Mvc` namespace. +Add cache-control headers, entity tags, and last-modified headers to ASP.NET Core MVC action results with fluent extension methods. Use this namespace when you need to apply HTTP caching headers to MVC action results. Start with `WithCacheableHeaders` on any object to combine entity-tag and last-modified headers in one call. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.AspNetCore.Mvc namespace](/api/aspnet/Cuemon.AspNetCore.Mvc.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|Object|⬇️|`WithLastModifiedHeader{T}`, `WithEntityTagHeader{T}`, `WithCacheableHeaders{T}`| -|ViewDataDictionary|⬇️|`AddBreadcrumbs{T}`, `GetBreadcrumbs`| +|T|⬇️|`WithLastModifiedHeader`, `WithEntityTagHeader`, `WithCacheableHeaders`| +|ViewDataDictionary|⬇️|`AddBreadcrumbs`, `GetBreadcrumbs`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Text.Json.Converters.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Text.Json.Converters.md index 0131a744..2280ed46 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Text.Json.Converters.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Text.Json.Converters.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.AspNetCore.Text.Json.Converters summary: *content --- -The `Cuemon.Extensions.AspNetCore.Text.Json.Converters` namespace contains extension methods that complements the `Cuemon.Extensions.Text.Json.Converters` namespace. +Register ASP.NET Core-specific `System.Text.Json` converters for HTTP types like `HttpExceptionDescriptor`, `StringValues`, `ProblemDetails`, and `HeaderDictionary`. Use this namespace when you need JSON serialization support for ASP.NET Core HTTP types. Start with `AddHttpExceptionDescriptorConverter` for structured error JSON or `AddStringValuesConverter` for header value serialization. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.Extensions.Text.Json.Converters namespace](/api/extensions/jsonnet/Cuemon.Extensions.Text.Json.Converters.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Text.Json.Formatters.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Text.Json.Formatters.md index d42dd45d..72b5aa0f 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Text.Json.Formatters.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Text.Json.Formatters.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.AspNetCore.Text.Json.Formatters summary: *content --- -The `Cuemon.Extensions.AspNetCore.Text.Json.Formatters` namespace contains both types and extension methods that complements the `Cuemon.Text.Json.Formatters` namespace. +Register JSON formatter options and exception response formatters for ASP.NET Core applications using `System.Text.Json`. Use this namespace when you need to configure JSON formatter settings or register exception response formatters. Start with `AddJsonFormatterOptions` on `IServiceCollection` to configure JSON formatting settings. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.Text.Json.Formatters namespace](/api/extensions/aspnet/Cuemon.Extensions.AspNetCore.Text.Json.Formatters.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Text.Json.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Text.Json.md new file mode 100644 index 00000000..7193a778 --- /dev/null +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Text.Json.md @@ -0,0 +1,15 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Text.Json +summary: *content +--- +Configure `System.Text.Json` for ASP.NET Core with minimal JSON serialization options. Use this namespace when you need Cuemon JSON serialization conventions in your ASP.NET Core application. Start with `AddMinimalJsonOptions` on `IServiceCollection` to register minimal JSON options. + +[!INCLUDE [availability-modern](../../includes/availability-modern.md)] + +Complements: [Cuemon.Extensions.AspNetCore namespace](/api/extensions/aspnet/Cuemon.Extensions.AspNetCore.html) 📘 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IServiceCollection|⬇️|`AddMinimalJsonOptions`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Xml.Converters.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Xml.Converters.md index 37677acd..5917356e 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Xml.Converters.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Xml.Converters.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.AspNetCore.Xml.Converters summary: *content --- -The `Cuemon.Extensions.AspNetCore.Xml.Converters` namespace contains extension methods that complements the `Cuemon.Extensions.Xml.Serialization.Converters` namespace. +Register ASP.NET Core-specific XML serialization converters for HTTP types like `StringValues`, `HeaderDictionary`, `QueryCollection`, `FormCollection`, `CookieCollection`, and `ProblemDetails`. Use this namespace when you need XML serialization support for ASP.NET Core HTTP types. Start with `AddHttpExceptionDescriptorConverter` for structured error XML or `AddStringValuesConverter` for header value serialization. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.Extensions.Xml.Serialization.Converters namespace](/api/extensions/dotnet/Cuemon.Extensions.Xml.Serialization.Converters.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Xml.Formatters.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Xml.Formatters.md index d2c132da..69fd5fa4 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Xml.Formatters.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Xml.Formatters.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.AspNetCore.Xml.Formatters summary: *content --- -The `Cuemon.Extensions.AspNetCore.Xml.Formatters` namespace contains both types and extension methods that complements the `Cuemon.Extensions.Xml` namespace while being an addition to the `Microsoft.AspNetCore.Mvc` namespace. Provides XML formatters for ASP.NET Core that offers same flexibility as the one provided by the JSON equivalent from Newtonsoft. +Register XML formatter options and XML exception response formatters for ASP.NET Core applications. Use this namespace when you need to configure XML formatter settings or register XML exception response formatters. Start with `AddXmlFormatterOptions` on `IServiceCollection` to configure XML formatting settings. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [Cuemon.Extensions.Xml namespace](/api/extensions/dotnet/Cuemon.Extensions.Xml.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Xml.md b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Xml.md new file mode 100644 index 00000000..b5a47797 --- /dev/null +++ b/.docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Xml.md @@ -0,0 +1,15 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Xml +summary: *content +--- +Configure XML serialization for ASP.NET Core applications with application-level XML settings. Use this namespace when you need Cuemon XML serialization conventions in your ASP.NET Core application. Start with `AddMinimalXmlOptions` on `IServiceCollection` to register the XML options for ASP.NET Core conventions. + +[!INCLUDE [availability-modern](../../includes/availability-modern.md)] + +Complements: [Cuemon.Extensions.AspNetCore namespace](/api/extensions/aspnet/Cuemon.Extensions.AspNetCore.html) 📘 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IServiceCollection|⬇️|`AddMinimalXmlOptions`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Collections.Generic.md b/.docfx/api/namespaces/Cuemon.Extensions.Collections.Generic.md index e7b68ad5..577305bc 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Collections.Generic.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Collections.Generic.md @@ -2,18 +2,22 @@ uid: Cuemon.Extensions.Collections.Generic summary: *content --- -The `Cuemon.Extensions.Collections.Generic` namespace contains extension methods that complements the `Cuemon.Collections.Generic` namespace while being an addition to the `System.Collections.Generic` namespace. +Partition, paginate, shuffle, and manage generic collections without writing custom extension methods. Use this namespace when you need safe, declarative collection operations like chunking, shuffling, ordering, or dictionary merging. Start with `Chunk` or `ToPagination` for batch processing of sequences, or `AddOrUpdate` on dictionaries for merge semantics. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon.Collections.Generic namespace](/api/dotnet/Cuemon.Collections.Generic.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|ICollection{T}|⬇️|`ToPartitioner{T}`, `AddRange{T}`| -|IDictionary{TKey, TValue}|⬇️|`CopyTo{TKey, TValue}`, `GetValueOrDefault{TKey, TValue}`, `TryGetValueOrFallback{TKey, TValue}`, `ToEnumerable{TKey, TValue}`, `TryAdd{TKey, TValue}`, `AddOrUpdate{TKey, TValue}`| -|IEnumerable{T}|⬇️|`Chunk{T}`, `Shuffle{T}`, `OrderAscending{T}`, `OrderDescending{T}`, `RandomOrDefault{T}`, `Yield{T}`, `ToDictionary{TKey, TValue}`, `ToPagination{T}`, `ToPaginationList{T}`| -|IList{T}|⬇️|`Remove{T}`, `HasIndex{T}`, `Next{T}`, `Previous{T}`, `TryAdd{T}`| -|Queue{T}|⬇️|`TryPeek{T}`| +|ICollection|⬇️|`AddRange`, `ToPartitioner`| +|IEnumerable|⬇️|`Chunk`, `Shuffle`, `OrderAscending`, `OrderDescending`, `RandomOrDefault`, `ToPagination`, `ToPaginationList`, `ToPartitioner`| +|IDictionary|⬇️|`CopyTo`, `GetValueOrDefault`, `TryGetValueOrFallback`, `ToEnumerable`, `TryAdd`, `AddOrUpdate`| +|IEnumerable|⬇️|`Chunk`, `Shuffle`, `OrderAscending`, `OrderDescending`, `RandomOrDefault`, `ToPagination`, `ToPaginationList`| +|IEnumerable>|⬇️|`ToDictionary`| +|IList|⬇️|`Remove`, `HasIndex`, `Next`, `Previous`, `TryAdd`| +|Queue|⬇️|`TryPeek`| +|Stack|⬇️|`TryPop`| +|T|⬇️|`Yield`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Collections.Specialized.md b/.docfx/api/namespaces/Cuemon.Extensions.Collections.Specialized.md index 0c0ed3e1..aaac78e6 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Collections.Specialized.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Collections.Specialized.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.Collections.Specialized summary: *content --- -The `Cuemon.Extensions.Collections.Specialized` namespace contains extension methods that complements the `Cuemon.Collections.Specialized` namespace while being an addition to the `System.Collections.Specialized` namespace. +Add dictionary-style operations like `ContainsKey` and `ToDictionary` to `NameValueCollection` for easier interoperability with generic collection types. Use this namespace when you need to bridge specialized `NameValueCollection` APIs with generic dictionary operations. Start with `ToDictionary` on `NameValueCollection` for LINQ integration, or `ToNameValueCollection` on `IDictionary{string, string[]}` for the reverse conversion. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon.Collections.Specialized namespace](/api/dotnet/Cuemon.Collections.Specialized.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Data.Integrity.md b/.docfx/api/namespaces/Cuemon.Extensions.Data.Integrity.md index 0ef64378..8da0d3b7 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Data.Integrity.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Data.Integrity.md @@ -2,17 +2,18 @@ uid: Cuemon.Extensions.Data.Integrity summary: *content --- -The `Cuemon.Extensions.Data.Integrity` namespace contains extension methods that complements the `Cuemon.Data.Integrity` namespace. +Generate cache validators, combine checksums, and compute content integrity hashes for caching and validation scenarios. Use this namespace when you need data integrity checks based on assembly versions, file timestamps, or content hashes. Start with `GetCacheValidator` on `Assembly` or `FileInfo` to generate a cache validator for integrity checks. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon.Data.Integrity namespace](/api/dotnet/Cuemon.Data.Integrity.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| |Assembly|⬇️|`GetCacheValidator`| -|ChecksumBuilder|⬇️|`CombineWith{T}`| +|ChecksumBuilder|⬇️|`CombineWith`| +|T|⬇️|`CombineWith`| |DateTime|⬇️|`GetCacheValidator`| |FileInfo|⬇️|`GetCacheValidator`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Data.md b/.docfx/api/namespaces/Cuemon.Extensions.Data.md index dd5f7806..9b447288 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Data.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Data.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.Data summary: *content --- -The `Cuemon.Extensions.Data` namespace contains extension methods that complements the `Cuemon.Data` namespace while being an addition to the System.Data namespace. +Convert `IDataReader` results into column or row collections, map `DbType` values to CLR types, and embed parameterized `QueryFormat` values safely. Use this namespace when you need streamlined ADO.NET data access without repetitive mapping code. Start with `ToColumns` or `ToRows` on `IDataReader` to consume query results as structured collections. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon.Data namespace](/api/dotnet/Cuemon.Data.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.DependencyInjection.md b/.docfx/api/namespaces/Cuemon.Extensions.DependencyInjection.md index d62e9d3c..a40489b0 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.DependencyInjection.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.DependencyInjection.md @@ -2,15 +2,16 @@ uid: Cuemon.Extensions.DependencyInjection summary: *content --- -The `Cuemon.Extensions.DependencyInjection` namespace contains extension methods that complements the `Microsoft.Extensions.DependencyInjection` namespace. +Register services in the Microsoft DI container with or without options, specifying service and implementation types through a rich set of generic extension methods. Use this namespace when you need flexible DI registration with typed options. Start with `Add` for basic registration, or `Add` when your service requires configuration options. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Microsoft.Extensions.DependencyInjection namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection?view=dotnet-plat-ext-8.0) 🔗 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|IServiceCollection|⬇️|`Add`, `Add{TOptions}`, `Add{TService, TImplementation}`, `Add{TService, TImplementation, TOptions}`, `TryAdd`, `TryAdd{TOptions}`, `TryAdd{TService, TImplementation}`, `TryAdd{TService, TImplementation, TOptions}`| +|IServiceCollection|⬇️|`Add`, `Add`, `Add`, `Add`, `Add`, `TryAdd`, `TryAdd`, `TryAdd`, `TryAdd`, `TryAdd`, `TryConfigure`, `PostConfigureAllOf`| +|IServiceProvider|⬇️|`GetServiceDescriptors`| |type|⬇️|`TryGetDependencyInjectionMarker`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Diagnostics.md b/.docfx/api/namespaces/Cuemon.Extensions.Diagnostics.md index 471daa94..6482f92b 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Diagnostics.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Diagnostics.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.Diagnostics summary: *content --- -The `Cuemon.Extensions.Diagnostics` namespace contains extension methods that complements the `Cuemon.Diagnostics` namespace while being an addition to the `System.Diagnostics` namespace. +Read product and file version information from assemblies in a standardized format. Use this namespace when you need consistent version reporting from assembly metadata. Start with `ToProductVersion` or `ToFileVersion` on `FileVersionInfo` to get standardized version strings. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon.Diagnostics namespace](/api/dotnet/Cuemon.Diagnostics.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Globalization.md b/.docfx/api/namespaces/Cuemon.Extensions.Globalization.md new file mode 100644 index 00000000..bcf12643 --- /dev/null +++ b/.docfx/api/namespaces/Cuemon.Extensions.Globalization.md @@ -0,0 +1,19 @@ +--- +uid: Cuemon.Extensions.Globalization +summary: *content +--- +Perform region-aware string comparisons, statistical region lookups, and locale-sensitive operations on `RegionInfo` and `StatisticalRegion` types through intuitive extension methods. Use these when you need to classify regions by type (country, natural region, or administrative region) or produce demographic and geographic markup. + +[!INCLUDE [availability-default](../../includes/availability-default.md)] + +Complements: [Cuemon.Extensions namespace](/api/extensions/dotnet/Cuemon.Extensions.html) 📘 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|RegionInfo|⬇️|`IsRegion`, `GetCultures`| +|StatisticalRegion|⬇️|`ToMarkup`, `GetDemographics`, `GetEconomy`, `GetGeography`| +|StatisticalRegionInfo|⬇️|`IsWorld`, `IsSubregion`, `IsIntermediateRegion`, `IsCountryOrTerritory`, `IsArea`, `HasIsoCodes`, `HasRegionInfo`| + +Related: [Cuemon.Globalization namespace](/api/dotnet/Cuemon.Globalization.html) 📘 diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Hosting.md b/.docfx/api/namespaces/Cuemon.Extensions.Hosting.md index c398aaa8..f3f203b0 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Hosting.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Hosting.md @@ -2,15 +2,16 @@ uid: Cuemon.Extensions.Hosting summary: *content --- -The `Cuemon.Extensions.Hosting` namespace contains extension methods and features related to the `Microsoft.Extensions.Hosting` namespace. +Detect local development or non-production environments in your application startup code without relying on the built-in development, staging, and production checks. Use this namespace when you need environment-detection beyond the standard ASP.NET Core checks. Start with `IsLocalDevelopment()` on `IHostEnvironment` for detecting local machines, or `IsNonProduction()` for checking non-production environments. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Microsoft.Extensions.Hosting namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting?view=dotnet-plat-ext-8.0) 🔗 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| +|IHostBuilder|⬇️|`ConfigureConfigurationSources`, `RemoveConfigurationSource`| |IHostEnvironment|⬇️|`IsLocalDevelopment`, `IsNonProduction`| |IHostingEnvironment|⬇️|`IsLocalDevelopment`, `IsNonProduction`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.IO.md b/.docfx/api/namespaces/Cuemon.Extensions.IO.md index 23a0b013..5f70f6ab 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.IO.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.IO.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.IO summary: *content --- -The `Cuemon.Extensions.IO` namespace contains extension methods that complements the `Cuemon.IO` namespace while being an addition to the `System.IO` namespace. +Convert strings and byte arrays to streams, compress and decompress using Brotli, Deflate, or GZip, detect unicode encoding, and read text content asynchronously. Use this namespace when you need comprehensive I/O operations like stream compression, encoding detection, or string-to-stream conversion. Start with `ToStream` on `String` or `byte[]` for stream conversion, or `CompressGZip` on `Stream` for compression. [!INCLUDE [availability-all](../../includes/availability-all.md)] Complements: [Cuemon.IO namespace](https://docs.cuemon.net/api/dotnet/Cuemon.IO.html) 🔗 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Net.Http.md b/.docfx/api/namespaces/Cuemon.Extensions.Net.Http.md index 33aa2c6b..ad9fcc5f 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Net.Http.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Net.Http.md @@ -2,11 +2,11 @@ uid: Cuemon.Extensions.Net.Http summary: *content --- -The `Cuemon.Extensions.Net.Http` namespace contains both types and extension methods that complements the `Cuemon.Net` namespace. Includes support for both traditional and factory based ways of working with HttpMangager instances while also including a simple and lightweight implementation of the IHttpClientFactory interface named SlimHttpClientFactory (that provides "managed" HttpClient instances). +Execute GET, POST, PUT, DELETE, PATCH, and other HTTP requests in a single line of code from a `Uri` without manually creating and configuring `HttpClient`. Use this namespace when you need concise HTTP calls from URI values. Start with `HttpGetAsync` on `Uri` for simple GET requests, or the generic `HttpAsync` method for any HTTP method. [!INCLUDE [availability-default](../../includes/availability-default.md)] -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Net.Security.md b/.docfx/api/namespaces/Cuemon.Extensions.Net.Security.md index 87c53b1b..eb05d1e6 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Net.Security.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Net.Security.md @@ -2,11 +2,11 @@ uid: Cuemon.Extensions.Net.Security summary: *content --- -The `Cuemon.Extensions.Net.Security` namespace contains extension methods that provides a generic way to make a Uniform Resource Identifier signed and tampering protected. This could be used to make your own lightweight concept of a Azure shared access signatures (SAS). Originally part of Cuemon .NET Framework: https://github.com/gimlichael/CuemonNetFramework/blob/master/Cuemon.Web/Security/WebSecurityUtility.cs. Greatly simplified anno 2020. +Create tamper-proof signed URIs that expire, enabling your own shared access signature (SAS) pattern without Azure dependencies. Use this namespace when you need to sign URIs with expiration for secure resource access. Start with `ToSignedUri` on a `String` or `Uri` to produce a signed URI, then call `ValidateSignedUri` to verify authenticity later. [!INCLUDE [availability-default](../../includes/availability-default.md)] -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Net.md b/.docfx/api/namespaces/Cuemon.Extensions.Net.md index 556762fe..fa94b038 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Net.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Net.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.Net summary: *content --- -The `Cuemon.Extensions.Net` namespace contains both types and extension methods that complements the `Cuemon.Net` namespace while being an addition to the `System.Net` namespace. Includes support for both traditional and factory based ways of working with HttpMangager instances while also including a simple and lightweight implementation of the IHttpClientFactory interface named SlimHttpClientFactory (that provides "managed" HttpClient instances). +Build query strings, encode and decode URLs, evaluate HTTP status codes concisely, and manage `HttpClient` instances without the boilerplate. Use this namespace when you need URL encoding, query string construction, HTTP status classification, or a lightweight `IHttpClientFactory`. Start with `ToQueryString` on `IDictionary{string, string[]}` for building query strings or `SlimHttpClientFactory` for managed HTTP clients. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon.Net namespace](/api/dotnet/Cuemon.Net.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Reflection.md b/.docfx/api/namespaces/Cuemon.Extensions.Reflection.md index dbf621d2..ebe9af8b 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Reflection.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Reflection.md @@ -2,17 +2,17 @@ uid: Cuemon.Extensions.Reflection summary: *content --- -The `Cuemon.Extensions.Reflection` namespace contains extension methods that complements the `Cuemon.Reflection` namespace while being an addition to the `System.Reflection` namespace. +Discover types, fields, properties, events, methods, and embedded resources at runtime, check auto-property status, and retrieve assembly version information. Use this namespace when you need advanced reflection without boilerplate. Start with `GetDerivedTypes` or `GetAllProperties` on `Type` for type discovery, or `GetAssemblyVersion` on `Assembly` for version information. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon.Reflection namespace](/api/dotnet/Cuemon.Reflection.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| |Assembly|⬇️|`GetAssemblyVersion`, `GetFileVersion`, `GetProductVersion`, `IsDebugBuild`| |MemberInfo|⬇️|`HasAttributes`| |PropertyInfo|⬇️|`IsAutoProperty`| -|Type|⬇️|`GetAllProperties`, `GetAllFields`, `GetAllEvents`, `GetAllMethods`, `GetDerivedTypes`, `GetInheritedTypes`, `GetHierarchyTypes`, `GetEmbeddedResources`, `GetRuntimePropertiesExceptOf{T}`, `ToFullNameIncludingAssemblyName`| +|Type|⬇️|`GetAllProperties`, `GetAllFields`, `GetAllEvents`, `GetAllMethods`, `GetDerivedTypes`, `GetInheritedTypes`, `GetHierarchyTypes`, `GetEmbeddedResources`, `GetRuntimePropertiesExceptOf`, `ToFullNameIncludingAssemblyName`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Runtime.Caching.md b/.docfx/api/namespaces/Cuemon.Extensions.Runtime.Caching.md index 54077890..bf799e2c 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Runtime.Caching.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Runtime.Caching.md @@ -2,14 +2,14 @@ uid: Cuemon.Extensions.Runtime.Caching summary: *content --- -The `Cuemon.Extensions.Runtime.Caching` namespace contains extension methods that complements the `Cuemon.Runtime.Caching` namespace by adding support for Memoization techniques and GetOrAdd convenience ; both with vast overloads and extended by the ICacheEnumerable{TKey} interface for loose coupling. +Cache expensive function results and reduce redundant computation through memoization and `GetOrAdd` patterns. Use this namespace when you need declarative caching with expiration management. Start with `GetOrAdd` on `ICacheEnumerable` for simple caching, or `Memoize` for function result caching. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon.Runtime.Caching namespace](/api/dotnet/Cuemon.Runtime.Caching.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|ICacheEnumerable{TKey}|⬇️|`GetOrAdd{TKey, TResult}`, `Memoize{TKey, T, TResult}`, `Memoize{TKey, T, TResult}`, `Memoize{TKey, T1, T2, TResult}`, `Memoize{TKey, T1, T2, T3, TResult}`, `Memoize{TKey, T1, T2, T3, T4, TResult}`, `Memoize{TKey, T1, T2, T3, T4, T5, TResult}`| +|ICacheEnumerable|⬇️|`GetOrAdd`, `Memoize`, `Memoize`, `Memoize`, `Memoize`, `Memoize`, `Memoize`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Runtime.Serialization.md b/.docfx/api/namespaces/Cuemon.Extensions.Runtime.Serialization.md new file mode 100644 index 00000000..a23fc9bd --- /dev/null +++ b/.docfx/api/namespaces/Cuemon.Extensions.Runtime.Serialization.md @@ -0,0 +1,15 @@ +--- +uid: Cuemon.Extensions.Runtime.Serialization +summary: *content +--- +Serialize hierarchical runtime data structures built from `IHierarchy` into persistent formats. Use this namespace when you need to persist or transmit object hierarchy data. Start with `HierarchySerializer` for converting object hierarchies into serialized output. + +[!INCLUDE [availability-default](../../includes/availability-default.md)] + +Complements: [Cuemon.Extensions.Runtime namespace](/api/extensions/dotnet/Cuemon.Extensions.Runtime.html) 📘 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator>|⬇️|`Serialize`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Runtime.md b/.docfx/api/namespaces/Cuemon.Extensions.Runtime.md new file mode 100644 index 00000000..ed0920e5 --- /dev/null +++ b/.docfx/api/namespaces/Cuemon.Extensions.Runtime.md @@ -0,0 +1,21 @@ +--- +uid: Cuemon.Extensions.Runtime +summary: *content +--- +Model runtime objects as hierarchical tree structures to inspect their relationships, paths, and structure during application execution. Use this namespace when you need to build and navigate object graphs as hierarchies. Start with `IHierarchy` for defining hierarchical data or `HierarchyDecoratorExtensions` for navigating tree structures. + +[!INCLUDE [availability-default](../../includes/availability-default.md)] + +Complements: [Cuemon.Extensions namespace](/api/extensions/dotnet/Cuemon.Extensions.html) 📘 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator>|⬇️|`UseConvertibleFormatter`, `UseUriFormatter`, `UseDateTimeFormatter`, `UseGuidFormatter`, `UseStringFormatter`, `UseDecimalFormatter`, `UseCollection`, `UseDictionary`| +|IDecorator>|⬇️|`FindFirstInstance`, `FindSingleInstance`, `FindInstance`, `FindFirst`, `FindSingle`, `Find`, `Replace`, `Root`, `AncestorsAndSelf`, `DescendantsAndSelf`, `SiblingsAndSelf`, `SiblingsAndSelfAt`, `NodeAt`, `FlattenAll`| +|IDecorator>>|⬇️|`ReplaceAll`| +|IHierarchy|⬇️|`UseGenericConverter`| +|IEnumerable>|⬇️|`ParseCollectionItem`, `ParseDictionaryItem`| + +Related: [Cuemon.Extensions.Runtime.Serialization namespace](/api/extensions/dotnet/Cuemon.Extensions.Runtime.Serialization.html) 📘 diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Text.Json.Converters.md b/.docfx/api/namespaces/Cuemon.Extensions.Text.Json.Converters.md index 3956c331..c12ff322 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Text.Json.Converters.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Text.Json.Converters.md @@ -2,14 +2,14 @@ uid: Cuemon.Extensions.Text.Json.Converters summary: *content --- -The `Cuemon.Extensions.Text.Json.Converters` namespace contains both types and extension methods that complements the `System.Text.Json` namespace. +Register `System.Text.Json` converters for Cuemon-specific types like `TransientFaultException`, `DataPair`, `ExceptionDescriptor`, and string-based enum serialization. Use this namespace when you need JSON serialization support for Cuemon types. Start with `AddStringEnumConverter` for enum serialization or `AddExceptionDescriptorConverterOf` for structured error serialization. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [System.Text.Json namespace](https://learn.microsoft.com/en-us/dotnet/api/system.text.json) 🔗 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|JsonConverter|⬇️|`AddTransientFaultExceptionConverter`, `AddDateTimeConverter`, `AddStringEnumConverter`, `AddStringFlagsEnumConverter`, `AddExceptionDescriptorConverterOf{T}`, `AddExceptionConverter`, `AddDataPairConverter`, `AddFailureConverter`, `RemoveAllOf` and `RemoveAllOf{T}`| +|ICollection|⬇️|`AddTransientFaultExceptionConverter`, `AddDateTimeConverter`, `AddStringEnumConverter`, `AddStringFlagsEnumConverter`, `AddExceptionDescriptorConverterOf`, `AddExceptionConverter`, `AddDataPairConverter`, `AddFailureConverter`, `RemoveAllOf`, `RemoveAllOf`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Text.Json.Formatters.md b/.docfx/api/namespaces/Cuemon.Extensions.Text.Json.Formatters.md index 018eed20..7e95a7ae 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Text.Json.Formatters.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Text.Json.Formatters.md @@ -2,7 +2,7 @@ uid: Cuemon.Extensions.Text.Json.Formatters summary: *content --- -The `Cuemon.Extensions.Text.Json.Formatters` namespace contains types that are used to serialize and deserialize objects into and from JSON format using a generic signature. +Serialize and deserialize objects using `System.Text.Json` through type-safe JSON formatters that integrate with ASP.NET Core's output formatter infrastructure. Use this namespace when you need configurable, generic JSON serialization in pipelines. Start with `JsonFormatter` for type-safe JSON formatting with custom options. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Text.Json.md b/.docfx/api/namespaces/Cuemon.Extensions.Text.Json.md index c6658922..3922869a 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Text.Json.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Text.Json.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.Text.Json summary: *content --- -The `Cuemon.Extensions.Text.Json` namespace contains both types and extension methods that complements the `System.Text.Json` namespace by adding new ways of working with JSON; both in terms of serialization and parsing. +Register custom JSON converters, configure naming policies, traverse JSON hierarchies, and configure `JsonSerializerOptions` without writing infrastructure code. Use this namespace when you need advanced `System.Text.Json` configuration beyond the defaults. Start with `JsonConverterCollectionExtensions` for registering custom converters, or `ToHierarchy` on `Utf8JsonReader` for JSON tree traversal. [!INCLUDE [availability-modern](../../includes/availability-modern.md)] Complements: [System.Text.Json namespace](https://learn.microsoft.com/en-us/dotnet/api/system.text.json) 🔗 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Text.md b/.docfx/api/namespaces/Cuemon.Extensions.Text.md index 828805f8..32fcd9c0 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Text.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Text.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.Text summary: *content --- -The `Cuemon.Extensions.Text` namespace contains extension methods that complements the `Cuemon.Text` namespace while being an addition to the `System` namespace. +Detect character encodings and convert strings to their encoded byte representations without manual encoding logic. Use this namespace when you need encoding detection or string-to-encoded-byte conversion. Start with `DetectUnicodeEncoding` on `IEncodingOptions` for encoding detection, or `ToEncodedString` on `String` for encoding-aware string conversion. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon.Text namespace](/api/dotnet/Cuemon.Text.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Threading.Tasks.md b/.docfx/api/namespaces/Cuemon.Extensions.Threading.Tasks.md index 9e23f7b2..bfe0e6ea 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Threading.Tasks.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Threading.Tasks.md @@ -2,14 +2,15 @@ uid: Cuemon.Extensions.Threading.Tasks summary: *content --- -The `Cuemon.Extensions.Threading.Tasks` namespace contains extension methods that complements the `System.Threading.Tasks` namespace. +Control the synchronization context in async task continuations explicitly with `ContinueWithCapturedContext` (resume on original context) and `ContinueWithSuppressedContext` (suppress context). Use this namespace when you need predictable async behavior in libraries without manual `ConfigureAwait` calls. Start with `ContinueWithSuppressedContext` on `Task` to avoid deadlocks in synchronous blocking patterns. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [System.Threading.Tasks namespace](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks) 🔗 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|Task|⬇️|`ContinueWithCapturedContext`, `ContinueWithCapturedContext{TResult}`, `ContinueWithSuppressedContext`, `ContinueWithSuppressedContext{TResult}`| +|Task|⬇️|`ContinueWithCapturedContext`, `ContinueWithSuppressedContext`| +|Task|⬇️|`ContinueWithCapturedContext`, `ContinueWithSuppressedContext`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Xml.Linq.md b/.docfx/api/namespaces/Cuemon.Extensions.Xml.Linq.md index 86d5ae28..89644155 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Xml.Linq.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Xml.Linq.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.Xml.Linq summary: *content --- -The `Cuemon.Extensions.Xml.Linq` namespace contains extension methods that complements the `Cuemon.Xml.Linq` namespace. +Validate XML content with `IsXmlString` and safely parse XML strings into `XElement` instances without exceptions using `TryParseXElement`. Use this namespace when you need safe XML parsing that avoids throwing exceptions on malformed input. Start with `TryParseXElement` on `String` for exception-free XML parsing, or `IsXmlString` to validate XML content before processing. Complements: [Cuemon.Xml.Linq namespace](/api/dotnet/Cuemon.Xml.Linq.html) 📘 [!INCLUDE [availability-default](../../includes/availability-default.md)] -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.Converters.md b/.docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.Converters.md index 7696d851..01b5b269 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.Converters.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.Converters.md @@ -2,14 +2,14 @@ uid: Cuemon.Extensions.Xml.Serialization.Converters summary: *content --- -The `Cuemon.Extensions.Xml.Serialization.Converters` namespace contains extension methods that complements the `Cuemon.Xml.Serialization.Converters` namespace. +Register XML serialization converters for enumerables, exceptions, URIs, date/time types, and strings on `IList`. Use this namespace when you need custom XML converter registration beyond the default converters. Start with `AddXmlConverter` for generic converter registration or `AddStringConverter` for string-specific XML conversion. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon.Xml.Serialization.Converters namespace](/api/dotnet/Cuemon.Xml.Serialization.Converters.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|IList{XmlConverter}|⬇️|`FirstOrDefaultReaderConverter`, `FirstOrDefaultWriterConverter`, `AddXmlConverter`, `InsertXmlConverter`, `AddEnumerableConverter`, `AddExceptionDescriptorConverter`, `AddUriConverter`, `AddDateTimeConverter`, `AddTimeSpanConverter`, `AddStringConverter`, `AddExceptionConverter` and `AddFailureConverter`| +|IList|⬇️|`FirstOrDefaultReaderConverter`, `FirstOrDefaultWriterConverter`, `AddXmlConverter`, `InsertXmlConverter`, `AddEnumerableConverter`, `AddExceptionDescriptorConverter`, `AddUriConverter`, `AddDateTimeConverter`, `AddTimeSpanConverter`, `AddStringConverter`, `AddExceptionConverter`, `AddFailureConverter`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.md b/.docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.md index 9d2d1536..6628da80 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.md @@ -2,13 +2,13 @@ uid: Cuemon.Extensions.Xml.Serialization summary: *content --- -The `Cuemon.Extensions.Xml.Serialization` namespace contains extension methods that complements the `Cuemon.Xml.Serialization` namespace. +Apply custom XML serializer settings as system-wide defaults for all XML serialization operations. Use this namespace when you need global XML serializer configuration that applies automatically. Start with `ApplyToDefaultSettings` on `XmlSerializerOptions` to propagate your settings without per-call setup. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon.Xml.Serialization namespace](/api/dotnet/Cuemon.Xml.Serialization.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.Xml.md b/.docfx/api/namespaces/Cuemon.Extensions.Xml.md index a3ff4d1a..25365249 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.Xml.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.Xml.md @@ -2,21 +2,23 @@ uid: Cuemon.Extensions.Xml summary: *content --- -The `Cuemon.Extensions.Xml` namespace contains extension methods that complements the `Cuemon.Xml` namespace while being an addition to the `System.Xml` namespace. +Parse streams and byte arrays into `XmlReader`, escape or sanitize XML text, traverse `XmlReader` hierarchies, write structured XML with custom element wrappers, and remove XML namespace declarations. Use this namespace when you need comprehensive XML processing without low-level XML API boilerplate. Start with `ToXmlReader` on `Stream` or `byte[]` for XML parsing, or `EscapeXml` on `String` for XML-safe text. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon.Xml namespace](/api/dotnet/Cuemon.Xml.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| |byte[]|⬇️|`ToXmlReader`| |DateTime|⬇️|`ToString`| -|IHierarchy{T}|⬇️|`HasXmlIgnoreAttribute`, `IsNodeEnumerable`, `GetXmlQualifiedEntity`, `OrderByXmlAttributes`| +|IHierarchy|⬇️|`HasXmlIgnoreAttribute`, `IsNodeEnumerable`, `GetXmlQualifiedEntity`| +|IEnumerable>|⬇️|`OrderByXmlAttributes`| +|XmlWriter|⬇️|`WriteObject`, `WriteStartElement`, `WriteEncapsulatingElementWhenNotNull`, `WriteXmlRootElement`, `WriteObject`| |Stream|⬇️|`ToXmlReader`, `CopyXmlStream`, `TryDetectXmlEncoding`, `RemoveXmlNamespaceDeclarations`| |String|⬇️|`EscapeXml`, `UnescapeXml`, `SanitizeXmlElementName`, `SanitizeXmlElementText`| |Uri|⬇️|`ToXmlReader`| |XmlReader|⬇️|`Chunk`, `ToHierarchy`, `ToStream`, `MoveToFirstElement`| -|XmlWriter|⬇️|`WriteObject`, `WriteObject{T}`, `WriteStartElement`, `WriteEncapsulatingElementWhenNotNull{T}`, `WriteXmlRootElement{T}`| +|XmlWriter|⬇️|`WriteObject`, `WriteStartElement`, `WriteEncapsulatingElementWhenNotNull`, `WriteXmlRootElement`| diff --git a/.docfx/api/namespaces/Cuemon.Extensions.md b/.docfx/api/namespaces/Cuemon.Extensions.md index 2c0cb592..fbef5d44 100644 --- a/.docfx/api/namespaces/Cuemon.Extensions.md +++ b/.docfx/api/namespaces/Cuemon.Extensions.md @@ -2,28 +2,32 @@ uid: Cuemon.Extensions summary: *content --- -The `Cuemon.Extensions` namespace contains extension methods that complements the `Cuemon` namespace while being an addition to the `System` namespace. +Write more expressive, fluent code by calling extension methods directly on .NET built-in types — `myString.ToUri()` replaces `new Uri(myString)`, `myException.Flatten()` unwraps an `AggregateException` in one call. Use this namespace when you want to reduce ceremony around common .NET operations. The `Cuemon.Extensions` namespace extends `String`, `DateTime`, `Object`, `Type`, `TimeSpan`, `Exception`, and many more types. If you are new to this namespace, start with the `String` or `Object` extension groups for the most frequently needed conversions and transformations. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [Cuemon namespace](/api/dotnet/Cuemon.html) 📘 -### Extension Methods +### Extension Members |Type|Ext|Methods| |--:|:-:|---| -|Action|⬇️|`Configure{TOptions}`, `CreateInstance{T}`| +|Action|⬇️|`Configure`| +|Action|⬇️|`CreateInstance`| |Byte|⬇️|`ToEncodedString`, `ToHexadecimalString`, `ToBinaryString`, `ToUrlEncodedBase64String`, `ToBase64String`, `TryDetectUnicodeEncoding`| |Char|⬇️|`ToEnumerable`, `FromChars`| |Condition|⬇️|`HasDifference`| |DateTime|⬇️|`ToUnixEpochTime`, `ToUtcKind`, `ToLocalKind`, `ToDefaultKind`, `IsWithinRange`, `IsTimeOfDayNight`, `IsTimeOfDayMorning`, `IsTimeOfDayForenoon`, `IsTimeOfDayAfternoon`, `IsTimeOfDayEvening`, `Floor`, `Ceiling`, `Round`| |Double|⬇️|`FromUnixEpochTime`, `ToTimeSpan`, `Factorial`, `RoundOff`| |Exception|⬇️|`Flatten`| +|IEnumerable|⬇️|`GetHashCode32`, `GetHashCode64`, `ToDelimitedString`| +|IEnumerable|⬇️|`IsSequenceOf`| |Int*|⬇️|`Min`, `Max`, `IsPrime`, `IsCountableSequence`, `IsEven`, `IsOdd`| |Mapping|⬇️|`AddMapping`| |MethodDescriptor|⬇️|`HasParameters`| -|Object|⬇️|`UseWrapper{T}`, `As{T}`, `As`, `GetHashCode32{T}`, `GetHashCode64{T}`, `ToDelimitedString{T}`, `Adjust{T}`, `Alter{T}`, `IsNullable{T}`| -|String|⬇️|`ReplaceLineEndings`, `Difference`, `ToByteArray`, `FromUrlEncodedBase64`, `ToGuid`, `FromBinaryDigits`, `FromBase64`, `ToCasing`, `ToUri`, `IsNullOrEmpty`, `IsNullOrWhiteSpace`, `IsEmailAddress`, `IsGuid`, `IsHex`, `IsNumeric`, `IsBase64`, `SplitDelimited`, `Count`, `RemoveAll`, `ReplaceAll`, `JsEscape`, `JsUnescape`, `ContainsAny`, `ContainsAll`, `EqualsAny`, `StartsWith`, `TrimAll`, `IsSequenceOf{T}`, `FromHexadecimal`, `ToHexadecimal`, `ToEnum{TEnum}`, `ToTimeSpan`, `SubstringBefore`, `Chunk`, `SuffixWith`, `SuffixWithForwardingSlash`, `PrefixWith`| +|Object|⬇️|`As`, `As`, `IsNullable`| +|String|⬇️|`Difference`, `ToByteArray`, `FromUrlEncodedBase64`, `ToGuid`, `FromBinaryDigits`, `FromBase64`, `ToCasing`, `ToUri`, `IsNullOrEmpty`, `IsNullOrWhiteSpace`, `IsEmailAddress`, `IsGuid`, `IsHex`, `IsNumeric`, `IsBase64`, `SplitDelimited`, `Count`, `RemoveAll`, `ReplaceAll`, `JsEscape`, `JsUnescape`, `ContainsAny`, `ContainsAll`, `EqualsAny`, `StartsWith`, `TrimAll`, `IsSequenceOf`, `FromHexadecimal`, `ToHexadecimal`, `ToEnum`, `ToTimeSpan`, `SubstringBefore`, `Chunk`, `SuffixWith`, `SuffixWithForwardingSlash`, `PrefixWith`| +|T|⬇️|`UseWrapper`, `As`, `Adjust`, `Alter`, `IsNullable`| |TimeSpan|⬇️|`GetTotalNanoseconds`, `GetTotalMicroseconds`, `Floor`, `Ceiling`, `Round`| -|Type|⬇️|`ToFriendlyName`, `ToTypeCode`, `HasEqualityComparerImplementation`, `HasComparableImplementation`, `HasComparerImplementation`, `HasEnumerableImplementation`, `HasDictionaryImplementation`, `HasKeyValuePairImplementation`, `IsNullable`, `HasAnonymousCharacteristics`, `IsComplex`, `IsSimple`, `GetDefaultValue`, `HasTypes`, `HasInterfaces`, `HasAttributes`| +|Type|⬇️|`ToFriendlyName`, `ToTypeCode`, `HasEqualityComparerImplementation`, `HasComparableImplementation`, `HasComparerImplementation`, `HasEnumerableImplementation`, `HasDictionaryImplementation`, `HasKeyValuePairImplementation`, `IsNullable`, `IsNullable`, `HasAnonymousCharacteristics`, `IsComplex`, `IsSimple`, `GetDefaultValue`, `HasTypes`, `HasInterfaces`, `HasAttributes`| |Validator|⬇️|`ContainsReservedKeyword`, `HasDifference`, `NoDifference`| diff --git a/.docfx/api/namespaces/Cuemon.Globalization.md b/.docfx/api/namespaces/Cuemon.Globalization.md index 59fa5f26..ddb8bdc3 100644 --- a/.docfx/api/namespaces/Cuemon.Globalization.md +++ b/.docfx/api/namespaces/Cuemon.Globalization.md @@ -2,7 +2,7 @@ uid: Cuemon.Globalization summary: *content --- -The `Cuemon.Globalization` namespace contains types that focuses on culture-related information, including language, country/region and localized resources useful for writing globalized (internationalized) applications. The namespace is an addition to the `System.Globalization` namespace. +The `Cuemon.Globalization` namespace provides types for culture-aware and region-aware application logic, extending the `System.Globalization` types with country/region classification, localized resource support, and statistical region data. Use `CountryRegion` to represent geographic entities, or `StatisticalRegion` when you need demographic, economic, or geographic data associated with a region. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.IO.md b/.docfx/api/namespaces/Cuemon.IO.md index 91629503..74360352 100644 --- a/.docfx/api/namespaces/Cuemon.IO.md +++ b/.docfx/api/namespaces/Cuemon.IO.md @@ -2,8 +2,15 @@ uid: Cuemon.IO summary: *content --- -The `Cuemon.IO` namespace contains types primarily focusing on configuration options for IO related operations. The namespace is an addition to the `System.IO` namespace. +Configure IO operations — compression, encoding, streaming, and buffering — through options types that extend `System.IO` infrastructure. Use this namespace when you need to configure stream compression, encoding, or buffering settings. Start with `CompressGZip` on `IDecorator` for GZip compression, or `ToEncodedString` for encoding-aware stream output. [!INCLUDE [availability-all](../../includes/availability-all.md)] Complements: [System.IO namespace](https://docs.microsoft.com/en-us/dotnet/api/system.io) + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator|⬇️|`CopyTo`, `CopyStream`, `CopyStreamAsync`, `ToByteArray`, `ToByteArrayAsync`, `ToEncodedString`, `ToEncodedStringAsync`, `InvokeToByteArray`, `WriteAllAsync`, `CompressBrotli`, `CompressBrotliAsync`, `DecompressBrotli`, `DecompressBrotliAsync`, `CompressGZip`, `CompressGZipAsync`, `DecompressGZip`, `DecompressGZipAsync`, `CompressDeflate`, `CompressDeflateAsync`, `DecompressDeflate`, `DecompressDeflateAsync`| +|IDecorator|⬇️|`CopyToAsync`| diff --git a/.docfx/api/namespaces/Cuemon.Messaging.md b/.docfx/api/namespaces/Cuemon.Messaging.md index 85c420ea..fa65da91 100644 --- a/.docfx/api/namespaces/Cuemon.Messaging.md +++ b/.docfx/api/namespaces/Cuemon.Messaging.md @@ -2,7 +2,7 @@ uid: Cuemon.Messaging summary: *content --- -The `Cuemon.Messaging` namespace contains types that assist in more advanced scenarios such as CQRS, microservices and event-driven architecture. The namespace is an addition to the `System.Messaging` namespace. +The `Cuemon.Messaging` namespace provides types for implementing CQRS, microservices communication, and event-driven architectures. Use `CorrelationToken` to correlate messages across service boundaries, or the message envelope types when you need standardized request/response patterns with correlation support. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Net.Collections.Specialized.md b/.docfx/api/namespaces/Cuemon.Net.Collections.Specialized.md index 910b6531..50552cc5 100644 --- a/.docfx/api/namespaces/Cuemon.Net.Collections.Specialized.md +++ b/.docfx/api/namespaces/Cuemon.Net.Collections.Specialized.md @@ -2,8 +2,15 @@ uid: Cuemon.Net.Collections.Specialized summary: *content --- -The `Cuemon.Net.Collections.Specialized` namespace contains extension methods that are hidden behind the [`IDecorator{IDecorator{T} interface](/api/dotnet/Cuemon.IDecorator-1.html). +Convert between `IDictionary` and `NameValueCollection` using extension methods on the `IDecorator>` type. The `Cuemon.Net.Collections.Specialized` namespace bridges generic dictionary parameters and legacy name-value collections for HTTP and form data scenarios. Use the `ToNameValueCollection` extension when you need to pass dictionary data to APIs that expect `NameValueCollection`. Start with this method on `IDecorator>` for the most common conversion scenario. [!INCLUDE [availability-default](../../includes/availability-default.md)] -Complements: [System.Net namespace](https://docs.microsoft.com/en-us/dotnet/api/system.collections.specialized) +Complements: [System.Collections.Specialized namespace](https://docs.microsoft.com/en-us/dotnet/api/system.collections.specialized) + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator>|⬇️|`ToNameValueCollection`| +|IDecorator|⬇️|`ToString`| diff --git a/.docfx/api/namespaces/Cuemon.Net.Http.md b/.docfx/api/namespaces/Cuemon.Net.Http.md index 311b8d12..5f241d3e 100644 --- a/.docfx/api/namespaces/Cuemon.Net.Http.md +++ b/.docfx/api/namespaces/Cuemon.Net.Http.md @@ -2,7 +2,7 @@ uid: Cuemon.Net.Http summary: *content --- -The `Cuemon.Net.Http` namespace contains types that is compliant with RFC 7231, section 4: Request methods and RFC 5789, section 2: Patch method while allowing custom definitions as well. The namespace is an addition to the `System.Net.Http` namespace. +Make HTTP calls using RFC 7231-compliant method definitions and an HTTP manager infrastructure. Use this namespace when you need to build and execute HTTP requests with RFC-compliant method constants. Start with `HttpMethods` for standard HTTP method constants, or `HttpManager` for building and sending HTTP requests. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Net.Mail.md b/.docfx/api/namespaces/Cuemon.Net.Mail.md index d5395061..bf7523b7 100644 --- a/.docfx/api/namespaces/Cuemon.Net.Mail.md +++ b/.docfx/api/namespaces/Cuemon.Net.Mail.md @@ -2,7 +2,7 @@ uid: Cuemon.Net.Mail summary: *content --- -The `Cuemon.Net.Mail` namespace contains types that makes delivery of mail a piece of cake. The namespace is an addition to the `System.Net.Mail` namespace. +Send email messages with custom delivery options, extending `System.Net.Mail` with additional convenience methods. Use this namespace when you need to compose and send email with Cuemon's mail infrastructure. Start with `ToMailMessage` on `Byte[]` for converting binary content into email messages. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Net.md b/.docfx/api/namespaces/Cuemon.Net.md index f9f5e1df..9c0b5e60 100644 --- a/.docfx/api/namespaces/Cuemon.Net.md +++ b/.docfx/api/namespaces/Cuemon.Net.md @@ -2,8 +2,15 @@ uid: Cuemon.Net summary: *content --- -The `Cuemon.Net` namespace contains types that provides a simple programming interface for HTTP and SMTP protocols. The namespace is an addition to the `System.Net` namespace. +Work with HTTP and SMTP protocols through a simple programming interface. Use this namespace when you need to work with URI encoding, query strings, or protocol-level conversions. Start with `UrlEncode` on `IDecorator` for encoding URI components, or `ToQueryString` for building query strings from name-value collections. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [System.Net namespace](https://docs.microsoft.com/en-us/dotnet/api/system.net) + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator|⬇️|`ToStream`, `UrlEncode`| +|IDecorator|⬇️|`ToStream`, `UrlEncode`, `UrlDecode`, `ToQueryString`| diff --git a/.docfx/api/namespaces/Cuemon.Reflection.md b/.docfx/api/namespaces/Cuemon.Reflection.md index 88262cd7..685d7e71 100644 --- a/.docfx/api/namespaces/Cuemon.Reflection.md +++ b/.docfx/api/namespaces/Cuemon.Reflection.md @@ -2,8 +2,18 @@ uid: Cuemon.Reflection summary: *content --- -The `Cuemon.Reflection` namespace contains types that focuses on working natural with the hidden gems of reflection in order to retrieve information about assemblies, members, parameters, and different versioning schemes that support both traditional and semantic. The namespace is an addition to the `System.Reflection` namespace. +Retrieve assembly metadata, inspect members and parameters, and resolve versioning schemes (traditional and semantic) without verbose reflection boilerplate. The `Cuemon.Reflection` namespace extends `Assembly`, `MemberInfo`, and `MethodInfo` through `IDecorator` extension methods for attribute inspection, type discovery, and version resolution. Use these extensions when you need to check assembly build type, detect custom attributes, or inspect member metadata. Start with `HasAttribute` on `IDecorator` for attribute detection, or `GetTypes` on `IDecorator` for type discovery. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [System.Reflection namespace](https://docs.microsoft.com/en-us/dotnet/api/system.reflection) 🔗 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator|⬇️|`GetTypes`, `IsDebugBuild`, `GetAssemblyVersion`, `GetFileVersion`, `GetProductVersion`, `GetManifestResources`| +|IDecorator|⬇️|`HasAttribute`, `HasAttribute`| +|IDecorator|⬇️|`IsOverridden`| +|IDecorator|⬇️|`IsOverridden`, `IsAutoProperty`| +|IDecorator>>|⬇️|`CreateException`| diff --git a/.docfx/api/namespaces/Cuemon.Resilience.md b/.docfx/api/namespaces/Cuemon.Resilience.md index 72c413c7..7a8cd424 100644 --- a/.docfx/api/namespaces/Cuemon.Resilience.md +++ b/.docfx/api/namespaces/Cuemon.Resilience.md @@ -2,6 +2,6 @@ uid: Cuemon.Resilience summary: *content --- -The `Cuemon.Resilience` namespace contains types related to applying transient fault handling to existing code using intuitively named methods taking both Action{..} and Func{..} delegates to provide a lightweight resilience framework. +Add retry, timeout, and transient fault handling to existing code without heavy infrastructure. Use this namespace when you need resilience patterns like retry or timeout for operations that may fail transiently. Start with the retry methods that match your operation pattern (synchronous or asynchronous) on `Action` or `Func` delegates. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Runtime.Caching.md b/.docfx/api/namespaces/Cuemon.Runtime.Caching.md index 56024146..4418ff80 100644 --- a/.docfx/api/namespaces/Cuemon.Runtime.Caching.md +++ b/.docfx/api/namespaces/Cuemon.Runtime.Caching.md @@ -2,7 +2,7 @@ uid: Cuemon.Runtime.Caching summary: *content --- -The `Cuemon.Runtime.Caching` namespace contains types related to interfaces for generic caching in applications while providing a concrete in-memory cache implementation named SlimMemoryCache. The namespace is an addition to the `System.Runtime.Caching` namespace. +Cache application data through a simple, generic caching API with `SlimMemoryCache` as the lightweight in-memory implementation. Use this namespace when you need application-level caching with a generic API. Start with `SlimMemoryCache` for in-memory caching, or implement `ICache` for custom cache backends. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Runtime.Serialization.Converters.md b/.docfx/api/namespaces/Cuemon.Runtime.Serialization.Converters.md index 06da75c6..56af5512 100644 --- a/.docfx/api/namespaces/Cuemon.Runtime.Serialization.Converters.md +++ b/.docfx/api/namespaces/Cuemon.Runtime.Serialization.Converters.md @@ -2,6 +2,6 @@ uid: Cuemon.Runtime.Serialization.Converters summary: *content --- -The `Cuemon.Runtime.Serialization.Converters` namespace contains types that are used to serialize and deserialize objects into and from a generic type. Inspired by JSON.Net. +The `Cuemon.Runtime.Serialization.Converters` namespace provides converter types that serialize and deserialize objects to and from a generic node representation, inspired by JSON.Net's converter model. Use `StringConverter` or `DateTimeConverter` to control how specific types are represented in the node-based serialization pipeline. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Runtime.Serialization.Formatters.md b/.docfx/api/namespaces/Cuemon.Runtime.Serialization.Formatters.md index d7ed939c..9edaeb42 100644 --- a/.docfx/api/namespaces/Cuemon.Runtime.Serialization.Formatters.md +++ b/.docfx/api/namespaces/Cuemon.Runtime.Serialization.Formatters.md @@ -2,7 +2,7 @@ uid: Cuemon.Runtime.Serialization.Formatters summary: *content --- -The `Cuemon.Runtime.Serialization.Formatters` namespace contains types that are used to serialize and deserialize objects into and from a generic type. The namespace is an addition to the `System.Runtime.Serialization` namespace. +Serialize and deserialize object graphs into JSON or XML through a node-based intermediate representation. Use this namespace when you need to format object hierarchies into JSON or XML output. Start with `JsonFormatter` for JSON serialization or `XmlFormatter` for XML serialization using the `HierarchySerializer` pipeline. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Runtime.Serialization.md b/.docfx/api/namespaces/Cuemon.Runtime.Serialization.md index 5a795d8c..ab15f79a 100644 --- a/.docfx/api/namespaces/Cuemon.Runtime.Serialization.md +++ b/.docfx/api/namespaces/Cuemon.Runtime.Serialization.md @@ -2,7 +2,7 @@ uid: Cuemon.Runtime.Serialization summary: *content --- -The `Cuemon.Runtime.Serialization` namespace contains types that are used to serialize objects into a hierarchy of nodes. The namespace is an addition to the `System.Runtime.Serialization` namespace. +The `Cuemon.Runtime.Serialization` namespace provides a node-based serialization model that converts objects into a traversable hierarchy of `IXNode` elements, then formats the result as JSON, XML, or other structured outputs. Use this namespace when you need serialization that preserves structure and supports multiple output formats from a single object graph traversal. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Runtime.md b/.docfx/api/namespaces/Cuemon.Runtime.md index 2eb93aef..5c328509 100644 --- a/.docfx/api/namespaces/Cuemon.Runtime.md +++ b/.docfx/api/namespaces/Cuemon.Runtime.md @@ -2,7 +2,7 @@ uid: Cuemon.Runtime summary: *content --- -The `Cuemon.Runtime` namespace contains types that support different namespaces such as the `Cuemon`, `Cuemon.Data`, `Cuemon.Net`, and the `Cuemon.Runtime.Caching` namespaces (to name a few). The namespace is an addition to the `System.Runtime` namespace. +The `Cuemon.Runtime` namespace provides base types for background tasks, timed operations, and resource management across the Cuemon framework. Use `BackgroundTask` for long-running operations, or `Timer` for interval-based execution. The types in this namespace support caching, data synchronization, and networking components throughout the rest of the framework. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Security.Cryptography.md b/.docfx/api/namespaces/Cuemon.Security.Cryptography.md index 46de077c..2105af04 100644 --- a/.docfx/api/namespaces/Cuemon.Security.Cryptography.md +++ b/.docfx/api/namespaces/Cuemon.Security.Cryptography.md @@ -2,7 +2,7 @@ uid: Cuemon.Security.Cryptography summary: *content --- -The `Cuemon.Security.Cryptography` namespace contains types related to cryptographic hashing (both keyed and non-keyed) and a ready-to-use implementation of the Advanced Encryption Standard (AES) symmetric algorithm. The namespace is an addition to the `System.Security.Cryptography` namespace. +Compute cryptographic hashes (keyed and non-keyed) and perform AES symmetric encryption through a service-oriented API. Use this namespace when you need HMAC, cryptographic hashing, or symmetric encryption. Start with `KeyedHashFactory` for HMAC, `HashFactory` for cryptographic hashing, or `AesCryptographyService` for AES encryption. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Security.md b/.docfx/api/namespaces/Cuemon.Security.md index 5861b0b6..32000235 100644 --- a/.docfx/api/namespaces/Cuemon.Security.md +++ b/.docfx/api/namespaces/Cuemon.Security.md @@ -2,7 +2,7 @@ uid: Cuemon.Security summary: *content --- -The `Cuemon.Security` namespace contains types related to hashing (both non-cryptographic and CRC) and has the base class from which all implementations of hash algorithms and checksums should derive. The namespace is an addition to the `System.Security` namespace. +Compute non-cryptographic hashes and CRC (Cyclic Redundancy Check) checksums for fast data integrity verification. Use this namespace when you need fast integrity verification without cryptographic overhead. Start with `Hash` or `Hash` for custom hash algorithms, or use the built-in CRC types for cyclic redundancy checks. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Text.md b/.docfx/api/namespaces/Cuemon.Text.md new file mode 100644 index 00000000..c816e621 --- /dev/null +++ b/.docfx/api/namespaces/Cuemon.Text.md @@ -0,0 +1,11 @@ +--- +uid: Cuemon.Text +summary: *content +--- +Parse strings into strongly-typed values, control GUID formatting, perform suffix-based string operations, and detect text encodings when the built-in `System.Text` types are not enough. Use this namespace when you need advanced text processing like string parsing, GUID formatting, or encoding detection. Start with `Parser` for parsing strings into typed values, or `GuidStringOptions` for GUID format control. + +[!INCLUDE [availability-default](../../includes/availability-default.md)] + +Complements: [System.Text namespace](https://docs.microsoft.com/en-us/dotnet/api/system.text) 🔗 + +Related: [Cuemon namespace](/api/dotnet/Cuemon.html) 📘 diff --git a/.docfx/api/namespaces/Cuemon.Threading.md b/.docfx/api/namespaces/Cuemon.Threading.md index 0f1cf318..8ea6a25c 100644 --- a/.docfx/api/namespaces/Cuemon.Threading.md +++ b/.docfx/api/namespaces/Cuemon.Threading.md @@ -2,7 +2,7 @@ uid: Cuemon.Threading summary: *content --- -The `Cuemon.Threading` namespace contains types related to working with long-running concurrent loops and regions that utilizes both synchronous and asynchronous delegates. The namespace is an addition to the `System.Threading` namespace. +Execute parallel loops, manage concurrent regions, and apply advanced threading patterns with synchronous or asynchronous delegates. Use this namespace when you need fine-grained control over concurrent iterations. Start with `ParallelLoop` for synchronous parallelism or `AsyncParallelLoop` for asynchronous patterns with cancellation, throttling, and aggregation. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Xml.Linq.md b/.docfx/api/namespaces/Cuemon.Xml.Linq.md index 69b3748b..6633e459 100644 --- a/.docfx/api/namespaces/Cuemon.Xml.Linq.md +++ b/.docfx/api/namespaces/Cuemon.Xml.Linq.md @@ -2,10 +2,16 @@ uid: Cuemon.Xml.Linq summary: *content --- -The `Cuemon.Xml.Linq` namespace contains types that is used internally by this and related assemblies and is not intended to be used directly from your code. The namespace is an addition to the `System.Xml.Linq` namespace. +Parse and validate XML strings using LINQ to XML extension methods. Use this namespace when you need to validate XML strings or safely attempt XML parsing. Start with `TryParseXElement` on `IDecorator` for safe element-level XML parsing, or `IsXmlString` to check whether a string is valid XML. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [System.Xml.Linq namespace](https://docs.microsoft.com/en-us/dotnet/api/system.xml.linq?) 🔗 +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator|⬇️|`TryParseXElement`, `IsXmlString`| + Related: [Cuemon.Extensions.Xml.Linq namespace](/api/extensions/dotnet/Cuemon.Extensions.Xml.Linq.html) 📘 diff --git a/.docfx/api/namespaces/Cuemon.Xml.Serialization.Converters.md b/.docfx/api/namespaces/Cuemon.Xml.Serialization.Converters.md index 585a3769..be3e7ae8 100644 --- a/.docfx/api/namespaces/Cuemon.Xml.Serialization.Converters.md +++ b/.docfx/api/namespaces/Cuemon.Xml.Serialization.Converters.md @@ -2,8 +2,15 @@ uid: Cuemon.Xml.Serialization.Converters summary: *content --- -The `Cuemon.Xml.Serialization.Converters` namespace contains types tailored to resemble the [JsonConverter](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonConverter.htm) except we convert objects to and from XML. +Convert objects to and from XML using converters that follow the familiar [JsonConverter](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonConverter.htm) pattern from Newtonsoft.Json. Use this namespace when you need custom XML converter registration for strings, time spans, URIs, or custom types. Start with `AddStringConverter` or `AddXmlConverter` on `ICollection` to register XML converters. [!INCLUDE [availability-default](../../includes/availability-default.md)] Related: [Cuemon.Extensions.Xml.Serialization.Converters namespace](/api/dotnet/Cuemon.Xml.Serialization.Converters.html) 📘 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator>|⬇️|`AddStringConverter`, `AddTimeSpanConverter`, `AddUriConverter`, `AddXmlConverter`, `InsertXmlConverter`, `FirstOrDefaultReaderConverter`, `FirstOrDefaultWriterConverter`| +|IDecorator>|⬇️|`AddXmlConverter`, `InsertXmlConverter`, `AddEnumerableConverter`, `AddExceptionDescriptorConverter`, `AddDateTimeConverter`, `AddExceptionConverter`, `AddFailureConverter`| diff --git a/.docfx/api/namespaces/Cuemon.Xml.Serialization.Formatters.md b/.docfx/api/namespaces/Cuemon.Xml.Serialization.Formatters.md index ac0e7629..0cd42efd 100644 --- a/.docfx/api/namespaces/Cuemon.Xml.Serialization.Formatters.md +++ b/.docfx/api/namespaces/Cuemon.Xml.Serialization.Formatters.md @@ -2,6 +2,6 @@ uid: Cuemon.Xml.Serialization.Formatters summary: *content --- -The `Cuemon.Xml.Serialization.Formatters` namespace contains types that are used to serialize and deserialize objects into and from XML format using a generic signature. +Serialize and deserialize objects to and from XML through a generic formatter interface. Use this namespace when you need type-safe XML serialization with a generic signature. Start with the XML formatter type that wraps the Cuemon XML serializer for typed XML serialization. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Xml.Serialization.md b/.docfx/api/namespaces/Cuemon.Xml.Serialization.md index 4d119220..4b2b4d86 100644 --- a/.docfx/api/namespaces/Cuemon.Xml.Serialization.md +++ b/.docfx/api/namespaces/Cuemon.Xml.Serialization.md @@ -2,10 +2,16 @@ uid: Cuemon.Xml.Serialization summary: *content --- -The `Cuemon.Xml.Serialization` namespace contains types that are used to serialize and deserialize objects into and from XML format. The namespace is an addition to the `System.Xml.Serialization` namespace. +Serialize and deserialize objects to and from XML format with a flexible serializer framework. Use this namespace when you need XML serialization with options configuration. Start with `XmlSerializer` for serialization operations, or configure settings with `XmlSerializerOptions` and apply defaults via `ApplyToDefaultSettings`. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [System.Xml.Serialization namespace](https://docs.microsoft.com/en-us/dotnet/api/system.xml.serialization?view=netstandard-2.0) 🔗 +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator|⬇️|`ApplyToDefaultSettings`| + Related: [Cuemon.Extensions.Xml.Serialization namespace](/api/extensions/dotnet/Cuemon.Extensions.Xml.Serialization.html) 📘 diff --git a/.docfx/api/namespaces/Cuemon.Xml.XPath.md b/.docfx/api/namespaces/Cuemon.Xml.XPath.md index 6074e85f..65b53d84 100644 --- a/.docfx/api/namespaces/Cuemon.Xml.XPath.md +++ b/.docfx/api/namespaces/Cuemon.Xml.XPath.md @@ -2,7 +2,7 @@ uid: Cuemon.Xml.XPath summary: *content --- -The `Cuemon.Xml.XPath` namespace contains types related to easing creation of XPathDocument instances. The namespace is an addition to the `System.Xml.XPath` namespace. +Simplify creating `XPathDocument` instances from various data sources without manual XPath document construction. Use this namespace when you need to query structured data with XPath expressions. Start with `XPathDocumentFactory` for creating XPath documents, or the extension methods on `IXPathNavigable` for XPath-based data queries. [!INCLUDE [availability-default](../../includes/availability-default.md)] diff --git a/.docfx/api/namespaces/Cuemon.Xml.md b/.docfx/api/namespaces/Cuemon.Xml.md index 9022fc78..f24b6ec3 100644 --- a/.docfx/api/namespaces/Cuemon.Xml.md +++ b/.docfx/api/namespaces/Cuemon.Xml.md @@ -2,10 +2,21 @@ uid: Cuemon.Xml summary: *content --- -The `Cuemon.Xml` namespace contains types related to encoding, converting and serialization. The included lightweight XML serializer framework offers same flexibility as the one provided by the JSON equivalent from Newtonsoft. The namespace is an addition to the `System.Xml` namespace. +Serialize, encode, convert, and transform XML data with a lightweight XML serializer framework offering flexibility comparable to the JSON equivalent from Newtonsoft. Use this namespace when you need XML encoding detection, reader chunking, structured XML writing, or serialization. Start with `ToXmlReader` on `IDecorator` for XML parsing, or `EscapeXml` on `IDecorator` for XML-safe text. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [System.Xml namespace](https://docs.microsoft.com/en-us/dotnet/api/system.xml) 🔗 +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator>|⬇️|`HasXmlIgnoreAttribute`, `IsNodeEnumerable`, `GetXmlQualifiedEntity`, `TryGetXmlTextAttribute`, `TryGetXmlAttributeAttribute`, `TryGetXmlRootAttribute`, `TryGetXmlElementAttribute`| +|IDecorator>>|⬇️|`OrderByXmlAttributes`| +|IDecorator|⬇️|`ToXmlReader`, `TryDetectXmlEncoding`| +|IDecorator|⬇️|`EscapeXml`, `UnescapeXml`, `SanitizeXmlElementName`, `SanitizeXmlElementText`| +|IDecorator|⬇️|`Chunk`, `MoveToFirstElement`, `ToHierarchy`| +|IDecorator|⬇️|`WriteStartElement`, `WriteObject`, `WriteObject`, `WriteEncapsulatingElementIfNotNull`, `WriteXmlRootElement`, `WriteXmlRootElement`| + Related: [Cuemon.Extensions.Xml namespace](/api/extensions/dotnet/Cuemon.Extensions.Xml.html) 📘 diff --git a/.docfx/api/namespaces/Cuemon.md b/.docfx/api/namespaces/Cuemon.md index 4944532e..d448a240 100644 --- a/.docfx/api/namespaces/Cuemon.md +++ b/.docfx/api/namespaces/Cuemon.md @@ -2,10 +2,36 @@ uid: Cuemon summary: *content --- -The `Cuemon` namespace contains fundamental types such as value and reference types, factories and utility classes, interfaces, attributes and feature rich delegates to support functional programming to a whole new level. The namespace is an addition to the `System` namespace. +The `Cuemon` namespace is the root of the Cuemon for .NET framework. It provides foundational types — value types, reference types, factories, utility classes, interfaces, attributes, and rich delegates — that underpin every Cuemon package. Use these types when you need common utilities like `Decorator`, `DateSpan`, `StringUtility`, or the functional delegates that enable a more expressive coding style. + +If you are new to Cuemon for .NET, start with `Decorator` for wrapping and extending existing instances, `DateSpan` for human-readable date ranges, or the `Condition` delegate for predicate-based control flow. For extension methods on core .NET types, see the [Cuemon.Extensions namespace](/api/extensions/dotnet/Cuemon.Extensions.html). + +For mutable tuple scenarios, start with `MutableTuple` — the one-arity variant that serves as the anchor for all arity levels. Higher-arity variants (`MutableTuple` through `MutableTuple`) follow the same pattern; choose the arity that matches your number of tuple elements. + +For Try-style delegate scenarios, start with `TesterFunc` — the two-arity variant that serves as the anchor for the full family. Higher-arity variants follow the same pattern; choose the arity that matches your number of input parameters plus the result and success type parameters. + +For exception handling scenarios, start with `ExceptionHandler` (one type parameter) or `ExceptionHandler` (two type parameters). The one-parameter variant handles a single exception type, while the two-parameter variant handles distinct input and exception types. Choose the variant that matches your handler's input and exception requirements. + +For exception invocation scenarios, start with `ExceptionInvoker` to invoke operations with one type parameter or `ExceptionInvoker` for two type parameters. Higher-arity variants follow the same pattern; choose the arity that matches your exception handler's needs. [!INCLUDE [availability-default](../../includes/availability-default.md)] Complements: [System namespace](https://docs.microsoft.com/en-us/dotnet/api/system) 🔗 Related: [Cuemon.Extensions namespace](/api/extensions/dotnet/Cuemon.Extensions.html) 📘 + +### Extension Members + +|Type|Ext|Methods| +|--:|:-:|---| +|IDecorator|⬇️|`ToEncodedString`, `ToHexadecimalString`, `ToBinaryString`, `ToUrlEncodedBase64String`, `ToBase64String`, `TryDetectUnicodeEncoding`, `ToStream`| +|IDecorator>|⬇️|`ToEnumerable`, `ToStringEquivalent`| +|IDecorator|⬇️|`GetUnixEpoch`, `ToUnixEpochTime`, `ToUtcKind`, `ToLocalKind`, `ToDefaultKind`| +|IDecorator|⬇️|`ResolveDelegateInfo`| +|IDecorator|⬇️|`ToTimeSpan`| +|IDecorator|⬇️|`Flatten`| +|IDecorator|⬇️|`Max`, `Min`, `IsPrime`, `IsCountableSequence`, `IsEven`, `IsOdd`| +|IDecorator|⬇️|`ChangeType`, `ChangeType`, `ChangeTypeOrDefault`, `DefaultPropertyValueResolver`| +|IDecorator|⬇️|`Difference`, `ToByteArray`, `FromUrlEncodedBase64`, `ToCasing`, `ToAsciiEncodedString`, `ToStream`, `ToUri`, `StartsWith`, `ContainsAny`| +|IDecorator|⬇️|`TraverseWhileNotEmpty`| +|IDecorator|⬇️|`ToFriendlyName`, `IsNullable`, `IsComplex`, `IsSimple`, `HasAnonymousCharacteristics`, `HasDefaultConstructor`, `HasEqualityComparerImplementation`, `HasComparableImplementation`, `HasComparerImplementation`, `HasEnumerableImplementation`, `HasDictionaryImplementation`, `HasKeyValuePairImplementation`, `HasTypes`, `HasInterfaces`, `HasAttribute`, `HasCircularReference`, `MatchMember`, `GetDefaultValue`, `GetAllProperties`, `GetAllFields`, `GetAllEvents`, `GetAllMethods`, `GetRuntimePropertiesExceptOf`, `GetInheritedTypes`, `GetDerivedTypes`, `GetHierarchyTypes`| diff --git a/.docfx/api/namespaces/System.Runtime.CompilerServices.md b/.docfx/api/namespaces/System.Runtime.CompilerServices.md new file mode 100644 index 00000000..346c3077 --- /dev/null +++ b/.docfx/api/namespaces/System.Runtime.CompilerServices.md @@ -0,0 +1,9 @@ +--- +uid: System.Runtime.CompilerServices +summary: *content +--- +The `System.Runtime.CompilerServices` namespace within Cuemon for .NET provides polyfill types that bridge compiler feature gaps across target frameworks. The `CallerArgumentExpressionAttribute` type enables capturing argument expressions as strings for improved diagnostic and validation messages, supporting the .NET Standard 2.0 target where the runtime attribute is not available. + +[!INCLUDE [availability-default](../../includes/availability-default.md)] + +Complements: [System.Runtime.CompilerServices namespace](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices) 🔗 diff --git a/.docfx/api/types/Cuemon.ActionFactory`1.md b/.docfx/api/types/Cuemon.ActionFactory`1.md new file mode 100644 index 00000000..8f32b669 --- /dev/null +++ b/.docfx/api/types/Cuemon.ActionFactory`1.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.ActionFactory`1 +example: +- *content +--- + +The following example demonstrates how to use to wrap and invoke a delegate with n-tuple arguments. + +```csharp +using System; +using Cuemon; + +namespace MyApp.Examples; + +public class ActionFactoryExample +{ + public void Demonstrate() + { + // Create a mutable tuple with string and int arguments + var tuple = new MutableTuple("Hello", 42); + + // Define an action that processes the tuple + void Process(MutableTuple t) + { + Console.WriteLine($"Message: {t.Arg1}, Value: {t.Arg2}"); + + // Wrap the action and tuple in an ActionFactory + var factory = new ActionFactory>(Process, tuple); + + // Inspect factory state + Console.WriteLine(factory.HasDelegate); // True + Console.WriteLine(factory.GenericArguments.Arg1); // "Hello" + Console.WriteLine(factory.GenericArguments.Arg2); // 42 + + // Invoke the wrapped delegate + factory.ExecuteMethod(); // Output: "Message: Hello, Value: 42" + + // Create a clone for safe concurrent use + var clone = factory.Clone() as ActionFactory>; + clone?.ExecuteMethod(); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Alphanumeric.md b/.docfx/api/types/Cuemon.Alphanumeric.md new file mode 100644 index 00000000..10f946fa --- /dev/null +++ b/.docfx/api/types/Cuemon.Alphanumeric.md @@ -0,0 +1,23 @@ +--- +uid: Cuemon.Alphanumeric +example: +- *content +--- + +```csharp +using System; +using Cuemon; + +namespace MyApp.CharacterSets; + +public class AlphanumericExample +{ + public void Demonstrate() + { + Console.WriteLine(Alphanumeric.Numbers); // "0123456789" + Console.WriteLine(Alphanumeric.UppercaseLetters); // "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + Console.WriteLine(Alphanumeric.Hexadecimal); // "0123456789ABCDEF" + Console.WriteLine(Alphanumeric.PunctuationMarks); // "!@#$%^&*()_-+=[{]};:<>|.,/?`~\"'" + } +} +``` diff --git a/.docfx/api/types/Cuemon.ArgumentReservedKeywordException.md b/.docfx/api/types/Cuemon.ArgumentReservedKeywordException.md new file mode 100644 index 00000000..f1605534 --- /dev/null +++ b/.docfx/api/types/Cuemon.ArgumentReservedKeywordException.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.ArgumentReservedKeywordException +example: +- *content +--- + +```csharp +using System; +using Cuemon; + +namespace MyApp.Validation +{ + public class ReservedKeywordValidator + { + private static readonly string[] SqlReservedKeywords = new[] + { + "select", "insert", "update", "delete", "from", "where" + }; + + public static void ValidateColumnName(string paramName, string value) + { + if (Array.Exists(SqlReservedKeywords, + kw => string.Equals(kw, value, StringComparison.OrdinalIgnoreCase))) + { + throw new ArgumentReservedKeywordException(paramName, value, + "Value must not be a reserved SQL keyword."); + + // Usage: + // try { ValidateColumnName("sortBy", "select"); } + // catch (ArgumentReservedKeywordException ex) when (ex.ParamName == "sortBy") + // { + // Console.WriteLine($"Validation failed: {ex.Message}"); + // } + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.AuthenticationHandlerFeature.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.AuthenticationHandlerFeature.md new file mode 100644 index 00000000..471c3ddf --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.AuthenticationHandlerFeature.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.AspNetCore.Authentication.AuthenticationHandlerFeature +example: +- *content +--- + +The following example demonstrates how to keep the authenticate result and user principal synchronized on the current HTTP features. + +```csharp +using System; +using System.Security.Claims; +using Cuemon.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features.Authentication; + +namespace MyApp.Examples; + +public static class AuthenticationHandlerFeatureExample +{ + public static void Demonstrate() + { + var principal = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, "Agent") }, "Basic")); + var result = AuthenticateResult.Success(new AuthenticationTicket(principal, "Basic")); + var context = new DefaultHttpContext(); + + AuthenticationHandlerFeature.Set(result, context); + + var authenticateFeature = (AuthenticationHandlerFeature)context.Features.Get()!; + var httpAuthenticationFeature = (AuthenticationHandlerFeature)context.Features.Get()!; + + Console.WriteLine(authenticateFeature.AuthenticateResult == result); + Console.WriteLine(httpAuthenticationFeature.User.Identity?.Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Authenticator.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Authenticator.md new file mode 100644 index 00000000..e87b222c --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Authenticator.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Authenticator +example: +- *content +--- + +The following example demonstrates how to authenticate an HTTP request by parsing the `Authorization` header and resolving a claims principal. + +```csharp +using System; +using System.Security.Claims; +using Cuemon; +using Cuemon.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.Net.Http.Headers; + +namespace MyApp.Examples; + +public static class AuthenticatorExample +{ + public static void Demonstrate() + { + var context = new DefaultHttpContext() + { + Request = { IsHttps = true } + }; + context.Request.Headers.Append(HeaderNames.Authorization, "Basic YWxpY2U6cGFzc3dvcmQ="); + + var result = Authenticator.Authenticate(context, false, + (HttpContext _, string authorizationHeader) => authorizationHeader, + (HttpContext _, string credentials, out ConditionalValue principal) => + { + principal = new SuccessfulValue( + new ClaimsPrincipal(new ClaimsIdentity( + new[] { new Claim(ClaimTypes.Name, "alice") }, "Basic"))); + return true; + }); + + Console.WriteLine("Succeeded: " + result.Succeeded); + Console.WriteLine("User: " + result.Result?.Identity?.Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.AuthorizationHeaderOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.AuthorizationHeaderOptions.md new file mode 100644 index 00000000..e81ad7bd --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.AuthorizationHeaderOptions.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.AspNetCore.Authentication.AuthorizationHeaderOptions +example: +- *content +--- + +The following example demonstrates how to customize the delimiters used when parsing authorization header credentials. + +```csharp +using System; +using Cuemon.AspNetCore.Authentication; + +namespace MyApp.Examples; + +public static class AuthorizationHeaderOptionsExample +{ + public static void Demonstrate() + { + var options = new AuthorizationHeaderOptions + { + CredentialsDelimiter = ", ", + CredentialsKeyValueDelimiter = "=" + }; + + options.ValidateOptions(); + + Console.WriteLine(options.CredentialsDelimiter); + Console.WriteLine(options.CredentialsKeyValueDelimiter); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationHandler.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationHandler.md new file mode 100644 index 00000000..b87bc0b1 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationHandler.md @@ -0,0 +1,48 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationHandler +example: +- *content +--- + +The following example demonstrates how to register `BasicAuthenticationHandler` with ASP.NET Core authentication services. + +```csharp +using System; +using System.Security.Claims; +using Cuemon.AspNetCore.Authentication.Basic; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples; + +public static class BasicAuthenticationHandlerExample +{ + public static void Demonstrate() + { + var services = new ServiceCollection(); + + services.AddLogging(); + services.AddAuthentication(BasicAuthorizationHeader.Scheme) + .AddScheme(BasicAuthorizationHeader.Scheme, options => + { + options.Realm = "docs-example"; + options.RequireSecureConnection = false; + options.Authenticator = (username, password) => + { + if (username == "Agent" && password == "Test") + { + return new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, BasicAuthorizationHeader.Scheme)); + } + + return null; + }; + }); + + using var provider = services.BuildServiceProvider(); + var handler = provider.GetRequiredService(); + + Console.WriteLine(handler.GetType().Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationMiddleware.md new file mode 100644 index 00000000..8aa46f3d --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationMiddleware.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationMiddleware +example: +- *content +--- + +The following example demonstrates how to construct `BasicAuthenticationMiddleware` with inline option setup. + +```csharp +using System; +using System.Threading.Tasks; +using Cuemon.AspNetCore.Authentication.Basic; + +namespace MyApp.Examples; + +public static class BasicAuthenticationMiddlewareExample +{ + public static void Demonstrate() + { + var middleware = new BasicAuthenticationMiddleware(_ => Task.CompletedTask, options => + { + options.Realm = "docs-example"; + options.RequireSecureConnection = false; + options.Authenticator = (username, password) => null; + }); + + Console.WriteLine(middleware.Options.Realm); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationOptions.md new file mode 100644 index 00000000..cb584a67 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationOptions.md @@ -0,0 +1,41 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationOptions +example: +- *content +--- + +The following example demonstrates how to configure `BasicAuthenticationOptions` with a realm and authenticator delegate. + +```csharp +using System; +using System.Security.Claims; +using Cuemon.AspNetCore.Authentication.Basic; + +namespace MyApp.Examples; + +public static class BasicAuthenticationOptionsExample +{ + public static void Demonstrate() + { + var options = new BasicAuthenticationOptions + { + Realm = "docs-example", + RequireSecureConnection = false, + Authenticator = (username, password) => + { + if (username == "Agent" && password == "Test") + { + return new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, BasicAuthorizationHeader.Scheme)); + } + + return null; + } + }; + + options.ValidateOptions(); + + Console.WriteLine(options.Realm); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticator.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticator.md new file mode 100644 index 00000000..80999bf5 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticator.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticator +example: +- *content +--- + +The following example demonstrates how to assign and invoke a delegate when validating a basic-auth username and password pair. + +```csharp +using System; +using System.Security.Claims; +using Cuemon.AspNetCore.Authentication.Basic; + +namespace MyApp.Examples; + +public static class BasicAuthenticatorExample +{ + public static void Demonstrate() + { + BasicAuthenticator authenticator = (username, password) => + { + return username == "Agent" && password == "Test" + ? new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, BasicAuthorizationHeader.Scheme)) + : null; + }; + + var principal = authenticator("Agent", "Test"); + + Console.WriteLine(principal?.Identity?.Name); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthorizationHeader.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthorizationHeader.md new file mode 100644 index 00000000..8579b0b9 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthorizationHeader.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Basic.BasicAuthorizationHeader +example: +- *content +--- + +The following example demonstrates how to serialize and parse a Basic authorization header. + +```csharp +using System; +using Cuemon.AspNetCore.Authentication.Basic; + +namespace MyApp.Examples; + +public static class BasicAuthorizationHeaderExample +{ + public static void Demonstrate() + { + var header = new BasicAuthorizationHeader("Agent", "Test"); + var parsed = BasicAuthorizationHeader.Create(header.ToString()); + + Console.WriteLine(parsed.UserName); + Console.WriteLine(parsed.Password); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthorizationHeaderBuilder.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthorizationHeaderBuilder.md new file mode 100644 index 00000000..6a3a78d0 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthorizationHeaderBuilder.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Basic.BasicAuthorizationHeaderBuilder +example: +- *content +--- + +The following example demonstrates how to build a Basic Authorization header value using `BasicAuthorizationHeaderBuilder`. + +```csharp +using Cuemon.AspNetCore.Authentication.Basic; + +namespace MyApp.Examples; + +public class BasicAuthorizationHeaderBuilderExample +{ + public void Demonstrate() + { + var builder = new BasicAuthorizationHeaderBuilder(); + builder.AddUserName("alice"); + builder.AddPassword("password"); + var headerValue = builder.Build(); // "Basic YWxpY2U6cGFzc3dvcmQ=" + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicFields.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicFields.md new file mode 100644 index 00000000..31ea9921 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicFields.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Basic.BasicFields +example: +- *content +--- + +The following example demonstrates how to use the field constants of `BasicFields` to construct a Basic authorization header. + +```csharp +using System; +using Cuemon.AspNetCore.Authentication.Basic; + +namespace MyApp.Examples; + +public static class BasicFieldsExample +{ + public static void Demonstrate() + { + var builder = new BasicAuthorizationHeaderBuilder(); + builder.AddUserName("alice"); + builder.AddPassword("s3cret"); + var header = builder.Build(); + + Console.WriteLine(BasicAuthorizationHeader.Scheme); + Console.WriteLine(BasicFields.Realm); + Console.WriteLine(BasicFields.Credentials); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationHandler.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationHandler.md new file mode 100644 index 00000000..df61f0b8 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationHandler.md @@ -0,0 +1,48 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationHandler +example: +- *content +--- + +The following example demonstrates how to register `DigestAuthenticationHandler` with ASP.NET Core authentication services. + +```csharp +using System; +using System.Security.Claims; +using Cuemon.AspNetCore.Authentication; +using Cuemon.AspNetCore.Authentication.Digest; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples; + +public static class DigestAuthenticationHandlerExample +{ + public static void Demonstrate() + { + var services = new ServiceCollection(); + + services.AddLogging(); + services.AddSingleton(); + services.AddAuthentication(DigestAuthorizationHeader.Scheme) + .AddScheme(DigestAuthorizationHeader.Scheme, options => + { + options.Realm = "docs-example"; + options.RequireSecureConnection = false; + options.Authenticator = (string username, out string password) => + { + password = username == "Agent" ? "Test" : null; + return password == null + ? null + : new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, DigestAuthorizationHeader.Scheme)); + }; + }); + + using var provider = services.BuildServiceProvider(); + var handler = provider.GetRequiredService(); + + Console.WriteLine(handler.GetType().Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationMiddleware.md new file mode 100644 index 00000000..afa669c8 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationMiddleware.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationMiddleware +example: +- *content +--- + +The following example demonstrates how to construct `DigestAuthenticationMiddleware` with inline option setup. + +```csharp +using System; +using System.Security.Claims; +using System.Threading.Tasks; +using Cuemon.AspNetCore.Authentication.Digest; + +namespace MyApp.Examples; + +public static class DigestAuthenticationMiddlewareExample +{ + public static void Demonstrate() + { + var middleware = new DigestAuthenticationMiddleware(_ => Task.CompletedTask, options => + { + options.Realm = "docs-example"; + options.RequireSecureConnection = false; + options.Authenticator = (string username, out string password) => + { + password = username == "Agent" ? "Test" : null; + return password == null ? null : new ClaimsPrincipal(new ClaimsIdentity()); + }; + }); + + Console.WriteLine(middleware.Options.Realm); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationOptions.md new file mode 100644 index 00000000..e81f8956 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationOptions.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationOptions +example: +- *content +--- + +The following example demonstrates how to configure `DigestAuthenticationOptions` with a realm, digest algorithm, and authenticator delegate. + +```csharp +using System; +using System.Security.Claims; +using Cuemon.AspNetCore.Authentication.Digest; + +namespace MyApp.Examples; + +public static class DigestAuthenticationOptionsExample +{ + public static void Demonstrate() + { + var options = new DigestAuthenticationOptions + { + DigestAlgorithm = DigestCryptoAlgorithm.Sha256, + Realm = "docs-example", + RequireSecureConnection = false, + Authenticator = (string username, out string password) => + { + password = username == "Agent" ? "Test" : null; + return password == null + ? null + : new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, DigestAuthorizationHeader.Scheme)); + } + }; + + options.ValidateOptions(); + + Console.WriteLine(options.DigestAlgorithm); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticator.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticator.md new file mode 100644 index 00000000..b799cd91 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticator.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticator +example: +- *content +--- + +The following example demonstrates how to assign and invoke a delegate when a digest-auth username resolves to a stored password. + +```csharp +using System; +using System.Security.Claims; +using Cuemon.AspNetCore.Authentication.Digest; + +namespace MyApp.Examples; + +public static class DigestAuthenticatorExample +{ + public static void Demonstrate() + { + DigestAuthenticator authenticator = (string username, out string password) => + { + password = username == "Agent" ? "Test" : null; + return password == null + ? null + : new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, DigestAuthorizationHeader.Scheme)); + }; + + var principal = authenticator("Agent", out var password); + + Console.WriteLine(password); + Console.WriteLine(principal?.Identity?.Name); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthorizationHeader.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthorizationHeader.md new file mode 100644 index 00000000..cb9dbd30 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthorizationHeader.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Digest.DigestAuthorizationHeader +example: +- *content +--- + +The following example demonstrates how to serialize and parse a Digest access authentication header. + +```csharp +using System; +using Cuemon.AspNetCore.Authentication.Digest; + +namespace MyApp.Examples; + +public static class DigestAuthorizationHeaderExample +{ + public static void Demonstrate() + { + var header = new DigestAuthorizationHeader( + realm: "docs-example", + nonce: "abc123", + opaque: "opaque456", + algorithm: "SHA-256", + userName: "Agent", + uri: "/resource", + nc: "00000001", + cNonce: "client-nonce", + qop: "auth", + response: "deadbeef"); + + var parsed = DigestAuthorizationHeader.Create(header.ToString()); + + Console.WriteLine(parsed.UserName); + Console.WriteLine(parsed.Response); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthorizationHeaderBuilder.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthorizationHeaderBuilder.md new file mode 100644 index 00000000..01f80d66 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthorizationHeaderBuilder.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Digest.DigestAuthorizationHeaderBuilder +example: +- *content +--- + +The following example demonstrates how to build a Digest access authorization header from a challenge header. + +```csharp +using System; +using Cuemon.AspNetCore.Authentication.Digest; +using Microsoft.AspNetCore.Http; +using Microsoft.Net.Http.Headers; + +namespace MyApp.Examples; + +public static class DigestAuthorizationHeaderBuilderExample +{ + public static void Demonstrate() + { + var headers = new HeaderDictionary + { + [HeaderNames.WWWAuthenticate] = "Digest realm=\"docs-example\", qop=\"auth, auth-int\", nonce=\"abc123\", opaque=\"opaque456\", stale=false, algorithm=SHA-256" + }; + + var builder = new DigestAuthorizationHeaderBuilder(DigestCryptoAlgorithm.Sha256) + .AddRealm("docs-example") + .AddUserName("Agent") + .AddUri("/resource") + .AddNc(1) + .AddCnonce("client-nonce") + .AddQopAuthentication() + .AddFromWwwAuthenticateHeader(headers) + .AddResponse("Test", "GET"); + + var header = builder.Build(); + + Console.WriteLine(header.ToString()); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestCryptoAlgorithm.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestCryptoAlgorithm.md new file mode 100644 index 00000000..a14d5bc3 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestCryptoAlgorithm.md @@ -0,0 +1,25 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Digest.DigestCryptoAlgorithm +example: +- *content +--- + +The following example demonstrates how `DigestCryptoAlgorithm` selects the hash algorithm used by `DigestAuthorizationHeaderBuilder`. + +```csharp +using System; +using Cuemon.AspNetCore.Authentication.Digest; + +namespace MyApp.Examples; + +public static class DigestCryptoAlgorithmExample +{ + public static void Demonstrate() + { + var builder = new DigestAuthorizationHeaderBuilder(DigestCryptoAlgorithm.Sha512Slash256); + + Console.WriteLine(builder.DigestAlgorithm); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestFields.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestFields.md new file mode 100644 index 00000000..2b200b8b --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestFields.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Digest.DigestFields +example: +- *content +--- + +The following example demonstrates how to use the field constants of `DigestFields` when building a Digest access authorization header. + +```csharp +using System; +using Cuemon.AspNetCore.Authentication.Digest; + +namespace MyApp.Examples; + +public static class DigestFieldsExample +{ + public static void Demonstrate() + { + var builder = new DigestAuthorizationHeaderBuilder(DigestCryptoAlgorithm.Sha256); + builder.AddRealm("my-realm"); + builder.AddUserName("alice"); + builder.AddUri("/api/resource"); + builder.AddNc(1); + builder.AddCnonce(Guid.NewGuid().ToString("N")); + + Console.WriteLine(DigestFields.Realm); + Console.WriteLine(DigestFields.Nonce); + Console.WriteLine(DigestFields.QualityOfProtection); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestHashFactory.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestHashFactory.md new file mode 100644 index 00000000..23b1bdd1 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestHashFactory.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Digest.DigestHashFactory +example: +- *content +--- + +The following example demonstrates how to create a cryptographic hash instance using `DigestHashFactory` with a specified algorithm. + +```csharp +using System; +using System.Text; +using Cuemon.AspNetCore.Authentication.Digest; +using Cuemon.Security; + +namespace MyApp.Examples; + +public static class DigestHashFactoryExample +{ + public static void Demonstrate() + { + Hash hash = DigestHashFactory.CreateCrypto(DigestCryptoAlgorithm.Sha256); + + var bytes = Encoding.UTF8.GetBytes("hello-world"); + var result = hash.ComputeHash(bytes); + + Console.WriteLine(result.ToHexadecimalString()); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationHandler.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationHandler.md new file mode 100644 index 00000000..23f130d6 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationHandler.md @@ -0,0 +1,47 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationHandler +example: +- *content +--- + +The following example demonstrates how to register `HmacAuthenticationHandler` with ASP.NET Core authentication services. + +```csharp +using System; +using System.Security.Claims; +using Cuemon.AspNetCore.Authentication.Hmac; +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples; + +public static class HmacAuthenticationHandlerExample +{ + public static void Demonstrate() + { + const string authenticationScheme = "hmac-docs"; + var services = new ServiceCollection(); + + services.AddLogging(); + services.AddAuthentication(authenticationScheme) + .AddScheme(authenticationScheme, options => + { + options.AuthenticationScheme = authenticationScheme; + options.RequireSecureConnection = false; + options.Authenticator = (string clientId, out string clientSecret) => + { + clientSecret = clientId == "Agent-Api" ? "Test" : null; + return clientSecret == null + ? null + : new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, clientId) }, authenticationScheme)); + }; + }); + + using var provider = services.BuildServiceProvider(); + var handler = provider.GetRequiredService(); + + Console.WriteLine(handler.GetType().Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationMiddleware.md new file mode 100644 index 00000000..a3954f91 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationMiddleware.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationMiddleware +example: +- *content +--- + +The following example demonstrates how to construct `HmacAuthenticationMiddleware` with inline option setup. + +```csharp +using System; +using System.Security.Claims; +using System.Threading.Tasks; +using Cuemon.AspNetCore.Authentication.Hmac; + +namespace MyApp.Examples; + +public static class HmacAuthenticationMiddlewareExample +{ + public static void Demonstrate() + { + var middleware = new HmacAuthenticationMiddleware(_ => Task.CompletedTask, options => + { + options.AuthenticationScheme = "hmac-docs"; + options.RequireSecureConnection = false; + options.Authenticator = (string clientId, out string clientSecret) => + { + clientSecret = clientId == "Agent-Api" ? "Test" : null; + return clientSecret == null ? null : new ClaimsPrincipal(new ClaimsIdentity()); + }; + }); + + Console.WriteLine(middleware.Options.AuthenticationScheme); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationOptions.md new file mode 100644 index 00000000..7922776e --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationOptions.md @@ -0,0 +1,41 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationOptions +example: +- *content +--- + +The following example demonstrates how to configure `HmacAuthenticationOptions` for HMAC request signing. + +```csharp +using System; +using System.Security.Claims; +using Cuemon.AspNetCore.Authentication.Hmac; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public static class HmacAuthenticationOptionsExample +{ + public static void Demonstrate() + { + var options = new HmacAuthenticationOptions + { + AuthenticationScheme = "hmac-docs", + Algorithm = KeyedCryptoAlgorithm.HmacSha256, + RequireSecureConnection = false, + Authenticator = (string clientId, out string clientSecret) => + { + clientSecret = clientId == "Agent-Api" ? "Test" : null; + return clientSecret == null + ? null + : new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, clientId) }, "hmac-docs")); + } + }; + + options.ValidateOptions(); + + Console.WriteLine(options.AuthenticationScheme); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticator.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticator.md new file mode 100644 index 00000000..24b275a9 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticator.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticator +example: +- *content +--- + +The following example demonstrates how to assign and invoke a delegate for client-id and shared-secret lookup. + +```csharp +using System; +using System.Security.Claims; +using Cuemon.AspNetCore.Authentication.Hmac; + +namespace MyApp.Examples; + +public static class HmacAuthenticatorExample +{ + public static void Demonstrate() + { + HmacAuthenticator authenticator = (string clientId, out string clientSecret) => + { + clientSecret = clientId == "Agent-Api" ? "Test" : null; + return clientSecret == null + ? null + : new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, clientId) }, HmacFields.Scheme)); + }; + + var principal = authenticator("Agent-Api", out var secret); + + Console.WriteLine(secret); + Console.WriteLine(principal?.Identity?.Name); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthorizationHeader.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthorizationHeader.md new file mode 100644 index 00000000..a15f110d --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthorizationHeader.md @@ -0,0 +1,24 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Hmac.HmacAuthorizationHeader +example: +- *content +--- + +The following example demonstrates how to parse an HMAC Authorization header value. + +```csharp +using Cuemon.AspNetCore.Authentication.Hmac; + +namespace MyApp.Examples; + +public class HmacAuthorizationHeaderExample +{ + public void Demonstrate() + { + var header = HmacAuthorizationHeader.Create( + HmacFields.Scheme, + "HMAC Credential=alice/some-scope, SignedHeaders=date;host, Signature=abc123"); + var clientId = header.ClientId; // "alice" + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthorizationHeaderBuilder.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthorizationHeaderBuilder.md new file mode 100644 index 00000000..dee289fa --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthorizationHeaderBuilder.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Hmac.HmacAuthorizationHeaderBuilder +example: +- *content +--- + +The following example demonstrates how to build an HMAC authorization header for an outgoing HTTP request. + +```csharp +using System; +using System.Globalization; +using System.Net.Http; +using Cuemon.AspNetCore.Authentication.Hmac; + +namespace MyApp.Examples; + +public static class HmacAuthorizationHeaderBuilderExample +{ + public static void Demonstrate() + { + using var request = new HttpRequestMessage(HttpMethod.Get, "https://api.cuemon.net/resource?name=Agent"); + request.Headers.Date = DateTimeOffset.Parse("2022-07-10T12:50:42Z", CultureInfo.InvariantCulture); + request.Headers.Host = "api.cuemon.net"; + + var builder = new HmacAuthorizationHeaderBuilder() + .AddFromRequest(request) + .AddClientId("Agent-Api") + .AddClientSecret("Test") + .AddCredentialScope("20220710/us-east-1/docs/request"); + + var header = builder.Build(); + + Console.WriteLine(header.ToString()); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacFields.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacFields.md new file mode 100644 index 00000000..a88ff94b --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacFields.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.AspNetCore.Authentication.Hmac.HmacFields +example: +- *content +--- + +The following example demonstrates how to reference the field constants of `HmacFields` when building an HMAC authorization header. + +```csharp +using System; +using System.Net.Http; +using Cuemon.AspNetCore.Authentication.Hmac; + +namespace MyApp.Examples; + +public static class HmacFieldsExample +{ + public static void Demonstrate() + { + using var request = new HttpRequestMessage(HttpMethod.Get, "https://api.example.com/resource"); + request.Headers.Date = DateTimeOffset.UtcNow; + request.Headers.Host = "api.example.com"; + + var builder = new HmacAuthorizationHeaderBuilder() + .AddFromRequest(request) + .AddClientId("my-client") + .AddClientSecret("my-secret") + .AddCredentialScope("20250101/us-east-1/service/aws4_request"); + + var header = builder.Build(); + + Console.WriteLine(HmacFields.Scheme); + Console.WriteLine(HmacFields.SignedHeaders); + Console.WriteLine(HmacFields.CanonicalRequest); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.MemoryNonceTracker.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.MemoryNonceTracker.md new file mode 100644 index 00000000..3983b3f7 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.MemoryNonceTracker.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.AspNetCore.Authentication.MemoryNonceTracker +example: +- *content +--- + +The following example demonstrates how to add, inspect, and remove nonce entries from the in-memory tracker. + +```csharp +using System; +using Cuemon.AspNetCore.Authentication; + +namespace MyApp.Examples; + +public static class MemoryNonceTrackerExample +{ + public static void Demonstrate() + { + using var tracker = new MemoryNonceTracker(); + + tracker.TryAddEntry("nonce-1", 7); + + if (tracker.TryGetEntry("nonce-1", out var entry)) + { + Console.WriteLine(entry.Count); + } + + Console.WriteLine(tracker.TryRemoveEntry("nonce-1")); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.NonceTrackerEntry.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.NonceTrackerEntry.md new file mode 100644 index 00000000..7668f890 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.NonceTrackerEntry.md @@ -0,0 +1,24 @@ +--- +uid: Cuemon.AspNetCore.Authentication.NonceTrackerEntry +example: +- *content +--- + +The following example demonstrates a nonce tracker entry that holds nonce data for authentication. + +```csharp +using System; +using Cuemon.AspNetCore.Authentication; + +namespace MyApp.Examples; + +public class NonceTrackerEntryExample +{ + public void Demonstrate() + { + var entry = new NonceTrackerEntry(1, DateTime.UtcNow); + Console.WriteLine($"Count: {entry.Count}, Created: {entry.Created}"); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Builder.MiddlewareBuilderFactory.md b/.docfx/api/types/Cuemon.AspNetCore.Builder.MiddlewareBuilderFactory.md new file mode 100644 index 00000000..aee815b3 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Builder.MiddlewareBuilderFactory.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.AspNetCore.Builder.MiddlewareBuilderFactory +example: +- *content +--- + +The following example demonstrates how to register a custom middleware in the application pipeline using `MiddlewareBuilderFactory`. + +```csharp +using System; +using System.Diagnostics; +using System.Threading.Tasks; +using Cuemon.AspNetCore.Builder; +using Cuemon.AspNetCore; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; + +namespace MyApp.Examples; + +public class TimingMiddleware : Middleware +{ + public TimingMiddleware(RequestDelegate next) : base(next) { } + + public override async Task InvokeAsync(HttpContext context) + { + var sw = Stopwatch.StartNew(); + await Next(context); + sw.Stop(); + Console.WriteLine($"{context.Request.Path} took {sw.ElapsedMilliseconds} ms"); + } +} + +public static class MiddlewareBuilderFactoryExample +{ + public static void Demonstrate() + { + var builder = WebApplication.CreateBuilder().Build(); + + MiddlewareBuilderFactory.UseMiddleware(builder); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Configuration.CacheBustingOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Configuration.CacheBustingOptions.md new file mode 100644 index 00000000..c3a31f76 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Configuration.CacheBustingOptions.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.AspNetCore.Configuration.CacheBustingOptions +example: +- *content +--- + +The following example demonstrates how to configure cache-busting options for static resources. + +```csharp +using System; +using Cuemon.Configuration; + + namespace Cuemon.AspNetCore.Configuration; + + public static class CacheBustingOptionsExample + { + public static void Demonstrate() + { + var options = new CacheBustingOptions + { + PreferredCasing = CasingMethod.UpperCase + }; + + Console.WriteLine(options.PreferredCasing); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Configuration.DynamicCacheBusting.md b/.docfx/api/types/Cuemon.AspNetCore.Configuration.DynamicCacheBusting.md new file mode 100644 index 00000000..4d1676bf --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Configuration.DynamicCacheBusting.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.AspNetCore.Configuration.DynamicCacheBusting +example: +- *content +--- + +The following example demonstrates how to use `DynamicCacheBusting` to resolve versioned static resource URLs at runtime. + +```csharp +using System; +using Cuemon; +using Cuemon.AspNetCore.Configuration; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public class DynamicCacheBustingExample +{ + public void Demonstrate() + { + var options = Options.Create(new DynamicCacheBustingOptions + { + PreferredLength = 8, + PreferredCharacters = Alphanumeric.LettersAndNumbers, + TimeToLive = TimeSpan.FromHours(12) + }); + + var cacheBusting = new DynamicCacheBusting(options); + + // Version is regenerated when the configured TimeToLive has elapsed. + string version = cacheBusting.Version; + Console.WriteLine(version); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Configuration.DynamicCacheBustingOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Configuration.DynamicCacheBustingOptions.md new file mode 100644 index 00000000..797d1ba2 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Configuration.DynamicCacheBustingOptions.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.AspNetCore.Configuration.DynamicCacheBustingOptions +example: +- *content +--- + +The following example demonstrates configuration options for dynamic cache busting. + +```csharp +using System; +using Cuemon.Configuration; +using Microsoft.Extensions.Options; + + namespace Cuemon.AspNetCore.Configuration; + + public static class DynamicCacheBustingOptionsExample + { + public static void Demonstrate() + { + var options = new DynamicCacheBustingOptions + { + PreferredCasing = CasingMethod.UpperCase, + PreferredLength = 6, + TimeToLive = TimeSpan.FromMinutes(5) + }; + + var cacheBusting = new DynamicCacheBusting(Options.Create(options)); + Console.WriteLine(cacheBusting.Version); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptions.md new file mode 100644 index 00000000..8171e897 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptions.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptions +example: +- *content +--- + +The following example demonstrates how to configure fault descriptor options for structured error responses. + +```csharp +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.Diagnostics; + +namespace MyApp.Examples; + +public class FaultDescriptorOptionsExample +{ + public void Demonstrate() + { + var options = new FaultDescriptorOptions + { + SensitivityDetails = FaultSensitivityDetails.FailureWithStackTrace, + RootHelpLink = new System.Uri("https://example.com/errors") + }; + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptionsDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptionsDecoratorExtensions.md new file mode 100644 index 00000000..a42ca3f7 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptionsDecoratorExtensions.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptionsDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the `FaultDescriptorOptions` decorator extensions to try resolving an HTTP exception descriptor from a failure. + +```csharp +using System; +using Cuemon; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.AspNetCore.Http; +using Microsoft.AspNetCore.Http; + +namespace MyApp.Examples; + +public class FaultDescriptorOptionsDecoratorExtensionsExample +{ + public void Demonstrate(HttpContext context) + { + var options = new FaultDescriptorOptions(); + var failure = new BadRequestException("Bad request"); + Decorator.Enclose(options).TryResolveHttpExceptionDescriptor( + failure, + context, + descriptor => Console.WriteLine("Resolved descriptor"), + out var descriptor); + Console.WriteLine(descriptor.StatusCode); // 400 + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptor.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptor.md new file mode 100644 index 00000000..247876f3 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptor.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptor +example: +- *content +--- + +The following example demonstrates creating an HTTP exception descriptor with diagnostic evidence. + +```csharp +using System; +using Cuemon.AspNetCore.Http; + + namespace Cuemon.AspNetCore.Diagnostics; + + public static class HttpExceptionDescriptorExample + { + public static void Demonstrate() + { + var descriptor = new HttpExceptionDescriptor(new BadRequestException()) + { + Instance = new Uri("urn:request:42"), + RequestId = "req-42", + CorrelationId = "corr-42" + }; + + Console.WriteLine($"{descriptor.StatusCode} {descriptor.Message}"); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorDecoratorExtensions.md new file mode 100644 index 00000000..cc1a1a3a --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorDecoratorExtensions.md @@ -0,0 +1,33 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to convert an `HttpExceptionDescriptor` to a `ProblemDetails` instance using the decorator extensions. + +```csharp +using System; +using Cuemon; +using Cuemon.AspNetCore.Http; +using Cuemon.Diagnostics; +using Microsoft.AspNetCore.Mvc; + + namespace Cuemon.AspNetCore.Diagnostics; + + public static class HttpExceptionDescriptorDecoratorExtensionsExample + { + public static void Demonstrate() + { + var descriptor = new HttpExceptionDescriptor(new BadRequestException()) + { + CorrelationId = "corr-42", + RequestId = "req-42", + TraceId = "trace-42" + }; + + ProblemDetails problem = Decorator.Enclose(descriptor).ToProblemDetails(FaultSensitivityDetails.None); + Console.WriteLine(problem.Title); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseFormatter`1.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseFormatter`1.md new file mode 100644 index 00000000..21940db2 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseFormatter`1.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseFormatter`1 +example: +- *content +--- + +The following example demonstrates how to use to support content negotiation for exceptions. + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using Cuemon.Configuration; +using Cuemon.Net.Http; + +namespace Cuemon.AspNetCore.Diagnostics; + +public static class HttpExceptionDescriptorResponseFormatterExample +{ + public static void Demonstrate() + { + var formatter = new HttpExceptionDescriptorResponseFormatter(_ => { }); + + formatter.Populate((exceptionDescriptor, mediaType) => + new StringContent($"{exceptionDescriptor.StatusCode}:{mediaType.MediaType}")); + + var exceptionDescriptor = new HttpExceptionDescriptor( + new InvalidOperationException("boom"), + 418, + "Teapot", + "Short and stout"); + + using var response = formatter.ExceptionDescriptorHandlers.First().ToHttpResponseMessage(exceptionDescriptor); + Console.WriteLine(response.Content.ReadAsStringAsync().GetAwaiter().GetResult()); + } + + private sealed class SampleFormatterOptions : IContentNegotiation, IParameterObject + { + public IReadOnlyCollection SupportedMediaTypes { get; } = + new[] { new MediaTypeHeaderValue("text/plain") }; + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandler.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandler.md new file mode 100644 index 00000000..7541540e --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandler.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandler +example: +- *content +--- + +The following example demonstrates how to use `HttpExceptionDescriptorResponseHandler` to write structured error responses. + +```csharp +using System; +using Cuemon.AspNetCore.Http; +using Cuemon.Diagnostics; + + namespace Cuemon.AspNetCore.Diagnostics; + + public static class HttpExceptionDescriptorResponseHandlerExample + { + public static void Demonstrate() + { + var handler = HttpExceptionDescriptorResponseHandler.CreateDefaultFallbackHandler(FaultSensitivityDetails.None); + var exceptionDescriptor = new HttpExceptionDescriptor(new BadRequestException()); + + using var response = handler.ToHttpResponseMessage(exceptionDescriptor); + Console.WriteLine($"{(int)response.StatusCode} {handler.ContentType.MediaType}"); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerDecoratorExtensions.md new file mode 100644 index 00000000..b6aea346 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerDecoratorExtensions.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to register additional HTTP exception descriptor response handlers using the decorator pattern. + +```csharp +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using Cuemon; +using Cuemon.AspNetCore.Diagnostics; + +namespace MyApp.Examples; + +public class HttpExceptionDescriptorResponseHandlerDecoratorExtensionsExample +{ + public void Demonstrate() + { + var handler = new HttpExceptionDescriptorResponseHandler( + new MediaTypeHeaderValue("application/json"), + ed => new HttpResponseMessage(HttpStatusCode.InternalServerError) + { + Content = new StringContent(ed.Message) + }); + var list = new List { handler }; + + Decorator.Enclose(list).AddResponseHandler(o => + { + o.ContentType = new MediaTypeHeaderValue("application/json"); + o.ContentFactory = ed => new StringContent(ed.Message); + o.StatusCodeFactory = ed => HttpStatusCode.InternalServerError; + }); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerOptions.md new file mode 100644 index 00000000..d0f3e24b --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerOptions.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerOptions +example: +- *content +--- + +The following example demonstrates response handler options for HTTP exception descriptors. + +```csharp +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; + + namespace Cuemon.AspNetCore.Diagnostics; + + public static class HttpExceptionDescriptorResponseHandlerOptionsExample + { + public static void Demonstrate() + { + var options = new HttpExceptionDescriptorResponseHandlerOptions + { + ContentType = new MediaTypeHeaderValue("text/plain"), + ContentFactory = exceptionDescriptor => new StringContent(exceptionDescriptor.Message), + StatusCodeFactory = exceptionDescriptor => (HttpStatusCode)exceptionDescriptor.StatusCode + }; + + options.ValidateOptions(); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpFaultResolver.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpFaultResolver.md new file mode 100644 index 00000000..84c549ce --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpFaultResolver.md @@ -0,0 +1,33 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.HttpFaultResolver +example: +- *content +--- + +The following example demonstrates how to create an HTTP fault resolver that maps exceptions to HTTP error responses. + +```csharp +using System; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.Diagnostics; + +namespace MyApp.Examples; + +public class HttpFaultResolverExample +{ + public void Demonstrate() + { + var resolver = new HttpFaultResolver( + exception => exception is ArgumentNullException, + exception => new HttpExceptionDescriptor(exception, 400, null, "Argument was null.")); + + if (resolver.TryResolveFault(new ArgumentNullException("value"), out var descriptor)) + { + Console.WriteLine(descriptor.StatusCode); // 400 + } + + var resolved = resolver.TryResolveFault(new InvalidOperationException(), out _); + Console.WriteLine(resolved); // False + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpFaultResolverDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpFaultResolverDecoratorExtensions.md new file mode 100644 index 00000000..3c115fac --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpFaultResolverDecoratorExtensions.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.HttpFaultResolverDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to register fault resolvers using the decorator pattern over a list of `HttpFaultResolver`. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.AspNetCore.Http; + +using Cuemon; +namespace Examples; + +public class FaultResolverRegistrationExample +{ + public IList RegisterResolvers() + { + var resolvers = new List(); + + // Add a resolver for NotFoundException (404) + Decorator.Enclose(resolvers).AddHttpFaultResolver( + message: "The requested resource was not found.", + helpLink: new Uri("https://example.com/errors/404")); + + // Add a resolver for UnauthorizedException (401) with a custom code + Decorator.Enclose(resolvers).AddHttpFaultResolver( + statusCode: 401, + code: "UNAUTHORIZED", + message: "Authentication is required."); + + return resolvers; + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpRequestEvidence.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpRequestEvidence.md new file mode 100644 index 00000000..b5c725ee --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpRequestEvidence.md @@ -0,0 +1,61 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.HttpRequestEvidence +example: +- *content +--- + +The following example demonstrates how to capture HTTP request evidence, including headers, query parameters, form data, and the request body, for diagnostic purposes. + +```csharp +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Cuemon.AspNetCore.Diagnostics; +using Microsoft.Extensions.Primitives; +using Microsoft.AspNetCore.Http; + +namespace MyApp.Diagnostics +{ + public class HttpRequestEvidenceExample + { + public void Demonstrate() + { + var context = new DefaultHttpContext(); + context.Request.Scheme = "https"; + context.Request.Host = new HostString("api.example.com"); + context.Request.Path = "/orders"; + context.Request.QueryString = new QueryString("?status=pending"); + context.Request.Method = HttpMethods.Post; + context.Request.ContentType = "application/x-www-form-urlencoded"; + context.Request.Headers["Authorization"] = "Bearer eyJhbGci..."; + context.Request.Headers["X-Trace-Id"] = "abc-123"; + context.Request.Form = new FormCollection( + new Dictionary + { + { "customerId", "42" } + }); + + // Capture the request body so HttpRequestEvidence can retrieve it + var bodyBytes = Encoding.UTF8.GetBytes("customerId=42"); + context.Items[HttpRequestEvidence.HttpContextItemsKeyForCapturedRequestBody] = + new MemoryStream(bodyBytes); + + var evidence = new HttpRequestEvidence(context.Request); + + Console.WriteLine($"Location: {evidence.Location}"); + Console.WriteLine($"Method: {evidence.Method}"); + Console.WriteLine($"Auth Header: {evidence.Headers["Authorization"]}"); + Console.WriteLine($"Query: status={evidence.Query["status"]}"); + Console.WriteLine($"Form: customerId={evidence.Form["customerId"]}"); + Console.WriteLine($"Body: {evidence.Body}"); + + // Provide a custom body converter to redact sensitive data + var redacted = new HttpRequestEvidence(context.Request, + stream => new StreamReader(stream).ReadToEnd().Replace("42", "***")); + Console.WriteLine($"Redacted Body: {redacted.Body}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.PreferredFaultDescriptor.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.PreferredFaultDescriptor.md new file mode 100644 index 00000000..ad1bb148 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.PreferredFaultDescriptor.md @@ -0,0 +1,22 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.PreferredFaultDescriptor +example: +- *content +--- + +The following example demonstrates how to use the enum to configure the error response format for the `FaultDescriptorFilter`. + +```csharp +using System; + +namespace Cuemon.AspNetCore.Diagnostics; + +public static class PreferredFaultDescriptorExample +{ + public static void Demonstrate() + { + var preferredFormat = PreferredFaultDescriptor.ProblemDetails; +Console.WriteLine(preferredFormat); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTiming.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTiming.md new file mode 100644 index 00000000..3d0dc54d --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTiming.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.ServerTiming +example: +- *content +--- + +The following example demonstrates how to use `ServerTiming` to communicate performance metrics via the Server-Timing header. + +```csharp +using System; +using System.Linq; + + namespace Cuemon.AspNetCore.Diagnostics; + + public static class ServerTimingExample + { + public static void Demonstrate() + { + var timing = new ServerTiming(); + timing.AddServerTiming("db", TimeSpan.FromMilliseconds(12), "SQL query"); + + var metric = timing.Metrics.First(); + Console.WriteLine($"{metric.Name}:{metric.Duration}"); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingMetric.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingMetric.md new file mode 100644 index 00000000..f3c721cb --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingMetric.md @@ -0,0 +1,54 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.ServerTimingMetric +example: +- *content +--- + +The following example demonstrates how to create `ServerTimingMetric` instances to record performance data for the Server-Timing header, supporting duration, description, and marker-only metrics. + +```csharp +using System; +using Cuemon.AspNetCore.Diagnostics; + +namespace MyApp.Diagnostics +{ + public class ServerTimingMetricExample + { + public void Demonstrate() + { + // Record a metric for a database query + var dbMetric = new ServerTimingMetric("db-query", + TimeSpan.FromMilliseconds(135.2), + "Customer order lookup"); + + Console.WriteLine($"Name: {dbMetric.Name}"); + Console.WriteLine($"Duration: {dbMetric.Duration}ms"); + Console.WriteLine($"Description: {dbMetric.Description}"); + Console.WriteLine($"Header value: {dbMetric}"); + // Output: db-query;dur=135.2;desc="Customer order lookup" + + // Record a metric without duration (marker only) + var marker = new ServerTimingMetric("cache-hit"); + Console.WriteLine(marker); + // Output: cache-hit + + // Record a metric without description + var fastMetric = new ServerTimingMetric("redis-get", + TimeSpan.FromMilliseconds(3.7)); + Console.WriteLine(fastMetric); + // Output: redis-get;dur=3.7 + + // Use with IServerTiming to add to response + IServerTiming serverTiming = new ServerTiming(); + serverTiming + .AddServerTiming("auth", TimeSpan.FromMilliseconds(12.5), "Token validation") + .AddServerTiming("sql", TimeSpan.FromMilliseconds(89.1), "Product search"); + + foreach (var metric in serverTiming.Metrics) + { + Console.WriteLine(metric); + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingMiddleware.md new file mode 100644 index 00000000..87189595 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingMiddleware.md @@ -0,0 +1,48 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.ServerTimingMiddleware +example: +- *content +--- + +The following example demonstrates how to register and use `ServerTimingMiddleware` to emit `Server-Timing` performance metrics in the response header. + +```csharp +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + + namespace Cuemon.AspNetCore.Diagnostics; + + public static class ServerTimingMiddlewareExample + { + public static async Task DemonstrateAsync() + { + var context = new DefaultHttpContext(); + var middleware = new ServerTimingMiddleware(httpContext => httpContext.Response.WriteAsync("Hello")); + + using var loggerFactory = LoggerFactory.Create(builder => { }); + var serverTiming = new ServerTiming(); + serverTiming.AddServerTiming("db", TimeSpan.FromMilliseconds(12), "SQL query"); + + await middleware.InvokeAsync( + context, + loggerFactory.CreateLogger(), + new SampleHostEnvironment(), + serverTiming, + Options.Create(new ServerTimingOptions { SuppressHeaderPredicate = _ => false })); + + Console.WriteLine(context.Response.Headers[ServerTiming.HeaderName].ToString()); + } + private sealed class SampleHostEnvironment : IHostEnvironment + { + public string ApplicationName { get; set; } = "Docs"; + public IFileProvider ContentRootFileProvider { get; set; } = new NullFileProvider(); + public string ContentRootPath { get; set; } = "."; + public string EnvironmentName { get; set; } = Environments.Development; + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingOptions.md new file mode 100644 index 00000000..31ab5d8c --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingOptions.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.AspNetCore.Diagnostics.ServerTimingOptions +example: +- *content +--- + +The following example demonstrates how to configure `ServerTimingOptions`. + +```csharp +using System; +using Cuemon.AspNetCore.Diagnostics; + +namespace MyApp.Examples; + +public class ServerTimingOptionsExample +{ + public void Demonstrate() + { + var options = new ServerTimingOptions + { + TimeMeasureCompletedThreshold = TimeSpan.FromMilliseconds(10) + }; + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Hosting.HostingEnvironmentMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Hosting.HostingEnvironmentMiddleware.md new file mode 100644 index 00000000..25b1d129 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Hosting.HostingEnvironmentMiddleware.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.AspNetCore.Hosting.HostingEnvironmentMiddleware +example: +- *content +--- + +The following example demonstrates how to register and use `HostingEnvironmentMiddleware` in the ASP.NET Core pipeline. + +```csharp +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; + + namespace Cuemon.AspNetCore.Hosting; + + public static class HostingEnvironmentMiddlewareExample + { + public static async Task DemonstrateAsync() + { + var context = new DefaultHttpContext(); + var middleware = new HostingEnvironmentMiddleware( + httpContext => httpContext.Response.WriteAsync("Hello"), + Options.Create(new HostingEnvironmentOptions + { + HeaderName = "X-Environment", + SuppressHeaderPredicate = _ => false + })); + + await middleware.InvokeAsync(context, new SampleHostEnvironment()); + Console.WriteLine(context.Response.Headers["X-Environment"].ToString()); + } + private sealed class SampleHostEnvironment : IHostEnvironment + { + public string ApplicationName { get; set; } = "Docs"; + public IFileProvider ContentRootFileProvider { get; set; } = new NullFileProvider(); + public string ContentRootPath { get; set; } = "."; + public string EnvironmentName { get; set; } = Environments.Staging; + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Hosting.HostingEnvironmentOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Hosting.HostingEnvironmentOptions.md new file mode 100644 index 00000000..ab4a919a --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Hosting.HostingEnvironmentOptions.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.AspNetCore.Hosting.HostingEnvironmentOptions +example: +- *content +--- + +The following example demonstrates how to configure hosting environment options. + +```csharp +using System; +using Microsoft.Extensions.Hosting; + + namespace Cuemon.AspNetCore.Hosting; + + public static class HostingEnvironmentOptionsExample + { + public static void Demonstrate() + { + var options = new HostingEnvironmentOptions + { + HeaderName = "X-Environment", + SuppressHeaderPredicate = environment => environment.IsProduction() + }; + + options.ValidateOptions(); + Console.WriteLine(options.HeaderName); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.BadRequestException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.BadRequestException.md new file mode 100644 index 00000000..7432de1e --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.BadRequestException.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.AspNetCore.Http.BadRequestException +example: +- *content +--- + +The following example demonstrates how to use `BadRequestException` for model validation errors in an API controller. + +```csharp +using System; + +namespace Cuemon.AspNetCore.Http; + +public static class BadRequestExceptionExample +{ + public static void Demonstrate() + { + var exception = new BadRequestException( + "The JSON payload is missing the required 'email' field.", + new FormatException("Unexpected end of JSON input.")); + + Console.WriteLine(exception.StatusCode); + Console.WriteLine(exception.InnerException?.GetType().Name); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.ConflictException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.ConflictException.md new file mode 100644 index 00000000..8424d438 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.ConflictException.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.AspNetCore.Http.ConflictException +example: +- *content +--- + +The following example demonstrates how to use to signal HTTP 409 Conflict responses. + +```csharp +using System; +using Cuemon.AspNetCore.Http; + +namespace MyApp.Examples; + +public class ConflictExceptionExample +{ + public void Demonstrate() + { + // Create a ConflictException with default message + var ex = new ConflictException(); + Console.WriteLine(ex.StatusCode); // 409 + Console.WriteLine(ex.ReasonPhrase); // Conflict + Console.WriteLine(ex.Message); // The request could not be completed due to a conflict... + + // Create with a custom message + var custom = new ConflictException("A record with the same email address already exists."); + Console.WriteLine(custom.Message); + + // Create with inner exception + var inner = new InvalidOperationException("Duplicate key violation."); + var withInner = new ConflictException("Resource update conflict.", inner); + Console.WriteLine(withInner.InnerException?.GetType().Name); // InvalidOperationException + + // Use TryParse from the base class to resolve by status code + if (HttpStatusCodeException.TryParse(409, out var parsed)) + { + Console.WriteLine(parsed.GetType().Name); // ConflictException + Console.WriteLine(parsed.StatusCode); // 409 + + // Simulate a conflict check without throwing + var dbTimestamp = DateTime.UtcNow; + var clientTimestamp = dbTimestamp.AddHours(-1); + if (clientTimestamp < dbTimestamp) + { + var conflict = new ConflictException( + "The resource was modified by another user. Please refresh and retry."); + Console.WriteLine(conflict.Message); // The resource was modified by another user... + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.ForbiddenException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.ForbiddenException.md new file mode 100644 index 00000000..4166670b --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.ForbiddenException.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.AspNetCore.Http.ForbiddenException +example: +- *content +--- + +The following example demonstrates how to use `ForbiddenException` to reject unauthorized access in an authorization filter. + +```csharp +using System; +using Cuemon.AspNetCore.Http; + +namespace MyApp.Examples; + +public class ForbiddenExceptionExample +{ + public void Demonstrate() + { + try + { + var userRole = "guest"; + if (userRole != "admin") + { + throw new ForbiddenException("Only administrators can perform this action."); + } + } + catch (ForbiddenException ex) + { + Console.WriteLine(ex.StatusCode); // 403 + Console.WriteLine(ex.Message); // Only administrators can perform this action. + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.GoneException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.GoneException.md new file mode 100644 index 00000000..cb59d3be --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.GoneException.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.AspNetCore.Http.GoneException +example: +- *content +--- + +The following example demonstrates how to return a `GoneException` from a deprecated API endpoint that has been removed. + +```csharp +using System; + +namespace Cuemon.AspNetCore.Http; + +public static class GoneExceptionExample +{ + public static void Demonstrate() + { + var exception = CreateArchivedEndpointException("/v1/orders"); + + Console.WriteLine(exception.Message); + Console.WriteLine(exception.StatusCode); + } + + private static GoneException CreateArchivedEndpointException(string route) + { + return new GoneException($"The resource at '{route}' has been retired."); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.HeaderDictionaryDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.HeaderDictionaryDecoratorExtensions.md new file mode 100644 index 00000000..aac856e0 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.HeaderDictionaryDecoratorExtensions.md @@ -0,0 +1,58 @@ +--- +uid: Cuemon.AspNetCore.Http.HeaderDictionaryDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the decorator extensions to merge, sanitize, and update HTTP header dictionaries. + +```csharp +using System; +using System.Net.Http; +using Cuemon; +using Cuemon.AspNetCore.Http; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace MyApp.AspNetCore.Http +{ + public class HeaderDictionaryDecoratorExtensionsExample + { + public void Demonstrate() + { + // Add non-existing headers from one dictionary into another + var target = new HeaderDictionary + { + { "X-Existing", "value1" } + }; + + var source = new HeaderDictionary + { + { "X-Existing", "value1" }, + { "X-New", "value2" } + }; + + // Only adds headers that do not already exist in target + Decorator.Enclose(target).AddRange(source); + + Console.WriteLine(target["X-Existing"]); // "value1" + Console.WriteLine(target["X-New"]); // "value2" + + // Add or update a single header with control-character sanitization + Decorator.Enclose(target).AddOrUpdateHeader( + "X-Sanitized", new StringValues("hello\r\nworld"), useAsciiEncodingConversion: false); + + Console.WriteLine(target["X-Sanitized"]); // "helloworld" + + // Copy response headers into an IHeaderDictionary + using var response = new HttpResponseMessage(); + response.Headers.Add("X-Custom", new[] { "alpha", "beta" }); + + Decorator.Enclose(target).AddOrUpdateHeaders(response.Headers); + + Console.WriteLine(target["X-Custom"]); // "alpha,beta" + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ApiKeyException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ApiKeyException.md new file mode 100644 index 00000000..b587f620 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ApiKeyException.md @@ -0,0 +1,23 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.ApiKeyException +example: +- *content +--- + +The following example demonstrates how a is used to signal that a request's API key header validation failed. + +```csharp +using System; +using Microsoft.AspNetCore.Http; + + namespace Cuemon.AspNetCore.Http.Headers; + + public static class ApiKeyExceptionExample + { + public static void Demonstrate() + { + var exception = new ApiKeyException(StatusCodes.Status403Forbidden, "The API key was rejected."); + Console.WriteLine($"{exception.StatusCode} {exception.ReasonPhrase}"); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ApiKeySentinelMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ApiKeySentinelMiddleware.md new file mode 100644 index 00000000..6f504c81 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ApiKeySentinelMiddleware.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.ApiKeySentinelMiddleware +example: +- *content +--- + +The following example demonstrates how to register and use `ApiKeySentinelMiddleware` in the ASP.NET Core pipeline. + +```csharp +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; + + namespace Cuemon.AspNetCore.Http.Headers; + + public static class ApiKeySentinelMiddlewareExample + { + public static async Task DemonstrateAsync() + { + var context = new DefaultHttpContext(); + var options = Options.Create(new ApiKeySentinelOptions + { + AllowedKeys = new List { "secret-key" } + }); + + context.Request.Headers[options.Value.HeaderName] = "secret-key"; + + var middleware = new ApiKeySentinelMiddleware( + httpContext => + { + httpContext.Response.StatusCode = StatusCodes.Status200OK; + return Task.CompletedTask; + }, + options); + + await middleware.InvokeAsync(context); + Console.WriteLine(context.Response.StatusCode); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ApiKeySentinelOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ApiKeySentinelOptions.md new file mode 100644 index 00000000..0717cf7b --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ApiKeySentinelOptions.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.ApiKeySentinelOptions +example: +- *content +--- + +The following example demonstrates configuring API key sentinel options. + +```csharp +using System; +using System.Collections.Generic; + + namespace Cuemon.AspNetCore.Http.Headers; + + public static class ApiKeySentinelOptionsExample + { + public static void Demonstrate() + { + var options = new ApiKeySentinelOptions + { + AllowedKeys = new List { "secret-key" } + }; + + options.ValidateOptions(); + using var response = options.ResponseHandler("wrong-key"); + var message = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + Console.WriteLine(message); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CacheableMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CacheableMiddleware.md new file mode 100644 index 00000000..fa25bfeb --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CacheableMiddleware.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.CacheableMiddleware +example: +- *content +--- + +The following example demonstrates how to register and use `CacheableMiddleware` in the ASP.NET Core pipeline. + +```csharp +using System; +using Cuemon.AspNetCore.Builder; +using Cuemon.AspNetCore.Http.Headers; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using Microsoft.Net.Http.Headers; + +namespace MyApp.Examples; + +public class CacheableMiddlewareExample +{ + public void Configure(IApplicationBuilder app) + { + // Standard registration via MiddlewareBuilderFactory (recommended) + MiddlewareBuilderFactory.UseConfigurableMiddleware(app, options => + { + options.CacheControl = new CacheControlHeaderValue + { + Public = true, + MaxAge = TimeSpan.FromDays(1) + }; + options.Expires = new ExpiresHeaderValue(TimeSpan.FromDays(1)); + }); + } + + public void DirectInstantiation(RequestDelegate next, IOptions options) + { + // Direct usage of the CacheableMiddleware type + var middleware = new CacheableMiddleware(next, options); + Console.WriteLine($"Middleware created (CacheControl: {options.Value.UseCacheControl})"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CacheableOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CacheableOptions.md new file mode 100644 index 00000000..d1e9acda --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CacheableOptions.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.CacheableOptions +example: +- *content +--- + +```csharp +using System; +using Microsoft.Net.Http.Headers; + + namespace Cuemon.AspNetCore.Http.Headers; + + public static class CacheableOptionsExample + { + public static void Demonstrate() + { + var options = new CacheableOptions + { + CacheControl = new CacheControlHeaderValue + { + Public = true, + MaxAge = TimeSpan.FromHours(12) + }, + Expires = new ExpiresHeaderValue(TimeSpan.FromHours(12)) + }; + + options.ValidateOptions(); + Console.WriteLine($"{options.UseCacheControl}:{options.UseExpires}"); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ChecksumBuilderDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ChecksumBuilderDecoratorExtensions.md new file mode 100644 index 00000000..a7f16fc6 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ChecksumBuilderDecoratorExtensions.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.ChecksumBuilderDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to create an `EntityTagHeaderValue` from a `ChecksumBuilder` using the decorator pattern. + +```csharp +using System; +using Cuemon; +using Cuemon.Data.Integrity; +using Cuemon.Security; + + namespace Cuemon.AspNetCore.Http.Headers; + + public static class ChecksumBuilderDecoratorExtensionsExample + { + public static void Demonstrate() + { + var builder = new ChecksumBuilder(() => HashFactory.CreateFnv128()); + var entityTag = Decorator.Enclose(builder).ToEntityTagHeaderValue(isWeak: true); + + Console.WriteLine(entityTag.ToString()); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierMiddleware.md new file mode 100644 index 00000000..432de2b6 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierMiddleware.md @@ -0,0 +1,50 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierMiddleware +example: +- *content +--- + +```csharp +using System.Threading.Tasks; +using System; +using Cuemon.AspNetCore.Http.Headers; +using Cuemon.Messaging; +using Cuemon.Net.Http; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Http.Headers +{ + public class CorrelationIdentifierMiddlewareRegistration + { + // Called from Startup.ConfigureServices or Program.cs + public void ConfigureServices(IServiceCollection services) + { + services.Configure(o => + { + // Use a custom header name + o.HeaderName = HttpHeaderNames.XCorrelationId; + // Provide a specific correlation token + o.Token = new CorrelationToken(); + }); + } + + // Called from Startup.Configure or Program.cs + public void Configure(IApplicationBuilder app) + { + // Add the Correlation ID middleware to the pipeline + app.UseMiddleware(); + + // Example endpoint that reads the correlation ID + app.Run(async context => + { + var correlationId = context.Items[CorrelationIdentifierMiddleware.HttpContextItemsKey]; + await context.Response.WriteAsync( + $"Correlation ID: {correlationId}"); + }); + } + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierOptions.md new file mode 100644 index 00000000..52f1bb09 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierOptions.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierOptions +example: +- *content +--- + +```csharp +using System; +using Cuemon.Messaging; + + namespace Cuemon.AspNetCore.Http.Headers; + + public static class CorrelationIdentifierOptionsExample + { + public static void Demonstrate() + { + var options = new CorrelationIdentifierOptions + { + Token = new CorrelationToken("corr-42") + }; + + options.ValidateOptions(); + Console.WriteLine(options.Token.CorrelationId); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ExpiresHeaderValue.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ExpiresHeaderValue.md new file mode 100644 index 00000000..67b5dc04 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.ExpiresHeaderValue.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.ExpiresHeaderValue +example: +- *content +--- + +The following example demonstrates how to use to specify when a response should be considered stale. + +```csharp +using System; +using Cuemon.AspNetCore.Http.Headers; + +namespace MyApp.Examples; + +public class ExpiresHeaderValueExample +{ + public void Demonstrate() + { + // Create an Expires header value that makes the response stale after 1 hour + var expires = new ExpiresHeaderValue(TimeSpan.FromHours(1)); + + // The ToString() method produces the RFC 1123 format + string headerValue = expires.ToString(); + Console.WriteLine($"Expires: {headerValue}"); + + // Output example: "Expires: Thu, 17 Jun 2026 12:00:00 GMT" + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RequestIdentifierMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RequestIdentifierMiddleware.md new file mode 100644 index 00000000..76e039cc --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RequestIdentifierMiddleware.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.RequestIdentifierMiddleware +example: +- *content +--- + +The following example demonstrates how to register the in the ASP.NET Core pipeline to add a unique Request-ID header to every response. + +```csharp +using System; +using System.Threading.Tasks; +using Cuemon.Messaging; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; + + namespace Cuemon.AspNetCore.Http.Headers; + + public static class RequestIdentifierMiddlewareExample + { + public static async Task DemonstrateAsync() + { + var context = new DefaultHttpContext(); + var options = Options.Create(new RequestIdentifierOptions + { + Token = new RequestToken("req-42") + }); + + var middleware = new RequestIdentifierMiddleware( + httpContext => httpContext.Response.WriteAsync("Hello"), + options); + + await middleware.InvokeAsync(context); + Console.WriteLine(context.Response.Headers[options.Value.HeaderName].ToString()); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RequestIdentifierOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RequestIdentifierOptions.md new file mode 100644 index 00000000..d107a326 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RequestIdentifierOptions.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.RequestIdentifierOptions +example: +- *content +--- + +The following example demonstrates how to configure to customize the Request-ID header name and token generator. + +```csharp +using System; +using Cuemon.Messaging; + + namespace Cuemon.AspNetCore.Http.Headers; + + public static class RequestIdentifierOptionsExample + { + public static void Demonstrate() + { + var options = new RequestIdentifierOptions + { + Token = new RequestToken("req-42") + }; + + options.ValidateOptions(); + Console.WriteLine(options.Token.RequestId); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RetryConditionScope.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RetryConditionScope.md new file mode 100644 index 00000000..13caf871 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RetryConditionScope.md @@ -0,0 +1,25 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.RetryConditionScope +example: +- *content +--- + +```csharp +using System; +using System.Net.Http.Headers; + +namespace Cuemon.AspNetCore.Http.Headers; + +public static class RetryConditionScopeExample +{ + public static void Demonstrate() + { + var scope = RetryConditionScope.DeltaSeconds; + string retryAfter = scope == RetryConditionScope.DeltaSeconds + ? new RetryConditionHeaderValue(TimeSpan.FromSeconds(30)).ToString() + : new RetryConditionHeaderValue(DateTimeOffset.UtcNow.AddMinutes(1)).ToString(); + + Console.WriteLine(retryAfter); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.UserAgentException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.UserAgentException.md new file mode 100644 index 00000000..303dfe82 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.UserAgentException.md @@ -0,0 +1,23 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.UserAgentException +example: +- *content +--- + +The following example demonstrates how a is used to signal that a request's User-Agent header was rejected. + +```csharp +using System; +using Microsoft.AspNetCore.Http; + + namespace Cuemon.AspNetCore.Http.Headers; + + public static class UserAgentExceptionExample + { + public static void Demonstrate() + { + var exception = new UserAgentException(StatusCodes.Status400BadRequest, "The User-Agent header is required."); + Console.WriteLine($"{exception.StatusCode} {exception.ReasonPhrase}"); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.UserAgentSentinelMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.UserAgentSentinelMiddleware.md new file mode 100644 index 00000000..f1badca4 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.UserAgentSentinelMiddleware.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.UserAgentSentinelMiddleware +example: +- *content +--- + +The following example demonstrates how to register the to require a specific User-Agent header on incoming requests. + +```csharp +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; +using Microsoft.Net.Http.Headers; + + namespace Cuemon.AspNetCore.Http.Headers; + + public static class UserAgentSentinelMiddlewareExample + { + public static async Task DemonstrateAsync() + { + var context = new DefaultHttpContext(); + var options = Options.Create(new UserAgentSentinelOptions + { + RequireUserAgentHeader = true, + ValidateUserAgentHeader = true, + AllowedUserAgents = new List { "Cuemon-Agent" } + }); + + context.Request.Headers[HeaderNames.UserAgent] = "Cuemon-Agent"; + + var middleware = new UserAgentSentinelMiddleware( + httpContext => + { + httpContext.Response.StatusCode = StatusCodes.Status200OK; + return Task.CompletedTask; + }, + options); + + await middleware.InvokeAsync(context); + Console.WriteLine(context.Response.StatusCode); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.UserAgentSentinelOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.UserAgentSentinelOptions.md new file mode 100644 index 00000000..38441c4b --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.UserAgentSentinelOptions.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.UserAgentSentinelOptions +example: +- *content +--- + +The following example demonstrates how to configure to restrict which User-Agent headers are allowed. + +```csharp +using System; +using System.Collections.Generic; + + namespace Cuemon.AspNetCore.Http.Headers; + + public static class UserAgentSentinelOptionsExample + { + public static void Demonstrate() + { + var options = new UserAgentSentinelOptions + { + RequireUserAgentHeader = true, + ValidateUserAgentHeader = true, + AllowedUserAgents = new List { "Cuemon-Agent" } + }; + + options.ValidateOptions(); + using var response = options.ResponseHandler("Unknown-Agent"); + var message = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); + Console.WriteLine(message); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.VaryAcceptMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.VaryAcceptMiddleware.md new file mode 100644 index 00000000..0392a8f9 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.VaryAcceptMiddleware.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.AspNetCore.Http.Headers.VaryAcceptMiddleware +example: +- *content +--- + +The following example demonstrates how to register the to append a `Vary: Accept` header to every response. + +```csharp +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Net.Http.Headers; + + namespace Cuemon.AspNetCore.Http.Headers; + + public static class VaryAcceptMiddlewareExample + { + public static async Task DemonstrateAsync() + { + var context = new DefaultHttpContext(); + var middleware = new VaryAcceptMiddleware(httpContext => httpContext.Response.WriteAsync("Hello")); + + await middleware.InvokeAsync(context); + Console.WriteLine(context.Response.Headers[HeaderNames.Vary].ToString()); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.HttpContextDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.HttpContextDecoratorExtensions.md new file mode 100644 index 00000000..e2182a08 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.HttpContextDecoratorExtensions.md @@ -0,0 +1,65 @@ +--- +uid: Cuemon.AspNetCore.Http.HttpContextDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the decorator extensions on `HttpContext` to invoke throttling sentinels, API key sentinels, user-agent sentinels, and write exception descriptor responses. + +```csharp +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Cuemon; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.AspNetCore.Http.Headers; +using Cuemon.AspNetCore.Http.Throttling; +using Microsoft.AspNetCore.Http; +using Microsoft.Net.Http.Headers; +using HttpMediaTypeHeaderValue = System.Net.Http.Headers.MediaTypeHeaderValue; + +namespace Cuemon.AspNetCore.Http; + +public static class HttpContextDecoratorExtensionsExample +{ + public static async Task DemonstrateAsync() + { + var context = new DefaultHttpContext(); + context.Request.Headers["X-Api-Key"] = "secret-key"; + context.Request.Headers[HeaderNames.UserAgent] = "Cuemon Docs"; + + var throttlingOptions = new ThrottlingSentinelOptions + { + ContextResolver = _ => "client-1", + Quota = new ThrottleQuota(2, TimeSpan.FromMinutes(1)) + }; + + await Decorator.Enclose(context).InvokeThrottlerSentinelAsync(new MemoryThrottlingCache(), throttlingOptions); + + var apiKeyOptions = new ApiKeySentinelOptions + { + AllowedKeys = new List { "secret-key" } + }; + + await Decorator.Enclose(context).InvokeApiKeySentinelAsync(apiKeyOptions); + + var userAgentOptions = new UserAgentSentinelOptions(); + await Decorator.Enclose(context).InvokeUserAgentSentinelAsync(userAgentOptions); + + var handler = new HttpExceptionDescriptorResponseHandler( + new HttpMediaTypeHeaderValue("text/plain"), + exceptionDescriptor => new HttpResponseMessage((HttpStatusCode)exceptionDescriptor.StatusCode) + { + Content = new StringContent(exceptionDescriptor.Message) + }); + + var descriptor = new HttpExceptionDescriptor(new InvalidOperationException("Bad request"), StatusCodes.Status400BadRequest); + await Decorator.Enclose(context).WriteExceptionDescriptorResponseAsync(handler, descriptor, CancellationToken.None); + + Console.WriteLine(context.Response.StatusCode); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.HttpRequestDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.HttpRequestDecoratorExtensions.md new file mode 100644 index 00000000..101fb7ad --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.HttpRequestDecoratorExtensions.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.AspNetCore.Http.HttpRequestDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to inspect HTTP request state using the class accessed through the class. + +```csharp +using System; +using Cuemon; +using Cuemon.Data.Integrity; +using Cuemon.Security; +using Microsoft.AspNetCore.Http; +using Microsoft.Net.Http.Headers; + +namespace Cuemon.AspNetCore.Http; + +public static class HttpRequestDecoratorExtensionsExample +{ + public static void Demonstrate() + { + var context = new DefaultHttpContext(); + context.Request.Method = HttpMethods.Get; + + var builder = new ChecksumBuilder(() => HashFactory.CreateFnv128()); + context.Request.Headers[HeaderNames.IfNoneMatch] = + string.Concat("\"", builder.Checksum.ToHexadecimalString(), "\""); + + var request = Decorator.Enclose(context.Request); + var canServeFromCache = request.IsGetOrHeadMethod() && request.IsClientSideResourceCached(builder); + + Console.WriteLine(canServeFromCache); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.HttpResponseDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.HttpResponseDecoratorExtensions.md new file mode 100644 index 00000000..2c6ac952 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.HttpResponseDecoratorExtensions.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.AspNetCore.Http.HttpResponseDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to add ETag and Last-Modified HTTP response headers using the class accessed through the class. + +```csharp +using System; +using System.Text; +using Cuemon; +using Cuemon.AspNetCore.Http; +using Cuemon.Data.Integrity; +using Cuemon.Security; +using Microsoft.AspNetCore.Http; + +namespace MyApp.Examples; + +public class HttpResponseDecoratorExtensionsExample +{ + public void AddCachingHeaders(HttpResponse response, HttpRequest request) + { + // Add an ETag header based on content integrity + var builder = new ChecksumBuilder(() => new FowlerNollVo64()); + builder.CombineWith(Encoding.UTF8.GetBytes("content-data")); + Decorator.Enclose(response).AddOrUpdateEntityTagHeader(request, builder); + + // Add a Last-Modified header + var lastModified = new DateTime(2025, 6, 1, 12, 0, 0, DateTimeKind.Utc); + Decorator.Enclose(response).AddOrUpdateLastModifiedHeader(request, lastModified); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.HttpStatusCodeExceptionDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.HttpStatusCodeExceptionDecoratorExtensions.md new file mode 100644 index 00000000..2a3c22ac --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.HttpStatusCodeExceptionDecoratorExtensions.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.AspNetCore.Http.HttpStatusCodeExceptionDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to add response headers to an `HttpStatusCodeException` using the decorator pattern. + +```csharp +using System.Net.Http; +using System.Net.Http.Headers; +using Cuemon.AspNetCore.Http; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +using Cuemon; +namespace Examples; + +public class HttpStatusCodeExceptionHeadersExample +{ + public void AddHeadersToException() + { + var exception = new NotFoundException("Resource not found."); + var headers = new HeaderDictionary + { + { "X-Correlation-Id", new StringValues("abc-123") }, + { "X-Request-Id", new StringValues("req-456") } + }; + + Decorator.Enclose(exception).AddResponseHeaders(headers); + + using var message = new HttpResponseMessage(); + message.Headers.Add("X-Server-Id", "server-01"); + + Decorator.Enclose(exception).AddResponseHeaders(message.Headers); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Int32DecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Int32DecoratorExtensions.md new file mode 100644 index 00000000..bc9885f1 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Int32DecoratorExtensions.md @@ -0,0 +1,50 @@ +--- +uid: Cuemon.AspNetCore.Http.Int32DecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the extension methods to classify HTTP status codes through the pattern. + +```csharp +using System; +using Cuemon; +using Cuemon.AspNetCore.Http; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + + int statusCode = 500; + + // Wrap the int in a Decorator and use the extension methods + var decorator = Decorator.Enclose(statusCode); + + bool isInfo = decorator.IsInformationStatusCode(); + bool isSuccess = decorator.IsSuccessStatusCode(); + bool isRedirect = decorator.IsRedirectionStatusCode(); + bool isClientError = decorator.IsClientErrorStatusCode(); + bool isServerError = decorator.IsServerErrorStatusCode(); + bool isNotModified = decorator.IsNotModifiedStatusCode(); + + Console.WriteLine($"HTTP {statusCode}:"); + Console.WriteLine($" Informational (100-199): {isInfo}"); + Console.WriteLine($" Successful (200-299): {isSuccess}"); + Console.WriteLine($" Redirection (300-399): {isRedirect}"); + Console.WriteLine($" Client Error (400-499): {isClientError}"); + Console.WriteLine($" Server Error (500-599): {isServerError}"); + Console.WriteLine($" Not Modified (304): {isNotModified}"); + + // Use with a success status code + int ok = 200; + var okDecorator = Decorator.Enclose(ok); + Console.WriteLine($"\n{ok} is success: {okDecorator.IsSuccessStatusCode()}"); // True + Console.WriteLine($"404 is client error: {Decorator.Enclose(404).IsClientErrorStatusCode()}"); // True + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.InternalServerErrorException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.InternalServerErrorException.md new file mode 100644 index 00000000..8dab158c --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.InternalServerErrorException.md @@ -0,0 +1,25 @@ +--- +uid: Cuemon.AspNetCore.Http.InternalServerErrorException +example: +- *content +--- + +The following example demonstrates how to use `InternalServerErrorException` to represent an unexpected server-side failure in an exception handling middleware. + +```csharp +using System; + +namespace Cuemon.AspNetCore.Http; + +public static class InternalServerErrorExceptionExample +{ + public static void Demonstrate() + { + var failure = new InvalidOperationException("The invoice pipeline failed to commit the transaction."); + var exception = new InternalServerErrorException(failure); + + Console.WriteLine(exception.StatusCode); + Console.WriteLine(exception.InnerException?.Message); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.MethodNotAllowedException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.MethodNotAllowedException.md new file mode 100644 index 00000000..408d64ce --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.MethodNotAllowedException.md @@ -0,0 +1,25 @@ +--- +uid: Cuemon.AspNetCore.Http.MethodNotAllowedException +example: +- *content +--- + +The following example demonstrates how to use `MethodNotAllowedException` when a POST-only endpoint receives a GET request. + +```csharp +using System; + +namespace Cuemon.AspNetCore.Http; + +public static class MethodNotAllowedExceptionExample +{ + public static void Demonstrate() + { + var allowedMethods = string.Join(", ", new[] { "POST", "PUT" }); + var exception = new MethodNotAllowedException($"Only {allowedMethods} are supported for /orders."); + + Console.WriteLine(exception.Message); + Console.WriteLine(exception.StatusCode); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.NotAcceptableException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.NotAcceptableException.md new file mode 100644 index 00000000..41f59ebd --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.NotAcceptableException.md @@ -0,0 +1,25 @@ +--- +uid: Cuemon.AspNetCore.Http.NotAcceptableException +example: +- *content +--- + +The following example demonstrates how to configure an ASP.NET Core MVC filter that returns a `NotAcceptableException`. + +```csharp +using System; + +namespace Cuemon.AspNetCore.Http; + +public static class NotAcceptableExceptionExample +{ + public static void Demonstrate() + { + var acceptHeader = "application/xml"; + var exception = new NotAcceptableException($"The endpoint cannot produce '{acceptHeader}'."); + + Console.WriteLine(exception.Message); + Console.WriteLine(exception.StatusCode); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.NotFoundException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.NotFoundException.md new file mode 100644 index 00000000..db3d85e8 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.NotFoundException.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.AspNetCore.Http.NotFoundException +example: +- *content +--- + +The following example demonstrates how to use `NotFoundException` when a requested resource does not exist. + +```csharp +using System; +using Cuemon.AspNetCore.Http; + +namespace MyApp.Examples; + +public class NotFoundExceptionExample +{ + public void Demonstrate() + { + try + { + var userId = 999; + var user = FindUser(userId); + if (user == null) + { + throw new NotFoundException($"User with ID {userId} was not found."); + } + } + catch (NotFoundException ex) + { + Console.WriteLine(ex.StatusCode); // 404 + Console.WriteLine(ex.Message); // User with ID 999 was not found. + } + } + + private object FindUser(int id) => null; +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.PayloadTooLargeException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.PayloadTooLargeException.md new file mode 100644 index 00000000..e0630ae2 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.PayloadTooLargeException.md @@ -0,0 +1,53 @@ +--- +uid: Cuemon.AspNetCore.Http.PayloadTooLargeException +example: +- *content +--- + +The following example demonstrates how to use to signal HTTP 413 Payload Too Large responses. + +```csharp +using System.IO; +using System; +using Cuemon.AspNetCore.Http; + +namespace MyApp.Examples; + +public class PayloadTooLargeExceptionExample +{ + public void Demonstrate() + { + // Create a PayloadTooLargeException with default message + var ex = new PayloadTooLargeException(); + Console.WriteLine(ex.StatusCode); // 413 + Console.WriteLine(ex.ReasonPhrase); // Payload Too Large + + // Create with a custom message + var custom = new PayloadTooLargeException("Upload size exceeds the maximum of 10 MB."); + Console.WriteLine(custom.Message); + + // Create with inner exception + var inner = new InvalidOperationException("Stream exceeded configured limit."); + var withInner = new PayloadTooLargeException("Request entity too large.", inner); + Console.WriteLine(withInner.InnerException?.GetType().Name); // InvalidOperationException + + // Use TryParse from the base class to resolve by status code + if (HttpStatusCodeException.TryParse(413, "File exceeds 10 MB limit.", out var parsed)) + { + Console.WriteLine(parsed.GetType().Name); // PayloadTooLargeException + Console.WriteLine(parsed.StatusCode); // 413 + Console.WriteLine(parsed.Message); // File exceeds 10 MB limit. + + // Simulate a payload size check + long uploadSize = 15 * 1024 * 1024; // 15 MB + long maxSize = 10 * 1024 * 1024; // 10 MB + if (uploadSize > maxSize) + { + var rejected = new PayloadTooLargeException( + $"Upload of {uploadSize / 1024 / 1024} MB exceeds the {maxSize / 1024 / 1024} MB limit."); + Console.WriteLine(rejected.Message); + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.PreconditionFailedException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.PreconditionFailedException.md new file mode 100644 index 00000000..7c92a980 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.PreconditionFailedException.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.AspNetCore.Http.PreconditionFailedException +example: +- *content +--- + +The following example demonstrates how to use `PreconditionFailedException` when a conditional request header check fails. + +```csharp +using System; + +namespace Cuemon.AspNetCore.Http; + +public static class PreconditionFailedExceptionExample +{ + public static void Demonstrate() + { + var exception = new PreconditionFailedException( + "The supplied If-Match value does not match the current ETag.", + new InvalidOperationException("ETag mismatch.")); + + Console.WriteLine(exception.StatusCode); + Console.WriteLine(exception.InnerException?.Message); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.PreconditionRequiredException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.PreconditionRequiredException.md new file mode 100644 index 00000000..4872b645 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.PreconditionRequiredException.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.AspNetCore.Http.PreconditionRequiredException +example: +- *content +--- + +The following example demonstrates how to use `PreconditionRequiredException` when a request requires conditional headers. + +```csharp +using System; + +namespace Cuemon.AspNetCore.Http; + +public static class PreconditionRequiredExceptionExample +{ + public static void Demonstrate() + { + var hasConditionHeader = false; + var exception = hasConditionHeader + ? new PreconditionRequiredException() + : new PreconditionRequiredException("Supply an If-Match header before retrying the update."); + + Console.WriteLine(exception.Message); + Console.WriteLine(exception.StatusCode); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.MemoryThrottlingCache.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.MemoryThrottlingCache.md new file mode 100644 index 00000000..a697c445 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.MemoryThrottlingCache.md @@ -0,0 +1,23 @@ +--- +uid: Cuemon.AspNetCore.Http.Throttling.MemoryThrottlingCache +example: +- *content +--- + +```csharp +using System; + +namespace Cuemon.AspNetCore.Http.Throttling; + +public static class MemoryThrottlingCacheExample +{ + public static void Demonstrate() + { + var cache = new MemoryThrottlingCache(); +var request = new ThrottleRequest(new ThrottleQuota(10, TimeSpan.FromMinutes(1))); + +cache.TryAdd("client-1", request); +Console.WriteLine(cache["client-1"].Total); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottleQuota.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottleQuota.md new file mode 100644 index 00000000..603563dd --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottleQuota.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.AspNetCore.Http.Throttling.ThrottleQuota +example: +- *content +--- + +```csharp +using System; +using Cuemon; +using Cuemon.AspNetCore.Http.Throttling; + +namespace MyApp.Http.Throttling +{ + public class ThrottleQuotaExample + { + public void Demonstrate() + { + // Allow 100 requests per 1 minute window + var quotaPerMinute = new ThrottleQuota(100, 1, TimeUnit.Minutes); + Console.WriteLine($"Rate limit: {quotaPerMinute.RateLimit}"); + Console.WriteLine($"Window: {quotaPerMinute.Window.TotalMinutes} min"); + + // Allow 1000 requests per 1 hour window (using TimeSpan directly) + var quotaPerHour = new ThrottleQuota(1000, TimeSpan.FromHours(1)); + Console.WriteLine($"Rate limit: {quotaPerHour.RateLimit}"); + Console.WriteLine($"Window: {quotaPerHour.Window.TotalHours} h"); + + // Allow 10 requests per 15 seconds + var quotaPer15Sec = new ThrottleQuota(10, 15, TimeUnit.Seconds); + Console.WriteLine($"Rate limit: {quotaPer15Sec.RateLimit}"); + Console.WriteLine($"Window: {quotaPer15Sec.Window.TotalSeconds} s"); + + // Use with ThrottleRequest to track usage + var request = new ThrottleRequest(quotaPerMinute); + Console.WriteLine($"Initial total: {request.Total}"); + Console.WriteLine($"Expires at: {request.Expires:R}"); + + request.IncrementTotal(); + Console.WriteLine($"After one request: {request.Total}"); + + request.Refresh(); // resets if window has expired + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottleRequest.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottleRequest.md new file mode 100644 index 00000000..6ecfddeb --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottleRequest.md @@ -0,0 +1,24 @@ +--- +uid: Cuemon.AspNetCore.Http.Throttling.ThrottleRequest +example: +- *content +--- + +The following example demonstrates how to use to track HTTP request usage and quota in a throttling scenario. + +```csharp +using System; + +namespace Cuemon.AspNetCore.Http.Throttling; + +public static class ThrottleRequestExample +{ + public static void Demonstrate() + { + var request = new ThrottleRequest(new ThrottleQuota(10, TimeSpan.FromMinutes(1))); +request.IncrementTotal(); + +Console.WriteLine(request.Total); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingException.md new file mode 100644 index 00000000..5a4a19ca --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingException.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.AspNetCore.Http.Throttling.ThrottlingException +example: +- *content +--- + +The following example demonstrates how a is thrown when a request rate limit has been exceeded. + +```csharp +using System; +using Cuemon.AspNetCore.Http.Throttling; + +namespace MyApp.Examples; + +public class ThrottlingExceptionExample +{ + public void Demonstrate() + { + try + { + // Simulate a rate-limit violation + var resetTime = DateTime.UtcNow.AddMinutes(5); + throw new ThrottlingException( + "API rate limit exceeded.", + rateLimit: 100, + delta: TimeSpan.FromMinutes(5), + reset: resetTime); + } + catch (ThrottlingException ex) + { + Console.WriteLine($"Message: {ex.Message}"); // API rate limit exceeded. + Console.WriteLine($"RateLimit: {ex.RateLimit}"); // 100 + Console.WriteLine($"Delta: {ex.Delta.TotalMinutes} minutes"); // 5 + Console.WriteLine($"Reset: {ex.Reset}"); // UTC reset time + Console.WriteLine($"StatusCode: {ex.StatusCode}"); // 429 + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelMiddleware.md new file mode 100644 index 00000000..a67a0021 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelMiddleware.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelMiddleware +example: +- *content +--- + +The following example demonstrates how to register the to enforce rate limiting in the ASP.NET Core pipeline. + +```csharp +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Options; + + namespace Cuemon.AspNetCore.Http.Throttling; + + public static class ThrottlingSentinelMiddlewareExample + { + public static async Task DemonstrateAsync() + { + var context = new DefaultHttpContext(); + var options = Options.Create(new ThrottlingSentinelOptions + { + ContextResolver = _ => "client-1", + Quota = new ThrottleQuota(10, TimeSpan.FromMinutes(1)) + }); + + var middleware = new ThrottlingSentinelMiddleware( + httpContext => + { + httpContext.Response.StatusCode = StatusCodes.Status200OK; + return Task.CompletedTask; + }, + options); + + await middleware.InvokeAsync(context, new MemoryThrottlingCache()); + Console.WriteLine(context.Response.Headers[options.Value.RateLimitHeaderName].ToString()); + } + } +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelOptions.md new file mode 100644 index 00000000..26e38583 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelOptions.md @@ -0,0 +1,56 @@ +--- +uid: Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelOptions +example: +- *content +--- + +```csharp +using System; +using Cuemon.AspNetCore.Http.Headers; +using Cuemon.AspNetCore.Http.Throttling; +using Microsoft.AspNetCore.Http; + +namespace MyApp.Http.Throttling +{ + public class ThrottlingSentinelOptionsExample + { + public ThrottlingSentinelOptions CreateDefault() + { + // Default: RateLimit-Limit header, 429 response with Retry-After + var options = new ThrottlingSentinelOptions(); + return options; + } + + public ThrottlingSentinelOptions CreateCustom() + { + var options = new ThrottlingSentinelOptions + { + // Allow 60 requests per 1 minute window per client + Quota = new ThrottleQuota(60, TimeSpan.FromMinutes(1)), + // Resolve context by client IP address + ContextResolver = ctx => + ctx.Connection.RemoteIpAddress?.ToString() ?? "unknown", + // Custom header names + RateLimitHeaderName = "X-Rate-Limit-Limit", + RateLimitRemainingHeaderName = "X-Rate-Limit-Remaining", + RateLimitResetHeaderName = "X-Rate-Limit-Reset", + // Use delta-seconds for Retry-After + RateLimitResetScope = RetryConditionScope.DeltaSeconds, + UseRetryAfterHeader = true, + RetryAfterScope = RetryConditionScope.DeltaSeconds, + // Custom response message + TooManyRequestsMessage = "Rate limit exceeded. Please slow down." + }; + + // Validate the configuration + options.ValidateOptions(); + + Console.WriteLine($"Quota: {options.Quota.RateLimit} req / {options.Quota.Window.TotalMinutes} min"); + Console.WriteLine($"RateLimitHeader: {options.RateLimitHeaderName}"); + Console.WriteLine($"RetryAfterScope: {options.RetryAfterScope}"); + + return options; + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.TooManyRequestsException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.TooManyRequestsException.md new file mode 100644 index 00000000..945811ef --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.TooManyRequestsException.md @@ -0,0 +1,55 @@ +--- +uid: Cuemon.AspNetCore.Http.TooManyRequestsException +example: +- *content +--- + +The following example demonstrates how to use to signal HTTP 429 Too Many Requests responses. + +```csharp +using System; +using Cuemon.AspNetCore.Http; + +namespace MyApp.Examples; + +public class TooManyRequestsExceptionExample +{ + public void Demonstrate() + { + // Create a TooManyRequestsException with default message + var ex = new TooManyRequestsException(); + Console.WriteLine(ex.StatusCode); // 429 + Console.WriteLine(ex.ReasonPhrase); // Too Many Requests + Console.WriteLine(ex.Message); // The allowed number of requests has been exceeded. + + // Create with a custom message + var custom = new TooManyRequestsException("Rate limit: maximum 100 requests per minute."); + Console.WriteLine(custom.Message); + + // Create with inner exception + var inner = new InvalidOperationException("Request quota exceeded."); + var withInner = new TooManyRequestsException("API rate limit reached.", inner); + Console.WriteLine(withInner.InnerException?.GetType().Name); // InvalidOperationException + + // Use TryParse from the base class to resolve by status code + if (HttpStatusCodeException.TryParse(429, "Slow down!", out var parsed)) + { + Console.WriteLine(parsed.GetType().Name); // TooManyRequestsException + Console.WriteLine(parsed.StatusCode); // 429 + Console.WriteLine(parsed.Message); // Slow down! + + // Simulate a rate-limit check using the RetryAfter header + var requestCount = 101; + var maxRequests = 100; + if (requestCount > maxRequests) + { + var rateLimited = new TooManyRequestsException( + $"Request #{requestCount} exceeds the limit of {maxRequests} requests per minute."); + rateLimited.Headers["Retry-After"] = "60"; + Console.WriteLine(rateLimited.Message); // Request #101 exceeds the limit... + Console.WriteLine(rateLimited.Headers["Retry-After"]); // 60 + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.UnauthorizedException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.UnauthorizedException.md new file mode 100644 index 00000000..d87aad14 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.UnauthorizedException.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.AspNetCore.Http.UnauthorizedException +example: +- *content +--- + +The following example demonstrates how to use `UnauthorizedException` to indicate missing or invalid authentication. + +```csharp +using System; + +namespace Cuemon.AspNetCore.Http; + +public static class UnauthorizedExceptionExample +{ + public static void Demonstrate() + { + var exception = new UnauthorizedException( + "The request is missing a valid bearer token.", + new InvalidOperationException("Token validation failed.")); + + Console.WriteLine(exception.StatusCode); + Console.WriteLine(exception.InnerException?.GetType().Name); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.UnsupportedMediaTypeException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.UnsupportedMediaTypeException.md new file mode 100644 index 00000000..98248a4b --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.UnsupportedMediaTypeException.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.AspNetCore.Http.UnsupportedMediaTypeException +example: +- *content +--- + +The following example demonstrates how to return an `UnsupportedMediaTypeException` when the API receives an unsupported file upload format. + +```csharp +using System; +using Cuemon.AspNetCore.Http; + +namespace MyApp.Examples; + +public class UnsupportedMediaTypeExceptionExample +{ + public void Demonstrate() + { + try + { + throw new UnsupportedMediaTypeException("text/html"); + } + catch (UnsupportedMediaTypeException ex) + { + Console.WriteLine(ex.StatusCode); // 415 + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Breadcrumb.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Breadcrumb.md new file mode 100644 index 00000000..6360d976 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Breadcrumb.md @@ -0,0 +1,47 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Breadcrumb +example: +- *content +--- + +The following example demonstrates how to use to build navigation breadcrumbs for an MVC application. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.AspNetCore.Mvc; + +namespace MyApp.Examples; + +public class BreadcrumbExample +{ + public void Demonstrate() + { + // Build a breadcrumb trail for a product detail page + var breadcrumbs = new List + { + new() { Label = "Home", ControllerName = "Home", ActionName = "Index" }, + new() { Label = "Products", ControllerName = "Product", ActionName = "Index" }, + new() { Label = "Electronics", ControllerName = "Product", ActionName = "Category" }, + new() { Label = "Smartphone X", ControllerName = "Product", ActionName = "Details" } + }; + + // Render breadcrumb items + foreach (var crumb in breadcrumbs) + { + Console.WriteLine($"{crumb.Label}"); + // Output: + // Home + // Products + // Electronics + // Smartphone X + + // The last breadcrumb typically represents the current page (no link) + var current = breadcrumbs[^1]; + Console.WriteLine($"{current.Label}"); + // Output: Smartphone X + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.CacheableFactory.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.CacheableFactory.md new file mode 100644 index 00000000..89033908 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.CacheableFactory.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.AspNetCore.Mvc.CacheableFactory +example: +- *content +--- + +The following example demonstrates how to create cacheable response objects using `CacheableFactory`. + +```csharp +using System; +using System.Security.Cryptography; +using System.Text; +using Cuemon.AspNetCore.Mvc; + +namespace MyApp.Examples; + +public static class CacheableFactoryExample +{ + public static void Demonstrate() + { + var content = "hello-world"; + + var lastModified = CacheableFactory.CreateHttpLastModified(content, o => + { + o.TimestampProvider = _ => DateTime.UtcNow; + o.ChangedTimestampProvider = _ => DateTime.UtcNow; + }); + + var entityTag = CacheableFactory.CreateHttpEntityTag(content, o => + { + o.ChecksumProvider = value => SHA256.HashData(Encoding.UTF8.GetBytes(value)); + o.WeakChecksumProvider = _ => false; + }); + + var combined = CacheableFactory.Create(content, o => + { + o.TimestampProvider = _ => DateTime.UtcNow; + o.ChecksumProvider = value => SHA256.HashData(Encoding.UTF8.GetBytes(value)); + o.ChangedTimestampProvider = _ => DateTime.UtcNow; + o.WeakChecksumProvider = _ => false; + }); + + Console.WriteLine(lastModified is ICacheableObjectResult); + Console.WriteLine(entityTag is ICacheableObjectResult); + Console.WriteLine(combined is ICacheableObjectResult); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.CacheableObjectResultOptions`1.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.CacheableObjectResultOptions`1.md new file mode 100644 index 00000000..0bf88935 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.CacheableObjectResultOptions`1.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.AspNetCore.Mvc.CacheableObjectResultOptions`1 +example: +- *content +--- + +The following example demonstrates how to configure to enable HTTP caching (ETag and Last-Modified) for a response model. + +```csharp +using System; +using System.Security.Cryptography; +using System.Text; +using Cuemon.AspNetCore.Mvc; + +namespace MyApp.Examples; + +public class CacheableObjectResultOptionsExample +{ + public void Demonstrate() + { + var options = new CacheableObjectResultOptions + { + ChecksumProvider = value => SHA256.HashData(Encoding.UTF8.GetBytes(value)), + WeakChecksumProvider = _ => false, + TimestampProvider = _ => DateTime.UtcNow, + ChangedTimestampProvider = _ => DateTime.UtcNow + }; + + options.ValidateOptions(); + + var data = "hello-world"; + byte[] checksum = options.ChecksumProvider(data); + Console.WriteLine($"Checksum length: {checksum.Length}"); // 32 bytes (SHA256) + Console.WriteLine($"Created: {options.TimestampProvider(data)}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.ContentBasedObjectResultOptions`1.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.ContentBasedObjectResultOptions`1.md new file mode 100644 index 00000000..530ce411 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.ContentBasedObjectResultOptions`1.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.AspNetCore.Mvc.ContentBasedObjectResultOptions`1 +example: +- *content +--- + +The following example demonstrates how to configure to provide a checksum provider for generating ETags. + +```csharp +using System; +using System.Security.Cryptography; +using System.Text; +using Cuemon.AspNetCore.Mvc; + +namespace MyApp.Examples; + +public class ContentBasedObjectResultOptionsExample +{ + public void Demonstrate() + { + var options = new ContentBasedObjectResultOptions + { + ChecksumProvider = value => SHA256.HashData(Encoding.UTF8.GetBytes(value)), + WeakChecksumProvider = _ => false // use strong ETag + }; + + // Validate that the required properties are configured + options.ValidateOptions(); + + Console.WriteLine("ChecksumProvider is configured."); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.ExceptionDescriptorResult.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.ExceptionDescriptorResult.md new file mode 100644 index 00000000..63e26b4d --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.ExceptionDescriptorResult.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.AspNetCore.Mvc.ExceptionDescriptorResult +example: +- *content +--- + +The following example shows how can return either an or ASP.NET Core . + +```csharp +using System; +using Cuemon; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.AspNetCore.Http; +using Cuemon.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; + +namespace MyApp.Examples; + +public static class ExceptionDescriptorResultExample +{ + public static void Demonstrate() + { + var descriptorResult = new ExceptionDescriptorResult( + new HttpExceptionDescriptor(new BadRequestException("City name is required."))); + + var descriptor = (HttpExceptionDescriptor)descriptorResult.Value; + Console.WriteLine(descriptor.StatusCode); + + var problemResult = new ExceptionDescriptorResult( + new ProblemDetails { Title = "Validation failed." }); + + Console.WriteLine(problemResult.Value is IDecorator); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpCacheableFilter.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpCacheableFilter.md new file mode 100644 index 00000000..20807fa9 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpCacheableFilter.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpCacheableFilter +example: +- *content +--- + +The following example shows how to compose from packet-local options and cache validators. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc.Filters.Cacheable; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class HttpCacheableFilterExample +{ + public static void Demonstrate() + { + var options = new HttpCacheableOptions(); + options.Filters.Add(new HttpEntityTagHeaderFilter(io => io.UseEntityTagResponseParser = true)); + options.Filters.Add(new HttpLastModifiedHeaderFilter()); + + var filter = new HttpCacheableFilter(Options.Create(options)); + + Console.WriteLine(filter.Options.Filters.Count); + Console.WriteLine(filter.Options.UseCacheControl); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpCacheableOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpCacheableOptions.md new file mode 100644 index 00000000..91353b51 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpCacheableOptions.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpCacheableOptions +example: +- *content +--- + +The following example configures with a custom `Cache-Control` header and manually adds both cacheable filters used by . + +```csharp +using System; +using Cuemon.AspNetCore.Mvc.Filters.Cacheable; +using Microsoft.Net.Http.Headers; + +namespace MyApp.Examples; + +public static class HttpCacheableOptionsExample +{ + public static void Demonstrate() + { + var options = new HttpCacheableOptions + { + CacheControl = new CacheControlHeaderValue + { + MaxAge = TimeSpan.FromMinutes(15), + Public = true, + MustRevalidate = false + } + }; + + options.Filters.Add(new HttpEntityTagHeaderFilter(o => o.UseEntityTagResponseParser = true)); + options.Filters.Add(new HttpLastModifiedHeaderFilter()); + + Console.WriteLine(options.UseCacheControl); + Console.WriteLine(options.Filters.Count); + Console.WriteLine(options.CacheControl.MaxAge); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpEntityTagHeaderFilter.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpEntityTagHeaderFilter.md new file mode 100644 index 00000000..6b0cc333 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpEntityTagHeaderFilter.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpEntityTagHeaderFilter +example: +- *content +--- + +The following example shows how is added to a cacheable filter pipeline and configured to fall back to parsing the response body. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc.Filters.Cacheable; +namespace MyApp.Examples; + +public static class HttpEntityTagHeaderFilterExample +{ + public static void Demonstrate() + { + var filter = new HttpEntityTagHeaderFilter(o => o.UseEntityTagResponseParser = true); + var options = new HttpCacheableOptions(); + options.Filters.Add(filter); + + Console.WriteLine(filter.Options.UseEntityTagResponseParser); + Console.WriteLine(options.Filters.Count); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpEntityTagHeaderOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpEntityTagHeaderOptions.md new file mode 100644 index 00000000..a0ab637b --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpEntityTagHeaderOptions.md @@ -0,0 +1,50 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpEntityTagHeaderOptions +example: +- *content +--- + +The following example uses the same way the unit tests exercise its default delegates: by applying an ETag from entity integrity data and then from a response-body fallback parser. + +```csharp +using System; +using System.IO; +using System.Text; +using Cuemon.AspNetCore.Mvc.Filters.Cacheable; +using Cuemon.Data.Integrity; +using Cuemon.Security; +using Microsoft.AspNetCore.Http; +using Microsoft.Net.Http.Headers; + +namespace MyApp.Examples; + +public static class HttpEntityTagHeaderOptionsExample +{ + public static void Demonstrate() + { + var options = new HttpEntityTagHeaderOptions + { + UseEntityTagResponseParser = true + }; + + var context = new DefaultHttpContext(); + context.Request.Method = HttpMethods.Get; + + options.EntityTagProvider(new SampleEntityDataIntegrity(), context); + + using var body = new MemoryStream(Encoding.UTF8.GetBytes("payload")); + options.EntityTagResponseParser(body, context.Request, context.Response); + + Console.WriteLine(options.HasEntityTagProvider); + Console.WriteLine(options.HasEntityTagResponseParser); + Console.WriteLine(context.Response.Headers.ContainsKey(HeaderNames.ETag)); + } + + private sealed class SampleEntityDataIntegrity : IEntityDataIntegrity + { + public HashResult Checksum => new HashResult(new byte[] { 1, 2, 3 }); + + public EntityDataIntegrityValidation Validation => EntityDataIntegrityValidation.Strong; + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpLastModifiedHeaderFilter.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpLastModifiedHeaderFilter.md new file mode 100644 index 00000000..ad9ba605 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpLastModifiedHeaderFilter.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpLastModifiedHeaderFilter +example: +- *content +--- + +The following example shows how can be added to a cacheable pipeline and inspected directly. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc.Filters.Cacheable; +namespace MyApp.Examples; + +public static class HttpLastModifiedHeaderFilterExample +{ + public static void Demonstrate() + { + var filter = new HttpLastModifiedHeaderFilter(); + var options = new HttpCacheableOptions(); + options.Filters.Add(filter); + + Console.WriteLine(filter.Options.HasLastModifiedProvider); + Console.WriteLine(options.Filters.Count); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpLastModifiedHeaderOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpLastModifiedHeaderOptions.md new file mode 100644 index 00000000..b9f76fbf --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpLastModifiedHeaderOptions.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpLastModifiedHeaderOptions +example: +- *content +--- + +The following example applies the default to a timestamped response model. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc.Filters.Cacheable; +using Cuemon.Data.Integrity; +using Microsoft.AspNetCore.Http; +using Microsoft.Net.Http.Headers; + +namespace MyApp.Examples; + +public static class HttpLastModifiedHeaderOptionsExample +{ + public static void Demonstrate() + { + var options = new HttpLastModifiedHeaderOptions(); + var context = new DefaultHttpContext(); + context.Request.Method = HttpMethods.Get; + + var timestamp = new SampleEntityDataTimestamp( + DateTime.Parse("2024-01-01T00:00:00Z"), + DateTime.Parse("2024-01-02T00:00:00Z")); + + options.LastModifiedProvider(timestamp, context); + + Console.WriteLine(options.HasLastModifiedProvider); + Console.WriteLine(context.Response.Headers[HeaderNames.LastModified].ToString()); + } + + private sealed class SampleEntityDataTimestamp : IEntityDataTimestamp + { + public SampleEntityDataTimestamp(DateTime created, DateTime? modified) + { + Created = created; + Modified = modified; + } + + public DateTime Created { get; } + + public DateTime? Modified { get; } + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.FaultDescriptorFilter.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.FaultDescriptorFilter.md new file mode 100644 index 00000000..2ec5eea5 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.FaultDescriptorFilter.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Diagnostics.FaultDescriptorFilter +example: +- *content +--- + +The following example creates directly from configured packet-local options. + +```csharp +using System; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.AspNetCore.Mvc.Filters.Diagnostics; +using Cuemon.Diagnostics; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class FaultDescriptorFilterExample +{ + public static void Demonstrate() + { + var options = Options.Create(new MvcFaultDescriptorOptions + { + MarkExceptionHandled = true, + FaultDescriptor = PreferredFaultDescriptor.ProblemDetails, + SensitivityDetails = FaultSensitivityDetails.Failure + }); + + var filter = new FaultDescriptorFilter(options); + + Console.WriteLine(filter.Options.MarkExceptionHandled); + Console.WriteLine(filter.Options.FaultDescriptor); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.MvcFaultDescriptorOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.MvcFaultDescriptorOptions.md new file mode 100644 index 00000000..7a7f308a --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.MvcFaultDescriptorOptions.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Diagnostics.MvcFaultDescriptorOptions +example: +- *content +--- + +The following example configures for Problem Details responses and marks MVC exceptions as handled after the filter runs. + +```csharp +using System; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.AspNetCore.Mvc.Filters.Diagnostics; +using Cuemon.Diagnostics; +namespace MyApp.Examples; + +public static class MvcFaultDescriptorOptionsExample +{ + public static void Demonstrate() + { + var options = new MvcFaultDescriptorOptions + { + MarkExceptionHandled = true, + FaultDescriptor = PreferredFaultDescriptor.ProblemDetails, + SensitivityDetails = FaultSensitivityDetails.Failure + }; + + Console.WriteLine(options.MarkExceptionHandled); + Console.WriteLine(options.FaultDescriptor); + Console.WriteLine(options.HttpFaultResolvers.Count); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingAttribute.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingAttribute.md new file mode 100644 index 00000000..be34491b --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingAttribute.md @@ -0,0 +1,57 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingAttribute +example: +- *content +--- + +The following example applies to a controller action and configures the attribute directly. + +```csharp +using System; +using System.Threading.Tasks; +using Cuemon; +using Cuemon.AspNetCore.Mvc.Filters.Diagnostics; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Logging; + +namespace MyApp.Examples; + +public static class ServerTimingAttributeExample +{ + public static void Demonstrate() + { + var attribute = new ServerTimingAttribute + { + Name = "weatherApi", + Description = "Weather API endpoint", + Threshold = 500, + ThresholdTimeUnit = TimeUnit.Milliseconds, + DesiredLogLevel = LogLevel.Warning, + EnvironmentName = string.Empty + }; + + Console.WriteLine(attribute.Name); + Console.WriteLine(attribute is IFilterFactory); + Console.WriteLine(attribute.IsReusable); + } +} + +[ApiController] +[Route("weather")] +public sealed class WeatherController : ControllerBase +{ + [HttpGet] + [ServerTiming( + Name = "weatherApi", + Description = "Weather API endpoint", + Threshold = 500, + ThresholdTimeUnit = TimeUnit.Milliseconds, + DesiredLogLevel = LogLevel.Warning)] + public async Task GetWeatherAsync() + { + await Task.Delay(300); + return Ok(new { Temperature = 22, Condition = "Sunny" }); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingFilter.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingFilter.md new file mode 100644 index 00000000..a44d73a6 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingFilter.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingFilter +example: +- *content +--- + +The following example shows the constructor dependencies used when creating directly. + +```csharp +using System; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.AspNetCore.Mvc.Filters.Diagnostics; +using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class ServerTimingFilterExample +{ + public static void Demonstrate() + { + var options = Options.Create(new ServerTimingOptions + { + UseTimeMeasureProfiler = true, + SuppressHeaderPredicate = _ => false + }); + + using var loggerFactory = LoggerFactory.Create(_ => { }); + var filter = new ServerTimingFilter( + options, + new SampleHostEnvironment(), + loggerFactory.CreateLogger()); + + Console.WriteLine(filter.Options.UseTimeMeasureProfiler); + Console.WriteLine(filter.GetType().Name); + } + + private sealed class SampleHostEnvironment : IHostEnvironment + { + public string EnvironmentName { get; set; } = Environments.Development; + + public string ApplicationName { get; set; } = nameof(ServerTimingFilterExample); + + public string ContentRootPath { get; set; } = AppContext.BaseDirectory; + + public IFileProvider ContentRootFileProvider { get; set; } = new NullFileProvider(); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Headers.ApiKeySentinelAttribute.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Headers.ApiKeySentinelAttribute.md new file mode 100644 index 00000000..71213b9e --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Headers.ApiKeySentinelAttribute.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Headers.ApiKeySentinelAttribute +example: +- *content +--- + +The following example applies to a controller and inspects the filter service type it resolves. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc.Filters.Headers; +using Microsoft.AspNetCore.Mvc; + +namespace MyApp.Examples; + +[ApiController] +[Route("api/[controller]")] +[ApiKeySentinel] +public sealed class SecureController : ControllerBase +{ + [HttpGet] + public IActionResult GetSecureData() + { + return Ok(new { Data = "Protected data" }); + } +} + +public static class ApiKeySentinelAttributeExample +{ + public static void Demonstrate() + { + var attribute = new ApiKeySentinelAttribute(); + + Console.WriteLine(attribute.ServiceType == typeof(ApiKeySentinelFilter)); + Console.WriteLine(attribute.IsReusable); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Headers.ApiKeySentinelFilter.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Headers.ApiKeySentinelFilter.md new file mode 100644 index 00000000..925949e8 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Headers.ApiKeySentinelFilter.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Headers.ApiKeySentinelFilter +example: +- *content +--- + +The following example creates directly from configured options. + +```csharp +using System; +using System.Net; +using Cuemon.AspNetCore.Http.Headers; +using Cuemon.AspNetCore.Mvc.Filters.Headers; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class ApiKeySentinelFilterExample +{ + public static void Demonstrate() + { + var options = Options.Create(new ApiKeySentinelOptions + { + UseGenericResponse = true, + GenericClientStatusCode = HttpStatusCode.NotFound, + GenericClientMessage = "Resource not found." + }); + options.Value.AllowedKeys.Add("Cuemon-Key"); + + var filter = new ApiKeySentinelFilter(options); + + Console.WriteLine(filter.Options.HeaderName); + Console.WriteLine(filter.Options.AllowedKeys.Count); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Headers.UserAgentSentinelFilter.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Headers.UserAgentSentinelFilter.md new file mode 100644 index 00000000..45dc2bf3 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Headers.UserAgentSentinelFilter.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Headers.UserAgentSentinelFilter +example: +- *content +--- + +The following example configures to require a known `User-Agent` header and then creates the filter directly from those options. + +```csharp +using System; +using Cuemon.AspNetCore.Http.Headers; +using Cuemon.AspNetCore.Mvc.Filters.Headers; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class UserAgentSentinelFilterExample +{ + public static void Demonstrate() + { + var options = Options.Create(new UserAgentSentinelOptions + { + RequireUserAgentHeader = true, + ValidateUserAgentHeader = true + }); + options.Value.AllowedUserAgents.Add("Cuemon-Agent"); + + var filter = new UserAgentSentinelFilter(options); + + Console.WriteLine(filter.Options.RequireUserAgentHeader); + Console.WriteLine(filter.Options.AllowedUserAgents.Count); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.ModelBinding.DisableModelBindingAttribute.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.ModelBinding.DisableModelBindingAttribute.md new file mode 100644 index 00000000..d10eb79e --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.ModelBinding.DisableModelBindingAttribute.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.ModelBinding.DisableModelBindingAttribute +example: +- *content +--- + +The following example demonstrates how to use the to disable a specific model binding value provider, such as when handling file uploads to prevent form value binding. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc.Filters.ModelBinding; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; + +namespace MyApp.Examples; + +[DisableModelBinding(typeof(FormValueProviderFactory))] +public class FileUploadController : Controller +{ + [HttpPost("/upload")] + public IActionResult Upload() + { + return Ok("File upload processed."); + } +} + +public class DisableModelBindingAttributeDirectUsage +{ + public void Demonstrate() + { + // Direct instantiation of DisableModelBindingAttribute + var attribute = new DisableModelBindingAttribute(typeof(FormValueProviderFactory)); + Console.WriteLine($"Disabled type: {attribute.ValueProviderFactoryType.Name}"); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Throttling.ThrottlingSentinelFilter.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Throttling.ThrottlingSentinelFilter.md new file mode 100644 index 00000000..586916bd --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Throttling.ThrottlingSentinelFilter.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.AspNetCore.Mvc.Filters.Throttling.ThrottlingSentinelFilter +example: +- *content +--- + +The following example constructs directly with a packet-local throttling cache and options object. + +```csharp +using System; +using Cuemon; +using Cuemon.AspNetCore.Http.Throttling; +using Cuemon.AspNetCore.Mvc.Filters.Throttling; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class ThrottlingSentinelFilterExample +{ + public static void Demonstrate() + { + var options = Options.Create(new ThrottlingSentinelOptions + { + ContextResolver = _ => "developer-workstation", + Quota = new ThrottleQuota(10, 5, TimeUnit.Seconds) + }); + + var filter = new ThrottlingSentinelFilter(options, new MemoryThrottlingCache()); + + Console.WriteLine(filter.Options.Quota.RateLimit); + Console.WriteLine(filter.Options.UseRetryAfterHeader); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.ForbiddenObjectResult.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.ForbiddenObjectResult.md new file mode 100644 index 00000000..3ce20409 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.ForbiddenObjectResult.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.AspNetCore.Mvc.ForbiddenObjectResult +example: +- *content +--- + +The following example demonstrates how to return a 403 Forbidden response with a diagnostic payload using `ForbiddenObjectResult`, optionally overriding the status code. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace MyApp.Mvc +{ + public class ForbiddenObjectResultExample + { + public IActionResult Demonstrate() + { + // Return 403 Forbidden with a diagnostic message + var forbidden = new ForbiddenObjectResult( + new { error = "Insufficient permissions", requiredRole = "admin" }); + + Console.WriteLine($"Status code: {forbidden.StatusCode}"); + Console.WriteLine($"Value: {forbidden.Value}"); + + return forbidden; + } + + public IActionResult DemonstrateWithCustomStatusCode() + { + // Return 404 Not Found instead of 403 (to "hide" the resource existence) + var hidden = new ForbiddenObjectResult( + "Resource not found.", + StatusCodes.Status404NotFound); + + Console.WriteLine($"Status code: {hidden.StatusCode}"); + + return hidden; + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.ForbiddenResult.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.ForbiddenResult.md new file mode 100644 index 00000000..f67869c1 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.ForbiddenResult.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.AspNetCore.Mvc.ForbiddenResult +example: +- *content +--- + +The following example shows how can return the default 403 status code or a different client-error code when you want to hide the existence of a protected resource. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc; +using Microsoft.AspNetCore.Http; + +namespace MyApp.Examples; + +public static class ForbiddenResultExample +{ + public static void Demonstrate() + { + var forbidden = new ForbiddenResult(); + var disguised = new ForbiddenResult(StatusCodes.Status404NotFound); + + Console.WriteLine(forbidden.StatusCode); + Console.WriteLine(disguised.StatusCode); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.GoneResult.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.GoneResult.md new file mode 100644 index 00000000..570b3b82 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.GoneResult.md @@ -0,0 +1,24 @@ +--- +uid: Cuemon.AspNetCore.Mvc.GoneResult +example: +- *content +--- + +The following example shows how can signal that a resource has been permanently removed. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc; + +namespace MyApp.Examples; + +public static class GoneResultExample +{ + public static void Demonstrate() + { + var result = new GoneResult(); + + Console.WriteLine(result.StatusCode); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.SeeOtherResult.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.SeeOtherResult.md new file mode 100644 index 00000000..862a2e3b --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.SeeOtherResult.md @@ -0,0 +1,25 @@ +--- +uid: Cuemon.AspNetCore.Mvc.SeeOtherResult +example: +- *content +--- + +The following example shows how supports a 303 POST-redirect-GET response. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc; + +namespace MyApp.Examples; + +public static class SeeOtherResultExample +{ + public static void Demonstrate() + { + var result = new SeeOtherResult(new Uri("https://example.com/orders/42")); + + Console.WriteLine(result.StatusCode); + Console.WriteLine(result.Location); + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.TimeBasedObjectResultOptions`1.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.TimeBasedObjectResultOptions`1.md new file mode 100644 index 00000000..911274fd --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.TimeBasedObjectResultOptions`1.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.AspNetCore.Mvc.TimeBasedObjectResultOptions`1 +example: +- *content +--- + +The following example demonstrates how to configure to provide timestamp providers for generating Last-Modified headers. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc; + +namespace MyApp.Examples; + +public class TimeBasedObjectResultOptionsExample +{ + public void Demonstrate() + { + var options = new TimeBasedObjectResultOptions + { + TimestampProvider = value => value, + ChangedTimestampProvider = value => value.AddHours(1) + }; + + // Validate that the required properties are configured + options.ValidateOptions(); + + var created = new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc); + Console.WriteLine($"Created: {options.TimestampProvider(created)}"); + Console.WriteLine($"Modified: {options.ChangedTimestampProvider(created)}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.TooManyRequestsObjectResult.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.TooManyRequestsObjectResult.md new file mode 100644 index 00000000..1d666d2f --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.TooManyRequestsObjectResult.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.AspNetCore.Mvc.TooManyRequestsObjectResult +example: +- *content +--- + +The following example demonstrates how to return a with a descriptive error object to produce a 429 HTTP response. + +```csharp +using Cuemon.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; + +namespace MyApp.Examples; + +public class RateLimitController : Controller +{ + [HttpGet("/api/rate-limited")] + public IActionResult GetData() + { + return new TooManyRequestsObjectResult(new + { + error = "API rate limit exceeded. Please try again later.", + retryAfter = 60 + }); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.TooManyRequestsResult.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.TooManyRequestsResult.md new file mode 100644 index 00000000..9a20f5ae --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.TooManyRequestsResult.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.AspNetCore.Mvc.TooManyRequestsResult +example: +- *content +--- + +The following example demonstrates how to return a from a controller action to produce a 429 HTTP response. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; + +namespace MyApp.Examples; + +public class RateLimitController : Controller +{ + [HttpGet("/api/rate-limited")] + public IActionResult GetData() + { + var result = new TooManyRequestsResult(); + Console.WriteLine(result.StatusCode); // 429 + return result; + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppImageTagHelper.md b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppImageTagHelper.md new file mode 100644 index 00000000..4d6c2631 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppImageTagHelper.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.AspNetCore.Razor.TagHelpers.AppImageTagHelper +example: +- *content +--- + +The following example demonstrates how to create `AppImageTagHelper` with application-scoped options. + +```csharp +using System; +using Cuemon.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class AppImageTagHelperExample +{ + public static void Demonstrate() + { + var options = Options.Create(CreateOptions()); + + var tagHelper = new AppImageTagHelper(options); + + Console.WriteLine(FormatAssetUrl(options.Value, "images/logo.svg")); + Console.WriteLine(tagHelper.GetType().Name); + } + + private static AppTagHelperOptions CreateOptions() => new() + { + Scheme = ProtocolUriScheme.Relative, + BaseUrl = "static.cuemon.net" + }; + + private static string FormatAssetUrl(AppTagHelperOptions options, string asset) + { + return options.GetFormattedBaseUrl() + asset; + } +} +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppLinkTagHelper.md b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppLinkTagHelper.md new file mode 100644 index 00000000..c8f41955 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppLinkTagHelper.md @@ -0,0 +1,41 @@ +--- +uid: Cuemon.AspNetCore.Razor.TagHelpers.AppLinkTagHelper +example: +- *content +--- + +The following example demonstrates how to create with application-scoped options. + +```csharp +using System; +using Cuemon.AspNetCore.Configuration; +using Cuemon.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class AppLinkTagHelperExample +{ + private sealed class StylesheetVersion : ICacheBusting + { + public string Version => "1.0.0"; + } + + public static void Demonstrate() + { + var options = new AppTagHelperOptions + { + Scheme = ProtocolUriScheme.Relative, + BaseUrl = "static.cuemon.net" + }; + + var version = new StylesheetVersion(); + var tagHelper = new AppLinkTagHelper(Options.Create(options), version); + var stylesheetHref = $"{options.GetFormattedBaseUrl()}css/site.css?v={version.Version}"; + + Console.WriteLine(stylesheetHref); + Console.WriteLine(tagHelper.GetType().Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppScriptTagHelper.md b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppScriptTagHelper.md new file mode 100644 index 00000000..2eaa4d57 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppScriptTagHelper.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.AspNetCore.Razor.TagHelpers.AppScriptTagHelper +example: +- *content +--- + +The following example demonstrates how to create with application-scoped options. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class AppScriptTagHelperExample +{ + public static void Demonstrate() + { + var options = Options.Create(new AppTagHelperOptions + { + Scheme = ProtocolUriScheme.Relative, + BaseUrl = "static.cuemon.net" + }); + + var tagHelper = new AppScriptTagHelper(options); + var segments = new List + { + options.Value.GetFormattedBaseUrl(), + "js/app.js" + }; + + Console.WriteLine(string.Concat(segments)); + Console.WriteLine(tagHelper.GetType().Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppTagHelperOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppTagHelperOptions.md new file mode 100644 index 00000000..bf233275 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.AppTagHelperOptions.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.AspNetCore.Razor.TagHelpers.AppTagHelperOptions +example: +- *content +--- + +The following example demonstrates how to configure to customize the base URL and URI scheme for application-scoped tag helpers. + +```csharp +using Cuemon.AspNetCore.Razor.TagHelpers; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples; + +public class AppTagHelperOptionsExample +{ + public static void Main(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + + builder.Services.AddRazorPages(); + builder.Services.Configure(o => + { + o.Scheme = ProtocolUriScheme.Https; + o.BaseUrl = "static.example.com"; + }); + + var app = builder.Build(); + app.Run(); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnImageTagHelper.md b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnImageTagHelper.md new file mode 100644 index 00000000..ef1bcc92 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnImageTagHelper.md @@ -0,0 +1,41 @@ +--- +uid: Cuemon.AspNetCore.Razor.TagHelpers.CdnImageTagHelper +example: +- *content +--- + +The following example demonstrates how to create `CdnImageTagHelper` with CDN-specific options. + +```csharp +using System; +using Cuemon.AspNetCore.Configuration; +using Cuemon.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class CdnImageTagHelperExample +{ + private sealed class AssetVersion : ICacheBusting + { + public string Version => "2.1.0"; + } + + public static void Demonstrate() + { + var settings = new CdnTagHelperOptions + { + Scheme = ProtocolUriScheme.Https, + BaseUrl = "nblcdn.net" + }; + + var version = new AssetVersion(); + var tagHelper = new CdnImageTagHelper(Options.Create(settings), version); + var imageUrl = settings.GetFormattedBaseUrl() + "images/logo.svg?v=" + version.Version; + + Console.WriteLine(imageUrl); + Console.WriteLine(tagHelper.GetType().Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnLinkTagHelper.md b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnLinkTagHelper.md new file mode 100644 index 00000000..cfa83b6f --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnLinkTagHelper.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.AspNetCore.Razor.TagHelpers.CdnLinkTagHelper +example: +- *content +--- + +The following example demonstrates how to create `CdnLinkTagHelper` with CDN-specific options. + +```csharp +using System; +using Cuemon.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class CdnLinkTagHelperExample +{ + public static void Demonstrate() + { + var options = Options.Create(CreateStylesheetOptions("nblcdn.net")); + + var tagHelper = new CdnLinkTagHelper(options); + var stylesheetHref = options.Value.GetFormattedBaseUrl() + "packages/fontawesome/5.15.3/css/all.css"; + + Console.WriteLine(stylesheetHref); + Console.WriteLine(tagHelper.GetType().Name); + } + + private static CdnTagHelperOptions CreateStylesheetOptions(string baseUrl) + { + return new CdnTagHelperOptions + { + Scheme = ProtocolUriScheme.Https, + BaseUrl = baseUrl + }; + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnScriptTagHelper.md b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnScriptTagHelper.md new file mode 100644 index 00000000..a61f8ca2 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnScriptTagHelper.md @@ -0,0 +1,41 @@ +--- +uid: Cuemon.AspNetCore.Razor.TagHelpers.CdnScriptTagHelper +example: +- *content +--- + +The following example demonstrates how to create `CdnScriptTagHelper` with CDN-specific options. + +```csharp +using System; +using Cuemon.AspNetCore.Configuration; +using Cuemon.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class CdnScriptTagHelperExample +{ + private sealed class ScriptVersion : ICacheBusting + { + public string Version => "1.0.0"; + } + + public static void Demonstrate() + { + var options = Options.Create(new CdnTagHelperOptions + { + Scheme = ProtocolUriScheme.Https, + BaseUrl = "nblcdn.net" + }); + + var cacheBusting = new ScriptVersion(); + var tagHelper = new CdnScriptTagHelper(options, cacheBusting); + var scriptPath = string.Concat(options.Value.GetFormattedBaseUrl(), "packages/fontawesome/5.15.3/js/all.js?v=", cacheBusting.Version); + + Console.WriteLine(scriptPath); + Console.WriteLine(tagHelper.GetType().Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnTagHelperOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnTagHelperOptions.md new file mode 100644 index 00000000..2588fb74 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.CdnTagHelperOptions.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.AspNetCore.Razor.TagHelpers.CdnTagHelperOptions +example: +- *content +--- + +The following example demonstrates how to configure for CDN-scoped tag helpers. + +```csharp +using System; +using Cuemon.AspNetCore.Razor.TagHelpers; + +namespace MyApp.Examples; + +public static class CdnTagHelperOptionsExample +{ + public static void Demonstrate() + { + var options = new CdnTagHelperOptions + { + Scheme = ProtocolUriScheme.Https, + BaseUrl = "nblcdn.net" + }; + + Console.WriteLine(options.GetFormattedBaseUrl()); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.ProtocolUriScheme.md b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.ProtocolUriScheme.md new file mode 100644 index 00000000..16dc2e20 --- /dev/null +++ b/.docfx/api/types/Cuemon.AspNetCore.Razor.TagHelpers.ProtocolUriScheme.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.AspNetCore.Razor.TagHelpers.ProtocolUriScheme +example: +- *content +--- + +The following example demonstrates how to use the enum when configuring tag helper options. + +```csharp +using Cuemon.AspNetCore.Razor.TagHelpers; +using System; + +namespace DocfxExamples; + +public class ProtocolUriSchemeExample +{ + public void Demonstrate() + { + var options = new CdnTagHelperOptions + { + Scheme = ProtocolUriScheme.Https, + BaseUrl = "cdn.example.com" + }; + + var formatted = options.GetFormattedBaseUrl(); + Console.WriteLine(formatted); // Output: https://cdn.example.com/ + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.AssignmentOperator.md b/.docfx/api/types/Cuemon.AssignmentOperator.md new file mode 100644 index 00000000..e03007c0 --- /dev/null +++ b/.docfx/api/types/Cuemon.AssignmentOperator.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.AssignmentOperator +example: +- *content +--- + +The following example demonstrates how to use the enum to specify arithmetic or bitwise compound assignment operations. + +```csharp +using System; +using Cuemon; + +namespace Contoso.Billing; + +public sealed class AssignmentOperatorExample +{ + public static void Run() + { + int total = Calculator.Calculate(5, AssignmentOperator.Addition, 3); + int shifted = Calculator.Calculate(5, AssignmentOperator.LeftShift, 2); + + Console.WriteLine($"Total: {total}"); + Console.WriteLine($"Shifted: {shifted}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.ByteArrayDecoratorExtensions.md b/.docfx/api/types/Cuemon.ByteArrayDecoratorExtensions.md new file mode 100644 index 00000000..0d405f67 --- /dev/null +++ b/.docfx/api/types/Cuemon.ByteArrayDecoratorExtensions.md @@ -0,0 +1,50 @@ +--- +uid: Cuemon.ByteArrayDecoratorExtensions +example: +- *content +--- + +The following example shows how to extend `byte[]` with `ByteArrayDecoratorExtensions` methods to convert byte arrays into encoded strings and seekable streams. + +```csharp +using System; +using System.IO; +using System.Text; +using Cuemon; +using Cuemon.Text; + +namespace MyApp +{ + public class ByteArrayDecoratorExtensionsExample + { + public void Demonstrate() + { + // Create a byte array from a string + byte[] data = Encoding.UTF8.GetBytes("Hello, World!"); + + // Convert bytes to a string with default UTF-8 encoding + string text = Decorator.Enclose(data).ToEncodedString(); + Console.WriteLine(text); // "Hello, World!" + + // Convert bytes to a string with specific encoding + byte[] isoData = Encoding.GetEncoding("iso-8859-1").GetBytes("Café"); + string isoText = Decorator.Enclose(isoData).ToEncodedString(o => + { + o.Encoding = Encoding.GetEncoding("iso-8859-1"); + }); + Console.WriteLine(isoText); // "Café" + + // Convert bytes to a seekable Stream + using Stream stream = Decorator.Enclose(data).ToStream(); + Console.WriteLine(stream.Length); // 13 + Console.WriteLine(stream.CanSeek); // True + + // Read the stream back + using var reader = new StreamReader(stream); + string fromStream = reader.ReadToEnd(); + Console.WriteLine(fromStream); // "Hello, World!" + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Calculator.md b/.docfx/api/types/Cuemon.Calculator.md new file mode 100644 index 00000000..5f423ed7 --- /dev/null +++ b/.docfx/api/types/Cuemon.Calculator.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Calculator +example: +- *content +--- + +```csharp +using System; +using Cuemon; + +namespace MyApp.Arithmetic; + +public class CalculatorExample +{ + public void Demonstrate() + { + int sum = Calculator.Add(10, 20); + Console.WriteLine(sum); // 30 + + int difference = Calculator.Subtract(20, 5); + Console.WriteLine(difference); // 15 + + int product = Calculator.Multiply(4, 5); + Console.WriteLine(product); // 20 + + int quotient = Calculator.Divide(20, 4); + Console.WriteLine(quotient); // 5 + + int remainder = Calculator.Remainder(10, 3); + Console.WriteLine(remainder); // 1 + + int bitwiseAnd = Calculator.And(0b1100, 0b1010); + Console.WriteLine(bitwiseAnd); // 8 (0b1000) + } +} +``` diff --git a/.docfx/api/types/Cuemon.CasingMethod.md b/.docfx/api/types/Cuemon.CasingMethod.md new file mode 100644 index 00000000..20beb6ba --- /dev/null +++ b/.docfx/api/types/Cuemon.CasingMethod.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.CasingMethod +example: +- *content +--- + +The following example demonstrates how to use `CasingMethod` to control string casing transformations. + +```csharp +using Cuemon; +using System; + +namespace MyApp.Examples; + +public class CasingMethodExample +{ + public void Demonstrate() + { + var lower = CasingMethod.LowerCase; + var upper = CasingMethod.UpperCase; + var title = CasingMethod.TitleCase; + + Console.WriteLine(lower); // outputs: LowerCase + Console.WriteLine(upper); // outputs: UpperCase + Console.WriteLine(title); // outputs: TitleCase + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.CharDecoratorExtensions.md b/.docfx/api/types/Cuemon.CharDecoratorExtensions.md new file mode 100644 index 00000000..d27a35f8 --- /dev/null +++ b/.docfx/api/types/Cuemon.CharDecoratorExtensions.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.CharDecoratorExtensions +example: +- *content +--- + +The following example shows how to extend `IEnumerable` with `CharDecoratorExtensions` methods to convert character sequences into single-character strings and back to a combined string. + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon; + +namespace MyApp +{ + public class CharDecoratorExtensionsExample + { + public void Demonstrate() + { + // Convert a sequence of characters to a sequence of single-character strings + IEnumerable characters = "Hello".AsEnumerable(); + + IEnumerable strings = Decorator.Enclose(characters).ToEnumerable(); + Console.WriteLine(string.Join(", ", strings)); // "H, e, l, l, o" + + // Convert a sequence of characters back to a single string + string result = Decorator.Enclose(characters).ToStringEquivalent(); + Console.WriteLine(result); // "Hello" + + // Works with any IEnumerable including char arrays + char[] charArray = { 'A', 'B', 'C' }; + string joined = Decorator.Enclose(charArray.AsEnumerable()).ToStringEquivalent(); + Console.WriteLine(joined); // "ABC" + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.Arguments.md b/.docfx/api/types/Cuemon.Collections.Generic.Arguments.md new file mode 100644 index 00000000..af3b775b --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.Arguments.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.Collections.Generic.Arguments +example: +- *content +--- + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon.Collections.Generic; + +namespace MyApp.Examples; + +public static class ArgumentsExample +{ + public static void Demonstrate() + { + int[] first = Arguments.ToArrayOf(1, 2, 3); + int[] second = Arguments.ToArrayOf(4, 5, 6); + + // Concat two arrays + int[] combined = Arguments.Concat(first, second); + Console.WriteLine(string.Join(", ", combined)); + + // Yield a single element + IEnumerable yielded = Arguments.Yield(42); + Console.WriteLine(yielded.First()); + + // Convert to IEnumerable + IEnumerable enumerable = Arguments.ToEnumerableOf("a", "b", "c"); + Console.WriteLine(string.Concat(enumerable)); + + // Object overloads + object[] objs = Arguments.ToArray(1, "two", 3.0); + IEnumerable objEnumerable = Arguments.ToEnumerable(true, false); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.CollectionDecoratorExtensions.md b/.docfx/api/types/Cuemon.Collections.Generic.CollectionDecoratorExtensions.md new file mode 100644 index 00000000..73d41ee2 --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.CollectionDecoratorExtensions.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Collections.Generic.CollectionDecoratorExtensions +example: +- *content +--- + +```csharp +using System; +using System.Collections.Generic; +using Cuemon; +using Cuemon.Collections.Generic; + +namespace MyApp.Examples +{ + public class CollectionDecoratorExtensionsExample + { + public static void Demonstrate() + { + var list = new List { "apple", "banana" }; + + // Use Decorator to access non-common extension methods + Decorator.Enclose(list).AddRange("cherry", "date", "elderberry"); + Decorator.Enclose(list).AddRange(new[] { "fig", "grape" }); + + Console.WriteLine(string.Join(", ", list)); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.DictionaryDecoratorExtensions.md b/.docfx/api/types/Cuemon.Collections.Generic.DictionaryDecoratorExtensions.md new file mode 100644 index 00000000..57bdde21 --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.DictionaryDecoratorExtensions.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Collections.Generic.DictionaryDecoratorExtensions +example: +- *content +--- + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon; +using Cuemon.Collections.Generic; + +namespace Contoso.Inventory; + +public sealed class DictionaryDecoratorExtensionsExample +{ + public static void Run() + { + IDictionary catalog = new Dictionary + { + [1] = "apples", + [2] = "bananas" + }; + + var decorated = Decorator.Enclose(catalog); + string fallback = decorated.GetValueOrDefault(3, () => "not found"); + bool found = decorated.TryGetValueOrFallback(42, keys => 2, out var alias); + bool added = decorated.TryAdd(3, "cherries"); + decorated.AddOrUpdate(2, "blueberries"); + KeyValuePair[] entries = decorated.ToEnumerable().ToArray(); + + IDictionary copy = decorated.CopyTo(new Dictionary()); + + IDictionary> depthIndexes = new Dictionary>(); + int depthIndex = Decorator.Enclose(depthIndexes).GetDepthIndex(readerDepth: 0, index: 1, nesting: 0); + + Console.WriteLine($"Fallback: {fallback}"); + Console.WriteLine($"Found fallback key: {found} -> {alias}"); + Console.WriteLine($"Added key 3: {added}"); + Console.WriteLine($"Enumerated entries: {entries.Length}"); + Console.WriteLine($"Copied entries: {copy.Count}"); + Console.WriteLine($"Depth index: {depthIndex}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.DynamicComparer.md b/.docfx/api/types/Cuemon.Collections.Generic.DynamicComparer.md new file mode 100644 index 00000000..94614fb1 --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.DynamicComparer.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Collections.Generic.DynamicComparer +example: +- *content +--- + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon.Collections.Generic; + +namespace MyApp.Examples; + +public static class DynamicComparerExample +{ + public static void Demonstrate() + { + string[] fruits = ["apple", "pear", "banana", "kiwi"]; + + // Create a dynamic comparer that sorts by string length + IComparer lengthComparer = DynamicComparer.Create((x, y) => + x.Length.CompareTo(y.Length)); + + Array.Sort(fruits, lengthComparer); + Console.WriteLine(string.Join(", ", fruits)); + + // Create a comparer that sorts descending + IComparer descendingComparer = DynamicComparer.Create((x, y) => + string.Compare(y, x, StringComparison.Ordinal)); + + Array.Sort(fruits, descendingComparer); + Console.WriteLine(string.Join(", ", fruits)); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.DynamicEqualityComparer.md b/.docfx/api/types/Cuemon.Collections.Generic.DynamicEqualityComparer.md new file mode 100644 index 00000000..5096e10e --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.DynamicEqualityComparer.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Collections.Generic.DynamicEqualityComparer +example: +- *content +--- + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon.Collections.Generic; + +namespace MyApp.Examples; + +public static class DynamicEqualityComparerExample +{ + public static void Demonstrate() + { + string[] words = ["Hello", "world", "hello", "World", "HELLO"]; + + // Create a case-insensitive equality comparer for strings + IEqualityComparer caseInsensitive = DynamicEqualityComparer.Create( + hashCalculator: s => StringComparer.OrdinalIgnoreCase.GetHashCode(s), + equalityComparer: (x, y) => string.Equals(x, y, StringComparison.OrdinalIgnoreCase)); + + string[] distinct = words.Distinct(caseInsensitive).ToArray(); + Console.WriteLine(string.Join(", ", distinct)); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.EnumReadOnlyDictionary`1.md b/.docfx/api/types/Cuemon.Collections.Generic.EnumReadOnlyDictionary`1.md new file mode 100644 index 00000000..43336bd6 --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.EnumReadOnlyDictionary`1.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.Collections.Generic.EnumReadOnlyDictionary`1 +example: +- *content +--- + +The following example demonstrates how to use to create a read-only dictionary that maps each enum value (as its underlying integral type wrapped in ) to its string name. + +```csharp +using System.Collections.Generic; +using System; +using System.Linq; +using Cuemon.Collections.Generic; + +namespace MyApp.Examples; + +public class EnumReadOnlyDictionaryExample +{ + public void Demonstrate() + { + // Create a dictionary that maps DayOfWeek values to their string names + var days = new EnumReadOnlyDictionary(); + + Console.WriteLine(days.Count); // 7 + + // Iterate through all entries (keys are the underlying integral values) + foreach (var kvp in days.OrderBy(kvp => kvp.Key.ToInt32(null))) + { + Console.WriteLine($"{kvp.Key.ToInt32(null)} -> {kvp.Value}"); + // Output: + // 0 -> Sunday + // 1 -> Monday + // 2 -> Tuesday + // 3 -> Wednesday + // 4 -> Thursday + // 5 -> Friday + // 6 -> Saturday + + // Access the values collection directly + foreach (var name in days.Values) + { + Console.WriteLine(name); // Sunday, Monday, ..., Saturday + + // Access the keys collection + foreach (var key in days.Keys) + { + Console.WriteLine(key.ToInt32(null)); // 0, 1, 2, ..., 6 + +}}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.EnumerableSizeComparer-1.md b/.docfx/api/types/Cuemon.Collections.Generic.EnumerableSizeComparer-1.md new file mode 100644 index 00000000..507be584 --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.EnumerableSizeComparer-1.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.Collections.Generic.EnumerableSizeComparer`1 +example: +- *content +--- + +```csharp +using System; +using System.Collections; +using System.Collections.Generic; +using Cuemon.Collections.Generic; + +namespace MyApp.Examples +{ + public class EnumerableSizeComparerExample + { + public static void Demonstrate() + { + var shortList = new[] { 10, 20, 30 }; + var longList = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + var equalList = new[] { "x", "y", "z" }; + + var comparer = EnumerableSizeComparer.Default; + + int result1 = comparer.Compare(shortList, longList); // -1 (shortList has fewer elements) + int result2 = comparer.Compare(longList, shortList); // 1 (longList has more elements) + int result3 = comparer.Compare(shortList, equalList); // 0 (both have 3 elements) + int result4 = comparer.Compare(null, longList); // -1 (null is less than any non-null) + int result5 = comparer.Compare(shortList, null); // 1 (non-null is greater than null) + + Console.WriteLine($"shortList vs longList : {result1}"); + Console.WriteLine($"longList vs shortList : {result2}"); + Console.WriteLine($"shortList vs equalList: {result3}"); + Console.WriteLine($"null vs longList : {result4}"); + Console.WriteLine($"shortList vs null : {result5}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.PaginationEnumerable-1.md b/.docfx/api/types/Cuemon.Collections.Generic.PaginationEnumerable-1.md new file mode 100644 index 00000000..5e09435e --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.PaginationEnumerable-1.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.Collections.Generic.PaginationEnumerable`1 +example: +- *content +--- + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon.Collections.Generic; + +namespace MyApp.Examples +{ + public class PaginationEnumerableExample + { + public static void Demonstrate() + { + var fruits = new[] { "Apple", "Banana", "Cherry", "Date", "Elderberry", "Fig", "Grape", "Honeydew" }; + + // Show page 2 with 3 items per page + var page = new PaginationEnumerable(fruits, () => fruits.Length, setup => + { + setup.PageSize = 3; + setup.PageNumber = 2; + }); + + Console.WriteLine($"Page {2} of {page.PageCount} (total items: {page.TotalElementCount})"); + Console.WriteLine($"Has previous page: {page.HasPreviousPage}"); + Console.WriteLine($"Has next page: {page.HasNextPage}"); + Console.WriteLine("Items on this page:"); + foreach (var item in page) + { + Console.WriteLine($" {item}"); + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.PaginationList-1.md b/.docfx/api/types/Cuemon.Collections.Generic.PaginationList-1.md new file mode 100644 index 00000000..2429a924 --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.PaginationList-1.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.Collections.Generic.PaginationList`1 +example: +- *content +--- + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.Collections.Generic; + +namespace MyApp.Examples +{ + public class PaginationListExample + { + public static void Demonstrate() + { + var customers = new List + { + "Alice", "Bob", "Carol", "Dave", "Eve", + "Frank", "Grace", "Hank", "Iris", "Jack", + "Kate", "Leo", "Mia", "Noah", "Olivia" + }; + + // Eagerly materialize page 3 with 5 items per page + var page = new PaginationList(customers, () => customers.Count, setup => + { + setup.PageSize = 5; + setup.PageNumber = 3; + }); + + Console.WriteLine($"Page items (count: {page.Count})"); + for (int i = 0; i < page.Count; i++) + { + Console.WriteLine($" [{i}] {page[i]}"); + Console.WriteLine($"Total items: {page.TotalElementCount}"); + Console.WriteLine($"Total pages: {page.PageCount}"); + Console.WriteLine($"First page: {page.FirstPage}"); + Console.WriteLine($"Last page: {page.LastPage}"); + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.PaginationOptions.md b/.docfx/api/types/Cuemon.Collections.Generic.PaginationOptions.md new file mode 100644 index 00000000..bf09a743 --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.PaginationOptions.md @@ -0,0 +1,64 @@ +--- +uid: Cuemon.Collections.Generic.PaginationOptions +example: +- *content +--- + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon.Collections.Generic; + +namespace MyApp.Collections; + +public class PaginationOptionsExample +{ + public void Demonstrate() + { + // Create a source sequence with 100 items + var allItems = Enumerable.Range(1, 100).ToList(); + + // Configure pagination options directly + var options = new PaginationOptions { PageSize = 10, PageNumber = 3 }; + Console.WriteLine($"Page size: {options.PageSize}, Page number: {options.PageNumber}"); + + // Paginate with 10 items per page, starting at page 3 + var page = new PaginationEnumerable(allItems, + () => allItems.Count, + setup => + { + setup.PageSize = 10; // show 10 items per page + setup.PageNumber = 3; // go to page 3 + }); + + Console.WriteLine($"Page 3 items: {string.Join(", ", page)}"); // 21..30 + Console.WriteLine($"Total pages: {page.PageCount}"); // 10 + Console.WriteLine($"Total items: {page.TotalElementCount}"); // 100 + Console.WriteLine($"Has next page: {page.HasNextPage}"); // True + Console.WriteLine($"First page: {page.FirstPage}"); // False + Console.WriteLine($"Last page: {page.LastPage}"); // False + + // Default PaginationOptions: page 1, 25 items per page + var firstPage = new PaginationEnumerable(allItems, + () => allItems.Count); + + Console.WriteLine($"First page items: {string.Join(", ", firstPage)}"); // 1..25 + Console.WriteLine($"Has previous page: {firstPage.HasPreviousPage}"); // False + + // Using PaginationList for eager materialization with indexer access + var thirdPage = new PaginationList(allItems, + () => allItems.Count, + setup => + { + setup.PageSize = 10; + setup.PageNumber = 3; + }); + + Console.WriteLine($"Third item on page 3: {thirdPage[2]}"); // 23 (zero-based index) + Console.WriteLine($"Page 3 count: {thirdPage.Count}"); // 10 + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.PartitionerCollection-1.md b/.docfx/api/types/Cuemon.Collections.Generic.PartitionerCollection-1.md new file mode 100644 index 00000000..d7d233d3 --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.PartitionerCollection-1.md @@ -0,0 +1,47 @@ +--- +uid: Cuemon.Collections.Generic.PartitionerCollection`1 +example: +- *content +--- + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.Collections.Generic; + +namespace MyApp.Examples +{ + public class PartitionerCollectionExample + { + public static void Demonstrate() + { + var numbers = new List(); + for (int i = 1; i <= 50; i++) numbers.Add(i); + + // Process in partitions of 12 items each + var partitioner = new PartitionerCollection(numbers, partitionSize: 12); + + Console.WriteLine($"Total items: {partitioner.Count}"); + Console.WriteLine($"Partition size: {partitioner.PartitionSize}"); + Console.WriteLine($"Total partitions: {partitioner.PartitionsCount}"); + Console.WriteLine($"Items remaining: {partitioner.Remaining}"); + Console.WriteLine(); + + int partitionIndex = 0; + while (partitioner.HasPartitions) + { + partitionIndex++; + Console.Write($"Partition {partitionIndex}: "); + foreach (var item in partitioner) + { + Console.Write($"{item} "); + Console.WriteLine(); + + Console.WriteLine(); + Console.WriteLine($"Iterated count: {partitioner.IteratedCount}"); + Console.WriteLine($"Has remaining partitions: {partitioner.HasPartitions}"); + +}}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.PartitionerEnumerable`1.md b/.docfx/api/types/Cuemon.Collections.Generic.PartitionerEnumerable`1.md new file mode 100644 index 00000000..d83d2639 --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.PartitionerEnumerable`1.md @@ -0,0 +1,66 @@ +--- +uid: Cuemon.Collections.Generic.PartitionerEnumerable`1 +example: +- *content +--- + +The following example demonstrates how to use to iterate over a sequence in fixed-size partitions. + +```csharp +using System; +using System.Linq; +using Cuemon.Collections.Generic; + +namespace MyApp.Examples; + +public class PartitionerEnumerableExample +{ + public void Demonstrate() + { + // Create a sequence of 1000 numbers + var numbers = Enumerable.Range(1, 1000); + + // Wrap in a partitioner with partition size of 100 + var partitioner = new PartitionerEnumerable(numbers, partitionSize: 100); + + Console.WriteLine(partitioner.PartitionSize); // 100 + Console.WriteLine(partitioner.HasPartitions); // True + Console.WriteLine(partitioner.IteratedCount); // 0 + + // Process the first partition (items 1-100) + var firstBatch = partitioner.ToList(); + Console.WriteLine(firstBatch.Count); // 100 + Console.WriteLine(firstBatch[0]); // 1 + Console.WriteLine(firstBatch[99]); // 100 + + Console.WriteLine(partitioner.IteratedCount); // 1 + Console.WriteLine(partitioner.HasPartitions); // True + + // Process the remaining partitions + while (partitioner.HasPartitions) + { + var batch = partitioner.ToList(); + Console.WriteLine($"Batch {partitioner.IteratedCount}: {batch.Count} items"); + // After exhausting the sequence: + Console.WriteLine(partitioner.HasPartitions); // False + Console.WriteLine(partitioner.IteratedCount); // 10 (1000/100) + + // A partitioner can be iterated multiple times (each iteration + // advances through the source sequence) + var words = new PartitionerEnumerable( + new[] { "a", "b", "c", "d", "e", "f", "g", "h" }, + partitionSize: 3); + + while (words.HasPartitions) + { + var chunk = words.ToList(); + Console.WriteLine(string.Join(",", chunk)); + // Output: + // a,b,c + // d,e,f + // g,h + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.ReferenceComparer-1.md b/.docfx/api/types/Cuemon.Collections.Generic.ReferenceComparer-1.md new file mode 100644 index 00000000..ed4d50d6 --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.ReferenceComparer-1.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.Collections.Generic.ReferenceComparer`1 +example: +- *content +--- + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.Collections.Generic; + +namespace MyApp.Collections; + +public class ReferenceComparerExample +{ + public void Demonstrate() + { + // ReferenceComparer compares objects by their inheritance depth. + // Objects with a deeper inheritance chain are considered "greater." + + // Compare two strings (string derives from object → depth 2) + string hello = "hello"; + string world = "world"; + IComparer comparer = ReferenceComparer.Default; + + int result1 = comparer.Compare(hello, world); + Console.WriteLine($"string vs string: {result1}"); // 0 (same depth) + + // Compare a string with an Exception (deeper hierarchy) + var exception = new InvalidOperationException(); + int result2 = comparer.Compare(hello, exception); + Console.WriteLine($"string vs Exception: {result2}"); // -1 (string is shallower) + + // Compare an ArgumentNullException (depth 4) with Exception (depth 3) + var argEx = new ArgumentNullException(); + int result3 = comparer.Compare(argEx, exception); + Console.WriteLine($"ArgumentNullException vs Exception: {result3}"); // 1 (deeper) + + // Compare with null values + int result4 = comparer.Compare(hello, null); + Console.WriteLine($"string vs null: {result4}"); // 1 (non-null is greater) + + int result5 = comparer.Compare(null, hello); + Console.WriteLine($"null vs string: {result5}"); // -1 (null is lesser) + + int result6 = comparer.Compare(null, null); + Console.WriteLine($"null vs null: {result6}"); // 0 (both null) + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Collections.Generic.StackDecoratorExtensions.md b/.docfx/api/types/Cuemon.Collections.Generic.StackDecoratorExtensions.md new file mode 100644 index 00000000..88d5cdef --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Generic.StackDecoratorExtensions.md @@ -0,0 +1,7 @@ +--- +uid: Cuemon.Collections.Generic.StackDecoratorExtensions +example: +- *content +--- + + diff --git a/.docfx/api/types/Cuemon.Collections.Specialized.DictionaryDecoratorExtensions.md b/.docfx/api/types/Cuemon.Collections.Specialized.DictionaryDecoratorExtensions.md new file mode 100644 index 00000000..3dd4a57c --- /dev/null +++ b/.docfx/api/types/Cuemon.Collections.Specialized.DictionaryDecoratorExtensions.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.Collections.Specialized.DictionaryDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the `ToNameValueCollection` extension method to convert an `IDictionary` into a `NameValueCollection`. + +```csharp +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using Cuemon; +using Cuemon.Collections.Specialized; + +namespace MyApp.Examples; + +public class DictionaryDecoratorExtensionsExample +{ + public static void Main() + { + var input = new Dictionary + { + ["colors"] = new[] { "red", "green", "blue" }, + ["sizes"] = new[] { "small", "medium", "large" } + }; + + // Wrap the dictionary with Decorator and call the extension method. + NameValueCollection nvc = Decorator.Enclose(input).ToNameValueCollection(); + + foreach (string key in nvc) + { + Console.WriteLine("{0} = {1}", key, nvc[key]); + + // Output: + // colors = red,green,blue + // sizes = small,medium,large + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Condition.md b/.docfx/api/types/Cuemon.Condition.md new file mode 100644 index 00000000..f6d74073 --- /dev/null +++ b/.docfx/api/types/Cuemon.Condition.md @@ -0,0 +1,116 @@ +--- +uid: Cuemon.Condition +example: +- *content +--- + +The following example demonstrates how to use the `Condition` class to perform common validation checks, equality comparisons, conditional branching, and range assertions. + +```csharp +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Threading.Tasks; +using Cuemon; + +namespace MyApp.Validation +{ + public class ConditionExamples + { + public void DemonstrateConditions() + { + // AreEqual / AreNotEqual with default and custom comparers + if (Condition.AreEqual("hello", "hello")) + { + Console.WriteLine("Strings are equal using default ordinal comparison."); + + if (Condition.AreEqual("hello", "HELLO", StringComparer.OrdinalIgnoreCase)) + { + Console.WriteLine("Strings are equal ignoring case."); + + if (Condition.AreNotEqual("hello", "world")) + { + Console.WriteLine("Strings are different."); + + // Reference equality checks + var same = new object(); + var different = new object(); + Console.WriteLine(Condition.AreSame(same, same)); // True + Console.WriteLine(Condition.AreSame(same, different)); // False + + // FlipFlop - executes one of two actions based on condition + var log = new List(); + Condition.FlipFlop(true, + () => log.Add("condition was true"), + () => log.Add("condition was false")); + + Condition.FlipFlop(false, + (int x) => log.Add($"got {x}"), + (int x) => log.Add($"skipped {x}"), + 42); + + Console.WriteLine(string.Join(", ", log)); // "condition was true, skipped 42" + + // TernaryIf - functional ternary + var result = Condition.TernaryIf(true, + () => "first branch", + () => "second branch"); + Console.WriteLine(result); // "first branch" + + var guided = Condition.TernaryIf(42 > 10, + (int x) => x * 2, + (int x) => x / 2, + 42); + Console.WriteLine(guided); // 84 + + // IsTrue / IsFalse as conditional invocations + Condition.IsTrue(Condition.IsEmailAddress("user@example.com"), () => + { + Console.WriteLine("Valid email address."); + }); + + Condition.IsFalse(string.IsNullOrEmpty("hello"), () => + { + Console.WriteLine("String is not null or empty."); + }); + + // Validation checks + Console.WriteLine(Condition.IsGuid("550e8400-e29b-41d4-a716-446655440000")); // True + Console.WriteLine(Condition.IsGuid("not-a-guid")); // False + Console.WriteLine(Condition.IsUri("https://example.com")); // True + Console.WriteLine(Condition.IsNumeric("3.14", NumberStyles.Float, CultureInfo.InvariantCulture)); // True + Console.WriteLine(Condition.IsEmailAddress("test@test.com")); // True + Console.WriteLine(Condition.IsEven(42)); // True + Console.WriteLine(Condition.IsOdd(41)); // True + Console.WriteLine(Condition.IsPrime(17)); // True + Console.WriteLine(Condition.IsDefault(0)); // True + Console.WriteLine(Condition.IsNotDefault(42)); // True + Console.WriteLine(Condition.IsHex("FF00A1")); // True + Console.WriteLine(Condition.IsBase64("SGVsbG8=")); // True + + // Range checks + Console.WriteLine(Condition.IsWithinRange(5, 1, 10)); // True + Console.WriteLine(Condition.IsNotWithinRange(15, 1, 10)); // True + Console.WriteLine(Condition.IsGreaterThan(100, 50)); // True + Console.WriteLine(Condition.IsLowerThan(3, 10)); // True + + // Consecutive characters + Console.WriteLine(Condition.HasConsecutiveCharacters("bookkeeper", 'o')); // True + Console.WriteLine(Condition.HasConsecutiveCharacters("abc", new[] { 'x', 'y' })); // False + + // Countable sequences + Console.WriteLine(Condition.IsCountableSequence(new[] { 1, 3, 5, 7 })); // True + Console.WriteLine(Condition.IsCountableSequence("abc")); // True + + // Async flip-flop + var asyncLog = new List(); + var task = Condition.FlipFlopAsync(true, + async () => { asyncLog.Add("async:true"); await Task.CompletedTask; }, + async () => { asyncLog.Add("async:false"); await Task.CompletedTask; }); + task.Wait(); + Console.WriteLine(string.Join(", ", asyncLog)); // "async:true" + +}}}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Convertible.md b/.docfx/api/types/Cuemon.Convertible.md new file mode 100644 index 00000000..0d1001cc --- /dev/null +++ b/.docfx/api/types/Cuemon.Convertible.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.Convertible +example: +- *content +--- + +```csharp +using System; +using Cuemon; + +namespace MyApp.Conversion; + +public class ConvertibleExample +{ + public void Demonstrate() + { + byte[] intBytes = Convertible.GetBytes(12345); + Console.WriteLine(intBytes.Length); // 4 + Console.WriteLine(BitConverter.ToInt32(intBytes)); // 12345 + + byte[] stringBytes = Convertible.GetBytes("Hello"); + Console.WriteLine(stringBytes.Length); // 5 + + int restored = BitConverter.ToInt32(intBytes); + Console.WriteLine(restored); // 12345 + } +} +``` diff --git a/.docfx/api/types/Cuemon.ConvertibleConverterDictionary.md b/.docfx/api/types/Cuemon.ConvertibleConverterDictionary.md new file mode 100644 index 00000000..ee5d999b --- /dev/null +++ b/.docfx/api/types/Cuemon.ConvertibleConverterDictionary.md @@ -0,0 +1,66 @@ +--- +uid: Cuemon.ConvertibleConverterDictionary +example: +- *content +--- + +The following example demonstrates how to use to register and use type-specific converters that transform values into byte arrays. + +```csharp +using System; +using System.Linq; +using System.Text; +using Cuemon; + +namespace MyApp.Examples; + +public class ConvertibleConverterDictionaryExample +{ + public void Demonstrate() + { + // Create a dictionary of converters for different IConvertible types + var converters = new ConvertibleConverterDictionary() + .Add(value => BitConverter.GetBytes(value)) + .Add(value => BitConverter.GetBytes(value)) + .Add(value => Encoding.UTF8.GetBytes(value)) + .Add(value => BitConverter.GetBytes(value)); + + Console.WriteLine(converters.Count); // 4 + + // Check if a converter exists for a specific type + Console.WriteLine(converters.ContainsKey(typeof(int))); // True + Console.WriteLine(converters.ContainsKey(typeof(float))); // False + + // Use a registered converter + if (converters.TryGetValue(typeof(string), out var stringConverter)) + { + byte[] bytes = stringConverter("Hello"); + Console.WriteLine(bytes.Length); // 5 + Console.WriteLine(Encoding.UTF8.GetString(bytes)); // Hello + + // Use the indexer to get a converter + var intConverter = converters[typeof(int)]; + if (intConverter != null) + { + byte[] intBytes = intConverter(42); + Console.WriteLine(BitConverter.ToInt32(intBytes)); // 42 + + // Iterate all registered converters + foreach (var kvp in converters) + { + Console.WriteLine($"{kvp.Key.Name} -> converter registered"); + // Output: + // Int32 -> converter registered + // Int64 -> converter registered + // String -> converter registered + // Boolean -> converter registered + + // Add a converter using the non-generic Add method + converters.Add(typeof(double), value => BitConverter.GetBytes(value.ToDouble(null))); + Console.WriteLine(converters.Count); // 5 + Console.WriteLine(converters.ContainsKey(typeof(double))); // True + +}}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.ConvertibleOptions.md b/.docfx/api/types/Cuemon.ConvertibleOptions.md new file mode 100644 index 00000000..049f8c4c --- /dev/null +++ b/.docfx/api/types/Cuemon.ConvertibleOptions.md @@ -0,0 +1,74 @@ +--- +uid: Cuemon.ConvertibleOptions +example: +- *content +--- + +The following example demonstrates how to use to configure byte-order (endianness) and custom converters for the class. + +```csharp +using System; +using Cuemon; // for ConvertibleOptions, Convertible, ConvertibleConverterDictionary, Endianness + +namespace MyApp.Examples; + +public class ConvertibleOptionsExample +{ + public void Demonstrate() + { + // Create options with default endianness (system-dependent) + var options = new ConvertibleOptions(); + Console.WriteLine($"Default byte order: {options.ByteOrder}"); + // Output (on x64): LittleEndian + + // Configure for big-endian byte order + options.ByteOrder = Endianness.BigEndian; + Console.WriteLine($"Byte order: {options.ByteOrder}"); // BigEndian + + // Register a custom converter for your own IConvertible type + options.Converters.Add(value => + { + // Convert MyValue to bytes according to the configured byte order + byte[] bytes = BitConverter.GetBytes(value.Amount); + if (options.ByteOrder == Endianness.BigEndian && BitConverter.IsLittleEndian) + { + Array.Reverse(bytes); + } + return bytes; + }); + + // Use Convertible.GetBytes with the configured options + MyValue myValue = new MyValue { Amount = 12345 }; + byte[] result = Convertible.GetBytes(myValue, o => + { + o.ByteOrder = options.ByteOrder; + }); + + Console.WriteLine($"Converted bytes: {BitConverter.ToString(result)}"); + } +} + +public struct MyValue : IConvertible +{ + public int Amount { get; set; } + + // Minimal IConvertible implementation for illustration + public TypeCode GetTypeCode() => TypeCode.Object; + public bool ToBoolean(IFormatProvider provider) => Convert.ToBoolean(Amount); + public byte ToByte(IFormatProvider provider) => Convert.ToByte(Amount); + public char ToChar(IFormatProvider provider) => Convert.ToChar(Amount); + public DateTime ToDateTime(IFormatProvider provider) => Convert.ToDateTime(Amount); + public decimal ToDecimal(IFormatProvider provider) => Amount; + public double ToDouble(IFormatProvider provider) => Amount; + public short ToInt16(IFormatProvider provider) => Convert.ToInt16(Amount); + public int ToInt32(IFormatProvider provider) => Amount; + public long ToInt64(IFormatProvider provider) => Amount; + public sbyte ToSByte(IFormatProvider provider) => Convert.ToSByte(Amount); + public float ToSingle(IFormatProvider provider) => Amount; + public string ToString(IFormatProvider provider) => Amount.ToString(); + public object ToType(Type conversionType, IFormatProvider provider) => Convert.ChangeType(Amount, conversionType); + public ushort ToUInt16(IFormatProvider provider) => Convert.ToUInt16(Amount); + public uint ToUInt32(IFormatProvider provider) => Convert.ToUInt32(Amount); + public ulong ToUInt64(IFormatProvider provider) => Convert.ToUInt64(Amount); +} +``` diff --git a/.docfx/api/types/Cuemon.Data.DataManagerOptions.md b/.docfx/api/types/Cuemon.Data.DataManagerOptions.md new file mode 100644 index 00000000..42934c77 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DataManagerOptions.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Data.DataManagerOptions +example: +- *content +--- + +The following example demonstrates how to configure `DataManagerOptions` with a connection string, reader behavior, and connection lifecycle settings. + +```csharp +using System; +using System.Data; +using Cuemon.Data; + +namespace MyApp.Data +{ + public sealed class DataManagerOptionsExample + { + public void Demonstrate() + { + var options = new DataManagerOptions + { + ConnectionString = "Data Source=app.db", + PreferredReaderBehavior = CommandBehavior.SequentialAccess | CommandBehavior.CloseConnection, + LeaveConnectionOpen = false, + LeaveCommandOpen = false + }; + + options.ValidateOptions(); + + Console.WriteLine($"Connection: {options.ConnectionString}"); + Console.WriteLine($"Reader behavior: {options.PreferredReaderBehavior}"); + Console.WriteLine($"Leave connection open: {options.LeaveConnectionOpen}"); + Console.WriteLine($"Leave command open: {options.LeaveCommandOpen}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.DataReaderDecoratorExtensions.md b/.docfx/api/types/Cuemon.Data.DataReaderDecoratorExtensions.md new file mode 100644 index 00000000..d16430ed --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DataReaderDecoratorExtensions.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.Data.DataReaderDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the decorator extensions to convert an `IDataReader` to an encoded string, an async string, or a stream. + +```csharp +using System; +using System.Data; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Cuemon; +using Cuemon.Data; + +namespace MyApp.Examples +{ + public class DataReaderDecoratorExtensionsExample + { + public static async Task DemonstrateAsync() + { + // Create a single-column DSV data source (must have exactly one field) + var csv = "Value\r\n1001\r\n1002\r\n1003\r\n"; + var bytes = Encoding.UTF8.GetBytes(csv); + + using (var stream = new MemoryStream(bytes)) + using (var reader = new DsvDataReader(new StreamReader(stream))) + { + // Convert the single-field IDataReader to an encoded string (sync) + string result = Decorator.Enclose((IDataReader)reader).ToEncodedString(); + Console.WriteLine(result); + + // Convert the single-field IDataReader to an encoded string (async) + stream.Position = 0; + using (var asyncReader = new DsvDataReader(new StreamReader(new MemoryStream(bytes)))) + { + string asyncResult = await Decorator.Enclose((IDataReader)asyncReader).ToEncodedStringAsync(); + Console.WriteLine(asyncResult); + + // Convert the data reader content to a stream + stream.Position = 0; + using (var readerAgain = new DsvDataReader(new StreamReader(new MemoryStream(bytes)))) + { + Stream dataStream = Decorator.Enclose((IDataReader)readerAgain).ToStream(); + Console.WriteLine($"Stream length: {dataStream.Length}"); + +}}}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.DataStatement.md b/.docfx/api/types/Cuemon.Data.DataStatement.md new file mode 100644 index 00000000..4d163b75 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DataStatement.md @@ -0,0 +1,69 @@ +--- +uid: Cuemon.Data.DataStatement +example: +- *content +--- + +The following example demonstrates how to create `DataStatement` instances for text queries, stored procedures, and parameterized commands. + +```csharp +using System; +using System.Data; +using System.Linq; +using Cuemon.Data; + +namespace MyApp.DataAccess +{ + public sealed class DataStatementExample + { + public void Demonstrate() + { + DataStatement textStatement = "SELECT * FROM Product"; + Console.WriteLine(textStatement.Text); + Console.WriteLine(textStatement.Type); + + var storedProcedure = new DataStatement("dbo.GetOrdersByDate", options => + { + options.Type = CommandType.StoredProcedure; + options.Timeout = TimeSpan.FromSeconds(120); + }); + Console.WriteLine($"{storedProcedure.Text} ({storedProcedure.Type})"); + + var parameterized = new DataStatement("UPDATE Inventory SET Quantity = Quantity - @qty WHERE ProductId = @id", options => + { + options.Parameters = new IDataParameter[] + { + new DemoParameter("@qty", 5), + new DemoParameter("@id", 1001) + }; + }); + + Console.WriteLine($"Parameter count: {parameterized.Parameters.Length}"); + Console.WriteLine(string.Join(", ", parameterized.Parameters.Select(parameter => parameter.ParameterName))); + } + + private sealed class DemoParameter : IDataParameter + { + public DemoParameter(string name, object value) + { + ParameterName = name; + Value = value; + } + + public DbType DbType { get; set; } + + public ParameterDirection Direction { get; set; } = ParameterDirection.Input; + + public bool IsNullable => true; + + public string ParameterName { get; set; } + + public string SourceColumn { get; set; } = string.Empty; + + public DataRowVersion SourceVersion { get; set; } = DataRowVersion.Current; + + public object Value { get; set; } + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.DataStatementOptions.md b/.docfx/api/types/Cuemon.Data.DataStatementOptions.md new file mode 100644 index 00000000..0aa1577d --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DataStatementOptions.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Data.DataStatementOptions +example: +- *content +--- + +The following example demonstrates how to configure `DataStatementOptions` for text commands and stored procedures with custom timeout and parameters. + +```csharp +using System; +using System.Data; +using Cuemon.Data; + +namespace MyApp.Data +{ + public class DataStatementOptionsExample + { + public void Demonstrate() + { + // Create options for a text command with default timeout (90 seconds) + var options = new DataStatementOptions + { + Type = CommandType.Text, + Timeout = TimeSpan.FromSeconds(30) + }; + + Console.WriteLine($"Command type: {options.Type}"); + Console.WriteLine($"Timeout: {options.Timeout.TotalSeconds} seconds"); + Console.WriteLine($"Default timeout: {DataStatementOptions.DefaultTimeout.TotalSeconds} seconds"); + + // Configure for a stored procedure + var spOptions = new DataStatementOptions + { + Type = CommandType.StoredProcedure, + Timeout = TimeSpan.FromMinutes(5), + Parameters = Array.Empty() + }; + + // Validate that parameters is not null + spOptions.ValidateOptions(); + Console.WriteLine("Stored procedure options are valid."); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.DataTransfer.md b/.docfx/api/types/Cuemon.Data.DataTransfer.md new file mode 100644 index 00000000..0a95931e --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DataTransfer.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.Data.DataTransfer +example: +- *content +--- + +The following example demonstrates how to use to convert an into row-based and column-based collections. + +```csharp +using System; +using System.Data; +using Cuemon.Data; + +namespace MyApp.Data; + +public sealed class DataTransferExample +{ + public void Demonstrate() + { + var table = new DataTable("Products"); + table.Columns.Add("Id", typeof(int)); + table.Columns.Add("Name", typeof(string)); + table.Columns.Add("Price", typeof(decimal)); + table.Rows.Add(1, "Widget", 9.99m); + table.Rows.Add(2, "Gadget", 24.95m); + + using IDataReader reader = table.CreateDataReader(); + + // Convert reader rows to a collection + DataTransferRowCollection rows = DataTransfer.GetRows(reader); + Console.WriteLine($"Row count: {rows.Count}"); + Console.WriteLine($"Columns: {string.Join(", ", rows.ColumnNames)}"); + + // Access data by column name + foreach (DataTransferRow row in rows) + { + Console.WriteLine($"{row["Id"]}: {row["Name"]} @ {row["Price"]:C}"); + } + + // Re-read and get columns + reader.Dispose(); + using IDataReader reader2 = table.CreateDataReader(); + reader2.Read(); + DataTransferColumnCollection columns = DataTransfer.GetColumns(reader2); + Console.WriteLine($"Column count: {columns.Count}"); + Console.WriteLine($"First column: {columns[0].Name} ({columns[0].DataType.Name})"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.DataTransferColumn.md b/.docfx/api/types/Cuemon.Data.DataTransferColumn.md new file mode 100644 index 00000000..80ed9f97 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DataTransferColumn.md @@ -0,0 +1,55 @@ +--- +uid: Cuemon.Data.DataTransferColumn +example: +- *content +--- + +The following example demonstrates how to use `DataTransferColumn` to inspect column metadata — name, ordinal, and data type — from a data reader. + +```csharp +using System; +using System.Data; +using Cuemon.Data; + +namespace MyApp.Data +{ + public class DataTransferColumnExample + { + public void Demonstrate() + { + // Create a DataTable as a sample data source + var table = new DataTable("Employees"); + table.Columns.Add("EmployeeId", typeof(int)); + table.Columns.Add("FirstName", typeof(string)); + table.Columns.Add("LastName", typeof(string)); + table.Columns.Add("HireDate", typeof(System.DateTime)); + + table.Rows.Add(1, "John", "Doe", new DateTime(2023, 6, 1)); + table.Rows.Add(2, "Jane", "Smith", new DateTime(2024, 1, 15)); + + // Obtain a DataTransferColumnCollection from an IDataReader via DataTransfer + using var reader = table.CreateDataReader(); + var columns = DataTransfer.GetColumns(reader); + + Console.WriteLine($"Columns ({columns.Count}):"); + foreach (DataTransferColumn column in columns) + { + Console.WriteLine($" [{column.Ordinal}] {column.Name} ({column.DataType.Name})"); + + // Output: + // [0] EmployeeId (Int32) + // [1] FirstName (String) + // [2] LastName (String) + // [3] HireDate (DateTime) + + // Access columns by name + DataTransferColumn firstNameCol = columns["FirstName"]; + Console.WriteLine($"Ordinal of 'FirstName': {firstNameCol.Ordinal}"); // 1 + + // ToString() returns the column name + Console.WriteLine($"Column ToString: {firstNameCol}"); // FirstName + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.DataTransferColumnCollection.md b/.docfx/api/types/Cuemon.Data.DataTransferColumnCollection.md new file mode 100644 index 00000000..09231a37 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DataTransferColumnCollection.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.Data.DataTransferColumnCollection +example: +- *content +--- + +The following example demonstrates how to use `DataTransferColumnCollection` to access column metadata retrieved from a data reader, including lookup by name or ordinal. + +```csharp +using System; +using System.Data; +using Cuemon.Data; + +namespace MyApp.Data +{ + public sealed class DataTransferColumnCollectionExample + { + public void Demonstrate() + { + var table = new DataTable(); + table.Columns.Add("Id", typeof(int)); + table.Columns.Add("Name", typeof(string)); + table.Columns.Add("Created", typeof(DateTime)); + table.Rows.Add(1, "Alice", new DateTime(2024, 1, 2, 3, 4, 5, DateTimeKind.Utc)); + + using var reader = table.CreateDataReader(); + reader.Read(); + + DataTransferColumnCollection columns = DataTransfer.GetColumns(reader); + + Console.WriteLine($"Column count: {columns.Count}"); + Console.WriteLine($"First column: {columns[0].Name} ({columns[0].DataType.Name})"); + Console.WriteLine($"Name column ordinal: {columns["Name"].Ordinal}"); + Console.WriteLine($"Missing column found: {columns["Missing"] != null}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.DataTransferRow.md b/.docfx/api/types/Cuemon.Data.DataTransferRow.md new file mode 100644 index 00000000..4fc3268c --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DataTransferRow.md @@ -0,0 +1,68 @@ +--- +uid: Cuemon.Data.DataTransferRow +example: +- *content +--- + +The following example demonstrates how to use `DataTransferRow` to access field values by index, column name, or column object, including type-safe access via generic methods. + +```csharp +using System; +using System.Data; +using Cuemon.Data; + +namespace MyApp.Data +{ + public static class DataTransferRowExamples + { + public static void Demonstrate() + { + // Build a DataTable to simulate a database result set. + var table = new DataTable(); + table.Columns.Add("Id", typeof(int)); + table.Columns.Add("Name", typeof(string)); + table.Columns.Add("Created", typeof(DateTime)); + table.Columns.Add("Notes", typeof(string)); + table.Rows.Add(1, "Alice", new DateTime(2024, 1, 2, 3, 4, 5, DateTimeKind.Utc), "First"); + table.Rows.Add(2, "Bob", new DateTime(2024, 2, 3, 4, 5, 6, DateTimeKind.Utc), DBNull.Value); + + // Convert the reader to rows. + using (IDataReader reader = table.CreateDataReader()) + { + DataTransferRowCollection rows = DataTransfer.GetRows(reader); + + // Access individual rows. + DataTransferRow first = rows[0]; + DataTransferRow second = rows[1]; + + Console.WriteLine("Row numbers: {0}, {1}", first.Number, second.Number); + + // Access values by column index. + object idValue = first[0]; + Console.WriteLine("First row Id: {0}", idValue); + + // Access values by column name. + object nameValue = first["Name"]; + Console.WriteLine("First row Name: {0}", nameValue); + + // Access values by DataTransferColumn object. + DataTransferColumn idCol = first.Columns["Id"]; + object viaColumn = first[idCol]; + Console.WriteLine("First row Id (via column): {0}", viaColumn); + + // Type-safe access using generics. + int idTyped = first.As("Id"); + DateTime created = first.As("Created"); + Console.WriteLine("Typed: Id={0}, Created={1:O}", idTyped, created); + + // Nullable value (DBNull is converted to null). + object notes = second["Notes"]; + Console.WriteLine("Second row Notes is null: {0}", notes == null); + + // String representation of the row. + Console.WriteLine("Row string: {0}", first); + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.DataTransferRowCollection.md b/.docfx/api/types/Cuemon.Data.DataTransferRowCollection.md new file mode 100644 index 00000000..e4747ed1 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DataTransferRowCollection.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Data.DataTransferRowCollection +example: +- *content +--- + +The following example demonstrates how to use to work with rows returned from a database query via an . + +```csharp +using System; +using System.Data; +using Cuemon.Data; + +namespace MyApp.Data +{ + public sealed class DataTransferRowCollectionExample + { + public void Demonstrate() + { + var table = new DataTable("Products"); + table.Columns.Add("Id", typeof(int)); + table.Columns.Add("Name", typeof(string)); + table.Columns.Add("Created", typeof(DateTime)); + table.Columns.Add("Notes", typeof(string)); + table.Rows.Add(1, "Apples", new DateTime(2024, 1, 2, 3, 4, 5, DateTimeKind.Utc), "Fresh"); + table.Rows.Add(2, "Bananas", new DateTime(2024, 2, 3, 4, 5, 6, DateTimeKind.Utc), DBNull.Value); + + using var reader = table.CreateDataReader(); + DataTransferRowCollection rows = DataTransfer.GetRows(reader); + + Console.WriteLine("Columns: " + string.Join(", ", rows.ColumnNames)); + Console.WriteLine($"Row count: {rows.Count}"); + + DataTransferRow firstRow = rows[0]; + Console.WriteLine(firstRow.ToString()); + Console.WriteLine($"First row name: {firstRow["Name"]}"); + Console.WriteLine($"Created: {firstRow.As("Created"):O}"); + + DataTransferRow secondRow = rows[1]; + Console.WriteLine($"Second row notes are null: {secondRow["Notes"] == null}"); + Console.WriteLine($"Contains first row: {rows.Contains(firstRow)}"); + Console.WriteLine($"Index of first row: {rows.IndexOf(firstRow)}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.DatabaseDependency.md b/.docfx/api/types/Cuemon.Data.DatabaseDependency.md new file mode 100644 index 00000000..f9e5f99a --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DatabaseDependency.md @@ -0,0 +1,80 @@ +--- +uid: Cuemon.Data.DatabaseDependency +example: +- *content +--- + +The following example demonstrates how to use to monitor a relational data source for changes and notify dependent objects. + +```csharp +using System; +using System.Data; +using System.Threading.Tasks; +using Cuemon.Data; +using Cuemon.Runtime; + +namespace MyApp.Examples; + +public class DatabaseDependencyExample +{ + public async Task DemonstrateAsync() + { + var lazyWatcher = new Lazy(() => + { + var connection = new StubConnection(); + return new DatabaseWatcher( + connection, + conn => + { + var command = conn.CreateCommand(); + command.CommandText = "SELECT COUNT(*) FROM Products"; + return command.ExecuteReader(); + }); + }); + + var dependency = new DatabaseDependency(lazyWatcher, breakTieOnChanged: true); + + dependency.DependencyChanged += (sender, args) => + { + Console.WriteLine("Database data has changed!"); + }; + + await dependency.StartAsync(); + } + + private sealed class StubConnection : IDbConnection + { + public string ConnectionString { get; set; } + public int ConnectionTimeout => 30; + public string Database => "MyDb"; + public ConnectionState State => ConnectionState.Closed; + public IDbTransaction BeginTransaction() => null; + public IDbTransaction BeginTransaction(IsolationLevel il) => null; + public void ChangeDatabase(string databaseName) { } + public void Close() { } + public IDbCommand CreateCommand() => new StubCommand(); + public void Open() { } + public void Dispose() { } + } + + private sealed class StubCommand : IDbCommand + { + public string CommandText { get; set; } + public int CommandTimeout { get; set; } + public CommandType CommandType { get; set; } + public IDbConnection Connection { get; set; } + public IDataParameterCollection Parameters => null; + public IDbTransaction Transaction { get; set; } + public UpdateRowSource UpdatedRowSource { get; set; } + public bool DesignTimeVisible { get; set; } + public void Cancel() { } + public IDbDataParameter CreateParameter() => null; + public int ExecuteNonQuery() => 0; + public IDataReader ExecuteReader() => null; + public IDataReader ExecuteReader(CommandBehavior behavior) => null; + public object ExecuteScalar() => 0; + public void Prepare() { } + public void Dispose() { } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.DatabaseWatcher.md b/.docfx/api/types/Cuemon.Data.DatabaseWatcher.md new file mode 100644 index 00000000..6540a1a4 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DatabaseWatcher.md @@ -0,0 +1,112 @@ +--- +uid: Cuemon.Data.DatabaseWatcher +example: +- *content +--- + +The following example demonstrates how to use `DatabaseWatcher` to monitor a database for data changes by comparing checksums over time. + +```csharp +using System; +using System.Data; +using System.Threading; +using System.Threading.Tasks; +using Cuemon.Data; +using Cuemon.Runtime; + +namespace MyApp.Data +{ + public sealed class DatabaseWatcherExample + { + public async Task DemonstrateAsync() + { + var table = new DataTable(); + table.Columns.Add("Id", typeof(int)); + table.Columns.Add("Name", typeof(string)); + table.Rows.Add(1, "Alpha"); + + using var connection = new InMemoryConnection(); + var watcher = new SampleDatabaseWatcher(connection, _ => table.CreateDataReader(), options => + { + options.DueTime = Timeout.InfiniteTimeSpan; + options.Period = Timeout.InfiniteTimeSpan; + }); + + var changedSignals = 0; + watcher.Changed += (_, args) => + { + changedSignals++; + Console.WriteLine($"Detected a change at {args.UtcLastModified:O}."); + }; + + await watcher.SignalAsync(); + Console.WriteLine($"Initial checksum: {watcher.Checksum}"); + + table.Rows[0]["Name"] = "Beta"; + + await watcher.SignalAsync(); + Console.WriteLine($"Signals raised: {changedSignals}"); + Console.WriteLine($"Updated checksum: {watcher.Checksum}"); + } + + private sealed class SampleDatabaseWatcher : DatabaseWatcher + { + public SampleDatabaseWatcher(IDbConnection connection, Func readerFactory, Action setup = null) + : base(connection, readerFactory, setup) + { + } + + public Task SignalAsync() + { + return HandleSignalingAsync(); + } + } + + private sealed class InMemoryConnection : IDbConnection + { + public string ConnectionString { get; set; } = string.Empty; + + public int ConnectionTimeout => 0; + + public string Database => "Sample"; + + public ConnectionState State { get; private set; } = ConnectionState.Closed; + + public IDbTransaction BeginTransaction() + { + throw new NotSupportedException(); + } + + public IDbTransaction BeginTransaction(IsolationLevel il) + { + throw new NotSupportedException(); + } + + public void ChangeDatabase(string databaseName) + { + throw new NotSupportedException(); + } + + public void Close() + { + State = ConnectionState.Closed; + } + + public IDbCommand CreateCommand() + { + throw new NotSupportedException(); + } + + public void Open() + { + State = ConnectionState.Open; + } + + public void Dispose() + { + Close(); + } + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.DbTypeDecoratorExtensions.md b/.docfx/api/types/Cuemon.Data.DbTypeDecoratorExtensions.md new file mode 100644 index 00000000..64faa7e5 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DbTypeDecoratorExtensions.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Data.DbTypeDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the `ToType` extension method to resolve the equivalent `System.Type` for a `DbType` value. + +```csharp +using System; +using System.Data; +using Cuemon; +using Cuemon.Data; + +namespace MyApp.Examples; + +public class DbTypeDecoratorExtensionsExample +{ + public static void Main() + { + DbType[] types = { DbType.Int32, DbType.String, DbType.DateTime, DbType.Boolean }; + + foreach (var dbType in types) + { + Type clrType = Decorator.Enclose(dbType).ToType(); + Console.WriteLine("DbType.{0} -> {1}", dbType, clrType); + + // Output: + // DbType.Int32 -> System.Int32 + // DbType.String -> System.String + // DbType.DateTime -> System.DateTime + // DbType.Boolean -> System.Boolean + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.DsvDataReader.md b/.docfx/api/types/Cuemon.Data.DsvDataReader.md new file mode 100644 index 00000000..76bfef6a --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.DsvDataReader.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.Data.DsvDataReader +example: +- *content +--- + +The following example demonstrates how to read a CSV (comma-separated values) file using `DsvDataReader`. + +```csharp +using System; +using System.IO; +using System.Text; +using Cuemon.Data; + +namespace MyApp.Examples +{ + public sealed class DsvDataReaderExample + { + public void Demonstrate() + { + var csv = "Name,Age,City" + Environment.NewLine + + "Alice,30,New York" + Environment.NewLine + + "Bob,25,London" + Environment.NewLine + + "Charlie,35,Tokyo"; + + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(csv)); + using var reader = new DsvDataReader(new StreamReader(stream)); + + Console.WriteLine($"Delimiter: {reader.Delimiter}"); + Console.WriteLine("Header: " + string.Join(", ", reader.Header)); + + while (reader.Read()) + { + Console.WriteLine($"Row {reader.RowCount}: Name={reader["Name"]}, Age={reader["Age"]}, City={reader["City"]}"); + } + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.InOperatorResult.md b/.docfx/api/types/Cuemon.Data.InOperatorResult.md new file mode 100644 index 00000000..fb83c533 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.InOperatorResult.md @@ -0,0 +1,66 @@ +--- +uid: Cuemon.Data.InOperatorResult +example: +- *content +--- + +The following example demonstrates how to create an `InOperatorResult` by using a custom `InOperator` subclass and then access its arguments, parameters, and string representation. + +```csharp +using System; +using System.Data; +using System.Linq; +using Cuemon.Data; + +namespace MyApp.Examples; + +public class InOperatorResultExample +{ + public static void Main() + { + var safeOperator = new IntInOperator(); + InOperatorResult result = safeOperator.ToSafeResult(10, 20, 30); + + Console.WriteLine("Arguments CSV: {0}", result); + Console.WriteLine("Parameter count: {0}", result.Parameters.Count()); + Console.WriteLine("First parameter value: {0}", result.Parameters.First().Value); + + // Output: + // Arguments CSV: @p0, @p1, @p2 + // Parameter count: 3 + // First parameter value: 10 + } + + private sealed class IntInOperator : InOperator + { + public IntInOperator() : base(() => "@p") { } + + protected override IDbDataParameter ParametersSelector(int expression, int index) + { + return new SimpleParameter(string.Concat(ParameterPrefix, index), expression); + } + + private sealed class SimpleParameter : IDbDataParameter + { + public SimpleParameter(string name, object value) + { + ParameterName = name; + Value = value; + } + + public DbType DbType { get; set; } = DbType.Int32; + public ParameterDirection Direction { get; set; } = ParameterDirection.Input; + public bool IsNullable => false; + public string ParameterName { get; set; } + public int Size { get; set; } + public string SourceColumn { get; set; } = string.Empty; + public bool SourceColumnNullMapping { get; set; } + public DataRowVersion SourceVersion { get; set; } = DataRowVersion.Current; + public object Value { get; set; } + public byte Precision { get; set; } + public byte Scale { get; set; } + } + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.Integrity.CacheValidator.md b/.docfx/api/types/Cuemon.Data.Integrity.CacheValidator.md new file mode 100644 index 00000000..e89f7d06 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.Integrity.CacheValidator.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.Data.Integrity.CacheValidator +example: +- *content +--- + +The following example demonstrates how to create a `CacheValidator` to represent cacheable data with integrity validation, combining timestamps and content checksums. + +```csharp +using System; +using Cuemon.Data.Integrity; +using Cuemon.Security; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + + var entity = new EntityInfo( + DateTime.UtcNow.AddHours(-2), + DateTime.UtcNow.AddMinutes(-30) + ); + + var validator = new CacheValidator(entity, () => HashFactory.CreateFnv128(), EntityDataIntegrityMethod.Combined); + + Console.WriteLine($"Created (UTC): {validator.Created:O}"); + Console.WriteLine($"Modified (UTC): {validator.Modified:O}"); + Console.WriteLine($"Validation: {validator.Validation}"); + Console.WriteLine($"Method: {validator.Method}"); + Console.WriteLine($"Checksum: {validator.Checksum.ToHexadecimalString()}"); + + // Combine with additional data + validator.CombineWith(BitConverter.GetBytes(67890L)); + Console.WriteLine($"Combined: {validator}"); + + // Get the most significant from a sequence + var v1 = new CacheValidator(new EntityInfo(new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc)), () => HashFactory.CreateFnv128()); + var v2 = new CacheValidator(new EntityInfo(DateTime.UtcNow.AddDays(-1)), () => HashFactory.CreateFnv128()); + var mostSignificant = CacheValidator.GetMostSignificant(v1, v2); + + Console.WriteLine($"Most significant created: {mostSignificant.Created:O}"); + + // Use assembly reference point + CacheValidator.AssemblyReference = typeof(CacheValidator).Assembly; + var referencePoint = CacheValidator.ReferencePoint; + Console.WriteLine($"Reference point: {referencePoint}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.Integrity.CacheValidatorFactory.md b/.docfx/api/types/Cuemon.Data.Integrity.CacheValidatorFactory.md new file mode 100644 index 00000000..f1638479 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.Integrity.CacheValidatorFactory.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.Data.Integrity.CacheValidatorFactory +example: +- *content +--- + +The following example demonstrates how to create a from a file using . + +```csharp +using System; +using System.IO; +using Cuemon.Data.Integrity; +using Cuemon.Security; + +namespace MyApp.Data; + +public sealed class CacheValidatorFactoryExample +{ + public void Demonstrate() + { + var file = new FileInfo(Path.GetTempFileName()); + try + { + File.WriteAllText(file.FullName, "Hello, world!"); + + CacheValidator validator = CacheValidatorFactory.CreateValidator(file); + Console.WriteLine($"Created (UTC): {validator.Created:O}"); + Console.WriteLine($"Modified (UTC): {validator.Modified:O}"); + Console.WriteLine($"Validation: {validator.Validation}"); + Console.WriteLine($"Method: {validator.Method}"); + Console.WriteLine($"Checksum: {validator.Checksum.ToHexadecimalString()}"); + + // Create validator using a custom hash algorithm + CacheValidator shaValidator = CacheValidatorFactory.CreateValidator( + file, + () => HashFactory.CreateFnv128()); + Console.WriteLine($"SHA-256: {shaValidator.Checksum.ToHexadecimalString()}"); + } + finally + { + file.Delete(); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.Integrity.ChecksumBuilder.md b/.docfx/api/types/Cuemon.Data.Integrity.ChecksumBuilder.md new file mode 100644 index 00000000..81e4c34a --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.Integrity.ChecksumBuilder.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Data.Integrity.ChecksumBuilder +example: +- *content +--- + +The following example demonstrates how to use `ChecksumBuilder` to compute and compare checksums for arbitrary data. + +```csharp +using System; +using System.Text; +using Cuemon.Data.Integrity; +using Cuemon.Security; + +namespace MyApp.Examples +{ + public sealed class ChecksumBuilderExample + { + public void Demonstrate() + { + var builder = new ChecksumBuilder(() => HashFactory.CreateFnv128()); + Console.WriteLine($"Empty checksum: {builder.Checksum.ToHexadecimalString()}"); + + builder.CombineWith(BitConverter.GetBytes(42L)); + builder.CombineWith(Encoding.UTF8.GetBytes("Hello, World!")); + + var comparison = new ChecksumBuilder(BitConverter.GetBytes(42L), () => HashFactory.CreateFnv128()); + comparison.CombineWith(Encoding.UTF8.GetBytes("Hello, World!")); + + Console.WriteLine($"Current checksum: {builder}"); + Console.WriteLine($"Checksums match: {builder.Equals(comparison)}"); + Console.WriteLine($"Hash code: {builder.GetHashCode()}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.Integrity.ChecksumBuilderDecoratorExtensions.md b/.docfx/api/types/Cuemon.Data.Integrity.ChecksumBuilderDecoratorExtensions.md new file mode 100644 index 00000000..719ef333 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.Integrity.ChecksumBuilderDecoratorExtensions.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.Data.Integrity.ChecksumBuilderDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use `ChecksumBuilderDecoratorExtensions` to combine typed values with a `ChecksumBuilder` through the `IDecorator` interface. + +```csharp +using System; +using Cuemon; +using Cuemon.Data.Integrity; +using Cuemon.Security; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + // Create a ChecksumBuilder wrapped in a Decorator + var builder = new ChecksumBuilder(() => HashFactory.CreateFnv128()); + var decorator = Decorator.Enclose(builder); + + // Combine various typed values using the decorator extensions + decorator.CombineWith(42); // int + decorator.CombineWith(3.14); // double + decorator.CombineWith("tag"); // string + + Console.WriteLine($"Combined checksum: {builder}"); + + // The extensions return the inner builder for chaining + var combined = decorator.CombineWith(12345L); // long + Console.WriteLine($"Returned type: {combined.GetType().Name}"); + + // Extension methods also work with short, float, ushort, uint, ulong + var shortDecorator = Decorator.Enclose(new ChecksumBuilder(() => HashFactory.CreateFnv32())); + shortDecorator.CombineWith((short)100); + shortDecorator.CombineWith(3.14f); + shortDecorator.CombineWith(42u); + + Console.WriteLine($"Short builder: {shortDecorator.Inner}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.Integrity.DataIntegrityFactory.md b/.docfx/api/types/Cuemon.Data.Integrity.DataIntegrityFactory.md new file mode 100644 index 00000000..2f6ffbb3 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.Integrity.DataIntegrityFactory.md @@ -0,0 +1,54 @@ +--- +uid: Cuemon.Data.Integrity.DataIntegrityFactory +example: +- *content +--- + +The following example demonstrates how to create an implementation from a file using . + +```csharp +using System; +using System.IO; +using Cuemon.Data.Integrity; +using Cuemon.Security; + +namespace MyApp.Data; + +public sealed class DataIntegrityFactoryExample +{ + public void Demonstrate() + { + var file = new FileInfo(Path.GetTempFileName()); + try + { + File.WriteAllText(file.FullName, "Sample data for integrity check."); + + IDataIntegrity integrity = DataIntegrityFactory.CreateIntegrity(file, options => + { + options.BytesToRead = 1024; + options.IntegrityConverter = (fi, checksumBytes) => + { + var hash = HashFactory.CreateCrc64().ComputeHash(checksumBytes); + return new DataIntegrity(fi, hash); + }; + }); + + Console.WriteLine($"Integrity: {integrity}"); + } + finally + { + file.Delete(); + } + } +} + +// Minimal IDataIntegrity implementation for demonstration +public class DataIntegrity(FileInfo file, HashResult checksum) : IDataIntegrity +{ + public FileInfo File { get; } = file; + + public HashResult Checksum { get; } = checksum; + + public override string ToString() => $"{File.Name}: {Checksum.ToHexadecimalString()}"; +} +``` diff --git a/.docfx/api/types/Cuemon.Data.Integrity.EntityDataIntegrityMethod.md b/.docfx/api/types/Cuemon.Data.Integrity.EntityDataIntegrityMethod.md new file mode 100644 index 00000000..40d8c48d --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.Integrity.EntityDataIntegrityMethod.md @@ -0,0 +1,47 @@ +--- +uid: Cuemon.Data.Integrity.EntityDataIntegrityMethod +example: +- *content +--- + +The following example demonstrates how to use the enum to specify how a checksum should be computed for data integrity validation. + +```csharp +using System; +using Cuemon.Data.Integrity; // for EntityDataIntegrityMethod + +namespace MyApp.Examples; + +public class EntityDataIntegrityMethodExample +{ + public void Demonstrate() + { + // Unaltered - the checksum is left as-is (default) + EntityDataIntegrityMethod method = EntityDataIntegrityMethod.Unaltered; + Console.WriteLine(method); // Unaltered + + // Combined - the checksum is computed from all inputs combined + method = EntityDataIntegrityMethod.Combined; + Console.WriteLine(method); // Combined + + // Timestamp - the checksum is generated from date-time inputs + method = EntityDataIntegrityMethod.Timestamp; + Console.WriteLine(method); // Timestamp + + // Switch on the method to determine behavior + switch (method) + { + case EntityDataIntegrityMethod.Unaltered: + Console.WriteLine("Checksum unchanged."); + break; + case EntityDataIntegrityMethod.Combined: + Console.WriteLine("Checksum computed from all data."); + break; + case EntityDataIntegrityMethod.Timestamp: + Console.WriteLine("Checksum based on timestamp."); + break; + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.Integrity.EntityDataIntegrityValidation.md b/.docfx/api/types/Cuemon.Data.Integrity.EntityDataIntegrityValidation.md new file mode 100644 index 00000000..a440c6b8 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.Integrity.EntityDataIntegrityValidation.md @@ -0,0 +1,47 @@ +--- +uid: Cuemon.Data.Integrity.EntityDataIntegrityValidation +example: +- *content +--- + +```csharp +using System; +using System.Text; +using Cuemon.Data.Integrity; +using Cuemon.Security; + +namespace MyApp.Data +{ + public sealed class EntityDataIntegrityValidationExample + { + public void Demonstrate() + { + var created = new DateTime(2024, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var modified = created.AddHours(1); + var entity = new EntityInfo( + created, + modified, + Encoding.UTF8.GetBytes("order-42"), + EntityDataIntegrityValidation.Strong); + + var validator = new CacheValidator(entity, () => HashFactory.CreateFnv128()); + + switch (validator.Validation) + { + case EntityDataIntegrityValidation.Unspecified: + Console.WriteLine("No checksum strength was supplied."); + break; + case EntityDataIntegrityValidation.Weak: + Console.WriteLine("The checksum is semantically valid."); + break; + case EntityDataIntegrityValidation.Strong: + Console.WriteLine("The checksum is byte-for-byte strong."); + break; + } + + Console.WriteLine($"Validation: {validator.Validation}"); + Console.WriteLine($"Checksum: {validator.Checksum.ToHexadecimalString()}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.Integrity.EntityInfo.md b/.docfx/api/types/Cuemon.Data.Integrity.EntityInfo.md new file mode 100644 index 00000000..70d122f4 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.Integrity.EntityInfo.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.Data.Integrity.EntityInfo +example: +- *content +--- + +```csharp +using System; +using Cuemon.Data.Integrity; +using Cuemon.Security; + +namespace MyApp.Data +{ + public static class EntityInfoExamples + { + public static void Demonstrate() + { + // Create EntityInfo with only a creation timestamp. + var entity = new EntityInfo(new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + Console.WriteLine("Created: {0:O}", entity.Created); + Console.WriteLine("Modified: {0}", entity.Modified.HasValue ? entity.Modified.Value.ToString("O") : "null"); + Console.WriteLine("Has checksum: {0}", entity.Checksum.HasValue); + Console.WriteLine("Validation: {0}", entity.Validation); + + // Create EntityInfo with creation and modification timestamps. + var modified = new EntityInfo( + new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc), + new DateTime(2025, 6, 15, 12, 30, 0, DateTimeKind.Utc)); + Console.WriteLine("Modified entity: Created={0:O}, LastModified={1:O}", + modified.Created, modified.Modified); + + // Create EntityInfo with a checksum for data integrity validation. + // The checksum can be used to detect changes to the underlying data. + byte[] checksumBytes = { 0x1A, 0x2B, 0x3C, 0x4D }; + var validated = new EntityInfo( + new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc), + null, + checksumBytes, + EntityDataIntegrityValidation.Strong); + + Console.WriteLine("Validated entity: Checksum={0}, Validation={1}", + validated.Checksum.ToHexadecimalString(), + validated.Validation); + + // Timestamps are always normalized to UTC. + var localTime = new EntityInfo(new DateTime(2025, 6, 1, 10, 0, 0, DateTimeKind.Local)); + Console.WriteLine("UTC created: {0:O}", localTime.Created); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.Integrity.FileChecksumOptions.md b/.docfx/api/types/Cuemon.Data.Integrity.FileChecksumOptions.md new file mode 100644 index 00000000..d41005be --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.Integrity.FileChecksumOptions.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.Data.Integrity.FileChecksumOptions +example: +- *content +--- + +```csharp +using System; +using System.IO; +using Cuemon.Data.Integrity; + +namespace MyApp.Data +{ + public sealed class FileChecksumOptionsExample + { + public void Demonstrate() + { + var defaults = new FileChecksumOptions(); + Console.WriteLine($"Default method: {defaults.Method}"); + Console.WriteLine($"Default bytes to read: {defaults.BytesToRead}"); + + var path = Path.Combine(AppContext.BaseDirectory, "payload.txt"); + File.WriteAllText(path, "cuemon"); + + try + { + var file = new FileInfo(path); + + var combinedValidator = CacheValidatorFactory.CreateValidator(file, setup: options => + { + options.Method = EntityDataIntegrityMethod.Combined; + }); + + var strongValidator = CacheValidatorFactory.CreateValidator(file, setup: options => + { + options.BytesToRead = 4; + }); + + Console.WriteLine($"Combined method: {combinedValidator.Method}"); + Console.WriteLine($"Strong validation: {strongValidator.Validation}"); + } + finally + { + if (File.Exists(path)) { File.Delete(path); } + } + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.Integrity.FileIntegrityOptions.md b/.docfx/api/types/Cuemon.Data.Integrity.FileIntegrityOptions.md new file mode 100644 index 00000000..90ecb57b --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.Integrity.FileIntegrityOptions.md @@ -0,0 +1,57 @@ +--- +uid: Cuemon.Data.Integrity.FileIntegrityOptions +example: +- *content +--- + +The following example demonstrates how to use to configure file integrity checksum computation. + +```csharp +using System; +using System.IO; +using Cuemon.Data.Integrity; +using Cuemon.Security; + +namespace MyApp.Examples +{ + public sealed class FileIntegrityOptionsExample + { + public void Demonstrate() + { + var defaults = new FileIntegrityOptions(); + Console.WriteLine($"Default bytes to read: {defaults.BytesToRead}"); + + var path = Path.Combine(AppContext.BaseDirectory, "sample.dat"); + File.WriteAllText(path, "Hello, World!"); + + try + { + IDataIntegrity integrity = DataIntegrityFactory.CreateIntegrity(new FileInfo(path), options => + { + options.BytesToRead = 8; + options.IntegrityConverter = (file, bytes) => new FilePreviewIntegrity(file.Name, bytes); + }); + + Console.WriteLine($"Checksum: {integrity.Checksum.ToHexadecimalString()}"); + } + finally + { + if (File.Exists(path)) { File.Delete(path); } + } + } + + private sealed class FilePreviewIntegrity : IDataIntegrity + { + public FilePreviewIntegrity(string fileName, byte[] bytes) + { + FileName = fileName; + Checksum = HashFactory.CreateFnv128().ComputeHash(bytes); + } + + public string FileName { get; } + + public HashResult Checksum { get; } + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.QueryFormat.md b/.docfx/api/types/Cuemon.Data.QueryFormat.md new file mode 100644 index 00000000..2fedda0b --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.QueryFormat.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.Data.QueryFormat +example: +- *content +--- + +The following example demonstrates how to use the `QueryFormat` enumeration to control how query fragments — including delimited, quoted, and bracketed formats — are generated when building SQL queries. + +```csharp +using System; +using Cuemon.Data; + +namespace MyApp.Data +{ + public class QueryFormatExample + { + public void Demonstrate() + { + // QueryFormat controls how query fragments are formatted. + + // Delimited: value, value, value + string delimited = QueryBuilder.EncodeFragment(QueryFormat.Delimited, new[] { "FirstName", "LastName", "Email" }); + Console.WriteLine($"Delimited: {delimited}"); // FirstName,LastName,Email + + // DelimitedString: 'value', 'value', 'value' + string delimitedString = QueryBuilder.EncodeFragment(QueryFormat.DelimitedString, new[] { "John", "Doe" }); + Console.WriteLine($"DelimitedString: {delimitedString}"); // 'John','Doe' + + // DelimitedSquareBracket: [value], [value], [value] + string delimitedSquareBracket = QueryBuilder.EncodeFragment(QueryFormat.DelimitedSquareBracket, new[] { "FirstName", "LastName" }); + Console.WriteLine($"DelimitedSquareBracket: {delimitedSquareBracket}"); // [FirstName],[LastName] + + // Distinct option removes duplicates + string distinct = QueryBuilder.EncodeFragment(QueryFormat.Delimited, new[] { "A", "B", "A", "C" }, distinct: true); + Console.WriteLine($"Distinct: {distinct}"); // A,B,C + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.QueryType.md b/.docfx/api/types/Cuemon.Data.QueryType.md new file mode 100644 index 00000000..6cdcf421 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.QueryType.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.Data.QueryType +example: +- *content +--- + +The following example demonstrates how to use the `QueryType` enumeration to identify the type of a data operation. + +```csharp +using System; +using Cuemon.Data; + +namespace MyApp.Examples; + +public class QueryTypeExample +{ + public static void Main() + { + var operation = QueryType.Select; + Console.WriteLine("Operation: {0} (value: {1})", operation, (int)operation); + + operation = QueryType.Insert; + Console.WriteLine("Operation: {0} (value: {1})", operation, (int)operation); + + // Use in a switch expression + string label = operation switch + { + QueryType.Select => "Read", + QueryType.Insert => "Create", + QueryType.Update => "Update", + QueryType.Delete => "Delete", + QueryType.Exists => "Check existence", + _ => "Unknown" + }; + Console.WriteLine("Label: {0}", label); + + // Output: + // Operation: Select (value: 0) + // Operation: Insert (value: 2) + // Label: Create + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.SqlClient.SqlDataManager.md b/.docfx/api/types/Cuemon.Data.SqlClient.SqlDataManager.md new file mode 100644 index 00000000..fe74f909 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.SqlClient.SqlDataManager.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.Data.SqlClient.SqlDataManager +example: +- *content +--- + +The following example demonstrates how to use `SqlDataManager` to execute commands against Microsoft SQL Server. + +```csharp +using System; +using Cuemon.Collections.Generic; +using Cuemon.Data; +using Cuemon.Data.SqlClient; +using Microsoft.Data.SqlClient; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + + // Configure the SQL data manager with a connection string + var manager = new SqlDataManager(o => + { + o.ConnectionString = "Server=.;Database=AdventureWorks;Trusted_Connection=True;TrustServerCertificate=True;"; + }); + + // Execute a scalar query (implicit string to DataStatement conversion) + var productCount = manager.ExecuteScalar("SELECT COUNT(*) FROM Production.Product"); + Console.WriteLine($"Product count: {productCount}"); + + // Execute a reader command with parameters +using var reader = manager.ExecuteReader(new DataStatement( + "SELECT ProductID, Name, ListPrice FROM Production.Product WHERE ListPrice > @minPrice", + o => o.Parameters = Arguments.ToArrayOf(new SqlParameter("@minPrice", 1000m)))); + + while (reader.Read()) + { + Console.WriteLine($" #{reader.GetInt32(0)}: {reader.GetString(1)} - ${reader.GetDecimal(2):F2}"); + + // Execute a non-query (INSERT) + var affected = manager.Execute(new DataStatement( + "UPDATE Production.Product SET ListPrice = ListPrice * 1.05 WHERE ProductID = @id", + o => o.Parameters = Arguments.ToArrayOf(new SqlParameter("@id", 999)))); + + Console.WriteLine($"Rows affected: {affected}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.SqlClient.SqlInOperator`1.md b/.docfx/api/types/Cuemon.Data.SqlClient.SqlInOperator`1.md new file mode 100644 index 00000000..143d6618 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.SqlClient.SqlInOperator`1.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.Data.SqlClient.SqlInOperator`1 +example: +- *content +--- + +The following example demonstrates how to use to safely generate parameterized SQL IN clauses that are protected against SQL injection. + +```csharp +using System; +using System.Data; +using Cuemon.Data; +using Cuemon.Data.SqlClient; +using Microsoft.Data.SqlClient; + +namespace MyApp.Examples +{ + public sealed class SqlInOperatorExample + { + public void Demonstrate() + { + var inOperator = new SqlInOperator(() => "@color"); + InOperatorResult result = inOperator.ToSafeResult("Red", "Green", "Blue"); + + var commandText = $"SELECT * FROM Products WHERE Color IN ({result})"; + using var command = new SqlCommand(commandText); + + foreach (IDataParameter dbParameter in result.ToParametersArray()) + { + command.Parameters.Add((SqlParameter)dbParameter); + Console.WriteLine($"{dbParameter.ParameterName} = {dbParameter.Value}"); + } + + Console.WriteLine(command.CommandText); + Console.WriteLine(string.Join(", ", result.Arguments)); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.SqlClient.SqlQueryBuilder.md b/.docfx/api/types/Cuemon.Data.SqlClient.SqlQueryBuilder.md new file mode 100644 index 00000000..d4c3c1e4 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.SqlClient.SqlQueryBuilder.md @@ -0,0 +1,98 @@ +--- +uid: Cuemon.Data.SqlClient.SqlQueryBuilder +example: +- *content +--- + +The following example demonstrates how to use `SqlQueryBuilder` to generate SELECT, INSERT, UPDATE, DELETE, and EXISTS queries for SQL Server with table and column encapsulation, dirty reads, and read limits. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.Data; +using Cuemon.Data.SqlClient; + +namespace MyApp.Data +{ + public class SqlQueryBuilderExample + { + public void Demonstrate() + { + // Build a SELECT query with key columns and optional columns + var selectBuilder = new SqlQueryBuilder( + "Employees", + new Dictionary { { "EmployeeId", "@EmployeeId" } }, + new Dictionary + { + { "FirstName", "@FirstName" }, + { "LastName", "@LastName" }, + { "Email", "@Email" } + }) + { + EnableTableAndColumnEncapsulation = true, + EnableDirtyReads = true, + EnableReadLimit = true, + ReadLimit = 50 + }; + + string selectQuery = selectBuilder.GetQuery(QueryType.Select); + Console.WriteLine(selectQuery); + // SELECT TOP 50 [EmployeeId],[FirstName],[LastName],[Email] FROM [Employees] WITH(NOLOCK) WHERE [EmployeeId]=@EmployeeId + + // Build an INSERT query + var insertBuilder = new SqlQueryBuilder( + "Employees", + new Dictionary(), + new Dictionary + { + { "FirstName", "@FirstName" }, + { "LastName", "@LastName" }, + { "Email", "@Email" } + }) + { + EnableTableAndColumnEncapsulation = true + }; + + string insertQuery = insertBuilder.GetQuery(QueryType.Insert); + Console.WriteLine(insertQuery); + // INSERT INTO [Employees] ([FirstName],[LastName],[Email]) VALUES (@FirstName,@LastName,@Email) + + // Build an UPDATE query + var updateBuilder = new SqlQueryBuilder( + "Employees", + new Dictionary { { "EmployeeId", "@EmployeeId" } }, + new Dictionary + { + { "FirstName", "@FirstName" }, + { "LastName", "@LastName" } + }) + { + EnableTableAndColumnEncapsulation = true + }; + + string updateQuery = updateBuilder.GetQuery(QueryType.Update); + Console.WriteLine(updateQuery); + // UPDATE [Employees] SET [FirstName]=@FirstName,[LastName]=@LastName WHERE [EmployeeId]=@EmployeeId + + // Build a DELETE query + var deleteBuilder = new SqlQueryBuilder( + "Employees", + new Dictionary { { "EmployeeId", "@EmployeeId" } }, + new Dictionary()) + { + EnableTableAndColumnEncapsulation = true + }; + + string deleteQuery = deleteBuilder.GetQuery(QueryType.Delete); + Console.WriteLine(deleteQuery); + // DELETE FROM [Employees] WHERE [EmployeeId]=@EmployeeId + + // Build an EXISTS query + string existsQuery = deleteBuilder.GetQuery(QueryType.Exists); + Console.WriteLine(existsQuery); + // SELECT 1 FROM [Employees] WHERE [EmployeeId]=@EmployeeId + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.TokenBuilder.md b/.docfx/api/types/Cuemon.Data.TokenBuilder.md new file mode 100644 index 00000000..32015847 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.TokenBuilder.md @@ -0,0 +1,48 @@ +--- +uid: Cuemon.Data.TokenBuilder +example: +- *content +--- + +The following example demonstrates how to use `TokenBuilder` to build delimited token strings with support for quoted fields. + +```csharp +using System; +using Cuemon.Data; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + + // Build a token string with 4 fields, comma-delimited, double-quote qualified + var builder = new TokenBuilder(',', '"', 4); + + builder.Append("Alice"); + builder.Append(",30,"); + builder.Append("New York"); + + Console.WriteLine($"Is valid: {builder.IsValid}"); // false - only 3 of 4 tokens + Console.WriteLine($"Current: '{builder}'"); + + // Append the last field to complete the token row + builder.Append("Engineer"); + Console.WriteLine($"Is valid: {builder.IsValid}"); // true + Console.WriteLine($"Complete: '{builder}'"); + + // TokenBuilder is used internally by DsvDataReader for multi-line quoted fields + // It accumulates input until the expected number of tokens is reached + var csvBuilder = new TokenBuilder(';', '\"', 3); + csvBuilder.Append("Product A"); + csvBuilder.Append("Description with ; semicolon"); + csvBuilder.Append("$49.99"); + + Console.WriteLine($"CSV line: '{csvBuilder}'"); + Console.WriteLine($"Tokens: {csvBuilder.Tokens}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Data.UniqueIndexViolationException.md b/.docfx/api/types/Cuemon.Data.UniqueIndexViolationException.md new file mode 100644 index 00000000..e48172f3 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.UniqueIndexViolationException.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.Data.UniqueIndexViolationException +example: +- *content +--- + +The following example demonstrates how to use `UniqueIndexViolationException` to represent a unique index or unique constraint violation in a data source. + +```csharp +using System; +using Cuemon.Data; + +namespace MyApp.Data +{ + public sealed class UniqueIndexViolationExceptionExample + { + public void Demonstrate() + { + try + { + throw new UniqueIndexViolationException("Cannot insert duplicate key row in object 'dbo.Users'."); + } + catch (UniqueIndexViolationException ex) + { + Console.WriteLine(ex.Message); + } + + var wrapped = new UniqueIndexViolationException( + "Failed to register user.", + new InvalidOperationException("IX_Users_Email was violated.")); + + Console.WriteLine(wrapped.Message); + Console.WriteLine(wrapped.InnerException?.Message); + + var empty = new UniqueIndexViolationException(); + Console.WriteLine(empty.GetType().Name); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Data.Xml.XmlDataReader.md b/.docfx/api/types/Cuemon.Data.Xml.XmlDataReader.md new file mode 100644 index 00000000..d837aed4 --- /dev/null +++ b/.docfx/api/types/Cuemon.Data.Xml.XmlDataReader.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.Data.Xml.XmlDataReader +example: +- *content +--- + +```csharp +using System; +using System.IO; +using System.Xml; +using Cuemon.Data.Xml; + +namespace MyApp.Data +{ + public class XmlDataReaderExample + { + public void Demonstrate() + { + // Create XML data to read + var xml = @" + 1Alice95.5 + 2Bob87.0 + 3Charlie92.3 + "; + + using var stringReader = new StringReader(xml); + using var xmlReader = XmlReader.Create(stringReader); + + // Create the XmlDataReader + using var dataReader = new XmlDataReader(xmlReader); + + // Read through the records like a database result set + while (dataReader.Read()) + { + Console.WriteLine($"Row {dataReader.RowCount}:"); + Console.WriteLine($" Id: {dataReader["id"]}"); + Console.WriteLine($" Name: {dataReader["name"]}"); + Console.WriteLine($" Score: {dataReader["score"]}"); + Console.WriteLine($" Depth: {dataReader.Depth}"); + } + + Console.WriteLine($"Total rows read: {dataReader.RowCount}"); + + // Verify field count + Console.WriteLine($"Fields per row: {dataReader.FieldCount}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.DataPair.md b/.docfx/api/types/Cuemon.DataPair.md new file mode 100644 index 00000000..cc4df606 --- /dev/null +++ b/.docfx/api/types/Cuemon.DataPair.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.DataPair +example: +- *content +--- + +The following example demonstrates how to use the and classes to represent named metadata with type information. + +```csharp +using System; +using Cuemon; // for DataPair, DataPair + +namespace MyApp.Examples; + +public class DataPairExample +{ + public void Demonstrate() + { + // Create a generic DataPair for compile-time type safety + var pair = new DataPair("Age", 30); + Console.WriteLine(pair); + // Output: Name: Age, Value: 30, Type: Int32 + + Console.WriteLine(pair.Name); // Age + Console.WriteLine(pair.Value); // 30 + Console.WriteLine(pair.Type); // System.Int32 + Console.WriteLine(pair.HasValue); // True + + // Create a non-generic DataPair + var generic = new DataPair("CreatedAt", DateTime.UtcNow, typeof(DateTime)); + Console.WriteLine(generic); + // Output: Name: CreatedAt, Value: ..., Type: DateTime + + // DataPair with null value + var nullPair = new DataPair("MiddleName", null); + Console.WriteLine(nullPair.HasValue); // False + Console.WriteLine(nullPair); + // Output: Name: MiddleName, Value: , Type: String + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.DataPair`1.md b/.docfx/api/types/Cuemon.DataPair`1.md new file mode 100644 index 00000000..b3bc8b18 --- /dev/null +++ b/.docfx/api/types/Cuemon.DataPair`1.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.DataPair`1 +example: +- *content +--- + +The following example demonstrates how to use the generic class to represent typed metadata. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon; + +namespace MyApp.Examples; + +public class DataPairOfTExample +{ + public void Demonstrate() + { + // Create a strongly typed DataPair for an integer value + var age = new DataPair("Age", 30); + Console.WriteLine(age.HasValue); // True + Console.WriteLine(age.Name); // Age + Console.WriteLine(age.Value); // 30 + Console.WriteLine(age.Type); // System.Int32 + + // Create a DataPair with a null value + var middleName = new DataPair("MiddleName", null); + Console.WriteLine(middleName.HasValue); // False + Console.WriteLine(middleName); // Name: MiddleName, Value: , Type: String + + // Override the type metadata (e.g., for a derived type) + var now = new DataPair("Created", DateTime.UtcNow, typeof(DateTimeOffset)); + Console.WriteLine(now.Type); // System.DateTimeOffset + + // Use DataPair in a collection + var pairs = new List> + { + new("Id", Guid.NewGuid()), + new("Timestamp", DateTime.UtcNow), + new("Active", true) + }; + + foreach (var pair in pairs) + { + Console.WriteLine(pair); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.DateSpan.md b/.docfx/api/types/Cuemon.DateSpan.md new file mode 100644 index 00000000..65262305 --- /dev/null +++ b/.docfx/api/types/Cuemon.DateSpan.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.DateSpan +example: +- *content +--- + +```csharp +using System; +using Cuemon; + +namespace MyApp.Time; + +public class DateSpanExample +{ + public void Demonstrate() + { + // Create a DateSpan between two dates + var start = new DateTime(2020, 1, 1); + var end = new DateTime(2025, 6, 15); + var span = new DateSpan(start, end); + + Console.WriteLine($"Years: {span.Years}"); // 5 + Console.WriteLine($"Months: {span.Months}"); // 65 + Console.WriteLine($"Days: {span.Days}"); // 1991 + Console.WriteLine($"Total days: {span.TotalDays:F1}"); // 1991.0 + + // Parse from ISO 8601 strings + var parsed = DateSpan.Parse("2020-01-01", "2025-06-15"); + Console.WriteLine(parsed.Years); // 5 + + // Single DateSpan defaults the end to DateTime.Today + var fromPast = new DateSpan(new DateTime(2023, 1, 1)); + Console.WriteLine($"Days since 2023-01-01: {fromPast.TotalDays:F0}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.DateTimeDecoratorExtensions.md b/.docfx/api/types/Cuemon.DateTimeDecoratorExtensions.md new file mode 100644 index 00000000..c23f022b --- /dev/null +++ b/.docfx/api/types/Cuemon.DateTimeDecoratorExtensions.md @@ -0,0 +1,48 @@ +--- +uid: Cuemon.DateTimeDecoratorExtensions +example: +- *content +--- + +The following example shows how to extend `DateTime` with `DateTimeDecoratorExtensions` methods to perform Unix epoch conversions and adjust `DateTimeKind` without changing the underlying ticks. + +```csharp +using System; +using Cuemon; + +namespace MyApp.DateTimeExamples +{ + public class DateTimeDecoratorExtensionsExample + { + public void Demonstrate() + { + // Get the Unix epoch (January 1st, 1970 UTC) + var unixEpoch = Decorator.Syntactic().GetUnixEpoch(); + Console.WriteLine(unixEpoch); // 1/1/1970 12:00:00 AM + + // Convert a DateTime to Unix epoch time (seconds since 1970-01-01 UTC) + var utcNow = DateTime.UtcNow; + var unixTime = Decorator.Enclose(utcNow).ToUnixEpochTime(); + Console.WriteLine(unixTime); // e.g., 1700000000 + + // Convert from local DateTime to UTC-kind DateTime (same ticks, different kind) + var localTime = new DateTime(2024, 6, 15, 12, 0, 0, DateTimeKind.Local); + var utcKind = Decorator.Enclose(localTime).ToUtcKind(); + Console.WriteLine(utcKind.Kind); // Utc + Console.WriteLine(utcKind.Ticks == localTime.Ticks); // True + + // Convert from UTC DateTime to local-kind DateTime + var utcTime = new DateTime(2024, 6, 15, 10, 0, 0, DateTimeKind.Utc); + var localKind = Decorator.Enclose(utcTime).ToLocalKind(); + Console.WriteLine(localKind.Kind); // Local + Console.WriteLine(localKind.Ticks == utcTime.Ticks); // True + + // Strip kind information (set to Unspecified) + var defaultKind = Decorator.Enclose(utcTime).ToDefaultKind(); + Console.WriteLine(defaultKind.Kind); // Unspecified + Console.WriteLine(defaultKind.Ticks == utcTime.Ticks); // True + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.DateTimeFormatPattern.md b/.docfx/api/types/Cuemon.DateTimeFormatPattern.md new file mode 100644 index 00000000..15012a20 --- /dev/null +++ b/.docfx/api/types/Cuemon.DateTimeFormatPattern.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.DateTimeFormatPattern +example: +- *content +--- + +The following example demonstrates how to use `DateTimeFormatPattern` to select a format pattern for date and time display. + +```csharp +using System; +using Cuemon; + +namespace MyApp.Examples; + +public class DateTimeFormatPatternExample +{ + public void Demonstrate() + { + var shortDate = DateTimeFormatPattern.ShortDate; + var longDateTime = DateTimeFormatPattern.LongDateTime; + + var now = DateTime.Now; + Console.WriteLine($"Selected pattern: {shortDate}"); + Console.WriteLine($"Selected pattern: {longDateTime}"); + + // Use the pattern with formatting utilities + // that accept DateTimeFormatPattern to control output. + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.DateTimeRange.md b/.docfx/api/types/Cuemon.DateTimeRange.md new file mode 100644 index 00000000..d73699f7 --- /dev/null +++ b/.docfx/api/types/Cuemon.DateTimeRange.md @@ -0,0 +1,58 @@ +--- +uid: Cuemon.DateTimeRange +example: +- *content +--- + +The following example demonstrates how to use `DateTimeRange` to represent and query a range between two `DateTime` values, including duration, formatting, and equality comparison. + +```csharp +using System; +using Cuemon; + +namespace MyApp.Time +{ + public class DateTimeRangeExample + { + public void Demonstrate() + { + // Create a date-time range representing January 2026 + var start = new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc); + var end = new DateTime(2026, 1, 31, 23, 59, 59, DateTimeKind.Utc); + var range = new DateTimeRange(start, end); + + // Access start and end points + Console.WriteLine($"Start: {range.Start:O}"); // 2026-01-01T00:00:00.0000000Z + Console.WriteLine($"End: {range.End:O}"); // 2026-01-31T23:59:59.0000000Z + + // Duration between start and end + Console.WriteLine($"Duration: {range.Duration.Days} days"); // 30 days + Console.WriteLine($"Duration: {range.Duration}"); // 30.23:59:59 + + // Default ToString() uses sortable format + Console.WriteLine(range.ToString()); // "2026-01-01T00:00:00" + + // Custom format with invariant culture + Console.WriteLine(range.ToString("d", null)); // "1/1/2026 ... 1/31/2026" + + // Equality comparison via the inherited IEqualityComparer> + var sameRange = new DateTimeRange(start, end); + Console.WriteLine(range.Equals(range, sameRange)); // True + + var differentRange = new DateTimeRange(start, new DateTime(2026, 2, 1)); + Console.WriteLine(range.Equals(range, differentRange)); // False + + // Hash code based on start and end + var hash = range.GetHashCode(range); + Console.WriteLine($"Hash: {hash}"); + + // Practical use: measure a business period + var quarterStart = new DateTime(2026, 4, 1); + var quarterEnd = new DateTime(2026, 6, 30); + var q1 = new DateTimeRange(quarterStart, quarterEnd); + Console.WriteLine($"Q2 2026 lasts {q1.Duration.TotalDays} days."); // 90 days + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.DayPart.md b/.docfx/api/types/Cuemon.DayPart.md new file mode 100644 index 00000000..57e1be60 --- /dev/null +++ b/.docfx/api/types/Cuemon.DayPart.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.DayPart +example: +- *content +--- + +The following example demonstrates how to use `DayPart` to determine the current part of the day and enumerate all built-in day parts. + +```csharp +using System; +using System.Linq; +using Cuemon; + +namespace MyApp.Examples; + +public class DayPartExample +{ + public void Demonstrate() + { + var now = DateTime.Now.TimeOfDay; + + var current = DayPart.All.FirstOrDefault(dp => + now >= dp.Range.Start && now < dp.Range.End); + + Console.WriteLine($"Current time: {now:hh\\:mm}"); + Console.WriteLine($"Day part: {current?.Name ?? "Unknown"}"); + + Console.WriteLine("All day parts:"); + foreach (var part in DayPart.All) + { + Console.WriteLine($" {part}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Decorator-1.md b/.docfx/api/types/Cuemon.Decorator-1.md new file mode 100644 index 00000000..bebdf5d9 --- /dev/null +++ b/.docfx/api/types/Cuemon.Decorator-1.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Decorator`1 +example: +- *content +--- + +The following example demonstrates how to use `Decorator` to wrap a value and access it through the decorator pattern. + +```csharp +using System; +using Cuemon; + +namespace MyApp.Wrapping; + +public class DecoratorOfTExample +{ + public void Demonstrate() + { + var numbers = new[] { 10, 20, 30 }; + var decorator = Decorator.Enclose(numbers); + + // Access the wrapped inner value through the Inner property + int[] inner = decorator.Inner; + Console.WriteLine(string.Join(", ", inner)); // "10, 20, 30" + + // ArgumentName is set automatically when using EncloseToExpose + var withArgName = Decorator.EncloseToExpose(numbers); + Console.WriteLine(withArgName.ArgumentName); // "numbers" + + // Syntactic sugar for type-level decoration + var syntactic = Decorator.Syntactic(); + Console.WriteLine(syntactic.Inner); // null (default) + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Decorator.md b/.docfx/api/types/Cuemon.Decorator.md new file mode 100644 index 00000000..3dc2a9da --- /dev/null +++ b/.docfx/api/types/Cuemon.Decorator.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.Decorator +example: +- *content +--- + +```csharp +using System; +using Cuemon; + +namespace MyApp.Wrapping; + +public class DecoratorExample +{ + public void Demonstrate() + { + var wrappedString = Decorator.Enclose("Hello, World!"); + Console.WriteLine(wrappedString.Inner); // "Hello, World!" + Console.WriteLine(wrappedString.ArgumentName); // "" + + var withArg = Decorator.EncloseToExpose("test", argumentName: "myArg"); + Console.WriteLine(withArg.ArgumentName); // "myArg" + + var syntactic = Decorator.Syntactic(); + Console.WriteLine(syntactic.Inner); // "01-01-0001 00:00:00" (default(DateTime)) + + var raw = Decorator.RawEnclose(null); + Console.WriteLine(raw.Inner is null); // True + } +} +``` diff --git a/.docfx/api/types/Cuemon.DelegateDecoratorExtensions.md b/.docfx/api/types/Cuemon.DelegateDecoratorExtensions.md new file mode 100644 index 00000000..43d3d423 --- /dev/null +++ b/.docfx/api/types/Cuemon.DelegateDecoratorExtensions.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.DelegateDecoratorExtensions +example: +- *content +--- + +The following example shows how to extend `Delegate` with `DelegateDecoratorExtensions` methods to resolve `MethodInfo` from a delegate instance through the decorator pattern. + +```csharp +using System; +using System.Reflection; +using Cuemon; + +namespace MyApp.Reflection +{ + public class DelegateDecoratorExtensionsExample + { + public void Demonstrate() + { + // Create a delegate + Func add = (a, b) => a + b; + + // Resolve the MethodInfo from the original delegate; + // the decorator is used as fallback when original is null + MethodInfo methodInfo = Decorator.Enclose(null, false).ResolveDelegateInfo(add); + + Console.WriteLine($"Method name: {methodInfo.Name}"); + Console.WriteLine($"Declaring type: {methodInfo.DeclaringType?.Name}"); + Console.WriteLine($"Is static: {methodInfo.IsStatic}"); + + // When the delegate is not available but the wrapper is: + Action greet = () => Console.WriteLine("Hello!"); + MethodInfo fromWrapper = Decorator.Enclose(greet).ResolveDelegateInfo(null); + Console.WriteLine($"\nGreet method: {fromWrapper.Name}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.DelimitedString.md b/.docfx/api/types/Cuemon.DelimitedString.md new file mode 100644 index 00000000..7dbc5892 --- /dev/null +++ b/.docfx/api/types/Cuemon.DelimitedString.md @@ -0,0 +1,33 @@ +--- +uid: Cuemon.DelimitedString +example: +- *content +--- + +```csharp +using System; +using System.Globalization; +using Cuemon; + +namespace MyApp.Delimited; + +public class DelimitedStringExample +{ + public void Demonstrate() + { + var numbers = new[] { 1, 2, 3, 4, 5 }; + string csv = DelimitedString.Create(numbers, o => + { + o.Delimiter = ","; + o.StringConverter = value => value.ToString(); + }); + Console.WriteLine(csv); // "1,2,3,4,5" + + string[] parts = DelimitedString.Split(csv, o => + { + o.Delimiter = ","; + }); + Console.WriteLine(string.Join(" | ", parts)); // "1 | 2 | 3 | 4 | 5" + } +} +``` diff --git a/.docfx/api/types/Cuemon.DelimitedStringOptions.md b/.docfx/api/types/Cuemon.DelimitedStringOptions.md new file mode 100644 index 00000000..5331e087 --- /dev/null +++ b/.docfx/api/types/Cuemon.DelimitedStringOptions.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.DelimitedStringOptions +example: +- *content +--- + +The following example demonstrates how to use to configure custom delimiters and qualifiers when parsing delimited strings using . + +```csharp +using System; +using Cuemon; // for DelimitedStringOptions, DelimitedString + +namespace MyApp.Examples; + +public class DelimitedStringOptionsExample +{ + public void Demonstrate() + { + // Default options: comma delimiter, double-quote qualifier + var defaultOptions = new DelimitedStringOptions(); + Console.WriteLine($"Delimiter: '{defaultOptions.Delimiter}'"); // ',' + Console.WriteLine($"Qualifier: '{defaultOptions.Qualifier}'"); // '"' + + // Custom tab-delimited options + var tabOptions = new DelimitedStringOptions + { + Delimiter = "\t", + Qualifier = "'" + }; + + // Parse a tab-delimited line using the setup action + string tabLine = "Alice\t30\tNew York"; + string[] fields = DelimitedString.Split(tabLine, o => + { + o.Delimiter = tabOptions.Delimiter; + o.Qualifier = tabOptions.Qualifier; + }); + Console.WriteLine($"Fields: {string.Join(", ", fields)}"); // Alice, 30, New York + + // Parse a pipe-delimited line + string pipeLine = "'Bob'|'25'|'London'"; + fields = DelimitedString.Split(pipeLine, o => + { + o.Delimiter = "|"; + o.Qualifier = "'"; + }); + Console.WriteLine($"Fields: {string.Join(", ", fields)}"); // Bob, 25, London + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.DelimitedStringOptions`1.md b/.docfx/api/types/Cuemon.DelimitedStringOptions`1.md new file mode 100644 index 00000000..bdd3fd1a --- /dev/null +++ b/.docfx/api/types/Cuemon.DelimitedStringOptions`1.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.DelimitedStringOptions`1 +example: +- *content +--- + +The following example demonstrates how to use to configure the conversion of a sequence of objects into a delimited string. + +```csharp +using System; +using System.Globalization; +using Cuemon; + +namespace Contoso.Telemetry; + +public sealed class DelimitedStringOptionsOfTExample +{ + public static void Run() + { + var options = new DelimitedStringOptions + { + Delimiter = " | ", + StringConverter = number => number.ToString("X2", CultureInfo.InvariantCulture) + }; + + int[] numbers = { 1, 2, 3, 4 }; + string hex = DelimitedString.Create(numbers, setup => + { + setup.Delimiter = options.Delimiter; + setup.StringConverter = options.StringConverter; + }); + + Console.WriteLine(hex); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.AsyncTimeMeasureOptions.md b/.docfx/api/types/Cuemon.Diagnostics.AsyncTimeMeasureOptions.md new file mode 100644 index 00000000..b807662d --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.AsyncTimeMeasureOptions.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Diagnostics.AsyncTimeMeasureOptions +example: +- *content +--- + +The following example demonstrates how to configure for an asynchronous time measurement scenario. + +```csharp +using System; +using System.Threading; +using Cuemon.Diagnostics; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public static class AsyncTimeMeasureOptionsExample +{ + public static void Demonstrate() + { + var options = new AsyncTimeMeasureOptions + { + TimeMeasureCompletedThreshold = TimeSpan.FromMilliseconds(100), + CancellationToken = CancellationToken.None, + MethodDescriptor = () => MethodDescriptor.Create(typeof(AsyncTimeMeasureOptionsExample).GetMethod(nameof(Demonstrate))!), + RuntimeParameters = new object[] { "warmup" } + }; + + Console.WriteLine(options.TimeMeasureCompletedThreshold); + Console.WriteLine(options.CancellationToken.CanBeCanceled); + Console.WriteLine(options.MethodDescriptor().MethodName); + Console.WriteLine(options.RuntimeParameters.Length); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.ExceptionDescriptor.md b/.docfx/api/types/Cuemon.Diagnostics.ExceptionDescriptor.md new file mode 100644 index 00000000..a121f5d1 --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.ExceptionDescriptor.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.Diagnostics.ExceptionDescriptor +example: +- *content +--- + +The following example demonstrates how to create and enrich it with contextual evidence. + +```csharp +using System; +using Cuemon.Diagnostics; + +namespace MyApp.Examples; + +public static class ExceptionDescriptorExample +{ + public static void Demonstrate() + { + var descriptor = new ExceptionDescriptor( + new InvalidOperationException("Order 12345 has already been processed."), + code: "OrderAlreadyProcessed", + message: "The order cannot be modified because it has already been processed.", + helpLink: new Uri("https://docs.example.com/errors/order-already-processed")); + + descriptor.AddEvidence("OrderId", 12345, value => value); + descriptor.AddEvidence("UserId", "alice@example.com", value => value); + + Console.WriteLine(descriptor.Code); + Console.WriteLine(descriptor.Message); + Console.WriteLine(descriptor.Evidence.Count); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.ExceptionDescriptorAttribute.md b/.docfx/api/types/Cuemon.Diagnostics.ExceptionDescriptorAttribute.md new file mode 100644 index 00000000..13e41ce7 --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.ExceptionDescriptorAttribute.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.Diagnostics.ExceptionDescriptorAttribute +example: +- *content +--- + +The following example demonstrates how to annotate a method with and inspect the configured metadata at runtime. + +```csharp +using System; +using System.Linq; +using Cuemon.Diagnostics; + +namespace MyApp.Examples; + +public static class ExceptionDescriptorAttributeExample +{ + [ExceptionDescriptor(typeof(ArgumentNullException), + Code = "ERR_NULL_ARGUMENT", + Message = "A required parameter was not provided.", + HelpLink = "https://example.com/errors/null-argument")] + public static void ProcessOrder(string orderId) + { + if (orderId == null) { throw new ArgumentNullException(nameof(orderId)); } + } + + public static void Demonstrate() + { + var attribute = (ExceptionDescriptorAttribute)Attribute + .GetCustomAttributes(typeof(ExceptionDescriptorAttributeExample).GetMethod(nameof(ProcessOrder))!, typeof(ExceptionDescriptorAttribute)) + .Single(); + + Console.WriteLine(attribute.FailureType.Name); + Console.WriteLine(attribute.Code); + Console.WriteLine(attribute.Message); + Console.WriteLine(attribute.HelpLink); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.ExceptionDescriptorOptions.md b/.docfx/api/types/Cuemon.Diagnostics.ExceptionDescriptorOptions.md new file mode 100644 index 00000000..a9b32862 --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.ExceptionDescriptorOptions.md @@ -0,0 +1,47 @@ +--- +uid: Cuemon.Diagnostics.ExceptionDescriptorOptions +example: +- *content +--- + +The following example demonstrates how to configure to control which sensitive details are included in serialized exception descriptors. + +```csharp +using System; +using Cuemon.Diagnostics; // for ExceptionDescriptorOptions, FaultSensitivityDetails + +namespace MyApp.Examples; + +public class ExceptionDescriptorOptionsExample +{ + public void Demonstrate() + { + // Create options that include only the stack trace + var options = new ExceptionDescriptorOptions + { + SensitivityDetails = FaultSensitivityDetails.StackTrace + }; + Console.WriteLine(options.SensitivityDetails); // StackTrace + + // Create options that include stack trace and exception data + var verbose = new ExceptionDescriptorOptions + { + SensitivityDetails = + FaultSensitivityDetails.StackTrace | + FaultSensitivityDetails.Data + }; + + // Verify flags are set + bool hasStack = verbose.SensitivityDetails.HasFlag(FaultSensitivityDetails.StackTrace); + bool hasData = verbose.SensitivityDetails.HasFlag(FaultSensitivityDetails.Data); + Console.WriteLine(hasStack); // True + Console.WriteLine(hasData); // True + + // Default is none + var defaults = new ExceptionDescriptorOptions(); + Console.WriteLine(defaults.SensitivityDetails); // None + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.Failure.md b/.docfx/api/types/Cuemon.Diagnostics.Failure.md new file mode 100644 index 00000000..dd53cad7 --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.Failure.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.Diagnostics.Failure +example: +- *content +--- + +The following example demonstrates how to use the record to expose structured exception details for diagnostics. + +```csharp +using System; +using Cuemon.Diagnostics; + +namespace MyApp.Examples; + +public static class FailureExample +{ + public static void Demonstrate() + { + var exception = new InvalidOperationException("The operation could not be completed."); + exception.Data["OperationId"] = "OP-42"; + + var failure = new Failure(exception, FaultSensitivityDetails.StackTrace | FaultSensitivityDetails.Data); + + Console.WriteLine(failure.Type); + Console.WriteLine(failure.Message); + Console.WriteLine(failure.Data["OperationId"]); + Console.WriteLine(failure.GetUnderlyingSensitivity()); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.FaultResolver.md b/.docfx/api/types/Cuemon.Diagnostics.FaultResolver.md new file mode 100644 index 00000000..468629b5 --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.FaultResolver.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.Diagnostics.FaultResolver +example: +- *content +--- + +The following example demonstrates how to use to register exception-to-descriptor mappings for structured error reporting. + +```csharp +using System; +using Cuemon.Diagnostics; // for FaultResolver, ExceptionDescriptor + +namespace MyApp.Examples; + +public class FaultResolverExample +{ + public void Demonstrate() + { + // Register a resolver that handles ArgumentNullException + var resolver = new FaultResolver( + validator: ex => ex is ArgumentNullException, + descriptor: ex => + { + var argEx = (ArgumentNullException)ex; + return new ExceptionDescriptor( + argEx, + "ERR_NULL_ARG", + $"The parameter '{argEx.ParamName}' cannot be null."); + }); + + // Try to resolve an ArgumentNullException + var testEx = new ArgumentNullException("value"); + bool resolved = resolver.TryResolveFault(testEx, out ExceptionDescriptor result); + + Console.WriteLine(resolved); // True + Console.WriteLine(result.Code); // ERR_NULL_ARG + Console.WriteLine(result.Message); // The parameter 'value' cannot be null. + Console.WriteLine(result.Failure.Message); // value + + // Try to resolve an unrelated exception + var otherEx = new InvalidOperationException("not handled"); + resolved = resolver.TryResolveFault(otherEx, out result); + Console.WriteLine(resolved); // False + Console.WriteLine(result is null); // True + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.FaultSensitivityDetails.md b/.docfx/api/types/Cuemon.Diagnostics.FaultSensitivityDetails.md new file mode 100644 index 00000000..2eb9ac86 --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.FaultSensitivityDetails.md @@ -0,0 +1,55 @@ +--- +uid: Cuemon.Diagnostics.FaultSensitivityDetails +example: +- *content +--- + +The following example demonstrates how to use the enum to control the level of sensitive details included when serializing an . + +```csharp +using System; +using Cuemon.Diagnostics; // for FaultSensitivityDetails, ExceptionDescriptor, FaultResolver + +namespace MyApp.Examples; + +public class FaultSensitivityDetailsExample +{ + public void Demonstrate() + { + // Create an exception descriptor with failure details + var descriptor = new ExceptionDescriptor( + new InvalidOperationException("Something went wrong."), + "ERR_OPERATION_FAILED", + "The requested operation could not be completed."); + + // FaultSensitivityDetails.None (default) - excludes all sensitive details + FaultSensitivityDetails details = FaultSensitivityDetails.None; + Console.WriteLine(details); // None + + // Include the Failure (exception) property + details = FaultSensitivityDetails.Failure; + Console.WriteLine(details); // Failure + + // Include both Failure and StackTrace + details = FaultSensitivityDetails.FailureWithStackTrace; + Console.WriteLine(details); // Failure, StackTrace + + // Include everything (development environments only) + details = FaultSensitivityDetails.All; + Console.WriteLine(details); // Failure, StackTrace, Data, Evidence + + // Combine flags manually + details = FaultSensitivityDetails.Failure | FaultSensitivityDetails.Data; + Console.WriteLine(details); // FailureWithData + + // Check if a specific flag is set + bool hasStackTrace = details.HasFlag(FaultSensitivityDetails.StackTrace); + Console.WriteLine(hasStackTrace); // False + + bool hasFailure = details.HasFlag(FaultSensitivityDetails.Failure); + Console.WriteLine(hasFailure); // True + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.MemberEvidence.md b/.docfx/api/types/Cuemon.Diagnostics.MemberEvidence.md new file mode 100644 index 00000000..1db29101 --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.MemberEvidence.md @@ -0,0 +1,48 @@ +--- +uid: Cuemon.Diagnostics.MemberEvidence +example: +- *content +--- + +The following example demonstrates how to retrieve a instance from an that has been enriched with embedded insights to capture member signature and runtime parameter evidence for diagnostic purposes. + +```csharp +using System; +using System.Linq; +using System.Reflection; +using Cuemon; +using Cuemon.Collections.Generic; +using Cuemon.Diagnostics; + +namespace MyApp.Examples; + +public class MemberEvidenceExample +{ + public void Demonstrate() + { + try + { + throw ExceptionInsights.Embed( + new ArgumentNullException("value", "Value cannot be null."), + MethodBase.GetCurrentMethod(), + Arguments.ToArray("value"), + SystemSnapshots.CaptureAll); + } + catch (Exception ex) + { + var descriptor = ExceptionDescriptor.Extract(ex); + if (descriptor.Evidence.TryGetValue("Thrower", out var thrower) && + thrower is MemberEvidence evidence) + { + Console.WriteLine($"Signature: {evidence.MemberSignature}"); + + Console.WriteLine($"Runtime parameters: {evidence.RuntimeParameters.Count}"); + foreach (var kvp in evidence.RuntimeParameters) + { + Console.WriteLine($" {kvp.Key} = {kvp.Value}"); + } + } + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.ProfilerOptions.md b/.docfx/api/types/Cuemon.Diagnostics.ProfilerOptions.md new file mode 100644 index 00000000..03045119 --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.ProfilerOptions.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Diagnostics.ProfilerOptions +example: +- *content +--- + +The following example demonstrates how to configure through a small derived options type. + +```csharp +using System; +using System.Reflection; +using Cuemon.Diagnostics; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public static class ProfilerOptionsExample +{ + private sealed class SampleProfilerOptions : ProfilerOptions + { + } + + public static void Demonstrate() + { + ProfilerOptions options = new SampleProfilerOptions + { + MethodDescriptor = () => MethodDescriptor.Create(MethodBase.GetCurrentMethod()!).AppendRuntimeArguments(500), + RuntimeParameters = new object[] { 500 } + }; + + Console.WriteLine(options.MethodDescriptor().MethodName); + Console.WriteLine(options.MethodDescriptor().RuntimeArguments.Count); + Console.WriteLine(options.RuntimeParameters.Length); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.TimeMeasure.md b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasure.md new file mode 100644 index 00000000..73d664d9 --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasure.md @@ -0,0 +1,54 @@ +--- +uid: Cuemon.Diagnostics.TimeMeasure +example: +- *content +--- + +The following example demonstrates how to profile actions and functions using . + +```csharp +using System; +using System.Threading; +using Cuemon.Diagnostics; + +namespace MyApp.Examples; + +public static class TimeMeasureExample +{ + public static void Demonstrate() + { + // Profile an action with no parameters + TimeMeasureProfiler actionProfiler = TimeMeasure.WithAction(() => + { + Thread.Sleep(50); + }); + Console.WriteLine($"Action elapsed: {actionProfiler.Elapsed}"); + Console.WriteLine($"Member: {actionProfiler.Member}"); + + // Profile an action with one parameter + TimeMeasureProfiler paramProfiler = TimeMeasure.WithAction( + (int ms) => Thread.Sleep(ms), 75); + Console.WriteLine($"Param action elapsed: {paramProfiler.Elapsed}"); + + // Profile a function that returns a value + TimeMeasureProfiler funcProfiler = TimeMeasure.WithFunc(() => + { + Thread.Sleep(100); + return 42; + }); + Console.WriteLine($"Func result: {funcProfiler.Result}"); + Console.WriteLine($"Func elapsed: {funcProfiler.Elapsed}"); + + // Profile a function with parameters + TimeMeasureProfiler greetProfiler = TimeMeasure.WithFunc( + (string name) => $"Hello, {name}!", "World"); + Console.WriteLine($"Func result: {greetProfiler.Result}"); + + // Configure options + TimeMeasureProfiler configured = TimeMeasure.WithAction( + () => Thread.Sleep(200), + options => options.TimeMeasureCompletedThreshold = TimeSpan.FromMilliseconds(50)); + Console.WriteLine($"Configured elapsed: {configured.Elapsed}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureOptions.md b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureOptions.md new file mode 100644 index 00000000..6d3f2430 --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureOptions.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.Diagnostics.TimeMeasureOptions +example: +- *content +--- + +The following example demonstrates how to configure for use with the class. + +```csharp +using System; +using System.Threading; +using Cuemon.Diagnostics; + +namespace MyApp.Examples; + +public class TimeMeasureOptionsExample +{ + public void Demonstrate() + { + // Configure options with a threshold + var options = new TimeMeasureOptions + { + TimeMeasureCompletedThreshold = TimeSpan.FromMilliseconds(100) + }; + + // Use with TimeMeasure to profile an action + var profiler = TimeMeasure.WithAction(() => + { + // Simulate work + Thread.Sleep(50); + }, setup: o => + { + o.TimeMeasureCompletedThreshold = TimeSpan.FromMilliseconds(100); + }); + + // The CompletedCallback will be invoked if elapsed time >= threshold + Console.WriteLine($"Elapsed: {profiler.Elapsed}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler.md b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler.md new file mode 100644 index 00000000..e7d3fce1 --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Diagnostics.TimeMeasureProfiler +example: +- *content +--- + +The following example demonstrates how returns instances for measured work. + +```csharp +using System; +using System.Threading; +using Cuemon.Diagnostics; + +namespace MyApp.Examples; + +public static class TimeMeasureProfilerExample +{ + public static void Demonstrate() + { + TimeMeasureProfiler profiler = TimeMeasure.WithAction(() => Thread.Sleep(25)); + var measured = TimeMeasure.WithFunc(() => 42); + + Console.WriteLine(profiler.Elapsed > TimeSpan.Zero); + Console.WriteLine(profiler.IsRunning); + Console.WriteLine(measured.Result); + Console.WriteLine(measured.Elapsed > TimeSpan.Zero); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler`1.md b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler`1.md new file mode 100644 index 00000000..0ae8de4b --- /dev/null +++ b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler`1.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Diagnostics.TimeMeasureProfiler`1 +example: +- *content +--- + +The following example demonstrates how to use to time an operation that returns a value and access the result through . + +```csharp +using System; +using System.Threading; +using Cuemon.Diagnostics; + +namespace MyApp.Examples; + +public class TimeMeasureProfilerOfTExample +{ + public void Demonstrate() + { + // TimeMeasure.WithFunc returns a TimeMeasureProfiler + TimeMeasureProfiler profiler = TimeMeasure.WithFunc(() => + { + Thread.Sleep(100); + return 42; + }); + + Console.WriteLine($"Result: {profiler.Result}"); // 42 + Console.WriteLine($"Elapsed: {profiler.Elapsed}"); // ~00:00:00.100 + Console.WriteLine($"IsRunning: {profiler.IsRunning}"); // False + Console.WriteLine($"Member: {profiler.Member}"); // + Console.WriteLine(profiler.ToString()); + // Output: took 00:00:00.100 to execute. + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.DisposableOptions.md b/.docfx/api/types/Cuemon.DisposableOptions.md new file mode 100644 index 00000000..cb010500 --- /dev/null +++ b/.docfx/api/types/Cuemon.DisposableOptions.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.DisposableOptions +example: +- *content +--- + +The following example demonstrates how to use to control whether a disposable resource is released when the owning wrapper is disposed. + +```csharp +using System; +using Cuemon; + +namespace Contoso.IO; + +public sealed class DisposableOptionsExample +{ + public static void Run() + { + var resource = new TrackedDisposable(); + var options = new DisposableOptions + { + LeaveOpen = true + }; + + DisposeWhenAllowed(resource, options); + Console.WriteLine($"Disposed after leave-open: {resource.IsDisposed}"); + + options.LeaveOpen = false; + DisposeWhenAllowed(resource, options); + Console.WriteLine($"Disposed after close: {resource.IsDisposed}"); + } + + private static void DisposeWhenAllowed(TrackedDisposable resource, DisposableOptions options) + { + if (!options.LeaveOpen) + { + resource.Dispose(); + } + } + + private sealed class TrackedDisposable : IDisposable + { + public bool IsDisposed { get; private set; } + + public void Dispose() + { + IsDisposed = true; + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.DoubleDecoratorExtensions.md b/.docfx/api/types/Cuemon.DoubleDecoratorExtensions.md new file mode 100644 index 00000000..34502b68 --- /dev/null +++ b/.docfx/api/types/Cuemon.DoubleDecoratorExtensions.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.DoubleDecoratorExtensions +example: +- *content +--- + +The following example shows how to extend `double` with `DoubleDecoratorExtensions` methods to convert numeric values into `TimeSpan` instances using a specified `TimeUnit`. + +```csharp +using System; +using Cuemon; + +namespace MyApp.Numeric +{ + public class DoubleDecoratorExtensionsExample + { + public void Demonstrate() + { + // Convert 1.5 days to a TimeSpan + double days = 1.5; + TimeSpan duration = Decorator.Enclose(days).ToTimeSpan(TimeUnit.Days); + Console.WriteLine(duration); // Output: 1.12:00:00 + + // Convert 90 minutes to a TimeSpan + double minutes = 90; + TimeSpan meeting = Decorator.Enclose(minutes).ToTimeSpan(TimeUnit.Minutes); + Console.WriteLine(meeting); // Output: 01:30:00 + + // Convert 5000 milliseconds to a TimeSpan + double ms = 5000; + TimeSpan interval = Decorator.Enclose(ms).ToTimeSpan(TimeUnit.Milliseconds); + Console.WriteLine(interval); // Output: 00:00:05 + + // Convert 2.5 hours to a TimeSpan + double hours = 2.5; + TimeSpan task = Decorator.Enclose(hours).ToTimeSpan(TimeUnit.Hours); + Console.WriteLine(task); // Output: 02:30:00 + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.EndianOptions.md b/.docfx/api/types/Cuemon.EndianOptions.md new file mode 100644 index 00000000..fc81fbc0 --- /dev/null +++ b/.docfx/api/types/Cuemon.EndianOptions.md @@ -0,0 +1,33 @@ +--- +uid: Cuemon.EndianOptions +example: +- *content +--- + +The following example demonstrates how to configure `EndianOptions` to explicitly set the byte order for binary data operations. + +```csharp +using System; +using Cuemon; + +namespace MyApp.Examples; + +public class EndianOptionsExample +{ + public void Demonstrate() + { + var options = new EndianOptions + { + ByteOrder = Endianness.BigEndian + }; + + var byteOrder = options.ByteOrder; + var isSystemLittleEndian = BitConverter.IsLittleEndian; + + Console.WriteLine($"Configured byte order: {byteOrder}"); + Console.WriteLine($"System is little-endian: {isSystemLittleEndian}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Endianness.md b/.docfx/api/types/Cuemon.Endianness.md new file mode 100644 index 00000000..27551736 --- /dev/null +++ b/.docfx/api/types/Cuemon.Endianness.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Endianness +example: +- *content +--- + +The following example demonstrates how to use `Endianness` to specify byte order when configuring `EndianOptions`. + +```csharp +using Cuemon; +using System; + +namespace MyApp.Examples; + +public class EndiannessExample +{ + public void Demonstrate() + { + var options = new EndianOptions + { + ByteOrder = Endianness.BigEndian + }; + + Console.WriteLine(options.ByteOrder == Endianness.BigEndian); + // outputs: True + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Eradicate.md b/.docfx/api/types/Cuemon.Eradicate.md new file mode 100644 index 00000000..076e8aa3 --- /dev/null +++ b/.docfx/api/types/Cuemon.Eradicate.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Eradicate +example: +- *content +--- + +The following example demonstrates how to use `Eradicate` to clean up byte arrays by removing trailing zero bytes or specific trailing byte sequences. + +```csharp +using System; +using System.Text; + +namespace Cuemon; + +public class EradicateExample +{ + public void Demonstrate() + { + // Remove trailing zero bytes from a byte array + byte[] dataWithZeros = { 1, 2, 3, 0, 0, 0 }; + byte[] cleaned = Eradicate.TrailingZeros(dataWithZeros); + Console.WriteLine(BitConverter.ToString(cleaned)); // 01-02-03 + + // Remove specific trailing byte sequence (e.g., CR/LF) + byte[] dataWithCrLf = { 72, 101, 108, 108, 111, 13, 10, 13, 10 }; + byte[] stripped = Eradicate.TrailingBytes(dataWithCrLf, new byte[] { 13, 10 }); + Console.WriteLine(Encoding.UTF8.GetString(stripped)); // Hello + } +} +``` diff --git a/.docfx/api/types/Cuemon.ExceptionCondition`1.md b/.docfx/api/types/Cuemon.ExceptionCondition`1.md new file mode 100644 index 00000000..ff4f3d66 --- /dev/null +++ b/.docfx/api/types/Cuemon.ExceptionCondition`1.md @@ -0,0 +1,53 @@ +--- +uid: Cuemon.ExceptionCondition`1 +example: +- *content +--- + +The following example demonstrates how to use to fluently define a condition under which a specific exception should be thrown. + +```csharp +using System; +using Cuemon; // for ExceptionCondition + +namespace MyApp.Examples; + +public class ExceptionConditionExample +{ + public void Demonstrate() + { + // Throw InvalidOperationException only when a condition is true + var invoker = new ExceptionCondition() + .IsTrue(() => DateTime.Now.DayOfWeek == DayOfWeek.Monday) + .Create(() => new InvalidOperationException("Cannot run this operation on Mondays.")); + + // If today is Monday, TryThrow will throw InvalidOperationException + // If today is not Monday, TryThrow does nothing + invoker.TryThrow(); + + // Throw ArgumentException only when a condition is false + var falseInvoker = new ExceptionCondition() + .IsFalse(() => Environment.UserName == "admin") + .Create(() => new ArgumentException("Only admin can call this method.")); + + falseInvoker.TryThrow(); + + // Use the TesterFunc overload to pass data to the exception + TesterFunc tryGetValue = (out string value) => + { + value = "cached-data"; + return true; // data exists + }; + + var dataInvoker = new ExceptionCondition() + .IsTrue(tryGetValue) + .Create(data => new InvalidOperationException( + $"Value '{data}' has expired. Please refresh.")); + + // Since condition returns true, this throws + dataInvoker.TryThrow(); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.ExceptionDecoratorExtensions.md b/.docfx/api/types/Cuemon.ExceptionDecoratorExtensions.md new file mode 100644 index 00000000..2242ef4f --- /dev/null +++ b/.docfx/api/types/Cuemon.ExceptionDecoratorExtensions.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.ExceptionDecoratorExtensions +example: +- *content +--- + +The following example shows how to extend `Exception` with `ExceptionDecoratorExtensions` methods to flatten nested exception hierarchies into a flat sequence. + +```csharp +using System; +using System.Linq; +using Cuemon; + +namespace Contoso.Diagnostics; + +public sealed class ExceptionDecoratorExtensionsExample +{ + public static void Run() + { + Exception nested = new InvalidOperationException( + "Request failed.", + new ArgumentException("Endpoint is invalid.", new TimeoutException("The call timed out."))); + + var flattened = Decorator.Enclose(nested).Flatten().ToList(); + + Exception aggregate = new AggregateException( + new InvalidOperationException("Retry later."), + new TimeoutException("The call timed out.")); + + var aggregateInner = Decorator.Enclose(aggregate).Flatten().ToList(); + + Console.WriteLine($"Nested chain: {string.Join(" -> ", flattened.Select(ex => ex.GetType().Name))}"); + Console.WriteLine($"Aggregate count: {aggregateInner.Count}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.ExceptionHandler`1.md b/.docfx/api/types/Cuemon.ExceptionHandler`1.md new file mode 100644 index 00000000..f17b7eb0 --- /dev/null +++ b/.docfx/api/types/Cuemon.ExceptionHandler`1.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.ExceptionHandler`1 +example: +- *content +--- + +The following example demonstrates how to use as the intermediate step in the fluent exception-triggering chain. + +```csharp +using System; +using Cuemon; // for ExceptionCondition, ExceptionHandler, ExceptionInvoker + +namespace MyApp.Examples; + +public class ExceptionHandlerExample +{ + public void Demonstrate() + { + // Build the chain: Condition -> Handler -> Invoker + ExceptionInvoker invoker = new ExceptionCondition() + .IsTrue(() => string.IsNullOrEmpty(Environment.GetEnvironmentVariable("API_KEY"))) + .Create(() => new ArgumentException("API_KEY environment variable is not set.")); + + // When TryThrow is called, it evaluates the condition + // and throws the exception created by the handler if the condition matches + invoker.TryThrow(); + + // The handler can be stored and reused to create different invokers + ExceptionHandler handler = + new ExceptionCondition().IsTrue(() => true); + + // Create different invokers from the same handler + var invokerA = handler.Create(() => new InvalidOperationException("Reason A")); + var invokerB = handler.Create(() => new InvalidOperationException("Reason B")); + + // invokerA.TryThrow(); // throws "Reason A" + // invokerB.TryThrow(); // throws "Reason B" + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.ExceptionHandler`2.md b/.docfx/api/types/Cuemon.ExceptionHandler`2.md new file mode 100644 index 00000000..cdcbbdd9 --- /dev/null +++ b/.docfx/api/types/Cuemon.ExceptionHandler`2.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.ExceptionHandler`2 +example: +- *content +--- + +The following example demonstrates how to use the generic class in the fluent exception-triggering chain with an out-value (tester) condition. + +```csharp +using System; +using Cuemon; + +namespace Cuemon.DocfxExamples; + +public sealed class ExceptionHandlerOfTResultExample +{ + public static void Run() + { + TesterFunc parsePort = (out int value) => int.TryParse("70000", out value); + + ExceptionHandler handler = + new ExceptionCondition().IsTrue(parsePort); + + var invoker = handler.Create(port => + new ArgumentOutOfRangeException(nameof(port), port, "Ports must be between 0 and 65535.")); + + try + { + invoker.TryThrow(); + } + catch (ArgumentOutOfRangeException ex) + { + Console.WriteLine($"Rejected port: {ex.ActualValue}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.ExceptionInsights.md b/.docfx/api/types/Cuemon.ExceptionInsights.md new file mode 100644 index 00000000..f6983a6f --- /dev/null +++ b/.docfx/api/types/Cuemon.ExceptionInsights.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.ExceptionInsights +example: +- *content +--- + +```csharp +using System; +using System.Reflection; + +namespace Cuemon; + +public class ExceptionInsightsExample +{ + public void Demonstrate() + { + try + { + throw new InvalidOperationException("Something went wrong."); + } + catch (InvalidOperationException ex) + { + // Enrich the exception with thread and environment information + ExceptionInsights.Embed(ex, + runtimeParameters: new object[] { "param1", 42 }, + snapshots: SystemSnapshots.CaptureThreadInfo | SystemSnapshots.CaptureEnvironmentInfo); + + // The enriched exception now has embedded insight data in its Data dictionary + Console.WriteLine(ex.Data.Contains(ExceptionInsights.Key) + ? "Insights embedded successfully." + : "No insights available."); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.ExceptionInvoker`1.md b/.docfx/api/types/Cuemon.ExceptionInvoker`1.md new file mode 100644 index 00000000..66d51f3e --- /dev/null +++ b/.docfx/api/types/Cuemon.ExceptionInvoker`1.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.ExceptionInvoker`1 +example: +- *content +--- + +The following example demonstrates the shared workflow for the family: evaluate a business condition, build the invoker from that condition, and call TryThrow() when the invalid state should surface as an exception. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon; + +namespace MyApp.Examples; + +public static class ExceptionInvokerExample +{ + public static void Demonstrate() + { + var settings = new Dictionary(StringComparer.OrdinalIgnoreCase); + + ExceptionInvoker invoker = + new ExceptionCondition() + .IsTrue(() => !settings.ContainsKey("ConnectionString")) + .Create(() => new InvalidOperationException("A ConnectionString setting is required before the data pipeline can start.")); + + bool threw = false; + + try + { + invoker.TryThrow(); + } + catch (InvalidOperationException ex) + { + threw = true; + Console.WriteLine(ex.Message); + } + + Console.WriteLine($"Threw: {threw}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.ExceptionInvoker`2.md b/.docfx/api/types/Cuemon.ExceptionInvoker`2.md new file mode 100644 index 00000000..cb025da7 --- /dev/null +++ b/.docfx/api/types/Cuemon.ExceptionInvoker`2.md @@ -0,0 +1,56 @@ +--- +uid: Cuemon.ExceptionInvoker`2 +example: +- *content +--- + +The following example demonstrates how to use the generic class to conditionally throw an exception using a tester function with an out value. + +```csharp +using System; +using Cuemon; + +namespace MyApp.Examples; + +public class ExceptionInvokerOfT2Example +{ + public void Demonstrate() + { + // Create a tester that extracts a value from a configuration string + // TesterFunc is: bool (out int result) + TesterFunc tryGetPort = (out int port) => + { + string configValue = Environment.GetEnvironmentVariable("APP_PORT") ?? "8080"; + return int.TryParse(configValue, out port); + }; + + // Build the full fluent chain + // The Create method returns an ExceptionInvoker + ExceptionInvoker invoker = new ExceptionCondition() + .IsFalse(tryGetPort) + .Create(port => new InvalidOperationException( + $"Invalid port number ({port}) configured in APP_PORT environment variable.")); + + // TryThrow evaluates tryGetPort; if it returns false (matching IsFalse), + // the exception is thrown with the out value (0) passed to the handler. + // If the environment variable is valid, no exception is thrown. + invoker.TryThrow(); + + // You can also create multiple invokers from tester conditions + TesterFunc tryGetName = (out string name) => + { + name = Environment.GetEnvironmentVariable("APP_NAME") ?? "MyApp"; + return !string.IsNullOrEmpty(name); + }; + + var nameInvoker = new ExceptionCondition() + .IsFalse(tryGetName) + .Create(name => new ArgumentNullException(nameof(name), + $"APP_NAME resolved to '{name}' which is not a valid application name.")); + + nameInvoker.TryThrow(); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.ActionExtensions.md b/.docfx/api/types/Cuemon.Extensions.ActionExtensions.md new file mode 100644 index 00000000..9842b3cb --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.ActionExtensions.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.Extensions.ActionExtensions +example: +- *content +--- + +The following example demonstrates applying the options pattern and factory initialization using the and extension methods. + +```csharp +using System; +using Cuemon.Configuration; +using Cuemon.Extensions; + +namespace MyApp.Examples; + +public static class ActionExtensionsExample +{ + private sealed class MyOptions : IParameterObject + { + public string Delimiter { get; set; } = ","; + + public string Qualifier { get; set; } = "\""; + } + + private sealed class MyService + { + public string ConnectionString { get; set; } = string.Empty; + + public int Timeout { get; set; } = 30; + } + + public static void Demonstrate() + { + var options = new Action(setup => + { + setup.Delimiter = ";"; + setup.Qualifier = "'"; + }).Configure(); + + var service = new Action(factory => + { + factory.ConnectionString = "Server=(localdb)\\MSSQLLocalDB;Database=Docs"; + factory.Timeout = 60; + }).CreateInstance(); + + Console.WriteLine($"{options.Delimiter} {options.Qualifier}"); + Console.WriteLine($"{service.ConnectionString} ({service.Timeout}s)"); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.ActionFactory.md b/.docfx/api/types/Cuemon.Extensions.ActionFactory.md new file mode 100644 index 00000000..3bb58fac --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.ActionFactory.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Extensions.ActionFactory +example: +- *content +--- + +```csharp +using System; +using Cuemon; +using Cuemon.Extensions; + +namespace Cuemon.Extensions; + +public class ActionFactoryExample +{ + public void Demonstrate() + { + Action callback = (name, count) => + { + for (int i = 0; i < count; i++) + Console.WriteLine(name); + }; + + var factory = ActionFactory.Create(callback, "Loop", 3); + factory.ExecuteMethod(); + + ActionFactory.Invoke(tuple => Console.WriteLine(tuple.Arg1), MutableTupleFactory.CreateOne("Direct invoke")); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.ApplicationBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.ApplicationBuilderExtensions.md new file mode 100644 index 00000000..6135aa91 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.ApplicationBuilderExtensions.md @@ -0,0 +1,75 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Authentication.ApplicationBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to register the Basic, Digest, and HMAC authentication middleware in an ASP.NET Core request pipeline. + +```csharp +using System; +using System.Security.Claims; +using Cuemon.Extensions.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples; + +public static class ApplicationBuilderExtensionsExample +{ + public static void Demonstrate() + { + var services = new ServiceCollection(); + + services.AddLogging(); + services.AddInMemoryDigestAuthenticationNonceTracker(); + services.AddAuthentication("docs") + .AddScheme(Cuemon.AspNetCore.Authentication.Basic.BasicAuthorizationHeader.Scheme, _ => { }) + .AddScheme(Cuemon.AspNetCore.Authentication.Digest.DigestAuthorizationHeader.Scheme, _ => { }) + .AddScheme("hmac-docs", _ => { }); + + var app = new ApplicationBuilder(services.BuildServiceProvider()); + + app.UseBasicAuthentication(options => + { + options.Realm = "SecureArea"; + options.Authenticator = (username, password) => + { + if (username == "admin" && password == "secret") + { + return new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, "Basic")); + } + + return null; + }; + options.RequireSecureConnection = false; + }); + + app.UseDigestAccessAuthentication(options => + { + options.Realm = "SecureArea"; + options.Authenticator = (string username, out string password) => + { + password = "storedPassword"; + return new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, "Digest")); + }; + options.RequireSecureConnection = false; + }); + + app.UseHmacAuthentication(options => + { + options.AuthenticationScheme = "MyHmac"; + options.Authenticator = (string clientId, out string clientSecret) => + { + clientSecret = "storedSecret"; + return new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, clientId) }, "Hmac")); + }; + options.RequireSecureConnection = false; + }); + + Console.WriteLine(app.GetType().Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthenticationBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthenticationBuilderExtensions.md new file mode 100644 index 00000000..6e18248c --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthenticationBuilderExtensions.md @@ -0,0 +1,62 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Authentication.AuthenticationBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to register the Basic, Digest, and HMAC authentication handlers through the extension methods on . + +```csharp +using System; +using System.Security.Claims; +using Cuemon.AspNetCore.Authentication.Basic; +using Cuemon.AspNetCore.Authentication.Digest; +using Cuemon.AspNetCore.Authentication.Hmac; +using Cuemon.Extensions.AspNetCore.Authentication; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples; + +public static class AuthenticationBuilderExtensionsExample +{ + public static void Demonstrate() + { + var services = new ServiceCollection(); + + services.AddLogging(); + services.AddInMemoryDigestAuthenticationNonceTracker(); + services.AddAuthentication(BasicAuthorizationHeader.Scheme) + .AddBasic(o => + { + o.Authenticator = (username, password) => new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, BasicAuthorizationHeader.Scheme)); + o.RequireSecureConnection = false; + }) + .AddDigestAccess(o => + { + o.Authenticator = (string username, out string password) => + { + password = "Test"; + return new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, DigestAuthorizationHeader.Scheme)); + }; + o.RequireSecureConnection = false; + }) + .AddHmac(o => + { + o.AuthenticationScheme = "hmac-docs"; + o.Authenticator = (string clientId, out string clientSecret) => + { + clientSecret = "Test"; + return new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, clientId) }, o.AuthenticationScheme)); + }; + o.RequireSecureConnection = false; + }); + + using var provider = services.BuildServiceProvider(); + + Console.WriteLine(provider.GetRequiredService().GetType().Name); + Console.WriteLine(provider.GetRequiredService().GetType().Name); + Console.WriteLine(provider.GetRequiredService().GetType().Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandler.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandler.md new file mode 100644 index 00000000..4818ee15 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandler.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandler +example: +- *content +--- + +The following example demonstrates how to construct `AuthorizationResponseHandler` with configured options and the required logger dependency. + +```csharp +using System; +using Cuemon.Extensions.AspNetCore.Authentication; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public static class AuthorizationResponseHandlerExample +{ + public static void Demonstrate() + { + var services = new ServiceCollection(); + + services.Configure(options => + { + options.SensitivityDetails = Cuemon.Diagnostics.FaultSensitivityDetails.All; + }); + + services.AddLogging(); + + using var provider = services.BuildServiceProvider(); + var logger = provider.GetRequiredService>(); + var options = provider.GetRequiredService>(); + var handler = new AuthorizationResponseHandler(logger, options); + + Console.WriteLine(handler.GetType().Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandlerOptions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandlerOptions.md new file mode 100644 index 00000000..8481e2bd --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandlerOptions.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandlerOptions +example: +- *content +--- + +The following example demonstrates how to configure `AuthorizationResponseHandlerOptions` to customize the behavior of the authorization response handler. + +```csharp +using Cuemon.Diagnostics; +using Cuemon.Extensions.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization.Policy; + +namespace MyApp.Examples; + +public class AuthorizationResponseHandlerOptionsExample +{ + public void Demonstrate() + { + var options = new AuthorizationResponseHandlerOptions + { + SensitivityDetails = FaultSensitivityDetails.All, + FallbackResponseHandler = new AuthorizationMiddlewareResultHandler() + }; + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.ServiceCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.ServiceCollectionExtensions.md new file mode 100644 index 00000000..33e5f1d0 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.ServiceCollectionExtensions.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Authentication.ServiceCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to register the in-memory digest nonce tracker and the authorization response handler services. + +```csharp +using System; +using Cuemon.AspNetCore.Authentication; +using Cuemon.Diagnostics; +using Cuemon.Extensions.AspNetCore.Authentication; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples; + +public static class ServiceCollectionExtensionsExample +{ + public static void Demonstrate() + { + var services = new ServiceCollection(); + + services.AddInMemoryDigestAuthenticationNonceTracker(); + services.AddAuthorizationResponseHandler(o => + { + o.SensitivityDetails = FaultSensitivityDetails.All; + }); + + using var provider = services.BuildServiceProvider(); + + Console.WriteLine(provider.GetRequiredService().GetType().Name); + Console.WriteLine(provider.GetRequiredService().GetType().Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Configuration.AssemblyCacheBusting.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Configuration.AssemblyCacheBusting.md new file mode 100644 index 00000000..c08d2580 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Configuration.AssemblyCacheBusting.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Configuration.AssemblyCacheBusting +example: +- *content +--- + +The following example demonstrates how to create an `AssemblyCacheBusting` instance to provide cache-busting version strings derived from the entry assembly. + +```csharp +using System; +using Cuemon.Extensions.AspNetCore.Configuration; +using Cuemon.Security.Cryptography; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public class AssemblyCacheBustingExample +{ + public void Demonstrate() + { + var options = Options.Create(new AssemblyCacheBustingOptions + { + Algorithm = UnkeyedCryptoAlgorithm.Sha256, + ReadByteForByteChecksum = true + }); + + var cacheBusting = new AssemblyCacheBusting(options); + string version = cacheBusting.Version; + + Console.WriteLine($"Cache-busting version: {version}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Configuration.AssemblyCacheBustingOptions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Configuration.AssemblyCacheBustingOptions.md new file mode 100644 index 00000000..48757f6e --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Configuration.AssemblyCacheBustingOptions.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Configuration.AssemblyCacheBustingOptions +example: +- *content +--- + +The following example demonstrates how to configure `AssemblyCacheBustingOptions` for a reproducible cache-busting version that is derived from a known assembly and hash algorithm. + +```csharp +using System; +using Cuemon; +using Cuemon.Extensions.AspNetCore.Configuration; +using Cuemon.Security.Cryptography; +using Microsoft.Extensions.Options; + +namespace DocfxExamples; + +public class AssemblyCacheBustingOptionsExample +{ + public static void Demonstrate() + { + var options = Options.Create(new AssemblyCacheBustingOptions + { + Assembly = typeof(AssemblyCacheBustingOptionsExample).Assembly, + Algorithm = UnkeyedCryptoAlgorithm.Sha256, + PreferredCasing = CasingMethod.UpperCase, + ReadByteForByteChecksum = true + }); + + var cacheBusting = new AssemblyCacheBusting(options); + + Console.WriteLine(cacheBusting.Version); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Configuration.ServiceCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Configuration.ServiceCollectionExtensions.md new file mode 100644 index 00000000..df6c046f --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Configuration.ServiceCollectionExtensions.md @@ -0,0 +1,47 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Configuration.ServiceCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to register the built-in cache-busting services and a custom `ICacheBusting` implementation. + +```csharp +using System; +using System.Linq; +using Cuemon.AspNetCore.Configuration; +using Cuemon.Extensions.AspNetCore.Configuration; +using Cuemon.Security.Cryptography; +using Microsoft.Extensions.DependencyInjection; + +namespace DocfxExamples; + +public class ConfigurationServiceCollectionExtensionsExample +{ + public static void ConfigureServices(IServiceCollection services) + { + services.AddOptions(); + services.Configure(options => + { + options.Assembly = typeof(ConfigurationServiceCollectionExtensionsExample).Assembly; + options.Algorithm = UnkeyedCryptoAlgorithm.Sha256; + options.ReadByteForByteChecksum = true; + }); + + services.AddAssemblyCacheBusting(); + services.AddDynamicCacheBusting(); + services.AddCacheBusting(); + + var provider = services.BuildServiceProvider(); + var versions = provider.GetServices().Select(cache => cache.Version).ToList(); + + Console.WriteLine(versions.Count); + Console.WriteLine(string.Join(", ", versions)); + } + + private sealed class ReleaseCacheBusting : ICacheBusting + { + public string Version => "20260618"; + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Data.Integrity.CacheValidatorExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Data.Integrity.CacheValidatorExtensions.md new file mode 100644 index 00000000..7657c840 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Data.Integrity.CacheValidatorExtensions.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Data.Integrity.CacheValidatorExtensions +example: +- *content +--- + +The following example demonstrates how to turn assembly-backed cache validators into ETag headers for weak and strong validation scenarios. + +```csharp +using System; +using Cuemon.Data.Integrity; +using Cuemon.Extensions.AspNetCore.Data.Integrity; +using Microsoft.Net.Http.Headers; + +namespace DocfxExamples; + +public class CacheValidatorExtensionsExample +{ + public static void Demonstrate() + { + CacheValidator weakValidator = CacheValidatorFactory.CreateValidator(typeof(CacheValidatorExtensionsExample).Assembly); + EntityTagHeaderValue weakEntityTag = weakValidator.ToEntityTagHeaderValue(); + + CacheValidator strongValidator = CacheValidatorFactory.CreateValidator( + typeof(CacheValidatorExtensionsExample).Assembly, + setup: options => options.BytesToRead = int.MaxValue); + + EntityTagHeaderValue strongEntityTag = strongValidator.ToEntityTagHeaderValue(); + + Console.WriteLine(weakEntityTag); + Console.WriteLine(strongEntityTag); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Data.Integrity.ChecksumBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Data.Integrity.ChecksumBuilderExtensions.md new file mode 100644 index 00000000..dba8db2e --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Data.Integrity.ChecksumBuilderExtensions.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Data.Integrity.ChecksumBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to create an `EntityTagHeaderValue` from a `ChecksumBuilder` instance. + +```csharp +using Cuemon.Data.Integrity; +using Cuemon.Extensions.AspNetCore.Data.Integrity; +using Microsoft.Net.Http.Headers; + +namespace Examples; + +public class EntityTagExample +{ + public EntityTagHeaderValue CreateEntityTag(ChecksumBuilder builder) + { + return builder.ToEntityTagHeaderValue(); + } + + public EntityTagHeaderValue CreateWeakEntityTag(ChecksumBuilder builder) + { + return builder.ToEntityTagHeaderValue(isWeak: true); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Diagnostics.ApplicationBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Diagnostics.ApplicationBuilderExtensions.md new file mode 100644 index 00000000..09e3aff2 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Diagnostics.ApplicationBuilderExtensions.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Diagnostics.ApplicationBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to add diagnostics middleware to the ASP.NET Core pipeline using the class. + +```csharp +using Cuemon.Extensions.AspNetCore.Diagnostics; +using Microsoft.AspNetCore.Builder; + +namespace MyApp.Examples; + +public class ApplicationBuilderExtensionsExample +{ + public void Configure(IApplicationBuilder app) + { + // Add Server-Timing header middleware + app.UseServerTiming(); + + // Add fault descriptor exception handler (catches exceptions and returns structured error responses) + app.UseFaultDescriptorExceptionHandler(); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Diagnostics.ServiceCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Diagnostics.ServiceCollectionExtensions.md new file mode 100644 index 00000000..88b6bd70 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Diagnostics.ServiceCollectionExtensions.md @@ -0,0 +1,56 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Diagnostics.ServiceCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to use the extension methods to configure diagnostics and fault handling in an ASP.NET Core application. + +```csharp +using System; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.Diagnostics; +using Cuemon.Extensions.AspNetCore.Diagnostics; +using Microsoft.Extensions.DependencyInjection; + +namespace MyAspNetCoreApp +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + // Add ServerTiming service for performance profiling + services.AddServerTiming(options => + { + options.TimeMeasureCompletedThreshold = TimeSpan.FromMilliseconds(10); + }); + + // Configure FaultDescriptor options (exception handling) + services.AddFaultDescriptorOptions(options => + { + options.SensitivityDetails = FaultSensitivityDetails.All; + options.RootHelpLink = new Uri("https://example.com/help"); + }); + + // Configure ExceptionDescriptor options + services.AddExceptionDescriptorOptions(options => + { + options.SensitivityDetails = FaultSensitivityDetails.None; + }); + + // Configure ServerTiming options separately + services.AddServerTimingOptions(options => + { + options.TimeMeasureCompletedThreshold = TimeSpan.FromMilliseconds(50); + }); + + // Post-configure all IExceptionDescriptorOptions instances + services.PostConfigureAllExceptionDescriptorOptions(options => + { + options.SensitivityDetails = FaultSensitivityDetails.FailureWithStackTrace; + }); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Diagnostics.ServiceProviderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Diagnostics.ServiceProviderExtensions.md new file mode 100644 index 00000000..c97f9042 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Diagnostics.ServiceProviderExtensions.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Diagnostics.ServiceProviderExtensions +example: +- *content +--- + +The following example demonstrates how to retrieve all registered `IHttpExceptionDescriptorResponseFormatter` services from the service provider. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.Extensions.AspNetCore.Diagnostics; +using Microsoft.Extensions.DependencyInjection; + +namespace Examples; + +public class ExceptionFormatterResolver +{ + public IEnumerable ResolveFormatters(IServiceProvider provider) + { + return provider.GetExceptionResponseFormatters(); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Hosting.ApplicationBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Hosting.ApplicationBuilderExtensions.md new file mode 100644 index 00000000..2072905e --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Hosting.ApplicationBuilderExtensions.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Hosting.ApplicationBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to add the hosting environment HTTP header middleware to an ASP.NET Core application pipeline. + +```csharp +using Cuemon.AspNetCore.Hosting; +using Cuemon.Extensions.AspNetCore.Hosting; +using Microsoft.AspNetCore.Builder; + +namespace Examples; + +public class StartupPipeline +{ + public void Configure(IApplicationBuilder app) + { + app.UseHostingEnvironment(o => + { + o.HeaderName = "X-Environment"; + }); + + app.UseRouting(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HeaderDictionaryExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HeaderDictionaryExtensions.md new file mode 100644 index 00000000..b797ef19 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HeaderDictionaryExtensions.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Http.HeaderDictionaryExtensions +example: +- *content +--- + +The following example demonstrates how to add or update HTTP headers in an using the class. + +```csharp +using System; +using System.Net.Http; +using System.Net.Http.Headers; +using Cuemon.Extensions.AspNetCore.Http; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace MyApp.Examples; + +public class HeaderDictionaryExtensionsExample +{ + public void Demonstrate() + { + var headers = new HeaderDictionary(); + + // Add or update a single header + headers.AddOrUpdateHeader("X-Custom", new StringValues("my-value")); + + // Add or update multiple headers from an HttpResponseHeaders collection + var responseMessage = new HttpResponseMessage(); + responseMessage.Headers.Add("X-Trace", "abc123"); + responseMessage.Headers.Add("X-Session", "session-456"); + + headers.AddOrUpdateHeaders(responseMessage.Headers); + + // Verify headers + Console.WriteLine(headers["X-Custom"]); // my-value + Console.WriteLine(headers["X-Trace"]); // abc123 + Console.WriteLine(headers["X-Session"]); // session-456 + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Headers.ApplicationBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Headers.ApplicationBuilderExtensions.md new file mode 100644 index 00000000..22c46772 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Headers.ApplicationBuilderExtensions.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Http.Headers.ApplicationBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to add correlation, request, validation, and cache headers to an ASP.NET Core request pipeline. + +```csharp +using System; +using Cuemon.AspNetCore.Http.Headers; +using Cuemon.Extensions.AspNetCore.Http.Headers; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Net.Http.Headers; + +namespace DocfxExamples; + +public class HeaderPipelineExample +{ + public static void Configure(IApplicationBuilder app) + { + app.UseCorrelationIdentifier(options => options.HeaderName = "X-Correlation-ID"); + app.UseRequestIdentifier(options => options.HeaderName = "X-Request-ID"); + app.UseUserAgentSentinel(options => + { + options.RequireUserAgentHeader = true; + options.ValidateUserAgentHeader = true; + options.AllowedUserAgents.Add("Cuemon-Agent"); + }); + app.UseApiKeySentinel(options => + { + options.HeaderName = "X-Test-Key"; + options.AllowedKeys.Add("known-key"); + }); + app.UseCacheControl(options => + { + options.CacheControl.MaxAge = TimeSpan.FromHours(1); + options.CacheControl.Public = true; + options.Expires = new ExpiresHeaderValue(TimeSpan.FromHours(1)); + }); + app.UseVaryAccept(); + app.Run(context => context.Response.WriteAsync("ok")); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Headers.EntityTagCacheableValidator.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Headers.EntityTagCacheableValidator.md new file mode 100644 index 00000000..5ba4826d --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Headers.EntityTagCacheableValidator.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Http.Headers.EntityTagCacheableValidator +example: +- *content +--- + +The following example demonstrates how to register as a cacheable validator in the ASP.NET Core pipeline. + +```csharp +using System; +using Cuemon.AspNetCore.Http.Headers; +using Cuemon.Extensions.AspNetCore.Http.Headers; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace DocfxExamples; + +public class EntityTagCacheableValidatorExample +{ + public void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + options.Validators.Add(new EntityTagCacheableValidator()); + }); + + var serviceProvider = services.BuildServiceProvider(); + var options = serviceProvider.GetRequiredService>(); + Console.WriteLine(options.Value.Validators.Count); // 1 + Console.WriteLine(options.Value.Validators[0] is EntityTagCacheableValidator); // True + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Headers.ServiceCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Headers.ServiceCollectionExtensions.md new file mode 100644 index 00000000..b1977198 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Headers.ServiceCollectionExtensions.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Http.Headers.ServiceCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to register API key and User-Agent validation rules and then inspect the resolved options through `IOptions`. + +```csharp +using System; +using Cuemon.AspNetCore.Http.Headers; +using Cuemon.Extensions.AspNetCore.Http.Headers; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace DocfxExamples; + +public class HeaderServiceCollectionExtensionsExample +{ + public static void ConfigureServices(IServiceCollection services) + { + services.AddOptions(); + services.AddApiKeySentinelOptions(options => + { + options.AllowedKeys.Add("known-key"); + options.HeaderName = "X-Test-Key"; + options.UseGenericResponse = true; + }); + services.AddUserAgentSentinelOptions(options => + { + options.AllowedUserAgents.Add("Cuemon-Agent"); + options.RequireUserAgentHeader = true; + options.ValidateUserAgentHeader = true; + }); + + var provider = services.BuildServiceProvider(); + var apiKeyOptions = provider.GetRequiredService>().Value; + var userAgentOptions = provider.GetRequiredService>().Value; + + Console.WriteLine($"{apiKeyOptions.HeaderName}:{apiKeyOptions.AllowedKeys.Count}"); + Console.WriteLine($"{userAgentOptions.RequireUserAgentHeader}:{userAgentOptions.AllowedUserAgents.Count}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpExceptionDescriptorResponseFormatterExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpExceptionDescriptorResponseFormatterExtensions.md new file mode 100644 index 00000000..2dbf05d3 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpExceptionDescriptorResponseFormatterExtensions.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Http.HttpExceptionDescriptorResponseFormatterExtensions +example: +- *content +--- + +The following example demonstrates how to project all exception descriptor handlers from a sequence of formatters into a single enumerable sequence. + +```csharp +using System.Collections.Generic; +using System.Linq; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.Extensions.AspNetCore.Http; + +namespace Examples; + +public class FormatterHandlerProjection +{ + public IEnumerable GetAllHandlers(IEnumerable formatters) + { + return formatters.SelectExceptionDescriptorHandlers(); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpRequestExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpRequestExtensions.md new file mode 100644 index 00000000..c31d5b6b --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpRequestExtensions.md @@ -0,0 +1,55 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Http.HttpRequestExtensions +example: +- *content +--- + +The following example demonstrates how to use HttpRequestExtensions to inspect HTTP request properties such as accepted MIME types, HTTP method checks, and client-side caching status using ETags and Last-Modified headers. + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon.Data.Integrity; +using Cuemon.Extensions.AspNetCore.Http; +using Cuemon.Security; +using Microsoft.AspNetCore.Http; + +namespace MyApp.AspNetCore.Http +{ + public class HttpRequestExtensionsExample + { + public void Demonstrate(HttpRequest request) + { + // Get ordered MIME types from the Accept header by quality value + request.Headers["Accept"] = "text/html;q=0.8, application/json;q=0.9, */*;q=0.1"; + IEnumerable preferredTypes = request.AcceptMimeTypesOrderedByQuality(); + Console.WriteLine(string.Join(", ", preferredTypes)); + // Output: "application/json, text/html, */*" (sorted by q-value descending) + + // Check if the request uses GET or HEAD method + request.Method = "GET"; + bool isGetOrHead = request.IsGetOrHeadMethod(); + Console.WriteLine(isGetOrHead); // True + + request.Method = "POST"; + isGetOrHead = request.IsGetOrHeadMethod(); + Console.WriteLine(isGetOrHead); // False + + // Check if the client has a cached version using If-None-Match (ETag) + request.Method = "GET"; + request.Headers["If-None-Match"] = "\"abc123\""; + var checksumBuilder = new ChecksumBuilder(() => HashFactory.CreateFnv128()); + bool isCached = request.IsClientSideResourceCached(checksumBuilder); + Console.WriteLine(isCached); // True or False depending on checksum match + + // Check if the client has a cached version using If-Modified-Since + request.Headers["If-Modified-Since"] = "Tue, 15 Jun 2024 10:00:00 GMT"; + var lastModified = new DateTime(2024, 6, 15, 9, 0, 0, DateTimeKind.Utc); + isCached = request.IsClientSideResourceCached(lastModified); + Console.WriteLine(isCached); // False (resource modified after If-Modified-Since date) + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpResponseExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpResponseExtensions.md new file mode 100644 index 00000000..8e98fe39 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpResponseExtensions.md @@ -0,0 +1,54 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Http.HttpResponseExtensions +example: +- *content +--- + +The following example demonstrates how to use HttpResponseExtensions to manage HTTP response headers such as ETag and Last-Modified, write response bodies, and transform HttpResponseMessage content into the ASP.NET Core response pipeline. + +```csharp +using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Cuemon.Data.Integrity; +using Cuemon.Extensions.AspNetCore.Http; +using Cuemon.Security; +using Microsoft.AspNetCore.Http; + +namespace MyApp.AspNetCore.Http +{ + public class HttpResponseExtensionsExample + { + public async Task DemonstrateAsync(HttpResponse response, HttpRequest request) + { + // Add or update an ETag header using a checksum builder + var builder = new ChecksumBuilder(() => HashFactory.CreateFnv128()); + response.AddOrUpdateEntityTagHeader(request, builder, isWeak: false); + // Response now has ETag: "..." header + + // Add or update a Last-Modified header with a specific date + var lastModified = new DateTime(2024, 6, 15, 10, 0, 0, DateTimeKind.Utc); + response.AddOrUpdateLastModifiedHeader(request, lastModified); + // Response now has Last-Modified: "Sat, 15 Jun 2024 10:00:00 GMT" header + + // Write bytes to the response body from a delegate + await response.WriteBodyAsync(() => new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F }); + // Response body now contains "Hello" + + // Transfer a HttpResponseMessage to the response pipeline + var message = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent("{\"status\":\"ok\"}") + }; + response.OnStartingInvokeTransformer(message, (msg, resp) => + { + resp.StatusCode = (int)msg.StatusCode; + resp.Headers["Content-Type"] = "application/json"; + }); + // The response will send the transformed content when the pipeline starts + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Int32Extensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Int32Extensions.md new file mode 100644 index 00000000..d453a477 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Int32Extensions.md @@ -0,0 +1,50 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Http.Int32Extensions +example: +- *content +--- + +The following example demonstrates how to use the extension methods to classify HTTP status codes by range. + +```csharp +using System; +using Cuemon.Extensions.AspNetCore.Http; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + + int statusCode = 404; + + // Check the status code range + bool isInfo = statusCode.IsInformationStatusCode(); + bool isSuccess = statusCode.IsSuccessStatusCode(); + bool isRedirect = statusCode.IsRedirectionStatusCode(); + bool isClientError = statusCode.IsClientErrorStatusCode(); + bool isServerError = statusCode.IsServerErrorStatusCode(); + bool isNotModified = statusCode.IsNotModifiedStatusCode(); + + Console.WriteLine($"HTTP {statusCode}:"); + Console.WriteLine($" Informational: {isInfo}"); + Console.WriteLine($" Success: {isSuccess}"); + Console.WriteLine($" Redirection: {isRedirect}"); + Console.WriteLine($" Client Error: {isClientError}"); + Console.WriteLine($" Server Error: {isServerError}"); + Console.WriteLine($" Not Modified: {isNotModified}"); + + // Use with common HTTP status codes + int ok = 200; + int notFound = 404; + int serverError = 500; + + Console.WriteLine($"\n{ok} is success: {ok.IsSuccessStatusCode()}"); + Console.WriteLine($"{notFound} is client error: {notFound.IsClientErrorStatusCode()}"); + Console.WriteLine($"{serverError} is server error: {serverError.IsServerErrorStatusCode()}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Throttling.ApplicationBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Throttling.ApplicationBuilderExtensions.md new file mode 100644 index 00000000..ebe6f5ab --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Throttling.ApplicationBuilderExtensions.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Http.Throttling.ApplicationBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to add a request rate limiting middleware to an ASP.NET Core application pipeline. + +```csharp +using System; +using Cuemon; +using Cuemon.AspNetCore.Http.Throttling; +using Cuemon.Extensions.AspNetCore.Http.Throttling; +using Microsoft.AspNetCore.Builder; + +namespace Examples; + +public class StartupPipeline +{ + public void Configure(IApplicationBuilder app) + { + app.UseThrottlingSentinel(o => + { + o.Quota = new ThrottleQuota(100, 1, TimeUnit.Minutes); + o.ContextResolver = ctx => ctx.Connection.RemoteIpAddress?.ToString() ?? "unknown"; + }); + + app.UseRouting(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Throttling.ServiceCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Throttling.ServiceCollectionExtensions.md new file mode 100644 index 00000000..5b4b9109 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Throttling.ServiceCollectionExtensions.md @@ -0,0 +1,54 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Http.Throttling.ServiceCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to register throttling and rate-limiting services in an ASP.NET Core application using ServiceCollectionExtensions, including in-memory throttling cache and custom rate-limit sentinel options. + +```csharp +using System; +using Cuemon; +using Cuemon.AspNetCore.Http.Headers; +using Cuemon.AspNetCore.Http.Throttling; +using Cuemon.Extensions.AspNetCore.Http.Throttling; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.AspNetCore.Throttling +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + // Register the in-memory throttling cache as a singleton + services.AddMemoryThrottlingCache(); + + // Register a custom IThrottlingCache implementation + services.AddThrottlingCache(); + + // Configure throttling sentinel options (rate limiting rules) + services.AddThrottlingSentinelOptions(o => + { + // Identify clients by their remote IP address + o.ContextResolver = ctx => ctx.Connection.RemoteIpAddress?.ToString() ?? "unknown"; + + // Allow 100 requests per minute per client + o.Quota = new ThrottleQuota(100, 1, TimeUnit.Minutes); + + // Customize the rate limit response message + o.TooManyRequestsMessage = "API rate limit exceeded. Please wait before retrying."; + + // Customize HTTP header names + o.RateLimitHeaderName = "X-RateLimit-Limit"; + o.RateLimitRemainingHeaderName = "X-RateLimit-Remaining"; + o.RateLimitResetHeaderName = "X-RateLimit-Reset"; + + // Use delta-seconds format for reset headers + o.RateLimitResetScope = RetryConditionScope.DeltaSeconds; + o.UseRetryAfterHeader = true; + }); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.CacheableObjectResultExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.CacheableObjectResultExtensions.md new file mode 100644 index 00000000..af6bc617 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.CacheableObjectResultExtensions.md @@ -0,0 +1,75 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.CacheableObjectResultExtensions +example: +- *content +--- + +The following example mirrors the cacheable object patterns covered by the unit tests: a payload can expose Last-Modified metadata, an ETag, or both headers at once. + +```csharp +using System; +using System.Text; +using Cuemon.AspNetCore.Mvc; +using Cuemon.Data.Integrity; +using Cuemon.Extensions.AspNetCore.Mvc; + +namespace Cuemon.Extensions.AspNetCore.Mvc.DocExamples; + +public sealed class CacheableObjectResultExample +{ + public ICacheableObjectResult CreateLastModifiedResult() + { + var product = new ProductDto(42, "Coffee Beans"); + return product.WithLastModifiedHeader(options => + { + options.TimestampProvider = _ => new DateTime(2024, 6, 1, 8, 0, 0, DateTimeKind.Utc); + options.ChangedTimestampProvider = _ => new DateTime(2024, 6, 18, 8, 30, 0, DateTimeKind.Utc); + }); + } + + public ICacheableObjectResult CreateEntityTagResult() + { + var product = new ProductDto(42, "Coffee Beans"); + return product.WithEntityTagHeader(options => + { + options.ChecksumProvider = dto => Encoding.UTF8.GetBytes($"{dto.Id}:{dto.Name}"); + options.WeakChecksumProvider = _ => false; + }); + } + + public ICacheableObjectResult CreateFullyCacheableResult() + { + var product = new ProductDto(42, "Coffee Beans"); + return product.WithCacheableHeaders(options => + { + options.TimestampProvider = _ => new DateTime(2024, 6, 1, 8, 0, 0, DateTimeKind.Utc); + options.ChangedTimestampProvider = _ => new DateTime(2024, 6, 18, 8, 30, 0, DateTimeKind.Utc); + options.ChecksumProvider = dto => Encoding.UTF8.GetBytes($"{dto.Id}:{dto.Name}"); + options.WeakChecksumProvider = _ => false; + }); + } + + public void Describe() + { + var result = CreateFullyCacheableResult(); + var timestamp = (IEntityDataTimestamp)result; + var integrity = (IEntityDataIntegrity)result; + var product = (ProductDto)result.Value; + + Console.WriteLine($"{product.Name}: {(timestamp.Modified ?? timestamp.Created):O} [{integrity.Validation}]"); + } +} + +public sealed class ProductDto +{ + public ProductDto(int id, string name) + { + Id = id; + Name = name; + } + + public int Id { get; } + + public string Name { get; } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable.CacheableAsyncResultFilterExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable.CacheableAsyncResultFilterExtensions.md new file mode 100644 index 00000000..5ce1beeb --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable.CacheableAsyncResultFilterExtensions.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable.CacheableAsyncResultFilterExtensions +example: +- *content +--- + +The following example configures the same cache-filter collection patterns exercised by the unit tests: use the convenience methods for the default pipeline, or switch to the generic overloads when you need explicit ordering and option control. + +```csharp +using System; +using Cuemon.AspNetCore.Mvc.Filters.Cacheable; +using Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable; + +namespace Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable.DocExamples; + +public sealed class CacheableAsyncResultFilterExtensionsExample +{ + public HttpCacheableOptions CreateDefaultProfile() + { + var options = new HttpCacheableOptions(); + options.Filters.AddLastModifiedHeader(); + options.Filters.AddEntityTagHeader(); + return options; + } + + public HttpCacheableOptions CreateCustomProfile() + { + var options = new HttpCacheableOptions(); + options.Filters.AddFilter(entityTag => + { + entityTag.UseEntityTagResponseParser = true; + }); + options.Filters.InsertFilter(0); + return options; + } + + public void Describe() + { + var defaultProfile = CreateDefaultProfile(); + var customProfile = CreateCustomProfile(); + + Console.WriteLine($"{defaultProfile.Filters.Count} default filters, {customProfile.Filters.Count} custom filters."); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics.HttpFaultResolverExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics.HttpFaultResolverExtensions.md new file mode 100644 index 00000000..81c7a2fd --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics.HttpFaultResolverExtensions.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics.HttpFaultResolverExtensions +example: +- *content +--- + +The following example builds a resolver list the same way MVC fault handling does internally: map known exception types to HTTP-friendly descriptors, then ask a resolver to translate the thrown exception. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.AspNetCore.Diagnostics; +using Cuemon.AspNetCore.Http; +using Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics; + +namespace Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics.DocExamples; + +public sealed class HttpFaultResolverExtensionsExample +{ + public void Describe() + { + var resolvers = new List() + .AddHttpFaultResolver( + message: "The request payload could not be processed.", + helpLink: new Uri("https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400")) + .AddHttpFaultResolver( + exception => new HttpExceptionDescriptor(exception), + exception => exception is TooManyRequestsException); + + var resolved = resolvers[1].TryResolveFault(new TooManyRequestsException(), out var descriptor); + + Console.WriteLine($"{resolved}: {descriptor.StatusCode} {descriptor.Code}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.FilterCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.FilterCollectionExtensions.md new file mode 100644 index 00000000..70fd214c --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.FilterCollectionExtensions.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Filters.FilterCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to use the extension methods to register common ASP.NET Core MVC filters. + +```csharp +using Cuemon.Extensions.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; + +namespace MyAspNetCoreApp +{ + public class Startup + { + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(options => + { + // Add HTTP cacheable filter for response caching + options.Filters.AddHttpCacheable(); + + // Add developer-friendly fault descriptor + options.Filters.AddFaultDescriptor(); + + // Add server timing header for performance profiling + options.Filters.AddServerTiming(); + + // Add User-Agent sentinel filter + options.Filters.AddUserAgentSentinel(); + + // Add API throttling sentinel + options.Filters.AddThrottlingSentinel(); + + // Add API key sentinel + options.Filters.AddApiKeySentinel(); + }); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.MvcBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.MvcBuilderExtensions.md new file mode 100644 index 00000000..fe0ffb7f --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.MvcBuilderExtensions.md @@ -0,0 +1,67 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Filters.MvcBuilderExtensions +example: +- *content +--- + +The following example configures the MVC builder with the same option families covered by the unit tests: API-key enforcement, throttling, user-agent validation, fault descriptors, and cache headers. + +```csharp +using System; +using Cuemon; +using Cuemon.AspNetCore.Http; +using Cuemon.AspNetCore.Http.Throttling; +using Cuemon.Diagnostics; +using Cuemon.Extensions.AspNetCore.Mvc.Filters; +using Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable; +using Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics; +using Microsoft.Extensions.DependencyInjection; + +namespace Cuemon.Extensions.AspNetCore.Mvc.Filters.DocExamples; + +public sealed class MvcBuilderExtensionsExample +{ + public IServiceCollection ConfigureServices() + { + var services = new ServiceCollection(); + + var builder = services + .AddMvc() + .AddApiKeySentinelOptions(options => + { + options.AllowedKeys.Add("demo-key"); + options.UseGenericResponse = true; + }) + .AddThrottlingSentinelOptions(options => + { + options.ContextResolver = context => context.Connection.RemoteIpAddress?.ToString() ?? "anonymous"; + options.Quota = new ThrottleQuota(100, 1, TimeUnit.Minutes); + options.TooManyRequestsMessage = "Rate limit exceeded."; + }) + .AddUserAgentSentinelOptions(options => + { + options.RequireUserAgentHeader = true; + options.ValidateUserAgentHeader = true; + options.AllowedUserAgents.Add("DocsSample/1.0"); + }) + .AddFaultDescriptorOptions(options => + { + options.MarkExceptionHandled = true; + options.SensitivityDetails = FaultSensitivityDetails.All; + options.HttpFaultResolvers.AddHttpFaultResolver(); + }) + .AddHttpCacheableOptions(options => + { + options.CacheControl.MaxAge = TimeSpan.FromMinutes(5); + options.Filters.AddLastModifiedHeader(); + options.Filters.AddEntityTagHeader(entityTag => + { + entityTag.UseEntityTagResponseParser = true; + }); + }); + + Console.WriteLine(builder.Services.Count); + return builder.Services; + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationInputFormatter.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationInputFormatter.md new file mode 100644 index 00000000..5d9f7650 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationInputFormatter.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationInputFormatter +example: +- *content +--- + +The following example demonstrates how to construct a and inspect its supported media types and encodings. + +```csharp +using System; +using System.Linq; +using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json; +using Cuemon.Extensions.Text.Json.Formatters; + +namespace DocfxExamples; + +public class JsonSerializationInputFormatterExample +{ + public void Demonstrate() + { + var options = new JsonFormatterOptions(); + var formatter = new JsonSerializationInputFormatter(options); + + Console.WriteLine($"Supported media types: {string.Join(", ", formatter.SupportedMediaTypes)}"); + Console.WriteLine($"Supported encodings: {string.Join(", ", formatter.SupportedEncodings.Select(e => e.WebName))}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationMvcOptionsSetup.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationMvcOptionsSetup.md new file mode 100644 index 00000000..831424f8 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationMvcOptionsSetup.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationMvcOptionsSetup +example: +- *content +--- + +The following example demonstrates how to register with the dependency injection container to configure with JSON serialization formatters. + +```csharp +using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json; +using System; +using Cuemon.Extensions.Text.Json.Formatters; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace DocfxExamples; + +public class JsonSerializationMvcOptionsSetupExample +{ + public void ConfigureServices(IServiceCollection services) + { + services.Configure(options => + { + options.Settings.WriteIndented = true; + }); + + services.AddTransient, JsonSerializationMvcOptionsSetup>(); + + var serviceProvider = services.BuildServiceProvider(); + var setup = serviceProvider.GetService>(); + Console.WriteLine(setup is JsonSerializationMvcOptionsSetup); // True + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationOutputFormatter.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationOutputFormatter.md new file mode 100644 index 00000000..37535a81 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationOutputFormatter.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.JsonSerializationOutputFormatter +example: +- *content +--- + +The following example demonstrates how to construct a and inspect its supported media types and encodings. + +```csharp +using System; +using System.Linq; +using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json; +using Cuemon.Extensions.Text.Json.Formatters; + +namespace DocfxExamples; + +public class JsonSerializationOutputFormatterExample +{ + public void Demonstrate() + { + var options = new JsonFormatterOptions(); + var formatter = new JsonSerializationOutputFormatter(options); + + Console.WriteLine($"Supported media types: {string.Join(", ", formatter.SupportedMediaTypes)}"); + Console.WriteLine($"Supported encodings: {string.Join(", ", formatter.SupportedEncodings.Select(e => e.WebName))}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.MvcBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.MvcBuilderExtensions.md new file mode 100644 index 00000000..562e2c01 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.MvcBuilderExtensions.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.MvcBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to register JSON serialization formatters on an using the extension methods. + +```csharp +using Cuemon.Diagnostics; +using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json; +using Microsoft.Extensions.DependencyInjection; + +namespace DocfxExamples; + +public class MvcBuilderExtensionsExample +{ + public void ConfigureMvc(IMvcBuilder builder) + { + // Invoke the AddJsonFormatters extension method + MvcBuilderExtensions.AddJsonFormatters(builder, options => + { + options.SensitivityDetails = FaultSensitivityDetails.All; + options.Settings.WriteIndented = true; + }); + + // Invoke the AddJsonFormattersOptions extension method + MvcBuilderExtensions.AddJsonFormattersOptions(builder, options => + { + options.Settings.WriteIndented = true; + }); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.MvcCoreBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.MvcCoreBuilderExtensions.md new file mode 100644 index 00000000..22a10255 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.MvcCoreBuilderExtensions.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json.MvcCoreBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to register JSON serialization formatters on an using the extension methods. + +```csharp +using System.Text.Json; +using System.Text.Json.Serialization; +using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json; +using Microsoft.Extensions.DependencyInjection; + +namespace DocfxExamples; + +public class MvcCoreBuilderExtensionsExample +{ + public void ConfigureMvc(IMvcCoreBuilder builder) + { + // Invoke the AddJsonFormatters extension method + MvcCoreBuilderExtensions.AddJsonFormatters(builder, options => + { + options.Settings.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + options.Settings.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + }); + + // Invoke the AddJsonFormattersOptions extension method + MvcCoreBuilderExtensions.AddJsonFormattersOptions(builder, options => + { + options.Settings.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + }); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcBuilderExtensions.md new file mode 100644 index 00000000..a9962c40 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcBuilderExtensions.md @@ -0,0 +1,33 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to add XML serialization formatters to an MVC builder. + +```csharp +using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples +{ + public static class MvcBuilderExtensionsExample + { + public static void ConfigureServices(IServiceCollection services) + { + var builder = services.AddControllers(); + + builder.AddXmlFormatters(options => + { + options.Settings.Writer.Indent = true; + }); + + builder.AddXmlFormattersOptions(options => + { + options.Settings.Writer.Indent = false; + }); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcCoreBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcCoreBuilderExtensions.md new file mode 100644 index 00000000..ba1bd069 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcCoreBuilderExtensions.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcCoreBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to add XML serialization formatters to an MVC core builder using the extension methods. + +```csharp +using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples; + +public class MvcCoreBuilderExtensionsExample +{ + public void ConfigureMvc(IMvcCoreBuilder builder) + { + // Invoke the AddXmlFormatters extension method + MvcCoreBuilderExtensions.AddXmlFormatters(builder, options => + { + options.SynchronizeWithXmlConvert = true; + }); + + // Invoke the AddXmlFormattersOptions extension method + MvcCoreBuilderExtensions.AddXmlFormattersOptions(builder, options => + { + options.SynchronizeWithXmlConvert = true; + }); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationInputFormatter.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationInputFormatter.md new file mode 100644 index 00000000..69c59559 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationInputFormatter.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationInputFormatter +example: +- *content +--- + +The following example demonstrates how to construct an and inspect its supported media types and encodings. + +```csharp +using System; +using System.Linq; +using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml; +using Cuemon.Xml.Serialization.Formatters; + +namespace DocfxExamples; + +public class XmlSerializationInputFormatterExample +{ + public void Demonstrate() + { + var options = new XmlFormatterOptions(); + var formatter = new XmlSerializationInputFormatter(options); + + Console.WriteLine($"Supported media types: {string.Join(", ", formatter.SupportedMediaTypes)}"); + Console.WriteLine($"Supported encodings: {string.Join(", ", formatter.SupportedEncodings.Select(e => e.WebName))}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationMvcOptionsSetup.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationMvcOptionsSetup.md new file mode 100644 index 00000000..c8c3882b --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationMvcOptionsSetup.md @@ -0,0 +1,33 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationMvcOptionsSetup +example: +- *content +--- + +The following example demonstrates how adds XML serialization formatters to . + +```csharp +using System; +using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml; +using Cuemon.Xml.Serialization.Formatters; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples +{ + public static class XmlSerializationMvcOptionsSetupExample + { + public static void Demonstrate() + { + var formatterOptions = Options.Create(new XmlFormatterOptions()); + var setup = new XmlSerializationMvcOptionsSetup(formatterOptions); + var mvcOptions = new MvcOptions(); + + setup.Configure(mvcOptions); + + Console.WriteLine(mvcOptions.InputFormatters.Count); + Console.WriteLine(mvcOptions.OutputFormatters.Count); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationOutputFormatter.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationOutputFormatter.md new file mode 100644 index 00000000..0bea5752 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationOutputFormatter.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.XmlSerializationOutputFormatter +example: +- *content +--- + +The following example demonstrates how to construct an and inspect its supported media types and encodings. + +```csharp +using System; +using System.Linq; +using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml; +using Cuemon.Xml.Serialization.Formatters; + +namespace DocfxExamples; + +public class XmlSerializationOutputFormatterExample +{ + public void Demonstrate() + { + var options = new XmlFormatterOptions(); + var formatter = new XmlSerializationOutputFormatter(options); + + Console.WriteLine($"Supported media types: {string.Join(", ", formatter.SupportedMediaTypes)}"); + Console.WriteLine($"Supported encodings: {string.Join(", ", formatter.SupportedEncodings.Select(e => e.WebName))}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.PageBaseExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.PageBaseExtensions.md new file mode 100644 index 00000000..50191b02 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.RazorPages.PageBaseExtensions.md @@ -0,0 +1,25 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.RazorPages.PageBaseExtensions +example: +- *content +--- + +The following example demonstrates how to resolve application-base URLs and CDN URLs for static resources from a Razor Page model. + +```csharp +using Cuemon.Extensions.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace MyApp.Examples; + +public class PageBaseExtensionsExample +{ + public void Demonstrate(PageBase pageModel) + { + string appScript = pageModel.GetAppUrl("js/site.js"); + string cdnImage = pageModel.GetCdnUrl("images/logo.png"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Rendering.HtmlHelperExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Rendering.HtmlHelperExtensions.md new file mode 100644 index 00000000..cb2b535c --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Rendering.HtmlHelperExtensions.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.Rendering.HtmlHelperExtensions +example: +- *content +--- + +The following example demonstrates how to conditionally render content based on the current controller and action using `UseWhenView`, and based on the current Razor Page using `UseWhenPage`. + +```csharp +using Cuemon.Extensions.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.Rendering; + +namespace MyApp.Examples; + +public class HtmlHelperExtensionsExample +{ + public void Demonstrate(IHtmlHelper helper) + { + var showBanner = helper.UseWhenView("Index", "Home", () => "
Welcome to the Home Page
"); + + var pageTitle = helper.UseWhenPage("Contact", () => "Contact Us"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.ViewDataDictionaryExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.ViewDataDictionaryExtensions.md new file mode 100644 index 00000000..54669ea0 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.ViewDataDictionaryExtensions.md @@ -0,0 +1,63 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Mvc.ViewDataDictionaryExtensions +example: +- *content +--- + +The following example follows the same pattern as the sample MVC app in the test project: controller actions populate breadcrumbs from the current model, and a shared Razor partial reads them back from . + +```csharp +using System.Collections.Generic; +using System.Linq; +using Cuemon.Extensions.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Razor; +using Microsoft.AspNetCore.Mvc.ViewFeatures; + +namespace Cuemon.Extensions.AspNetCore.Mvc.DocExamples; + +public sealed class RegionController : Controller +{ + public IActionResult Index() + { + var model = new RegionPageModel("Regions", "Northern Europe", "Danish"); + ViewData.AddBreadcrumbs(this, model, page => page.Labels); + return View(model); + } + + public IActionResult Region(string regionName, string regionDisplayName) + { + var model = new RegionPageModel("Regions", regionDisplayName, "Danish"); + ViewData.AddBreadcrumbs(this, model, page => page.Labels); + return View("CultureCollection", model); + } + + public IActionResult Culture(string regionName, string regionDisplayName, string cultureName) + { + var model = new RegionPageModel("Regions", regionDisplayName, cultureName); + ViewData.AddBreadcrumbs(this, model, page => page.Labels); + return View("Culture", model); + } +} + +public sealed class BreadcrumbPartial +{ + public IReadOnlyList Render(ViewDataDictionary viewData, IRazorPage currentPage) + { + return viewData + .GetBreadcrumbs(currentPage) + .Select(link => $"{link.Label} ({link.ControllerName}/{link.ActionName})") + .ToList(); + } +} + +public sealed class RegionPageModel +{ + public RegionPageModel(params string[] labels) + { + Labels = labels; + } + + public IReadOnlyList Labels { get; } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.Converters.JsonConverterCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.Converters.JsonConverterCollectionExtensions.md new file mode 100644 index 00000000..de001e7d --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.Converters.JsonConverterCollectionExtensions.md @@ -0,0 +1,63 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Text.Json.Converters.JsonConverterCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to register ASP.NET Core-specific JSON converters using the class. + +```csharp +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; +using Cuemon.Extensions.AspNetCore.Text.Json.Converters; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Primitives; + +namespace MyApp.Examples; + +public class JsonConverterCollectionExtensionsExample +{ + public void Demonstrate() + { + var converters = new List(); + + // Add converter for IHeaderDictionary + converters.AddHeaderDictionaryConverter(); + + // Add converter for ProblemDetails + converters.AddProblemDetailsConverter(); + + // Add converter for HttpExceptionDescriptor + converters.AddHttpExceptionDescriptorConverter(); + + // Add converter for StringValues + converters.AddStringValuesConverter(); + + var options = new JsonSerializerOptions(); + foreach (var converter in converters) + { + options.Converters.Add(converter); + + // Example: serialize a HeaderDictionary + var headers = new HeaderDictionary + { + { "X-Custom", "value1" }, + { "X-Another", "value2" } + }; + + string json = JsonSerializer.Serialize(headers, options); + Console.WriteLine(json); + // Output: {"X-Custom":"value1","X-Another":"value2"} + + // Example: serialize StringValues + var values = new StringValues(new[] { "a", "b", "c" }); + string svJson = JsonSerializer.Serialize(values, options); + Console.WriteLine(svJson); + // Output: ["a","b","c"] + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.Formatters.ServiceCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.Formatters.ServiceCollectionExtensions.md new file mode 100644 index 00000000..f6c60d61 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.Formatters.ServiceCollectionExtensions.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Text.Json.Formatters.ServiceCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to register JSON formatter options and a JSON-based exception response formatter in the ASP.NET Core service collection. + +```csharp +using Cuemon.Extensions.AspNetCore.Text.Json.Formatters; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples; + +public class JsonFormattersServiceCollectionExtensionsExample +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddJsonFormatterOptions(options => + { + options.SensitivityDetails = Cuemon.Diagnostics.FaultSensitivityDetails.All; + }); + + services.AddJsonExceptionResponseFormatter(); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.MinimalJsonOptions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.MinimalJsonOptions.md new file mode 100644 index 00000000..99796d42 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.MinimalJsonOptions.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Text.Json.MinimalJsonOptions +example: +- *content +--- + +The following example demonstrates how to register in an ASP.NET Core application to propagate custom into the minimal API JSON serialization pipeline. + +```csharp +using System; +using System.Text.Json; +using Cuemon.Extensions.AspNetCore.Text.Json; +using Cuemon.Extensions.Text.Json.Formatters; +using Microsoft.AspNetCore.Http.Json; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace MyApp.Examples; + +public class MinimalJsonOptionsExample +{ + public void Demonstrate() + { + var services = new ServiceCollection(); + + // Configure JsonFormatterOptions with custom settings + services.Configure(o => + { + o.Settings.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + o.Settings.WriteIndented = false; + }); + + // Register MinimalJsonOptions so that JsonOptions (minimal API) + // receives the same settings and converters + services.AddTransient, MinimalJsonOptions>(); + + var provider = services.BuildServiceProvider(); + var jsonOptions = provider.GetRequiredService>(); + + Console.WriteLine($"Property naming policy: {jsonOptions.Value.SerializerOptions.PropertyNamingPolicy}"); // CamelCase + Console.WriteLine($"Write indented: {jsonOptions.Value.SerializerOptions.WriteIndented}"); // False + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.ServiceCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.ServiceCollectionExtensions.md new file mode 100644 index 00000000..a872fdb4 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Text.Json.ServiceCollectionExtensions.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Text.Json.ServiceCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to register minimal JSON formatter options using `AddMinimalJsonOptions` in the ASP.NET Core service collection. + +```csharp +using Cuemon.Extensions.AspNetCore.Text.Json; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples; + +public class TextJsonServiceCollectionExtensionsExample +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddMinimalJsonOptions(options => + { + options.SensitivityDetails = Cuemon.Diagnostics.FaultSensitivityDetails.All; + }); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Xml.Converters.XmlConverterExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Xml.Converters.XmlConverterExtensions.md new file mode 100644 index 00000000..1e632e27 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Xml.Converters.XmlConverterExtensions.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Xml.Converters.XmlConverterExtensions +example: +- *content +--- + +The following example demonstrates how to register ASP.NET Core-friendly XML converters on an instance. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.Diagnostics; +using Cuemon.Extensions.AspNetCore.Xml.Converters; +using Cuemon.Xml.Serialization.Converters; +using Cuemon.Xml.Serialization; + +namespace MyApp.Examples +{ +public static class XmlConverterExtensionsExample +{ + public static void Demonstrate() + { + var converters = new List(); + converters.AddProblemDetailsConverter(); + converters.AddHttpExceptionDescriptorConverter(options => + { + options.SensitivityDetails = FaultSensitivityDetails.All; + }); + converters.AddStringValuesConverter(); + converters.AddHeaderDictionaryConverter(); + converters.AddQueryCollectionConverter(); + converters.AddFormCollectionConverter(); + converters.AddCookieCollectionConverter(); + + var serializerOptions = new XmlSerializerOptions(); + foreach (var converter in converters) + { + serializerOptions.Converters.Add(converter); + } + + Console.WriteLine(serializerOptions.Converters.Count); + Console.WriteLine(serializerOptions.Converters[0].CanConvert(typeof(object))); + } +} +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Xml.Formatters.ServiceCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Xml.Formatters.ServiceCollectionExtensions.md new file mode 100644 index 00000000..e85218e3 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Xml.Formatters.ServiceCollectionExtensions.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Xml.Formatters.ServiceCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to register XML formatter options and an XML-based exception response formatter in the ASP.NET Core service collection. + +```csharp +using Cuemon.Extensions.AspNetCore.Xml.Formatters; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples; + +public class XmlFormattersServiceCollectionExtensionsExample +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddXmlFormatterOptions(options => + { + options.SynchronizeWithXmlConvert = true; + }); + + services.AddXmlExceptionResponseFormatter(); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Xml.ServiceCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Xml.ServiceCollectionExtensions.md new file mode 100644 index 00000000..b7da6cff --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Xml.ServiceCollectionExtensions.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.Extensions.AspNetCore.Xml.ServiceCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to register minimal XML formatter options using `AddMinimalXmlOptions` in the ASP.NET Core service collection. + +```csharp +using Cuemon.Extensions.AspNetCore.Xml; +using Microsoft.Extensions.DependencyInjection; + +namespace MyApp.Examples; + +public class XmlServiceCollectionExtensionsExample +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddMinimalXmlOptions(options => + { + options.SynchronizeWithXmlConvert = true; + }); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.ByteExtensions.md b/.docfx/api/types/Cuemon.Extensions.ByteExtensions.md new file mode 100644 index 00000000..9e0028f7 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.ByteExtensions.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.Extensions.ByteExtensions +example: +- *content +--- + +The following example demonstrates how to use the extension methods to convert byte arrays to various string representations and detect Unicode encoding. + +```csharp +using System; +using System.Text; +using Cuemon.Extensions; + +namespace MyApp.Examples; + +public static class ByteExtensionsExample +{ + public static void Demonstrate() + { + byte[] data = { 0xEF, 0xBB, 0xBF, 0x48, 0x65, 0x6C, 0x6C, 0x6F }; + string text = data.ToEncodedString(); + string hex = data.ToHexadecimalString(); + string binary = data.ToBinaryString(); + string base64 = data.ToBase64String(); + string urlBase64 = data.ToUrlEncodedBase64String(); + + data.TryDetectUnicodeEncoding(out Encoding detectedEncoding); + + Console.WriteLine(text); + Console.WriteLine(hex); + Console.WriteLine(binary); + Console.WriteLine(base64); + Console.WriteLine(urlBase64); + Console.WriteLine(detectedEncoding?.WebName ?? "unknown"); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.CharExtensions.md b/.docfx/api/types/Cuemon.Extensions.CharExtensions.md new file mode 100644 index 00000000..ce170277 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.CharExtensions.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.Extensions.CharExtensions +example: +- *content +--- + +The following example demonstrates converting sequences of values to strings and string sequences using the and extension methods. + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon.Extensions; + +namespace MyApp.Examples; + +public static class CharExtensionsExample +{ + public static void Demonstrate() + { + char[] chars = "Hello World".ToCharArray(); + string text = chars.FromChars(); + IEnumerable strings = chars.ToEnumerable(); + string alphabet = Enumerable.Range('A', 26).Select(c => (char)c).FromChars(); + + Console.WriteLine(text); + Console.WriteLine(strings.Count()); + Console.WriteLine(alphabet); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.CollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.CollectionExtensions.md new file mode 100644 index 00000000..bec19afd --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.CollectionExtensions.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Extensions.Collections.Generic.CollectionExtensions +example: +- *content +--- + +The following example demonstrates how to add a range of values to a collection and iterate it through a partitioner. + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon.Extensions.Collections.Generic; + +namespace MyApp.Examples; + +public static class CollectionExtensionsExample +{ + public static void Demonstrate() + { + ICollection values = new List(); + values.AddRange(1, 2, 3, 4); + + var partitioner = values.ToPartitioner(2); + + Console.WriteLine(values.Count); + Console.WriteLine(partitioner.Count()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.DictionaryExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.DictionaryExtensions.md new file mode 100644 index 00000000..54fba270 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.DictionaryExtensions.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.Extensions.Collections.Generic.DictionaryExtensions +example: +- *content +--- + +The following example demonstrates how to populate, update, and query a dictionary through the available extension methods. + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon.Extensions.Collections.Generic; + +namespace MyApp.Examples +{ + public static class DictionaryExtensionsExample + { + public static void Demonstrate() + { + IDictionary source = new Dictionary + { + ["alpha"] = 1, + ["beta"] = 2 + }; + + var destination = new Dictionary(); + source.CopyTo(destination); + + source.TryAdd("gamma", 3, dictionary => !dictionary.ContainsKey("gamma")); + source.AddOrUpdate("beta", 20); + + var configuredFallback = source.GetValueOrDefault("delta", () => 42); + var foundFallback = source.TryGetValueOrFallback("missing", keys => keys.OrderBy(key => key).First(), out var fallbackValue); + var rows = source.ToEnumerable().Select(pair => $"{pair.Key}:{pair.Value}"); + + Console.WriteLine(destination.Count); + Console.WriteLine(configuredFallback); + Console.WriteLine(foundFallback); + Console.WriteLine(fallbackValue); + Console.WriteLine(string.Join(", ", rows)); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.EnumerableExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.EnumerableExtensions.md new file mode 100644 index 00000000..e98c4224 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.EnumerableExtensions.md @@ -0,0 +1,54 @@ +--- +uid: Cuemon.Extensions.Collections.Generic.EnumerableExtensions +example: +- *content +--- + +The following example demonstrates how to partition, reorder, paginate, and materialize a sequence by using the available enumerable extensions. + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon.Extensions.Collections.Generic; +using CuemonEnumerableExtensions = Cuemon.Extensions.Collections.Generic.EnumerableExtensions; + +namespace MyApp.Examples +{ + public static class EnumerableExtensionsExample + { + public static void Demonstrate() + { + var values = new[] { 4, 1, 3, 2 }; + var chunked = CuemonEnumerableExtensions.Chunk(values, 2).ToList(); + var shuffled = CuemonEnumerableExtensions.Shuffle(values).ToArray(); + var deterministicShuffle = CuemonEnumerableExtensions.Shuffle(values, (min, max) => min).ToArray(); + var ascending = values.OrderAscending().ToArray(); + var ascendingWithComparer = values.OrderAscending(Comparer.Default).ToArray(); + var descending = CuemonEnumerableExtensions.OrderDescending(values).ToArray(); + var random = values.RandomOrDefault(); + var yielded = 5.Yield().Single(); + var dictionary = CuemonEnumerableExtensions.ToDictionary(new[] + { + new KeyValuePair("alpha", 1), + new KeyValuePair("beta", 2) + }); + var partitioner = values.ToPartitioner(2).ToList(); + var pagination = values.ToPagination(() => values.Length).ToList(); + var paginationList = values.ToPaginationList(() => values.Length); + + Console.WriteLine(chunked.Count); + Console.WriteLine(shuffled.Length + deterministicShuffle.Length); + Console.WriteLine(string.Join(", ", ascending)); + Console.WriteLine(string.Join(", ", ascendingWithComparer)); + Console.WriteLine(string.Join(", ", descending)); + Console.WriteLine(random); + Console.WriteLine(yielded); + Console.WriteLine(dictionary["beta"]); + Console.WriteLine(partitioner.Count); + Console.WriteLine(pagination.Count); + Console.WriteLine(paginationList.Count); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.ListExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.ListExtensions.md new file mode 100644 index 00000000..643f2b5e --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.ListExtensions.md @@ -0,0 +1,55 @@ +--- +uid: Cuemon.Extensions.Collections.Generic.ListExtensions +example: +- *content +--- + +The following example demonstrates how to use the extension methods to safely navigate and manipulate lists. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.Extensions.Collections.Generic; + +namespace DocExamples +{ + public static class ListExtensionsExample + { + public static void Main() + { + var fruits = new List { "Apple", "Banana", "Cherry", "Date" }; + + // Remove the first element matching a condition + bool removed = fruits.Remove(f => f == "Banana"); + Console.WriteLine($"Removed 'Banana': {removed}"); + Console.WriteLine($"Fruits after removal: {string.Join(", ", fruits)}"); + + // Check if an index exists in the list + bool hasIndex = fruits.HasIndex(5); + Console.WriteLine($"Has index 5: {hasIndex}"); + Console.WriteLine($"Has index 1: {fruits.HasIndex(1)}"); + + // Get the next element relative to an index + string next = fruits.Next(0); + Console.WriteLine($"Element after index 0: {next}"); + + // Get the previous element relative to an index + string prev = fruits.Previous(2); + Console.WriteLine($"Element before index 2: {prev}"); + + // Returns default when out of bounds + string beyond = fruits.Next(10); + Console.WriteLine($"Element after index 10: {(beyond == null ? "null (default)" : beyond)}"); + + // Try to add an element (only if not already present) + bool added = fruits.TryAdd("Cherry"); + Console.WriteLine($"Added 'Cherry' (duplicate): {added}"); + + bool addedNew = fruits.TryAdd("Elderberry"); + Console.WriteLine($"Added 'Elderberry' (new): {addedNew}"); + Console.WriteLine($"Fruits: {string.Join(", ", fruits)}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.QueueExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.QueueExtensions.md new file mode 100644 index 00000000..aa011221 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.QueueExtensions.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.Extensions.Collections.Generic.QueueExtensions +example: +- *content +--- + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.Extensions.Collections.Generic; + +namespace Cuemon.Extensions.Collections.Generic; + +public class QueueExtensionsExample +{ + public void Demonstrate() + { + var queue = new Queue(); + queue.Enqueue("first"); + queue.Enqueue("second"); + + if (queue.TryPeek(out string result)) + { + Console.WriteLine($"Peeked: {result}"); + } + + queue.TryPeek(out string same); + Console.WriteLine(same); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.StackExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.StackExtensions.md new file mode 100644 index 00000000..ed80d412 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.StackExtensions.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.Extensions.Collections.Generic.StackExtensions +example: +- *content +--- + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.Extensions.Collections.Generic; + +namespace Cuemon.Extensions.Collections.Generic; + +public class StackExtensionsExample +{ + public void Demonstrate() + { + var stack = new Stack(); + stack.Push("bottom"); + stack.Push("top"); + + if (stack.TryPop(out string item)) + { + Console.WriteLine($"Popped: {item}"); + } + + stack.TryPop(out string next); + Console.WriteLine(next); + + stack.TryPop(out string empty); + Console.WriteLine(empty == null); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.DictionaryExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.DictionaryExtensions.md new file mode 100644 index 00000000..9ef03792 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.DictionaryExtensions.md @@ -0,0 +1,47 @@ +--- +uid: Cuemon.Extensions.Collections.Specialized.DictionaryExtensions +example: +- *content +--- + +The following example demonstrates how to convert a Dictionary with string array values into a NameValueCollection using DictionaryExtensions, with support for custom delimiters. + +```csharp +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using Cuemon; +using Cuemon.Extensions.Collections.Specialized; + +namespace MyApp.Extensions.Collections.Specialized +{ + public class DictionaryExtensionsExample + { + public void Demonstrate() + { + // Create a dictionary with string array values + var source = new Dictionary + { + ["colors"] = new[] { "red", "green", "blue" }, + ["sizes"] = new[] { "small", "large" } + }; + + // Convert to a NameValueCollection (default delimiter is comma) + NameValueCollection nvc = source.ToNameValueCollection(); + + Console.WriteLine(nvc["colors"]); // "red,green,blue" + Console.WriteLine(nvc["sizes"]); // "small,large" + + // Convert with a custom delimiter + NameValueCollection nvcSemicolon = source.ToNameValueCollection(o => + { + o.Delimiter = ";"; + }); + + Console.WriteLine(nvcSemicolon["colors"]); // "red;green;blue" + Console.WriteLine(nvcSemicolon["sizes"]); // "small;large" + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.NameValueCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.NameValueCollectionExtensions.md new file mode 100644 index 00000000..19b9569e --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.NameValueCollectionExtensions.md @@ -0,0 +1,60 @@ +--- +uid: Cuemon.Extensions.Collections.Specialized.NameValueCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to use NameValueCollectionExtensions to check for key existence and convert a NameValueCollection into a dictionary with string array values. + +```csharp +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using Cuemon; +using Cuemon.Extensions.Collections.Specialized; + +namespace MyApp.Extensions.Collections.Specialized +{ + public class NameValueCollectionExtensionsExample + { + public void Demonstrate() + { + // Create a NameValueCollection with some query parameters + var nvc = new NameValueCollection + { + { "name", "John Doe" }, + { "tag", "dotnet" }, + { "tag", "csharp" } + }; + + // Check if a key exists (case-insensitive) + bool hasName = nvc.ContainsKey("NAME"); + Console.WriteLine(hasName); // True + + bool hasMissing = nvc.ContainsKey("missing"); + Console.WriteLine(hasMissing); // False + + // Convert to a dictionary with string[] values + IDictionary dict = nvc.ToDictionary(); + + Console.WriteLine(dict["name"][0]); // "John Doe" + Console.WriteLine(dict["tag"][0]); // "dotnet" + Console.WriteLine(dict["tag"][1]); // "csharp" + + // Use a custom delimiter for splitting values + var nvcSemicolon = new NameValueCollection + { + { "items", "a;b;c" } + }; + + IDictionary dictSemicolon = nvcSemicolon.ToDictionary(o => + { + o.Delimiter = ";"; + }); + + Console.WriteLine(dictSemicolon["items"].Length); // 3 + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Data.DataReaderExtensions.md b/.docfx/api/types/Cuemon.Extensions.Data.DataReaderExtensions.md new file mode 100644 index 00000000..91a69a65 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Data.DataReaderExtensions.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Extensions.Data.DataReaderExtensions +example: +- *content +--- + +The following example demonstrates how to turn a delimiter-separated reader into row and column transfer objects. + +```csharp +using System; +using System.IO; +using System.Linq; +using System.Text; +using Cuemon.Data; +using Cuemon.Extensions.Data; + +namespace MyApp.Examples; + +public static class DataReaderExtensionsExample +{ + public static void Demonstrate() + { + var csv = "Id,Name\n1,Alice\n2,Bob"; + using var reader = new DsvDataReader(new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(csv)))); + + var rows = reader.ToRows(); + Console.WriteLine(rows.Count); + Console.WriteLine(rows.ColumnNames.Contains("Name")); + + using var columnReader = new DsvDataReader(new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(csv)))); + columnReader.Read(); + var columns = columnReader.ToColumns(); + + Console.WriteLine(columns.Count); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Data.DbTypeExtensions.md b/.docfx/api/types/Cuemon.Extensions.Data.DbTypeExtensions.md new file mode 100644 index 00000000..3357c86b --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Data.DbTypeExtensions.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Extensions.Data.DbTypeExtensions +example: +- *content +--- + +The following example demonstrates converting values to their equivalent using the extension method. + +```csharp +using System; +using System.Data; +using Cuemon.Extensions.Data; + +namespace MyApp.Examples; + +public class DbTypeExtensionsExample +{ + public static void Main() + { + // Access the extension method via the declaring type explicitly + var stringType = DbTypeExtensions.ToType(DbType.String); + var int32Type = DbTypeExtensions.ToType(DbType.Int32); + var dateTimeType = DbTypeExtensions.ToType(DbType.DateTime); + + Console.WriteLine($"DbType.String -> {stringType}"); // System.String + Console.WriteLine($"DbType.Int32 -> {int32Type}"); // System.Int32 + Console.WriteLine($"DbType.DateTime -> {dateTimeType}"); // System.DateTime + + // Equivalent form using extension method syntax on DbType value + var extended = DbType.Decimal.ToType(); + Console.WriteLine($"DbType.Decimal -> {extended}"); // System.Decimal + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Data.Integrity.AssemblyExtensions.md b/.docfx/api/types/Cuemon.Extensions.Data.Integrity.AssemblyExtensions.md new file mode 100644 index 00000000..281329e4 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Data.Integrity.AssemblyExtensions.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.Extensions.Data.Integrity.AssemblyExtensions +example: +- *content +--- + +The following example demonstrates generating a from an assembly using the extension method. + +```csharp +using System; +using System.Reflection; +using Cuemon.Data.Integrity; +using Cuemon.Extensions.Data.Integrity; + +namespace MyApp.Examples; + +public class AssemblyExtensionsExample +{ + public static void Main() + { + // Get a reference to any loaded assembly + Assembly assembly = typeof(AssemblyExtensionsExample).Assembly; + + // Generate a CacheValidator from the assembly's file metadata + CacheValidator validator = assembly.GetCacheValidator(); + + Console.WriteLine($"Assembly: {assembly.GetName().Name}"); + Console.WriteLine($"Created (UTC): {validator.Created:O}"); + Console.WriteLine($"Modified (UTC): {validator.Modified?.ToString("O") ?? "N/A"}"); + Console.WriteLine($"Checksum (hex): {validator.Checksum.ToHexadecimalString()}"); + Console.WriteLine($"Validation strength: {validator.Validation}"); + + // Use the CacheValidator for HTTP cache validation scenarios + Console.WriteLine($"\nETag candidate: \"{validator.Checksum.ToHexadecimalString()}\""); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Data.Integrity.ChecksumBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.Data.Integrity.ChecksumBuilderExtensions.md new file mode 100644 index 00000000..4427f35b --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Data.Integrity.ChecksumBuilderExtensions.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.Extensions.Data.Integrity.ChecksumBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to use `ChecksumBuilderExtensions` to fluently combine typed values directly on a `ChecksumBuilder` instance. + +```csharp +using System; +using Cuemon.Data.Integrity; +using Cuemon.Extensions.Data.Integrity; +using Cuemon.Security; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + // Create a ChecksumBuilder and use extension methods directly + var builder = new ChecksumBuilder(() => HashFactory.CreateFnv128()); + + // Extension methods allow combining typed values without a Decorator wrapper + builder.CombineWith(42); // int overload + builder.CombineWith(3.14); // double overload + builder.CombineWith("data"); // string overload + + Console.WriteLine($"Combined checksum: {builder}"); + + // Works with all numeric types + var checksum = new ChecksumBuilder(() => HashFactory.CreateFnv32()) + .CombineWith((short)1) + .CombineWith(2u) + .CombineWith(3L) + .CombineWith(4.0f) + .CombineWith(5ul); + + Console.WriteLine($"All types: {checksum}"); + + // Combine with byte arrays + var withBytes = new ChecksumBuilder(() => HashFactory.CreateFnv32()) + .CombineWith(new byte[] { 0x01, 0x02, 0x03 }); + + Console.WriteLine($"With bytes: {withBytes}"); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Data.Integrity.DateTimeExtensions.md b/.docfx/api/types/Cuemon.Extensions.Data.Integrity.DateTimeExtensions.md new file mode 100644 index 00000000..fadee0b4 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Data.Integrity.DateTimeExtensions.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.Extensions.Data.Integrity.DateTimeExtensions +example: +- *content +--- + +The following example demonstrates generating a from timestamp values using the and extension methods. + +```csharp +using System; +using Cuemon.Data.Integrity; +using Cuemon.Extensions.Data.Integrity; +using Cuemon.Security; + +namespace MyApp.Examples; + +public class DateTimeExtensionsExample +{ + public static void Main() + { + // Define timestamps for when data was created and last modified + DateTime created = new DateTime(2025, 1, 15, 10, 0, 0, DateTimeKind.Utc); + DateTime modified = new DateTime(2025, 6, 10, 14, 30, 0, DateTimeKind.Utc); + + // Basic timestamp-only validator (weak integrity based on timestamps) + CacheValidator timestampValidator = created.GetCacheValidator(modified); + Console.WriteLine($"Created (UTC): {timestampValidator.Created:O}"); + Console.WriteLine($"Modified (UTC): {timestampValidator.Modified:O}"); + Console.WriteLine($"Checksum (hex): {timestampValidator.Checksum.ToHexadecimalString()}"); + + // Create a validator using the Timestamp method + // (checksum is derived purely from timestamps) + CacheValidator timeBasedValidator = created.GetCacheValidator(modified, + hashFactory: () => HashFactory.CreateFnv128(), + method: EntityDataIntegrityMethod.Timestamp); + Console.WriteLine($"Time-based method checksum: {timeBasedValidator.Checksum.ToHexadecimalString()}"); + + // Create a validator with both timestamps and a content checksum + byte[] contentChecksum = HashFactory.CreateFnv128().ComputeHash("content-data").GetBytes(); + CacheValidator strongValidator = created.GetCacheValidator(modified, contentChecksum, + validation: EntityDataIntegrityValidation.Strong); + Console.WriteLine($"Strong validator checksum: {strongValidator.Checksum.ToHexadecimalString()}"); + Console.WriteLine($"Validation level: {strongValidator.Validation}"); + + // Create a validator with only the created timestamp (no modified date) + CacheValidator createdOnly = created.GetCacheValidator(); + Console.WriteLine($"Created-only checksum: {createdOnly.Checksum.ToHexadecimalString()}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Data.Integrity.FileInfoExtensions.md b/.docfx/api/types/Cuemon.Extensions.Data.Integrity.FileInfoExtensions.md new file mode 100644 index 00000000..3edd8985 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Data.Integrity.FileInfoExtensions.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.Extensions.Data.Integrity.FileInfoExtensions +example: +- *content +--- + +The following example demonstrates generating a from a file using the extension method. + +```csharp +using System; +using System.IO; +using System.Text; +using Cuemon.Data.Integrity; +using Cuemon.Extensions.Data.Integrity; + +namespace MyApp.Examples; + +public class FileInfoExtensionsExample +{ + public static void Main() + { + // Create a temporary file to work with + string tempFile = Path.GetTempFileName(); + File.WriteAllText(tempFile, "Hello, World!", Encoding.UTF8); + + try + { + var fileInfo = new FileInfo(tempFile); + + // Generate a CacheValidator with default FNV-1a/128 hashing + CacheValidator validator = fileInfo.GetCacheValidator(); + + Console.WriteLine($"File: {fileInfo.Name}"); + Console.WriteLine($"Created (UTC): {validator.Created}"); + Console.WriteLine($"Modified (UTC): {validator.Modified}"); + Console.WriteLine($"Checksum (hex): {validator.Checksum.ToHexadecimalString()}"); + Console.WriteLine($"Validation: {validator.Validation}"); + + // Combine with an additional semantic checksum + validator.CombineWith(Encoding.UTF8.GetBytes("additional-context")); + Console.WriteLine($"Combined checksum: {validator.Checksum.ToHexadecimalString()}"); + } + finally + { + File.Delete(tempFile); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Data.QueryFormatExtensions.md b/.docfx/api/types/Cuemon.Extensions.Data.QueryFormatExtensions.md new file mode 100644 index 00000000..8b5d3164 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Data.QueryFormatExtensions.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.Extensions.Data.QueryFormatExtensions +example: +- *content +--- + +The following example demonstrates generating query fragments for SQL IN clauses using the extension method. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.Data; +using Cuemon.Extensions.Data; + +namespace MyApp.Examples; + +public class QueryFormatExtensionsExample +{ + public static void Main() + { + // Embed string values in a delimited format: value, value, value + var productIds = new[] { "ALFKI", "BONAP", "FRANS" }; + string delimited = QueryFormat.Delimited.Embed(productIds); + Console.WriteLine(delimited); // Output: "ALFKI", "BONAP", "FRANS" + + // Embed string values with single quotes: 'value', 'value', 'value' + string delimitedString = QueryFormat.DelimitedString.Embed(productIds); + Console.WriteLine(delimitedString); // Output: 'ALFKI', 'BONAP', 'FRANS' + + // Embed integer values + var ids = new[] { 1, 2, 3, 4, 5 }; + string intEmbedded = QueryFormat.Delimited.Embed(ids); + Console.WriteLine(intEmbedded); // Output: 1, 2, 3, 4, 5 + + // Embed with distinct filtering to remove duplicates + var withDuplicates = new[] { "apple", "banana", "apple", "cherry" }; + string distinctFragment = QueryFormat.DelimitedString.Embed(withDuplicates, distinct: true); + Console.WriteLine(distinctFragment); // Output: 'apple', 'banana', 'cherry' + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.DateTimeExtensions.md b/.docfx/api/types/Cuemon.Extensions.DateTimeExtensions.md new file mode 100644 index 00000000..fc4f62ca --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.DateTimeExtensions.md @@ -0,0 +1,53 @@ +--- +uid: Cuemon.Extensions.DateTimeExtensions +example: +- *content +--- + +The following example demonstrates common `DateTime` extension methods for rounding, range checking, time-of-day classification, and timezone kind conversion. + +```csharp +using System; +using Cuemon; +using Cuemon.Extensions; + +namespace MyApp.Examples; + +public static class DateTimeExtensionsExample +{ + public static void Demonstrate() + { + var utc = new DateTime(2025, 6, 16, 14, 33, 22, DateTimeKind.Utc); + var local = new DateTime(2025, 6, 16, 14, 33, 22, DateTimeKind.Local); + + var floorHour = utc.Floor(TimeSpan.FromHours(1)); + var ceilingHour = utc.Ceiling(TimeSpan.FromHours(1)); + var floorFifteenMinutes = utc.Floor(15, TimeUnit.Minutes); + var roundedUp = utc.Round(TimeSpan.FromMinutes(30), VerticalDirection.Up); + var isWithinRange = utc.IsWithinRange(new DateTimeRange(utc.AddHours(-1), utc.AddHours(1))); + + var isNight = new DateTime(2025, 6, 16, 22, 15, 0, DateTimeKind.Utc).IsTimeOfDayNight(); + var isMorning = new DateTime(2025, 6, 16, 6, 15, 0, DateTimeKind.Utc).IsTimeOfDayMorning(); + var isForenoon = new DateTime(2025, 6, 16, 10, 15, 0, DateTimeKind.Utc).IsTimeOfDayForenoon(); + var isAfternoon = utc.IsTimeOfDayAfternoon(); + var isEvening = new DateTime(2025, 6, 16, 19, 15, 0, DateTimeKind.Utc).IsTimeOfDayEvening(); + + var utcKind = local.ToUtcKind(); + var localKind = utc.ToLocalKind(); + var unspecifiedKind = utc.ToDefaultKind(); + + var unixTime = utc.ToUnixEpochTime(); + var restored = unixTime.FromUnixEpochTime(); + + Console.WriteLine(floorHour.ToString("O")); + Console.WriteLine(ceilingHour.ToString("O")); + Console.WriteLine(floorFifteenMinutes.ToString("O")); + Console.WriteLine(roundedUp.ToString("O")); + Console.WriteLine(isWithinRange); + Console.WriteLine($"{isNight}, {isMorning}, {isForenoon}, {isAfternoon}, {isEvening}"); + Console.WriteLine($"{utcKind.Kind}, {localKind.Kind}, {unspecifiedKind.Kind}"); + Console.WriteLine(restored.ToString("O")); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceCollectionExtensions.md new file mode 100644 index 00000000..e81097d9 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceCollectionExtensions.md @@ -0,0 +1,96 @@ +--- +uid: Cuemon.Extensions.DependencyInjection.ServiceCollectionExtensions +example: +- *content +--- + +The following example registers a concrete handler once and lets `Add` forward both its typed service contract and its dependency-injection marker so the same scoped instance can be resolved through each public entry point. + +```csharp +using System; +using Cuemon.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace Cuemon.Docs.Samples.DependencyInjection +{ + public static class ServiceCollectionExtensionsExample + { + public static void Demonstrate() + { + var services = new ServiceCollection(); + + services.Add(options => + { + options.Lifetime = ServiceLifetime.Scoped; + }); + services.TryAdd(options => + { + options.Lifetime = ServiceLifetime.Scoped; + }); + services.TryAdd, OrdersMessageHandler>(options => + { + options.Lifetime = ServiceLifetime.Singleton; + }); + services.TryAdd(typeof(IMessageHandler), typeof(OrdersMessageHandler), options => + { + options.Lifetime = ServiceLifetime.Singleton; + }); + services.TryAdd(typeof(IMessageHandler), typeof(OrdersMessageHandler), ServiceLifetime.Scoped, options => + { + options.Label = "typed"; + }); + services.TryAdd, OrdersMessageHandler, HandlerOptions>(ServiceLifetime.Scoped, options => + { + options.Enabled = true; + }); + services.TryConfigure(options => + { + options.Label = "configured"; + }); + services.PostConfigureAllOf(options => + { + options.Label = "post-configured"; + }); + + using var provider = services.BuildServiceProvider(); + using var scope = provider.CreateScope(); + + var concrete = scope.ServiceProvider.GetRequiredService(); + var typedContract = scope.ServiceProvider.GetRequiredService>(); + var marker = scope.ServiceProvider.GetRequiredService>(); + var handlerOptions = scope.ServiceProvider.GetRequiredService>().Value; + + Console.WriteLine(object.ReferenceEquals(concrete, typedContract)); + Console.WriteLine(object.ReferenceEquals(concrete, marker)); + Console.WriteLine(typedContract.Name); + Console.WriteLine(handlerOptions.Label); + } + + public sealed class OrdersChannel + { + } + + public interface IMessageHandler + { + string Name { get; } + } + + public interface IMessageHandler : IMessageHandler, IDependencyInjectionMarker + { + } + + public sealed class HandlerOptions + { + public bool Enabled { get; set; } + + public string Label { get; set; } = string.Empty; + } + + public sealed class OrdersMessageHandler : IMessageHandler + { + public string Name => nameof(OrdersMessageHandler); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceOptions.md b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceOptions.md new file mode 100644 index 00000000..14160c0e --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceOptions.md @@ -0,0 +1,53 @@ +--- +uid: Cuemon.Extensions.DependencyInjection.ServiceOptions +example: +- *content +--- + +The following example uses `ServiceOptions` to choose the lifetime that is applied when the Cuemon registration helpers add a service to `IServiceCollection`. + +```csharp +using System; +using Cuemon.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; + +namespace Cuemon.Docs.Samples.DependencyInjection +{ + public static class ServiceOptionsExample + { + public static void Demonstrate() + { + var defaults = new ServiceOptions(); + Console.WriteLine(defaults.Lifetime); + + var registration = new ServiceOptions + { + Lifetime = ServiceLifetime.Singleton + }; + + var services = new ServiceCollection(); + services.Add(registration.Lifetime); + + using var provider = services.BuildServiceProvider(); + + var first = provider.GetRequiredService(); + var second = provider.GetRequiredService(); + + Console.WriteLine(object.ReferenceEquals(first, second)); + } + + public interface IMessageWriter + { + void Write(string message); + } + + public sealed class ConsoleMessageWriter : IMessageWriter + { + public void Write(string message) + { + Console.WriteLine(message); + } + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceProviderExtensions.md b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceProviderExtensions.md new file mode 100644 index 00000000..c9db7fc6 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceProviderExtensions.md @@ -0,0 +1,66 @@ +--- +uid: Cuemon.Extensions.DependencyInjection.ServiceProviderExtensions +example: +- *content +--- + +The following example wraps the built service provider and then uses `GetServiceDescriptors()` to inspect the registrations that were added to the container. + +```csharp +using System; +using System.Linq; +using Cuemon.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; + +namespace Cuemon.Docs.Samples.DependencyInjection +{ + public static class ServiceProviderExtensionsExample + { + public static void Demonstrate() + { + var services = new ServiceCollection(); + services.AddSingleton(); + services.AddScoped(); + + using var provider = services.BuildServiceProvider(); + var wrappedProvider = new DelegatingServiceProvider(provider); + + var descriptors = wrappedProvider.GetServiceDescriptors().ToList(); + + Console.WriteLine(descriptors.Any(descriptor => descriptor.ServiceType == typeof(IClock))); + Console.WriteLine(descriptors.Any(descriptor => descriptor.ServiceType == typeof(IJobRepository))); + } + + public interface IClock + { + } + + public sealed class SystemClock : IClock + { + } + + public interface IJobRepository + { + } + + public sealed class InMemoryJobRepository : IJobRepository + { + } + + private sealed class DelegatingServiceProvider : IServiceProvider + { + private readonly IServiceProvider _provider; + + public DelegatingServiceProvider(IServiceProvider provider) + { + _provider = provider; + } + + public object GetService(Type serviceType) + { + return _provider.GetService(serviceType); + } + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.DependencyInjection.TypeExtensions.md b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.TypeExtensions.md new file mode 100644 index 00000000..c51028de --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.TypeExtensions.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.Extensions.DependencyInjection.TypeExtensions +example: +- *content +--- + +The following example asks `TryGetDependencyInjectionMarker` whether a generic service type carries an `IDependencyInjectionMarker` contract and then reads the discovered marker type. + +```csharp +using System; +using Cuemon.Extensions.DependencyInjection; + +namespace Cuemon.Docs.Samples.DependencyInjection +{ + public static class TypeExtensionsExample + { + public static void Demonstrate() + { + var marked = typeof(DefaultService).TryGetDependencyInjectionMarker(out var markerType); + var plain = typeof(string).TryGetDependencyInjectionMarker(out _); + + Console.WriteLine(marked); + Console.WriteLine(markerType == typeof(OrdersChannel)); + Console.WriteLine(plain); + } + + public sealed class OrdersChannel + { + } + + public interface IMessageService + { + } + + public interface IMessageService : IMessageService, IDependencyInjectionMarker + { + } + + public sealed class DefaultService : IMessageService + { + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.DependencyInjection.TypeForwardServiceOptions.md b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.TypeForwardServiceOptions.md new file mode 100644 index 00000000..f9cc5eff --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.TypeForwardServiceOptions.md @@ -0,0 +1,73 @@ +--- +uid: Cuemon.Extensions.DependencyInjection.TypeForwardServiceOptions +example: +- *content +--- + +The following example customizes `TypeForwardServiceOptions` so only one nested contract is forwarded when a concrete implementation is added to the dependency-injection container. + +```csharp +using System; +using Cuemon.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; + +namespace Cuemon.Docs.Samples.DependencyInjection +{ + public static class TypeForwardServiceOptionsExample + { + public static void Demonstrate() + { + var forwarding = new TypeForwardServiceOptions + { + Lifetime = ServiceLifetime.Singleton, + NestedTypeSelector = type => type.GetInterfaces(), + NestedTypePredicate = type => type == typeof(IMessageHandler) + }; + + Console.WriteLine(forwarding.UseNestedTypeForwarding); + forwarding.ValidateOptions(); + + var services = new ServiceCollection(); + services.Add(options => + { + options.Lifetime = forwarding.Lifetime; + options.UseNestedTypeForwarding = forwarding.UseNestedTypeForwarding; + options.NestedTypeSelector = forwarding.NestedTypeSelector; + options.NestedTypePredicate = forwarding.NestedTypePredicate; + }); + + using var provider = services.BuildServiceProvider(); + + var dispatcher = provider.GetRequiredService(); + var handler = provider.GetRequiredService(); + var diagnostics = provider.GetService(); + + Console.WriteLine(object.ReferenceEquals(dispatcher, handler)); + Console.WriteLine(diagnostics is null); + } + + public interface IMessageHandler + { + void Handle(string message); + } + + public interface IDiagnosticSink + { + void Write(string message); + } + + public sealed class MessageDispatcher : IMessageHandler, IDiagnosticSink + { + public void Handle(string message) + { + Console.WriteLine(message); + } + + public void Write(string message) + { + Console.WriteLine(message); + } + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Diagnostics.FileVersionInfoExtensions.md b/.docfx/api/types/Cuemon.Extensions.Diagnostics.FileVersionInfoExtensions.md new file mode 100644 index 00000000..089cb0be --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Diagnostics.FileVersionInfoExtensions.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.Extensions.Diagnostics.FileVersionInfoExtensions +example: +- *content +--- + +The following example demonstrates how to use FileVersionInfoExtensions to extract structured product and file version information from an assembly's FileVersionInfo. + +```csharp +using System; +using System.Diagnostics; +using System.Reflection; +using Cuemon.Extensions.Diagnostics; +using Cuemon.Reflection; + +namespace MyApp.Diagnostics +{ + public static class FileVersionInfoExtensionsExamples + { + public static void Demonstrate() + { + // Get the FileVersionInfo for the current assembly. + Assembly assembly = typeof(FileVersionInfoExtensionsExamples).Assembly; + FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(assembly.Location); + + Console.WriteLine("Assembly: {0}", assembly.FullName); + Console.WriteLine("Original ProductVersion: {0}", fvi.ProductVersion); + Console.WriteLine("Original FileVersion: {0}", fvi.FileVersion); + + // Convert to a structured VersionResult using the extension methods. + + // ToProductVersion returns the NuGet/semantic version string (e.g., "1.2.3-beta"). + VersionResult productVersion = fvi.ToProductVersion(); + Console.WriteLine("Product VersionResult: {0}", productVersion.Value); + Console.WriteLine("Is semantic version? {0}", productVersion.IsSemanticVersion()); + Console.WriteLine("Has alphanumeric part? {0}", productVersion.HasAlphanumericVersion); + + // ToFileVersion returns the file version string (e.g., "1.2.3.0"). + VersionResult fileVersion = fvi.ToFileVersion(); + Console.WriteLine("File VersionResult: {0}", fileVersion.Value); + + // Both VersionResult objects can be converted to System.Version. + Version numericVersion = fileVersion.ToVersion(); + Console.WriteLine("Parsed as System.Version: {0}", numericVersion); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.DoubleExtensions.md b/.docfx/api/types/Cuemon.Extensions.DoubleExtensions.md new file mode 100644 index 00000000..ff938afb --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.DoubleExtensions.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.Extensions.DoubleExtensions +example: +- *content +--- + +The following example demonstrates how to use DoubleExtensions for numeric operations such as Unix epoch conversion, time span creation, factorial computation, and rounding to specified accuracy. + +```csharp +using System; +using Cuemon; +using Cuemon.Extensions; + +namespace MyApp.Numerics; + +public static class DoubleExtensionsExample +{ + public static void Demonstrate() + { + double unixTimestamp = 1617738277d; + DateTime fromUnix = unixTimestamp.FromUnixEpochTime().ToLocalTime(); + + TimeSpan fromSeconds = 3661d.ToTimeSpan(TimeUnit.Seconds); + double factorial = 5d.Factorial(); + + double value = 123456789.987654321d; + double nearestThousand = value.RoundOff(RoundOffAccuracy.NearestThousandth); + double nearestMillion = value.RoundOff(RoundOffAccuracy.NearestMillion); + + Console.WriteLine(fromUnix.ToString("O")); + Console.WriteLine(fromSeconds); + Console.WriteLine(factorial); + Console.WriteLine(nearestThousand); + Console.WriteLine(nearestMillion); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.ExceptionExtensions.md b/.docfx/api/types/Cuemon.Extensions.ExceptionExtensions.md new file mode 100644 index 00000000..ab376b25 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.ExceptionExtensions.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.Extensions.ExceptionExtensions +example: +- *content +--- + +The following example demonstrates flattening nested exception hierarchies using the extension method. + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Cuemon.Extensions; + +namespace MyApp.Examples; + +public static class ExceptionExtensionsExample +{ + public static void Demonstrate() + { + var exception = new InvalidOperationException( + "First", + new AmbiguousMatchException( + "Second", + new OutOfMemoryException( + "Third", + new AggregateException(new AccessViolationException("Fourth"))))); + + IEnumerable flattened = exception.Flatten(); + + Console.WriteLine(flattened.Count()); + foreach (var ex in flattened) + { + Console.WriteLine(ex.GetType().Name); + } + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.FuncFactory.md b/.docfx/api/types/Cuemon.Extensions.FuncFactory.md new file mode 100644 index 00000000..78d4846e --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.FuncFactory.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.Extensions.FuncFactory +example: +- *content +--- + +```csharp +using System; +using Cuemon; +using Cuemon.Extensions; + +namespace Cuemon.Extensions; + +public class FuncFactoryExample +{ + public void Demonstrate() + { + Func formatter = (x, y) => $"{x} + {y} = {x + y}"; + + var factory = FuncFactory.Create(formatter, 3, 4); + string result = factory.ExecuteMethod(); + + Console.WriteLine(result); + + int sum = FuncFactory.Invoke, int>(tuple => tuple.Arg1 + tuple.Arg2, MutableTupleFactory.CreateTwo(10, 20)); + Console.WriteLine(sum); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Globalization.RegionInfoExtensions.md b/.docfx/api/types/Cuemon.Extensions.Globalization.RegionInfoExtensions.md new file mode 100644 index 00000000..0241131b --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Globalization.RegionInfoExtensions.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.Extensions.Globalization.RegionInfoExtensions +example: +- *content +--- + +The following example demonstrates how to use RegionInfoExtensions to retrieve the cultures associated with a specific geographic region. + +```csharp +using System; +using System.Globalization; +using System.Linq; +using Cuemon.Extensions.Globalization; + +namespace MyApp.Globalization +{ + public class RegionInfoExtensionsExample + { + public void Demonstrate() + { + // Get cultures associated with a specific region + var region = new RegionInfo("US"); + + var cultures = region.GetCultures().ToList(); + Console.WriteLine($"Cultures for {region.EnglishName} ({region.TwoLetterISORegionName}):"); + foreach (var culture in cultures) + { + Console.WriteLine($" {culture.Name} - {culture.EnglishName}"); + } + + // Try another region + var japan = new RegionInfo("JP"); + var jpCultures = japan.GetCultures().ToList(); + Console.WriteLine($"\nCultures for {japan.EnglishName}:"); + foreach (var culture in jpCultures) + { + Console.WriteLine($" {culture.Name} - {culture.EnglishName}"); + } + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Globalization.StatisticalRegionExtensions.md b/.docfx/api/types/Cuemon.Extensions.Globalization.StatisticalRegionExtensions.md new file mode 100644 index 00000000..7ea703f0 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Globalization.StatisticalRegionExtensions.md @@ -0,0 +1,72 @@ +--- +uid: Cuemon.Extensions.Globalization.StatisticalRegionExtensions +example: +- *content +--- + +The following example demonstrates how to use the to classify geographic regions using the UN M.49 standard. + +```csharp +using System; +using System.Globalization; +using System.Linq; +using Cuemon.Extensions.Globalization; +using Cuemon.Globalization; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + + // Access regions via the World class + var world = World.GetStatisticalRegion("001"); + var europe = World.GetStatisticalRegion("150"); + var westernEurope = World.GetStatisticalRegion("155"); + var denmark = World.GetCountry("208"); // Denmark M.49 code + var usa = World.GetCountry("840"); // United States M.49 code + + // Classify by kind using the extension methods + bool isWorld = world.IsWorld(); // true + bool isRegion = europe.IsRegion(); // true (continent) + bool isSubregion = westernEurope.IsSubregion(); // true + bool isCountry = denmark.IsCountryOrTerritory(); // true + bool isArea = europe.IsArea(); // true (not a country) + bool isCountryArea = denmark.IsArea(); // false (is a country) + + // Check intermediate regions (sub-Saharan Africa, Latin America) + var subSaharanAfrica = World.GetStatisticalRegion("202"); + bool isIntermediate = subSaharanAfrica.IsIntermediateRegion(); // true + + // Verify hierarchy + bool denmarkIsInEurope = denmark.Parent.IsSubregion(); // true (Northern Europe, M.49: 154) + + // Check if a country has associated .NET RegionInfo + bool hasRegionInfo = usa.HasRegionInfo(); // true (US has RegionInfo) + bool noRegionInfo = world.HasRegionInfo(); // false (World is not a country) + + // Check if a region has ISO codes + bool hasIso = denmark.HasIsoCodes(); // true + + // Iterate all countries + int countryCount = world.Countries.Count(); + Console.WriteLine($"Total countries/territories: {countryCount}"); + + // Find a country by RegionInfo + var regionInfo = new RegionInfo("US"); + var usaByRegion = World.GetCountry(regionInfo); + Console.WriteLine(usaByRegion.IsCountryOrTerritory()); // True + + // Traverse the hierarchy + foreach (var ancestor in denmark.GetAncestors()) + { + Console.WriteLine($"{ancestor.Name} ({ancestor.Kind})"); + // "Northern Europe (Subregion)" + // "Europe (Region)" + // "World (World)" + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Hosting.Environments.md b/.docfx/api/types/Cuemon.Extensions.Hosting.Environments.md new file mode 100644 index 00000000..b9b41725 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Hosting.Environments.md @@ -0,0 +1,24 @@ +--- +uid: Cuemon.Extensions.Hosting.Environments +example: +- *content +--- + +```csharp +using Cuemon.Extensions.Hosting; +using Microsoft.Extensions.Hosting; + +namespace Cuemon.Extensions.Hosting; + +public class EnvironmentsExample +{ + public void Demonstrate() + { + var builder = Host.CreateDefaultBuilder() + .UseEnvironment(Environments.LocalDevelopment); + + using var host = builder.Build(); + host.Run(); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Hosting.HostBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.Hosting.HostBuilderExtensions.md new file mode 100644 index 00000000..e6704bcc --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Hosting.HostBuilderExtensions.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.Extensions.Hosting.HostBuilderExtensions +example: +- *content +--- + +The following example demonstrates how to add and remove configuration sources through . + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.Extensions.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Memory; +using Microsoft.Extensions.Hosting; + +namespace MyApp.Examples; + +public static class HostBuilderExtensionsExample +{ + public static void Demonstrate() + { + var hostBuilder = Host.CreateDefaultBuilder() + .ConfigureConfigurationSources((environment, sources) => + { + sources.Add(new MemoryConfigurationSource + { + InitialData = new Dictionary + { + ["App:Environment"] = environment.EnvironmentName + } + }); + }) + .RemoveConfigurationSource((environment, source) => + environment.IsProduction() && source is MemoryConfigurationSource); + + using var host = hostBuilder.Build(); + var configuration = (IConfiguration)host.Services.GetService(typeof(IConfiguration)); + + Console.WriteLine(configuration["App:Environment"] == null); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Hosting.HostEnvironmentExtensions.md b/.docfx/api/types/Cuemon.Extensions.Hosting.HostEnvironmentExtensions.md new file mode 100644 index 00000000..7210cfea --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Hosting.HostEnvironmentExtensions.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.Extensions.Hosting.HostEnvironmentExtensions +example: +- *content +--- + +The following example demonstrates how to use HostEnvironmentExtensions to check if the current hosting environment is a local development or non-production environment. + +```csharp +using System; +using Cuemon.Extensions.Hosting; +using Microsoft.Extensions.Hosting; + +namespace MyApp.Startup; + +public class EnvironmentReporter +{ + public void Report(IHostEnvironment env) + { + if (env.IsLocalDevelopment()) + { + Console.WriteLine("Running on a developer machine."); + + if (env.IsNonProduction()) + { + Console.WriteLine("Environment is not Production."); + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.IO.ByteArrayExtensions.md b/.docfx/api/types/Cuemon.Extensions.IO.ByteArrayExtensions.md new file mode 100644 index 00000000..f4aa97c9 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.IO.ByteArrayExtensions.md @@ -0,0 +1,50 @@ +--- +uid: Cuemon.Extensions.IO.ByteArrayExtensions +example: +- *content +--- + +The following example demonstrates how to convert a byte array into a seekable MemoryStream using ByteArrayExtensions, with both synchronous and asynchronous overloads. + +```csharp +using System.Threading; +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Cuemon.Extensions.IO; + +namespace MyApp.Extensions.IO +{ + public class ByteArrayExtensionsExample + { + public async Task DemonstrateAsync() + { + byte[] data = Encoding.UTF8.GetBytes("Hello, World!"); + + // Convert a byte array to a seekable Stream (synchronous) + using Stream stream = data.ToStream(); + Console.WriteLine(stream.Length); // 13 + Console.WriteLine(stream.CanSeek); // True + + // Read the content back + using var reader = new StreamReader(stream); + string content = reader.ReadToEnd(); + Console.WriteLine(content); // "Hello, World!" + + // Convert a byte array to a Stream (asynchronous) + using Stream asyncStream = await data.ToStreamAsync(); + + // Verify the async stream content + using var asyncReader = new StreamReader(asyncStream); + string asyncContent = asyncReader.ReadToEnd(); + Console.WriteLine(asyncContent); // "Hello, World!" + + // Use cancellation with the async overload + using var cts = new System.Threading.CancellationTokenSource(); + using Stream cancelStream = await data.ToStreamAsync(cts.Token); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.IO.StreamExtensions.md b/.docfx/api/types/Cuemon.Extensions.IO.StreamExtensions.md new file mode 100644 index 00000000..b04346ad --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.IO.StreamExtensions.md @@ -0,0 +1,114 @@ +--- +uid: Cuemon.Extensions.IO.StreamExtensions +example: +- *content +--- + +The following example demonstrates how to transform, compress, and decompress streams by invoking the available stream extensions. + +```csharp +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Cuemon.Extensions.IO; + +namespace MyApp.Examples +{ + public static class StreamExtensionsExample + { + public static async Task DemonstrateAsync() + { + using var first = CreateStream("Cue"); + using var second = CreateStream("mon"); + using var combined = first.Concat(second, options => options.LeaveOpen = true); + + var bytes = combined.ToByteArray(); + combined.Position = 0; + var bytesAsync = await combined.ToByteArrayAsync(); + combined.Position = 0; + var chars = combined.ToCharArray(); + combined.Position = 0; + var text = combined.ToEncodedString(); + combined.Position = 0; + var asyncText = await combined.ToEncodedStringAsync(); + + using var bomStream = CreateStream("Hello with BOM", includePreamble: true); + bomStream.TryDetectUnicodeEncoding(out var detectedEncoding); + + using var writable = new MemoryStream(); + await writable.WriteAllAsync(Encoding.UTF8.GetBytes("written asynchronously")); + writable.Position = 0; + + using var gzipSource = CreateStream("gzip payload"); + using var gzipCompressed = gzipSource.CompressGZip(); + gzipCompressed.Position = 0; + using var gzipDecompressed = gzipCompressed.DecompressGZip(); + gzipDecompressed.Position = 0; + var gzipRoundTrip = gzipDecompressed.ToEncodedString(); + + using var gzipAsyncSource = CreateStream("gzip async payload"); + using var gzipCompressedAsync = await gzipAsyncSource.CompressGZipAsync(); + gzipCompressedAsync.Position = 0; + using var gzipDecompressedAsync = await gzipCompressedAsync.DecompressGZipAsync(); + gzipDecompressedAsync.Position = 0; + var gzipAsyncRoundTrip = await gzipDecompressedAsync.ToEncodedStringAsync(); + + using var deflateSource = CreateStream("deflate payload"); + using var deflateCompressed = deflateSource.CompressDeflate(); + deflateCompressed.Position = 0; + using var deflateDecompressed = deflateCompressed.DecompressDeflate(); + deflateDecompressed.Position = 0; + var deflateRoundTrip = deflateDecompressed.ToEncodedString(); + + using var deflateAsyncSource = CreateStream("deflate async payload"); + using var deflateCompressedAsync = await deflateAsyncSource.CompressDeflateAsync(); + deflateCompressedAsync.Position = 0; + using var deflateDecompressedAsync = await deflateCompressedAsync.DecompressDeflateAsync(); + deflateDecompressedAsync.Position = 0; + var deflateAsyncRoundTrip = await deflateDecompressedAsync.ToEncodedStringAsync(); + + using var brotliSource = CreateStream("brotli payload"); + using var brotliCompressed = brotliSource.CompressBrotli(); + brotliCompressed.Position = 0; + using var brotliDecompressed = brotliCompressed.DecompressBrotli(); + brotliDecompressed.Position = 0; + var brotliRoundTrip = brotliDecompressed.ToEncodedString(); + + using var brotliAsyncSource = CreateStream("brotli async payload"); + using var brotliCompressedAsync = await brotliAsyncSource.CompressBrotliAsync(); + brotliCompressedAsync.Position = 0; + using var brotliDecompressedAsync = await brotliCompressedAsync.DecompressBrotliAsync(); + brotliDecompressedAsync.Position = 0; + var brotliAsyncRoundTrip = await brotliDecompressedAsync.ToEncodedStringAsync(); + + Console.WriteLine(bytes.Length == bytesAsync.Length); + Console.WriteLine(chars.Length); + Console.WriteLine(text == asyncText); + Console.WriteLine(detectedEncoding?.WebName); + Console.WriteLine(writable.ToEncodedString()); + Console.WriteLine(gzipRoundTrip); + Console.WriteLine(gzipAsyncRoundTrip); + Console.WriteLine(deflateRoundTrip); + Console.WriteLine(deflateAsyncRoundTrip); + Console.WriteLine(brotliRoundTrip); + Console.WriteLine(brotliAsyncRoundTrip); + } + + private static MemoryStream CreateStream(string value, bool includePreamble = false) + { + var content = Encoding.UTF8.GetBytes(value); + if (!includePreamble) + { + return new MemoryStream(content); + } + + var preamble = Encoding.UTF8.GetPreamble(); + var buffer = new byte[preamble.Length + content.Length]; + Buffer.BlockCopy(preamble, 0, buffer, 0, preamble.Length); + Buffer.BlockCopy(content, 0, buffer, preamble.Length, content.Length); + return new MemoryStream(buffer); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.IO.StringExtensions.md b/.docfx/api/types/Cuemon.Extensions.IO.StringExtensions.md new file mode 100644 index 00000000..cc874295 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.IO.StringExtensions.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.Extensions.IO.StringExtensions +example: +- *content +--- + +The following example demonstrates how to convert a string into a stream or text reader with . + +```csharp +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Cuemon.Extensions.IO; + +namespace MyApp.Examples +{ + public static class StringExtensionsExample + { + public static async Task DemonstrateAsync() + { + const string json = "{\"key\":\"value\"}"; + + using Stream stream = json.ToStream(options => + { + options.Encoding = Encoding.UTF8; + }); + + using Stream asyncStream = await json.ToStreamAsync(); + using TextReader reader = json.ToTextReader(); + + Console.WriteLine(stream.Length > 0); + Console.WriteLine((await asyncStream.ToEncodedStringAsync()) == json); + Console.WriteLine(reader.ReadToEnd()); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.IO.TextReaderExtensions.md b/.docfx/api/types/Cuemon.Extensions.IO.TextReaderExtensions.md new file mode 100644 index 00000000..8cd86ddc --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.IO.TextReaderExtensions.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.Extensions.IO.TextReaderExtensions +example: +- *content +--- + +The following example demonstrates how to read lines from a and copy its content asynchronously. + +```csharp +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Cuemon.Extensions.IO; + +namespace MyApp.Examples +{ + public static class TextReaderExtensionsExample + { + public static async Task DemonstrateAsync() + { + const string input = "line one\nline two\nline three"; + + using var linesReader = input.ToTextReader(); + var lines = linesReader.ReadAllLines().ToList(); + + using var asyncLinesReader = input.ToTextReader(); + using var writer = new StringWriter(); + var asyncLines = await asyncLinesReader.ReadAllLinesAsync(); + + using var copyReader = input.ToTextReader(); + await copyReader.CopyToAsync(writer); + + Console.WriteLine(lines.Count); + Console.WriteLine(asyncLines.Count); + Console.WriteLine(writer.ToString().Contains("line two")); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.IntegerExtensions.md b/.docfx/api/types/Cuemon.Extensions.IntegerExtensions.md new file mode 100644 index 00000000..19aca8a6 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.IntegerExtensions.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Extensions.IntegerExtensions +example: +- *content +--- + +The following example demonstrates how to use the extension methods to check whether a given integer is prime, even, or odd, and to find the smallest or largest of two values. + +```csharp +using System; +using Cuemon.Extensions; + +namespace MyApp.Examples; + +public static class IntegerExtensionsExample +{ + public static void Demonstrate() + { + var number = 17; + bool isPrime = number.IsPrime(); + bool isEven = number.IsEven(); + bool isOdd = number.IsOdd(); + + Console.WriteLine(isPrime); + Console.WriteLine(isEven); + Console.WriteLine(isOdd); + Console.WriteLine(5.Max(10)); + Console.WriteLine(15.Min(10)); + Console.WriteLine(500L.Min(1000L)); + Console.WriteLine(((short)3).Max((short)7)); + Console.WriteLine(new[] { 1, 3, 5, 7 }.IsCountableSequence()); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.MethodDescriptorExtensions.md b/.docfx/api/types/Cuemon.Extensions.MethodDescriptorExtensions.md new file mode 100644 index 00000000..bf1f1c8a --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.MethodDescriptorExtensions.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.Extensions.MethodDescriptorExtensions +example: +- *content +--- + +The following example demonstrates how to use MethodDescriptorExtensions to inspect a method's parameter information using the MethodDescriptor API. + +```csharp +using System; +using System.Reflection; +using Cuemon.Extensions; +using Cuemon.Reflection; + +namespace MyApp.Reflection; + +public static class MethodDescriptorExtensionsExample +{ + public static void Demonstrate() + { + MethodInfo writeLine = typeof(Console).GetMethod(nameof(Console.WriteLine), new[] { typeof(string) }); + MethodInfo newGuid = typeof(Guid).GetMethod(nameof(Guid.NewGuid), BindingFlags.Public | BindingFlags.Static); + + MethodDescriptor withParameters = MethodDescriptor.Create(writeLine); + MethodDescriptor withoutParameters = MethodDescriptor.Create(newGuid); + + Console.WriteLine(withParameters.HasParameters()); + Console.WriteLine(withoutParameters.HasParameters()); + Console.WriteLine(withParameters.Method.Name); + Console.WriteLine(withParameters.Caller?.Name); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.MutableTupleFactory.md b/.docfx/api/types/Cuemon.Extensions.MutableTupleFactory.md new file mode 100644 index 00000000..1b03848b --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.MutableTupleFactory.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.Extensions.MutableTupleFactory +example: +- *content +--- + +```csharp +using System; +using Cuemon; +using Cuemon.Extensions; + +namespace Cuemon.Extensions; + +public class MutableTupleFactoryExample +{ + public void Demonstrate() + { + var zero = MutableTupleFactory.CreateZero(); + + var one = MutableTupleFactory.CreateOne(42); + Console.WriteLine(one.Arg1); + + var two = MutableTupleFactory.CreateTwo("Alice", 30); + Console.WriteLine($"{two.Arg1} is {two.Arg2} years old"); + + var three = MutableTupleFactory.CreateThree(1, 2, 3); + + var five = MutableTupleFactory.CreateFive('a', 'b', 'c', 'd', 'e'); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.ByteArrayExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.ByteArrayExtensions.md new file mode 100644 index 00000000..d94bf03a --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.ByteArrayExtensions.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.Extensions.Net.ByteArrayExtensions +example: +- *content +--- + +The following example demonstrates how to URL-encode byte array data for safe HTTP transmission using ByteArrayExtensions, with support for partial encoding and custom character encodings. + +```csharp +using System; +using System.Text; +using Cuemon.Extensions.Net; +using Cuemon.Text; + +namespace MyApp.Net +{ + public class ByteArrayExtensionsExample + { + public void Demonstrate() + { + // Encode a byte array for safe URL transmission + byte[] data = Encoding.UTF8.GetBytes("hello world"); + + // URL-encode the entire byte array + byte[] encoded = data.UrlEncode(); + Console.WriteLine(Encoding.UTF8.GetString(encoded)); + // Output: hello%20world + + // Encode only a portion starting at position 0 for 5 bytes + byte[] partial = data.UrlEncode(position: 0, bytesToRead: 5); + Console.WriteLine(Encoding.UTF8.GetString(partial)); + // Output: hello + + // Use a custom encoding (e.g., UTF-32) + byte[] utf32Data = Encoding.UTF32.GetBytes("test data"); + byte[] utf32Encoded = utf32Data.UrlEncode(setup: o => o.Encoding = Encoding.UTF32); + string result = Encoding.UTF32.GetString(utf32Encoded); + Console.WriteLine(result); + // Output: test%00%00%00%20%00%00%00data + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.DictionaryExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.DictionaryExtensions.md new file mode 100644 index 00000000..8fa7f22d --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.DictionaryExtensions.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Extensions.Net.DictionaryExtensions +example: +- *content +--- + +The following example demonstrates how to build a query string from a dictionary of string arrays using DictionaryExtensions, with optional URL encoding. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.Extensions.Net; + +namespace MyApp.Net +{ + public class DictionaryExtensionsExample + { + public void Demonstrate() + { + // Build a query string from a dictionary + var parameters = new Dictionary + { + { "search", new[] { "dotnet" } }, + { "page", new[] { "1" } }, + { "tags", new[] { "aspnet", "core" } } + }; + + // Convert to a query string (not URL-encoded) + string queryString = parameters.ToQueryString(); + Console.WriteLine(queryString); + // Output: search=dotnet&page=1&tags=aspnet&tags=core + + // URL-encode the values + string encoded = parameters.ToQueryString(urlEncode: true); + Console.WriteLine(encoded); + // Output: search=dotnet&page=1&tags=aspnet&tags=core + + // Useful for building API request URLs + var empty = new Dictionary(); + string emptyQs = empty.ToQueryString(); + Console.WriteLine($"Empty: '{emptyQs}'"); // Empty: '' + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.Http.HttpManagerFactory.md b/.docfx/api/types/Cuemon.Extensions.Net.Http.HttpManagerFactory.md new file mode 100644 index 00000000..c5e9cd81 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.Http.HttpManagerFactory.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Extensions.Net.Http.HttpManagerFactory +example: +- *content +--- + +```csharp +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Cuemon.Extensions.Net.Http; + +namespace Cuemon.Extensions.Net.Http; + +public class HttpManagerFactoryExample +{ + public async Task DemonstrateAsync() + { + var clientFactory = new HttpClientFactoryStub(); + + var manager = HttpManagerFactory.CreateManager(clientFactory, "github"); + var response = await manager.HttpGetAsync(new Uri("https://api.github.com")); + Console.WriteLine(await response.Content.ReadAsStringAsync()); + } + + private class HttpClientFactoryStub : IHttpClientFactory + { + public HttpClient CreateClient(string name) + { + var client = new HttpClient(); + client.DefaultRequestHeaders.UserAgent.ParseAdd("HttpManagerFactoryExample"); + return client; + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.Http.HttpMethodExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.Http.HttpMethodExtensions.md new file mode 100644 index 00000000..2362f90a --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.Http.HttpMethodExtensions.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.Extensions.Net.Http.HttpMethodExtensions +example: +- *content +--- + +The following example demonstrates how to convert between System.Net.Http.HttpMethod and the Cuemon HttpMethods enum using HttpMethodExtensions. + +```csharp +using System; +using System.Net.Http; +using Cuemon.Extensions.Net.Http; +using Cuemon.Net.Http; + +namespace MyApp.Net +{ + public class HttpMethodExtensionsExample + { + public void Demonstrate() + { + // Convert System.Net.Http.HttpMethod to the Cuemon HttpMethods enum + HttpMethod getMethod = HttpMethod.Get; + HttpMethods method = getMethod.ToHttpMethod(); + Console.WriteLine($"{getMethod} -> {method}"); // GET -> Get + + HttpMethod postMethod = HttpMethod.Post; + HttpMethods post = postMethod.ToHttpMethod(); + Console.WriteLine($"{postMethod} -> {post}"); // POST -> Post + + // Custom HTTP methods are also supported + var patchMethod = new HttpMethod("PATCH"); + HttpMethods patch = patchMethod.ToHttpMethod(); + Console.WriteLine($"{patchMethod} -> {patch}"); // PATCH -> Patch + + // Check flags with bitwise operations + if (method.HasFlag(HttpMethods.Get)) + { + Console.WriteLine("This is a GET request."); + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.Http.SlimHttpClientFactory.md b/.docfx/api/types/Cuemon.Extensions.Net.Http.SlimHttpClientFactory.md new file mode 100644 index 00000000..23ba4253 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.Http.SlimHttpClientFactory.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.Extensions.Net.Http.SlimHttpClientFactory +example: +- *content +--- + +The following example demonstrates how to use to create named instances with a shared handler pool and configurable lifetime. + +```csharp +using System; +using System.Net.Http; +using Cuemon.Extensions.Net.Http; + +namespace MyApp.Examples; + +public class SlimHttpClientFactoryExample +{ + public void Demonstrate() + { + // Create a factory that reuses HttpClientHandler instances per name + var factory = new SlimHttpClientFactory( + () => new HttpClientHandler + { + AllowAutoRedirect = false, + MaxAutomaticRedirections = 5 + }); + + // Create two named clients - they share the same handler pool + using var clientA = factory.CreateClient("ServiceA"); + using var clientB = factory.CreateClient("ServiceB"); + + clientA.BaseAddress = new Uri("https://service-a.example.com"); + clientB.BaseAddress = new Uri("https://service-b.example.com"); + + Console.WriteLine($"ClientA base: {clientA.BaseAddress}"); + Console.WriteLine($"ClientB base: {clientB.BaseAddress}"); + + // The handler for "ServiceA" is reused across calls to CreateClient("ServiceA") + // until the configured handler lifetime expires. + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.Http.SlimHttpClientFactoryOptions.md b/.docfx/api/types/Cuemon.Extensions.Net.Http.SlimHttpClientFactoryOptions.md new file mode 100644 index 00000000..366701c5 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.Http.SlimHttpClientFactoryOptions.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.Extensions.Net.Http.SlimHttpClientFactoryOptions +example: +- *content +--- + +The following example demonstrates how to configure with a custom handler lifetime and use it alongside to create named instances. + +```csharp +using System; +using System.Net.Http; +using Cuemon.Extensions.Net.Http; + +namespace MyApp.Examples; + +public class SlimHttpClientFactoryOptionsExample +{ + public void Demonstrate() + { + // Direct instantiation of SlimHttpClientFactoryOptions + var factoryOptions = new SlimHttpClientFactoryOptions + { + HandlerLifetime = TimeSpan.FromSeconds(30) + }; + + var factory = new SlimHttpClientFactory( + () => new HttpClientHandler(), + o => + { + o.HandlerLifetime = TimeSpan.FromSeconds(30); + }); + + // Create a named client + using var client = factory.CreateClient("MyApi"); + client.BaseAddress = new Uri("https://api.example.com"); + + Console.WriteLine($"Client ready: {client.BaseAddress}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.Http.UriExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.Http.UriExtensions.md new file mode 100644 index 00000000..bd366a98 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.Http.UriExtensions.md @@ -0,0 +1,179 @@ +--- +uid: Cuemon.Extensions.Net.Http.UriExtensions +example: +- *content +--- + +The following example demonstrates how to perform HTTP requests (GET, POST, PUT, DELETE, and more) directly on a Uri using UriExtensions, with support for media types and cancellation tokens. + +```csharp +using System.Text; +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading; +using System.Threading.Tasks; +using Cuemon.Extensions.Net.Http; + +namespace MyApp.Http +{ + public class UriExtensionsExample + { + public async Task DemonstrateAsync() + { + // Configure a test HTTP client factory that returns predictable responses + UriExtensions.DefaultHttpClientFactory = new StubHttpClientFactory(HttpStatusCode.OK); + + var location = new Uri("https://example.com/api/items"); + + // GET request + using (var response = await location.HttpGetAsync()) + { + Console.WriteLine($"GET: {response.StatusCode}"); // 200 + } + + // DELETE request + using (var response = await location.HttpDeleteAsync()) + { + Console.WriteLine($"DELETE: {response.StatusCode}"); // 200 + } + + // HEAD request + using (var response = await location.HttpHeadAsync()) + { + Console.WriteLine($"HEAD: {response.StatusCode}"); // 200 + } + + // OPTIONS request + using (var response = await location.HttpOptionsAsync()) + { + Console.WriteLine($"OPTIONS: {response.StatusCode}"); // 200 + } + + // POST with string content type + using (var response = await location.HttpPostAsync( + "application/json", ToStream("{\"name\":\"New Item\"}"))) + { + Console.WriteLine($"POST: {response.StatusCode}"); // 200 + } + + // POST with MediaTypeHeaderValue + using (var response = await location.HttpPostAsync( + MediaTypeHeaderValue.Parse("application/json; charset=utf-8"), + ToStream("{\"name\":\"Another\"}"))) + { + Console.WriteLine($"POST (typed): {response.StatusCode}"); // 200 + } + + // PUT + using (var response = await location.HttpPutAsync( + "application/json", ToStream("{\"name\":\"Updated\"}"))) + { + Console.WriteLine($"PUT: {response.StatusCode}"); // 200 + } + + // PATCH + using (var response = await location.HttpPatchAsync( + "application/json-patch+json", ToStream("[{\"op\":\"replace\",\"path\":\"/name\",\"value\":\"Patched\"}]"))) + { + Console.WriteLine($"PATCH: {response.StatusCode}"); // 200 + } + + // TRACE + using (var response = await location.HttpTraceAsync()) + { + Console.WriteLine($"TRACE: {response.StatusCode}"); // 200 + } + + // Generic HTTP method with string content type + using (var response = await location.HttpAsync( + HttpMethod.Post, "text/plain", ToStream("Hello"))) + { + Console.WriteLine($"Generic POST: {response.StatusCode}"); // 200 + } + + // Generic HTTP method with typed content type + using (var response = await location.HttpAsync( + HttpMethod.Put, + MediaTypeHeaderValue.Parse("application/octet-stream"), + ToStream("binary"))) + { + Console.WriteLine($"Generic PUT: {response.StatusCode}"); // 200 + } + + // Full control via HttpRequestOptions + using (var response = await location.HttpAsync(o => + { + o.Request.Method = HttpMethod.Get; + o.Request.Headers.Add("X-Custom", "my-value"); + o.CancellationToken = CancellationToken.None; + })) + { + Console.WriteLine($"Custom GET: {response.StatusCode}"); // 200 + } + + // Use cancellation token + using var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromSeconds(5)); + try + { + using var response = await location.HttpGetAsync(cts.Token); + Console.WriteLine($"Cancellable GET: {response.StatusCode}"); + } + catch (TaskCanceledException) + { + Console.WriteLine("Request was cancelled."); + } + } + + private static Stream ToStream(string value) + { + var bytes = Encoding.UTF8.GetBytes(value); + return new MemoryStream(bytes); + } + } + + /// + /// A stub factory that returns an HttpClient backed by a handler + /// that returns a fixed status code for all requests. + /// + internal class StubHttpClientFactory : IHttpClientFactory + { + private readonly HttpStatusCode _statusCode; + + public StubHttpClientFactory(HttpStatusCode statusCode) + { + _statusCode = statusCode; + } + + public HttpClient CreateClient(string name) + { + return new HttpClient(new StubHttpMessageHandler(_statusCode)); + } + } + + internal class StubHttpMessageHandler : HttpMessageHandler + { + private readonly HttpStatusCode _statusCode; + + public StubHttpMessageHandler(HttpStatusCode statusCode) + { + _statusCode = statusCode; + } + + protected override Task SendAsync( + HttpRequestMessage request, CancellationToken ct) + { + var response = new HttpResponseMessage(_statusCode) + { + Content = new StringContent("OK"), + RequestMessage = request + }; + return Task.FromResult(response); + } + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.HttpStatusCodeExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.HttpStatusCodeExtensions.md new file mode 100644 index 00000000..685107e0 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.HttpStatusCodeExtensions.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Extensions.Net.HttpStatusCodeExtensions +example: +- *content +--- + +The following example demonstrates how to use the extension methods to classify HTTP status codes by range directly from values. + +```csharp +using System; +using System.Net; +using Cuemon.Extensions.Net; + +namespace DocExamples +{ + public static class HttpStatusCodeExtensionsExample + { + public static void Main() + { + HttpStatusCode statusCode = HttpStatusCode.NotFound; + + // Check the status code HTTP range + bool isInfo = statusCode.IsInformationStatusCode(); + bool isSuccess = statusCode.IsSuccessStatusCode(); + bool isRedirect = statusCode.IsRedirectionStatusCode(); + bool isClientError = statusCode.IsClientErrorStatusCode(); + bool isServerError = statusCode.IsServerErrorStatusCode(); + + Console.WriteLine($"HTTP {(int)statusCode} ({statusCode}):"); + Console.WriteLine($" Informational (100-199): {isInfo}"); + Console.WriteLine($" Successful (200-299): {isSuccess}"); + Console.WriteLine($" Redirection (300-399): {isRedirect}"); + Console.WriteLine($" Client Error (400-499): {isClientError}"); + Console.WriteLine($" Server Error (500-599): {isServerError}"); + + // Verify common status codes + Console.WriteLine($"\n200 OK is success: {HttpStatusCode.OK.IsSuccessStatusCode()}"); + Console.WriteLine($"301 Moved is redirect: {HttpStatusCode.MovedPermanently.IsRedirectionStatusCode()}"); + Console.WriteLine($"403 Forbidden is client error: {HttpStatusCode.Forbidden.IsClientErrorStatusCode()}"); + Console.WriteLine($"500 Error is server error: {HttpStatusCode.InternalServerError.IsServerErrorStatusCode()}"); + Console.WriteLine($"100 Continue is informational: {HttpStatusCode.Continue.IsInformationStatusCode()}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.NameValueCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.NameValueCollectionExtensions.md new file mode 100644 index 00000000..ed3405d1 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.NameValueCollectionExtensions.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Extensions.Net.NameValueCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to convert a NameValueCollection into a query string using NameValueCollectionExtensions, with optional URL encoding for safe HTTP transmission. + +```csharp +using System; +using System.Collections.Specialized; +using Cuemon.Extensions.Net; + +namespace MyApp.Net +{ + public class NameValueCollectionExtensionsExample + { + public void Demonstrate() + { + var nvc = new NameValueCollection + { + { "name", "John Doe" }, + { "city", "Copenhagen" }, + { "hobbies", "reading" }, + { "hobbies", "coding" } + }; + + // Convert NameValueCollection to a query string (not URL-encoded) + string queryString = nvc.ToQueryString(); + Console.WriteLine(queryString); + // Output: name=John Doe&city=Copenhagen&hobbies=reading&hobbies=coding + + // URL-encode the values for safe HTTP transmission + string encoded = nvc.ToQueryString(urlEncode: true); + Console.WriteLine(encoded); + // Output: name=John+Doe&city=Copenhagen&hobbies=reading&hobbies=coding + + // Empty collection + var empty = new NameValueCollection(); + string emptyResult = empty.ToQueryString(); + Console.WriteLine($"Empty: '{emptyResult}'"); // Empty: '' + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.Security.SignedUriOptions.md b/.docfx/api/types/Cuemon.Extensions.Net.Security.SignedUriOptions.md new file mode 100644 index 00000000..1e9eafad --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.Security.SignedUriOptions.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.Extensions.Net.Security.SignedUriOptions +example: +- *content +--- + +The following example demonstrates how to configure `SignedUriOptions` for generating time-limited signed URIs with HMAC-SHA256. + +```csharp +using Cuemon.Extensions.Net.Security; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public class SignedUriOptionsExample +{ + public void Demonstrate() + { + var options = new SignedUriOptions + { + Algorithm = KeyedCryptoAlgorithm.HmacSha256, + SignatureFieldName = "sig", + StartFieldName = "st", + ExpiryFieldName = "se", + UrlEncode = true + }; + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.Security.StringExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.Security.StringExtensions.md new file mode 100644 index 00000000..2d9a072f --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.Security.StringExtensions.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.Extensions.Net.Security.StringExtensions +example: +- *content +--- + +The following example demonstrates how to sign a URI string and validate the signature later. + +```csharp +using System; +using System.Security; +using System.Text; +using Cuemon.Extensions.Net.Security; + +namespace MyApp.Examples +{ + public static class SignedStringExtensionsExample + { + public static void Demonstrate() + { + var secret = Encoding.UTF8.GetBytes("1234"); + var uriString = "https://example.com/search?q=cuemon"; + var signedUri = uriString.ToSignedUri(secret, DateTime.UtcNow.AddMinutes(-1), DateTime.UtcNow.AddMinutes(1)); + + signedUri.OriginalString.ValidateSignedUri(secret); + + Console.WriteLine(signedUri); + + try + { + var tampered = new UriBuilder(signedUri); + tampered.Query = tampered.Query.TrimStart('?') + "&tampered=1"; + tampered.Uri.OriginalString.ValidateSignedUri(secret); + } + catch (SecurityException ex) + { + Console.WriteLine(ex.Message); + } + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.Security.UriExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.Security.UriExtensions.md new file mode 100644 index 00000000..475f1099 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.Security.UriExtensions.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.Extensions.Net.Security.UriExtensions +example: +- *content +--- + +The following example demonstrates how to sign and validate a with . + +```csharp +using System; +using System.Text; +using Cuemon.Extensions.Net.Security; + +namespace MyApp.Examples +{ + public static class SignedUriExtensionsExample + { + public static void Demonstrate() + { + var secret = Encoding.UTF8.GetBytes("1234"); + var location = new Uri("https://example.com/search?q=cuemon"); + var signed = location.ToSignedUri(secret, DateTime.UtcNow.AddMinutes(-1), DateTime.UtcNow.AddMinutes(1)); + + signed.ValidateSignedUri(secret); + + Console.WriteLine(signed != location); + Console.WriteLine(signed.AbsoluteUri); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Net.StringExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.StringExtensions.md new file mode 100644 index 00000000..d4a15a90 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Net.StringExtensions.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.Extensions.Net.StringExtensions +example: +- *content +--- + +The following example demonstrates how to URL-encode and URL-decode strings directly using StringExtensions, with support for custom encodings and null-safe handling. + +```csharp +using System.Text; +using System; +using Cuemon.Extensions.Net; +using Cuemon.Text; + +using Cuemon; +namespace MyApp.Extensions.Net +{ + public class StringExtensionsExample + { + public void Demonstrate() + { + // URL-encode a string directly (no Decorator needed) + string encoded = "hello world".UrlEncode(); + Console.WriteLine(encoded); // "hello+world" + + // URL-decode a previously encoded string + string decoded = "hello+world".UrlDecode(); + Console.WriteLine(decoded); // "hello world" + + // Encode with a custom encoding + string encodedUtf32 = "a & b".UrlEncode(o => + { + o.Encoding = Encoding.UTF32; + }); + + // Encode query-string special characters + string queryEncoded = "name=Jane Doe&city=Copenhagen".UrlEncode(); + Console.WriteLine(queryEncoded); // "name%3dJane+Doe%26city%3dCopenhagen" + + // Decode back + string queryDecoded = queryEncoded.UrlDecode(); + Console.WriteLine(queryDecoded); // "name=Jane Doe&city=Copenhagen" + + // Handle null input safely + string nullResult = ((string)null).UrlEncode(); + Console.WriteLine(nullResult == null); // True + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.ObjectExtensions.md b/.docfx/api/types/Cuemon.Extensions.ObjectExtensions.md new file mode 100644 index 00000000..3d1f92ee --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.ObjectExtensions.md @@ -0,0 +1,62 @@ +--- +uid: Cuemon.Extensions.ObjectExtensions +example: +- *content +--- + +The following example demonstrates how to use the to wrap, convert, and adjust objects. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon.Extensions; + +namespace MyApp.Examples; + +public static class ObjectExtensionsExample +{ + public static void Demonstrate() + { + object raw = "42"; + int number = raw.As(0); + int fallback = "not-a-number".As(99); + object nullValue = null; + int safe = nullValue.As(0); + string upper = "hello".As(value => value.ToUpperInvariant()); + object converted = raw.As(typeof(int)); + + var wrapped = "docs".UseWrapper(extender => + { + extender["source"] = "example"; + }); + + var memberWrapped = 42.UseWrapper(typeof(int).GetMethod("ToString"), data => + { + data["category"] = "number"; + }); + + var numbers = new List { 1, 2, 3 }; + var adjusted = numbers.Adjust(list => + { + var copy = new List(list); + copy.Add(4); + return copy; + }); + var altered = numbers.Alter(list => list.Add(4)); + string delimited = adjusted.ToDelimitedString(options => options.Delimiter = ";"); + + Console.WriteLine(number); + Console.WriteLine(fallback); + Console.WriteLine(safe); + Console.WriteLine(upper); + Console.WriteLine(converted); + Console.WriteLine(wrapped.Data["source"]); + Console.WriteLine(memberWrapped.MemberReference?.Name); + Console.WriteLine(adjusted.GetHashCode32()); + Console.WriteLine(altered.GetHashCode64()); + Console.WriteLine(delimited); + Console.WriteLine(default(int?).IsNullable()); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Reflection.AssemblyExtensions.md b/.docfx/api/types/Cuemon.Extensions.Reflection.AssemblyExtensions.md new file mode 100644 index 00000000..51ede81b --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Reflection.AssemblyExtensions.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.Extensions.Reflection.AssemblyExtensions +example: +- *content +--- + +The following example demonstrates how to retrieve assembly version, file version, and product version information from an assembly using AssemblyExtensions. + +```csharp +using System; +using System.Reflection; +using Cuemon.Extensions.Reflection; + +namespace MyApp.Reflection +{ + public class AssemblyExtensionsExample + { + public void Demonstrate() + { + var assembly = typeof(AssemblyExtensionsExample).Assembly; + + // Get the assembly version (from AssemblyVersionAttribute) + var assemblyVersion = assembly.GetAssemblyVersion(); + Console.WriteLine($"Assembly version: {assemblyVersion}"); // e.g., "1.0.0.0" + Console.WriteLine($"Has alphanumeric version: {assemblyVersion.HasAlphanumericVersion}"); // False + Console.WriteLine($"Is semantic version: {assemblyVersion.IsSemanticVersion()}"); // False + + // Get the file version (from AssemblyFileVersionAttribute) + var fileVersion = assembly.GetFileVersion(); + Console.WriteLine($"File version: {fileVersion}"); // e.g., "1.0.0.0" + + // Get the product version (from AssemblyInformationalVersionAttribute) + var productVersion = assembly.GetProductVersion(); + Console.WriteLine($"Product version: {productVersion}"); // e.g., "1.0.0" + Console.WriteLine($"Has alphanumeric version: {productVersion.HasAlphanumericVersion}"); // True (usually) + Console.WriteLine($"Is semantic version: {productVersion.IsSemanticVersion()}"); // True + + // Check if the assembly is a debug build + var isDebug = assembly.IsDebugBuild(); + Console.WriteLine($"Is debug build: {isDebug}"); // True in Debug, False in Release + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Reflection.MemberInfoExtensions.md b/.docfx/api/types/Cuemon.Extensions.Reflection.MemberInfoExtensions.md new file mode 100644 index 00000000..fc968739 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Reflection.MemberInfoExtensions.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.Extensions.Reflection.MemberInfoExtensions +example: +- *content +--- + +The following example demonstrates checking whether a member has specific custom attributes using the extension method. + +```csharp +using System; +using System.ComponentModel; +using System.Reflection; +using Cuemon.Extensions.Reflection; + +namespace MyApp.Examples; + +public class MemberInfoExtensionsExample +{ + [Description("Sample property with a DescriptionAttribute")] + public string AnnotatedProperty { get; set; } + + [Obsolete("This field is obsolete.")] + public string ObsoleteField; + + public string RegularProperty { get; set; } + + public static void Main() + { + var example = new MemberInfoExtensionsExample(); + var members = typeof(MemberInfoExtensionsExample).GetMembers(BindingFlags.Instance | BindingFlags.Public); + + foreach (MemberInfo member in members) + { + bool hasAttributes = member.HasAttributes(typeof(DescriptionAttribute), typeof(ObsoleteAttribute)); + Console.WriteLine($"{member.Name} ({member.MemberType}): has target attributes = {hasAttributes}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Reflection.PropertyInfoExtensions.md b/.docfx/api/types/Cuemon.Extensions.Reflection.PropertyInfoExtensions.md new file mode 100644 index 00000000..fa887e2a --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Reflection.PropertyInfoExtensions.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.Extensions.Reflection.PropertyInfoExtensions +example: +- *content +--- + +The following example demonstrates how to detect whether a property uses an auto-implemented backing field. + +```csharp +using System; +using System.Reflection; +using Cuemon.Extensions.Reflection; + +namespace MyApp.Examples; + +public static class PropertyInfoExtensionsExample +{ + public static void Demonstrate() + { + var autoProperty = typeof(Sample).GetProperty(nameof(Sample.AutoProperty), BindingFlags.Instance | BindingFlags.Public); + var manualProperty = typeof(Sample).GetProperty(nameof(Sample.ManualProperty), BindingFlags.Instance | BindingFlags.Public); + + Console.WriteLine(autoProperty.IsAutoProperty()); + Console.WriteLine(manualProperty.IsAutoProperty()); + } + + private sealed class Sample + { + private string _manual; + + public string AutoProperty { get; set; } + + public string ManualProperty + { + get => _manual; + set => _manual = value ?? throw new ArgumentNullException(nameof(value)); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Reflection.TypeExtensions.md b/.docfx/api/types/Cuemon.Extensions.Reflection.TypeExtensions.md new file mode 100644 index 00000000..daf41ae2 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Reflection.TypeExtensions.md @@ -0,0 +1,66 @@ +--- +uid: Cuemon.Extensions.Reflection.TypeExtensions +example: +- *content +--- + +The following example demonstrates how to inspect a type hierarchy and member set with . + +```csharp +using System; +using System.IO; +using System.Linq; +using Cuemon; +using Cuemon.Extensions.Reflection; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public static class TypeExtensionsExample +{ + public static void Demonstrate() + { + var streamType = typeof(Stream); + var derivedTypes = streamType.GetDerivedTypes().Where(type => type.IsPublic).Select(type => type.Name).Take(3).ToArray(); + var inheritedTypes = streamType.GetInheritedTypes().Select(type => type.Name).ToArray(); + var properties = typeof(TypeArgumentOutOfRangeException).GetAllProperties().Select(property => property.Name).ToArray(); + var events = typeof(TypeCatalog).GetAllEvents().Select(@event => @event.Name).ToArray(); + var fields = typeof(TypeCatalog).GetAllFields().Select(field => field.Name).ToArray(); + var methods = typeof(TypeCatalog).GetAllMethods().Select(method => method.Name).ToArray(); + var hierarchy = typeof(Stream).GetHierarchyTypes().Select(type => type.Name).ToArray(); + var resources = typeof(TypeExtensionsExample).GetEmbeddedResources("missing", ManifestResourceMatch.ContainsName); + var ownProperties = typeof(TypeCatalog).GetRuntimePropertiesExceptOf().Select(property => property.Name).ToArray(); + var fullName = typeof(TypeCatalog).ToFullNameIncludingAssemblyName(); + + Console.WriteLine(string.Join(", ", derivedTypes)); + Console.WriteLine(string.Join(", ", inheritedTypes)); + Console.WriteLine(properties.Contains(nameof(TypeArgumentOutOfRangeException.ActualValue))); + Console.WriteLine(events.Contains(nameof(TypeCatalog.Changed))); + Console.WriteLine(fields.Contains(nameof(TypeCatalog._state))); + Console.WriteLine(methods.Contains(nameof(TypeCatalog.MarkChanged))); + Console.WriteLine(hierarchy.Contains(nameof(Stream))); + Console.WriteLine(resources.Count); + Console.WriteLine(ownProperties.Contains(nameof(TypeCatalog.Name))); + Console.WriteLine(fullName.Contains(nameof(TypeCatalog))); + } + + private abstract class BaseCatalog + { + public int Id { get; set; } + } + + private sealed class TypeCatalog : BaseCatalog + { + internal string _state = "draft"; + + public string Name { get; set; } = "Extensions"; + + public event EventHandler Changed; + + public void MarkChanged() + { + Changed?.Invoke(this, EventArgs.Empty); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.RoundOffAccuracy.md b/.docfx/api/types/Cuemon.Extensions.RoundOffAccuracy.md new file mode 100644 index 00000000..4b66a909 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.RoundOffAccuracy.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.Extensions.RoundOffAccuracy +example: +- *content +--- + +The following example demonstrates how to use the enum with the extension method to round double values to the nearest specified accuracy. + +```csharp +using System; +using Cuemon.Extensions; + +namespace MyApp.Examples; + +public static class RoundOffAccuracyExample +{ + public static void Demonstrate() + { + double value = 123456789.987654321d; + + Console.WriteLine(value.RoundOff(RoundOffAccuracy.NearestTenth)); + Console.WriteLine(value.RoundOff(RoundOffAccuracy.NearestHundredth)); + Console.WriteLine(value.RoundOff(RoundOffAccuracy.NearestThousandth)); + Console.WriteLine(value.RoundOff(RoundOffAccuracy.NearestMillion)); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.md b/.docfx/api/types/Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.md new file mode 100644 index 00000000..ab4eea86 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions +example: +- *content +--- + +The following example demonstrates how to cache a generated value and memoize a delegate with . + +```csharp +using System; +using Cuemon.Extensions.Runtime.Caching; +using Cuemon.Runtime.Caching; + +namespace MyApp.Examples; + +public static class CacheEnumerableExtensionsExample +{ + public static void Demonstrate() + { + ICacheEnumerable cache = new SlimMemoryCache(); + + var timestamp = cache.GetOrAdd("current-time", TimeSpan.FromSeconds(30), () => DateTime.UtcNow.ToString("O")); + var cachedAgain = cache.GetOrAdd("current-time", TimeSpan.FromSeconds(30), () => "should-not-be-used"); + + var memoized = cache.Memoize(TimeSpan.FromSeconds(30), () => 42); + + Console.WriteLine(timestamp == cachedAgain); + Console.WriteLine(memoized()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Runtime.Hierarchy.md b/.docfx/api/types/Cuemon.Extensions.Runtime.Hierarchy.md new file mode 100644 index 00000000..9823d73b --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Runtime.Hierarchy.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.Extensions.Runtime.Hierarchy +example: +- *content +--- + +```csharp +using System; +using System.Linq; +using Cuemon.Extensions.Runtime; + +namespace Cuemon.Extensions.Runtime; + +public class HierarchyExample +{ + public void Demonstrate() + { + var root = new Hierarchy(); + root.Add("root"); + + var child1 = root.Add("department"); + var child2 = root.Add("team"); + + child1.Add("employee1"); + child1.Add("employee2"); + + Console.WriteLine(root.GetPath()); + Console.WriteLine(child1.GetPath(n => n.Instance.ToString().ToUpper())); + + var matches = Hierarchy.Find(root, n => n.Instance.ToString().StartsWith("employee")); + Console.WriteLine($"Found {matches.Count()} node(s)"); + + var obj = new { Name = "Root", Items = new[] { new { Id = 1 }, new { Id = 2 } } }; + IHierarchy tree = Hierarchy.GetObjectHierarchy(obj); + Console.WriteLine(tree.GetPath(n => n.InstanceType.Name)); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Runtime.HierarchyDecoratorExtensions.md b/.docfx/api/types/Cuemon.Extensions.Runtime.HierarchyDecoratorExtensions.md new file mode 100644 index 00000000..4e38ff56 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Runtime.HierarchyDecoratorExtensions.md @@ -0,0 +1,152 @@ +--- +uid: Cuemon.Extensions.Runtime.HierarchyDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the to navigate a hierarchy, replace matching nodes, and materialize typed values from nodes. + +```csharp +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Cuemon; +using Cuemon.Extensions.Runtime; + +namespace MyApp.Examples; + +public static class HierarchyDecoratorExtensionsExample +{ + public static void Demonstrate() + { + var root = BuildStringHierarchy(out var childOne, out var grandchild, out _); + + var rootNode = Decorator.Enclose(grandchild).Root(); + var ancestors = Decorator.Enclose(grandchild).AncestorsAndSelf().Select(node => node.Instance).ToArray(); + var descendants = Decorator.Enclose(root).DescendantsAndSelf().Select(node => node.Instance).ToArray(); + var siblings = Decorator.Enclose(childOne).SiblingsAndSelf().Select(node => node.Instance).ToArray(); + var nodesAtDepth = Decorator.Enclose(grandchild).SiblingsAndSelfAt(1).Select(node => node.Instance).ToArray(); + var flattened = Decorator.Enclose(childOne).FlattenAll().Select(node => node.Instance).ToArray(); + var firstChildName = Decorator.Enclose(root).FindFirstInstance(node => node.Instance.StartsWith("child", StringComparison.Ordinal)); + var grandchildName = Decorator.Enclose(root).FindSingleInstance(node => node.Instance == "grandchild"); + var firstChildNode = Decorator.Enclose(root).FindFirst(node => node.Depth == 1); + var grandchildNode = Decorator.Enclose(root).FindSingle(node => node.Instance == "grandchild"); + var childNames = Decorator.Enclose(root).FindInstance(node => node.Depth == 1).OrderBy(name => name).ToArray(); + var childNodes = Decorator.Enclose(root).Find(node => node.Depth == 1).ToArray(); + var indexedNode = Decorator.Enclose(root).NodeAt(2); + + Decorator.Enclose(grandchild).Replace((node, value) => node.Replace(value.ToUpperInvariant())); + Decorator.Enclose(Decorator.Enclose(root).Find(node => node.Depth == 1)).ReplaceAll((node, value) => node.Replace(value.ToUpperInvariant())); + + var integerNode = BuildDataPairHierarchy(new DataPair(typeof(int).Name, "42", typeof(string))); + var timestamp = new DateTime(2024, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var dateTimeNode = BuildDataPairHierarchy(new DataPair("When", timestamp, typeof(DateTime))); + var guid = Guid.Parse("11111111-2222-3333-4444-555555555555"); + var guidNode = BuildDataPairHierarchy(new DataPair("Value", guid.ToString("D"), typeof(string))); + var stringNode = BuildDataPairHierarchy(new DataPair("Text", "hello", typeof(string))); + var decimalNode = BuildDataPairHierarchy(new DataPair("Amount", "42.5", typeof(string))); + var uri = new Uri("https://example.com/path?value=42", UriKind.Absolute); + var uriNode = BuildDataPairHierarchy(new DataPair("OriginalString", uri.OriginalString, typeof(string))); + + var typedValues = new object[] + { + Decorator.Enclose(integerNode).UseConvertibleFormatter(), + Decorator.Enclose(dateTimeNode).UseDateTimeFormatter(), + Decorator.Enclose(guidNode).UseGuidFormatter(), + Decorator.Enclose(stringNode).UseStringFormatter(), + Decorator.Enclose(decimalNode).UseDecimalFormatter(), + Decorator.Enclose(uriNode).UseUriFormatter() + }; + + ICollection prices = Decorator.Enclose(BuildCollectionHierarchy(typeof(decimal), "42.5", "84.0")).UseCollection(typeof(decimal)); + IDictionary milestones = Decorator.Enclose(BuildDictionaryHierarchy( + typeof(DateTime), + new KeyValuePair("created", timestamp), + new KeyValuePair("updated", timestamp.AddHours(2)))) + .UseDictionary(new[] { typeof(string), typeof(DateTime) }); + + Console.WriteLine(rootNode.Instance); + Console.WriteLine(string.Join(" > ", ancestors)); + Console.WriteLine(string.Join(", ", descendants)); + Console.WriteLine(string.Join(", ", siblings)); + Console.WriteLine(string.Join(", ", nodesAtDepth)); + Console.WriteLine(string.Join(", ", flattened)); + Console.WriteLine(firstChildName); + Console.WriteLine(grandchildName); + Console.WriteLine(firstChildNode.Instance); + Console.WriteLine(grandchildNode.Instance); + Console.WriteLine(string.Join(", ", childNames)); + Console.WriteLine(childNodes.Length); + Console.WriteLine(indexedNode.Instance); + Console.WriteLine(grandchild.Instance); + Console.WriteLine(string.Join(", ", root.GetChildren().Select(node => node.Instance))); + Console.WriteLine(string.Join(", ", typedValues)); + Console.WriteLine(string.Join(", ", prices.Cast())); + Console.WriteLine(string.Join(", ", milestones.Keys.Cast())); + } + + private static Hierarchy BuildStringHierarchy(out IHierarchy childOne, out IHierarchy grandchild, out IHierarchy childTwo) + { + var root = new Hierarchy(); + root.Add("root"); + childOne = root.Add("child-one"); + grandchild = childOne.Add("grandchild"); + childTwo = root.Add("child-two"); + return root; + } + + private static IHierarchy BuildDataPairHierarchy(DataPair pair) + { + var hierarchy = new Hierarchy(); + hierarchy.Add(pair); + return hierarchy; + } + + private static IHierarchy BuildCollectionHierarchy(Type valueType, params object[] values) + { + var hierarchy = new Hierarchy(); + hierarchy.Add(new DataPair("Items", null, typeof(List))); + foreach (var value in values) + { + hierarchy.Add(CreateValuePair(valueType, value)); + } + + return hierarchy; + } + + private static IHierarchy BuildDictionaryHierarchy(Type valueType, params KeyValuePair[] values) + { + var hierarchy = new Hierarchy(); + hierarchy.Add(new DataPair("Entries", null, typeof(Dictionary))); + foreach (var value in values) + { + var keyNode = hierarchy.Add(new DataPair("Key", value.Key, typeof(string))); + keyNode.Add(CreateValuePair(valueType, value.Value)); + } + + return hierarchy; + } + + private static DataPair CreateValuePair(Type valueType, object value) + { + if (valueType.IsPrimitive) + { + return new DataPair(valueType.Name, value, value.GetType()); + } + + if (valueType == typeof(Uri)) + { + return new DataPair("OriginalString", value, typeof(string)); + } + + if (valueType == typeof(DateTime)) + { + return new DataPair("When", value, typeof(DateTime)); + } + + return new DataPair("Value", value, value?.GetType() ?? typeof(object)); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Runtime.HierarchyOptions.md b/.docfx/api/types/Cuemon.Extensions.Runtime.HierarchyOptions.md new file mode 100644 index 00000000..21cd8682 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Runtime.HierarchyOptions.md @@ -0,0 +1,54 @@ +--- +uid: Cuemon.Extensions.Runtime.HierarchyOptions +example: +- *content +--- + +The following example demonstrates how to configure to control the depth of object hierarchy traversal and skip specific property types. + +```csharp +using System; +using System.Linq; +using Cuemon.Extensions.Runtime; + +namespace MyApp.Examples; + +public class HierarchyOptionsExample +{ + public void Demonstrate() + { + // Direct instantiation of HierarchyOptions + var hierarchyOptions = new HierarchyOptions + { + MaxDepth = 2, + SkipPropertyType = t => t == typeof(string) || t.IsValueType + }; + + var source = new + { + Name = "Root", + Value = 42, + Nested = new + { + Deep = new + { + Deeper = "found" + } + } + }; + + // Limit depth to 2 and skip string types + var hierarchy = Hierarchy.GetObjectHierarchy(source, o => + { + o.MaxDepth = 2; + o.SkipPropertyType = t => t == typeof(string) || t.IsValueType; + }); + + var root = hierarchy; + Console.WriteLine($"Root type: {root.InstanceType.Name}"); // Anonymous type + + var children = root.GetChildren().ToList(); + Console.WriteLine($"Children count: {children.Count}"); // 0 (all primitive types skipped) + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Runtime.Hierarchy`1.md b/.docfx/api/types/Cuemon.Extensions.Runtime.Hierarchy`1.md new file mode 100644 index 00000000..2c08b531 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Runtime.Hierarchy`1.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Extensions.Runtime.Hierarchy`1 +example: +- *content +--- + +The following example demonstrates how to build a tree structure using and navigate nodes through parent-child relationships, depth, index, and path. + +```csharp +using System; +using System.Linq; +using Cuemon.Extensions.Runtime; + +namespace MyApp.Examples; + +public class HierarchyOfTExample +{ + public void Demonstrate() + { + var root = new Hierarchy(); + var rootNode = root.Add("Root"); + var child = root.Add("Child"); + var grandchild = child.Add("Grandchild"); + var sibling = root.Add("Sibling"); + + Console.WriteLine($"Root depth: {root.Depth}, index: {root.Index}"); // 0, 0 + Console.WriteLine($"Child depth: {child.Depth}, index: {child.Index}"); // 1, 1 + Console.WriteLine($"Grandchild depth: {grandchild.Depth}"); // 2 + Console.WriteLine($"Path: {grandchild.GetPath()}"); // Root.Child.Grandchild + Console.WriteLine($"HasChildren: {root.HasChildren}"); // True + Console.WriteLine($"HasParent: {child.HasParent}"); // True + + // Retrieve via indexer + Console.WriteLine(root[0].Instance); // Root + Console.WriteLine(root[2].Instance); // Grandchild + + // Enumerate children + foreach (var node in root.GetChildren()) + { + Console.WriteLine(node.Instance); + // Output: Child, Sibling + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Runtime.Serialization.HierarchySerializer.md b/.docfx/api/types/Cuemon.Extensions.Runtime.Serialization.HierarchySerializer.md new file mode 100644 index 00000000..b886b195 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Runtime.Serialization.HierarchySerializer.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.Extensions.Runtime.Serialization.HierarchySerializer +example: +- *content +--- + +The following example demonstrates how to use to convert any object graph into a hierarchical node structure and display its path-based tree representation. + +```csharp +using System; +using Cuemon.Extensions.Runtime.Serialization; + +namespace MyApp.Examples; + +public static class HierarchySerializerExample +{ + private sealed class ReportRoot + { + public string Name { get; set; } = string.Empty; + + public ReportChild Child { get; set; } = new ReportChild(); + } + + private sealed class ReportChild + { + public int Count { get; set; } + } + + public static void Demonstrate() + { + var serializer = new HierarchySerializer(new ReportRoot + { + Name = "alpha", + Child = new ReportChild { Count = 7 } + }); + + Console.WriteLine(serializer.Nodes.InstanceType.Name); + Console.WriteLine(serializer.Nodes.HasChildren); + Console.WriteLine(serializer.ToString()); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.StringExtensions.md b/.docfx/api/types/Cuemon.Extensions.StringExtensions.md new file mode 100644 index 00000000..9ca0cb4c --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.StringExtensions.md @@ -0,0 +1,101 @@ +--- +uid: Cuemon.Extensions.StringExtensions +example: +- *content +--- + +The following example demonstrates how to use the extension methods to manipulate and inspect a string value. + +```csharp +using System.Text; +using System; +using System.Globalization; +using Cuemon; +using Cuemon.Extensions; +using Cuemon.Text; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + + var value = " Hello, World! "; + + // Trim all whitespace characters + var trimmed = value.TrimAll(); // "Hello,World!" + + // Convert to different casing styles + var lower = value.ToCasing(CasingMethod.LowerCase); // " hello, world! " + var upper = value.ToCasing(CasingMethod.UpperCase); // " HELLO, WORLD! " + var title = value.ToCasing(CasingMethod.TitleCase, new CultureInfo("en-US")); // " Hello, World! " + + // Check string characteristics + bool isEmail = value.IsEmailAddress(); // false + bool isGuid = value.IsGuid(); // false + bool isHex = value.IsHex(); // false + bool isNumeric = value.IsNumeric(); // false + bool isBase64 = value.IsBase64(); // false + + // Substring operations + var before = value.SubstringBefore(","); // " Hello" + var after = value.SuffixWithForwardingSlash(); // " Hello, World! /" + var prefixed = value.PrefixWith(">>"); // ">> Hello, World! " + + // Remove and replace + var removed = value.RemoveAll(" ", "!"); // "Hello,World" + var replaced = value.ReplaceAll("world", "Earth"); // " Hello, Earth! " + + // Contains checks + bool hasHello = value.ContainsAny("Hello", "World"); // true + bool hasAll = value.ContainsAll("Hello", "World"); // true + bool hasChar = value.ContainsAny('o', 'x'); // true + + // Equality checks + bool equalsAny = "yes".EqualsAny("yes", "no"); // true + + // StartsWith + bool starts = value.StartsWith(" Hello"); // true + + // Chunk + var chunks = "abcdefgh".Chunk(3); // ["abc", "def", "gh"] + + // Encoding conversions + byte[] bytes = "Hello".ToByteArray(o => o.Encoding = Encoding.UTF8); + string hex = "Hello".ToHexadecimal(); + string fromHex = hex.FromHexadecimal(); + + // Base64 + byte[] base64Bytes = "SGVsbG8=".FromBase64(); + + // Enum parsing + var day = "Monday".ToEnum(); // DayOfWeek.Monday + + // TimeSpan from string + var ts = "42".ToTimeSpan(TimeUnit.Minutes); // 00:42:00 + + // Delimited string splitting + string csv = "apple,\"orange, citrus\",banana"; + string[] parts = csv.SplitDelimited(); // ["apple", "orange, citrus", "banana"] + + // Validate a sequence of strings against a target type + bool isIntegerSequence = new[] { "1", "2", "3" }.IsSequenceOf(); // true + + // Additional string utilities + int charCount = "hello".Count('l'); // 2 + string diff = "hello".Difference("world"); // "world" + var biDigits = "1101".FromBinaryDigits(); // new byte[] { 13 } + var urlB64 = "SGVsbG8=".FromUrlEncodedBase64(); // "Hello" + bool emptyCheck = "".IsNullOrEmpty(); // true + bool whiteSpaceCheck = " ".IsNullOrWhiteSpace(); // true + string jsEsc = "hello's".JsEscape(); // "hello\\u0027s" + string jsUnesc = "hello\\u0027s".JsUnescape(); // "hello's" + string suffixed = "hello".SuffixWith(" world"); // "hello world" + Guid asGuid = "550e8400-e29b-41d4-a716-446655440000".ToGuid(); + Uri asUri = "https://example.com".ToUri(); + Console.WriteLine(isIntegerSequence); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.TesterFuncFactory.md b/.docfx/api/types/Cuemon.Extensions.TesterFuncFactory.md new file mode 100644 index 00000000..9bff3609 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.TesterFuncFactory.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.Extensions.TesterFuncFactory +example: +- *content +--- + +```csharp +using System; +using Cuemon; +using Cuemon.Extensions; + +namespace Cuemon.Extensions; + +public class TesterFuncFactoryExample +{ + public void Demonstrate() + { + TesterFunc tryParse = (string input, out int result) => int.TryParse(input, out result); + + var factory = TesterFuncFactory.Create(tryParse, "42"); + bool success = factory.ExecuteMethod(out int value); + Console.WriteLine($"Parsed: {value}, Success: {success}"); + + var failFactory = TesterFuncFactory.Create(tryParse, "not-a-number"); + bool failed = failFactory.ExecuteMethod(out int fallback); + Console.WriteLine($"Fallback: {fallback}, Success: {failed}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.EncodingOptionsExtensions.md b/.docfx/api/types/Cuemon.Extensions.Text.EncodingOptionsExtensions.md new file mode 100644 index 00000000..a162e608 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.EncodingOptionsExtensions.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.Extensions.Text.EncodingOptionsExtensions +example: +- *content +--- + +The following example demonstrates detecting the Unicode encoding of a byte array or stream using the and extension methods. + +```csharp +using System; +using System.IO; +using System.Text; +using Cuemon.Extensions.Text; +using Cuemon.Text; + +namespace MyApp.Examples; + +public class EncodingOptionsExtensionsExample +{ + public static void Main() + { + // Create an EncodingOptions instance with a fallback encoding + var options = new EncodingOptions { Encoding = Encoding.UTF8 }; + + // Byte array with UTF-8 BOM + byte[] utf8WithBom = { 0xEF, 0xBB, 0xBF, 0x48, 0x65, 0x6C, 0x6C, 0x6F }; + + // Detect encoding from bytes + Encoding detected = options.DetectUnicodeEncoding(utf8WithBom); + Console.WriteLine($"Detected encoding from bytes: {detected.EncodingName}"); + + // Stream with UTF-16 LE BOM + using var stream = new MemoryStream(); + byte[] utf16Bom = { 0xFF, 0xFE, 0x48, 0x00, 0x65, 0x00, 0x6C, 0x00 }; + stream.Write(utf16Bom, 0, utf16Bom.Length); + stream.Position = 0; + + Encoding streamEncoding = options.DetectUnicodeEncoding(stream); + Console.WriteLine($"Detected encoding from stream: {streamEncoding.EncodingName}"); + + // When no BOM is present, the fallback encoding is returned + byte[] noBom = { 0x48, 0x65, 0x6C, 0x6C, 0x6F }; + Encoding fallback = options.DetectUnicodeEncoding(noBom); + Console.WriteLine($"Fallback encoding: {fallback.EncodingName}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.DateTimeConverter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.DateTimeConverter.md new file mode 100644 index 00000000..78eb65db --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.DateTimeConverter.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Extensions.Text.Json.Converters.DateTimeConverter +example: +- *content +--- + +The following example demonstrates how to register and use the to serialize and deserialize values with a custom format and culture-specific formatting. + +```csharp +using System; +using System.Globalization; +using System.Text.Json; +using Cuemon.Extensions.Text.Json.Converters; + +namespace MyApp.Examples; + +public class DateTimeConverterExample +{ + public void Demonstrate() + { + var options = new JsonSerializerOptions(); + + // Register a converter that writes dates in the French "dd/MM/yyyy" format + options.Converters.Add(new DateTimeConverter("dd/MM/yyyy", new CultureInfo("fr-FR"))); + + var original = new DateTime(2026, 6, 16, 14, 30, 0, DateTimeKind.Utc); + + string json = JsonSerializer.Serialize(original, options); + Console.WriteLine(json); // "16/06/2026" + + var restored = JsonSerializer.Deserialize(json, options); + Console.WriteLine(restored.ToString("dd/MM/yyyy")); // 16/06/2026 + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.ExceptionConverter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.ExceptionConverter.md new file mode 100644 index 00000000..5218675b --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.ExceptionConverter.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.Extensions.Text.Json.Converters.ExceptionConverter +example: +- *content +--- + +The following example demonstrates how to serialize an to JSON including its stack trace and data dictionary. + +```csharp +using System; +using System.Text.Json; +using Cuemon.Extensions.Text.Json.Converters; + +namespace MyApp.Examples; + +public class ExceptionConverterExample +{ + public void Demonstrate() + { + var options = new JsonSerializerOptions + { + WriteIndented = true + }; + + // Include both stack trace and exception data + options.Converters.Add(new ExceptionConverter(includeStackTrace: true, includeData: true)); + + var inner = new InvalidOperationException("Inner operation failed."); + var ex = new InvalidOperationException("Outer operation failed.", inner); + ex.Data["CorrelationId"] = "abc-123"; + + string json = JsonSerializer.Serialize(ex, options); + Console.WriteLine(json); + // { + // "Type": "System.InvalidOperationException", + // "Source": "...", + // "Message": "Outer operation failed.", + // "Stack": [ " at ..." ], + // "Data": { "CorrelationId": "abc-123" }, + // "Inner": { + // "Type": "System.InvalidOperationException", + // "Message": "Inner operation failed." + // } + // } + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.JsonConverterCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.JsonConverterCollectionExtensions.md new file mode 100644 index 00000000..1fa0c612 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.JsonConverterCollectionExtensions.md @@ -0,0 +1,64 @@ +--- +uid: Cuemon.Extensions.Text.Json.Converters.JsonConverterCollectionExtensions +example: +- *content +--- + +The following example demonstrates how to use the to configure a custom with specialized converters. + +```csharp +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; +using Cuemon; +using Cuemon.Diagnostics; +using Cuemon.Extensions.Text.Json.Converters; +using Cuemon.Extensions.Text.Json.Formatters; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + var converters = new List(); + converters.AddDateTimeConverter("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + converters.AddStringEnumConverter(); + converters.AddStringFlagsEnumConverter(); + converters.AddExceptionConverter(true, false); + converters.AddFailureConverter(); + converters.AddTransientFaultExceptionConverter(); + converters.AddExceptionDescriptorConverterOf( + o => o.SensitivityDetails = FaultSensitivityDetails.All); + converters.AddDataPairConverter(); + converters.RemoveAllOf(); + converters.RemoveAllOf(typeof(TimeSpan)); + + var formatter = new JsonFormatter(o => + { + o.Settings.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + foreach (var converter in converters) + { + o.Settings.Converters.Add(converter); + } + }); + + var person = new { FullName = "Alice Johnson", BirthDate = new DateTime(1990, 6, 15) }; + using var jsonStream = JsonFormatter.SerializeObject(person, options => + { + options.Settings.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + foreach (var converter in converters) + { + options.Settings.Converters.Add(converter); + } + }); + jsonStream.Position = 0; + using var reader = new System.IO.StreamReader(jsonStream); + string json = reader.ReadToEnd(); + Console.WriteLine(json); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringEnumConverter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringEnumConverter.md new file mode 100644 index 00000000..9391952b --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringEnumConverter.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.Extensions.Text.Json.Converters.StringEnumConverter +example: +- *content +--- + +The following example demonstrates how to use the to serialize and deserialize non-flags enum values as their string representation rather than their underlying integer value. + +```csharp +using System; +using System.Text.Json; +using Cuemon.Extensions.Text.Json.Converters; + +namespace MyApp.Examples; + +public class StringEnumConverterExample +{ + public void Demonstrate() + { + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + options.Converters.Add(new StringEnumConverter()); + + var payload = new { Day = DayOfWeek.Friday, Status = UriKind.Relative }; + + string json = JsonSerializer.Serialize(payload, options); + Console.WriteLine(json); + // { "day": "Friday", "status": "Relative" } + + var restored = JsonSerializer.Deserialize(json, options); + Console.WriteLine(restored.Day); // Friday + } + + public class Payload + { + public DayOfWeek Day { get; set; } + public UriKind Status { get; set; } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringFlagsEnumConverter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringFlagsEnumConverter.md new file mode 100644 index 00000000..854110ef --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringFlagsEnumConverter.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.Extensions.Text.Json.Converters.StringFlagsEnumConverter +example: +- *content +--- + +The following example demonstrates how to use the to serialize and deserialize enum values decorated with as an array of strings. + +```csharp +using System; +using System.IO; +using System.Text.Json; +using Cuemon.Extensions.Text.Json.Converters; + +namespace MyApp.Examples; + +public class StringFlagsEnumConverterExample +{ + public void Demonstrate() + { + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + options.Converters.Add(new StringFlagsEnumConverter()); + + var value = FileShare.Read | FileShare.Write; + + string json = JsonSerializer.Serialize(value, options); + Console.WriteLine(json); + // ["Read", "Write"] + + var restored = JsonSerializer.Deserialize(json, options); + Console.WriteLine(restored); // Read, Write + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.TransientFaultExceptionConverter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.TransientFaultExceptionConverter.md new file mode 100644 index 00000000..2a332b13 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.TransientFaultExceptionConverter.md @@ -0,0 +1,95 @@ +--- +uid: Cuemon.Extensions.Text.Json.Converters.TransientFaultExceptionConverter +example: +- *content +--- + +The following example demonstrates how to serialize and deserialize a using the . + +```csharp +using System; +using System.IO; +using System.Text; +using Cuemon.Extensions.Text.Json.Converters; +using Cuemon.Extensions.Text.Json; +using Cuemon.Extensions.Text.Json.Formatters; +using Cuemon.Reflection; +using Cuemon.Resilience; + +namespace MyApp.Examples; + +public class TransientFaultExceptionConverterExample +{ + public void SerializeTransientFaultException() + { + // Create a transient fault exception with evidence + var evidence = new TransientFaultEvidence( + attempts: 3, + recoveryWaitTime: TimeSpan.FromSeconds(2), + totalRecoveryWaitTime: TimeSpan.FromSeconds(6), + latency: TimeSpan.FromMilliseconds(500), + descriptor: new MethodSignature( + "MyService", + "ConnectAsync", + new[] { "connectionString" }, + new object[] { "server=db;timeout=30" })); + + var exception = new TransientFaultException( + "Failed to connect after 3 retries.", + new TimeoutException("Connection timed out."), + evidence); + + // Configure JSON formatter with the converter + var options = new JsonFormatterOptions(); + options.Settings.Converters.Add(new TransientFaultExceptionConverter()); + + // Serialize to JSON + var formatter = new JsonFormatter(options); + using (var stream = formatter.Serialize(exception)) + using (var reader = new StreamReader(stream)) + { + string json = reader.ReadToEnd(); + Console.WriteLine(json); + // The output includes exception details, inner exception, and evidence: + // { + // "type": "Cuemon.Resilience.TransientFaultException", + // "message": "Failed to connect after 3 retries.", + // "evidence": { + // "attempts": 3, + // ... + // } + // } + } + } + + public void DeserializeTransientFaultException() + { + string json = @"{ + ""type"": ""Cuemon.Resilience.TransientFaultException"", + ""message"": ""Failed to connect after 3 retries."", + ""evidence"": { + ""attempts"": 3, + ""recoveryWaitTime"": ""00:00:02"", + ""totalRecoveryWaitTime"": ""00:00:06"", + ""latency"": ""00:00:00.500"", + ""descriptor"": { + ""caller"": ""MyService"", + ""methodName"": ""ConnectAsync"", + ""parameters"": [""connectionString""], + ""arguments"": [""server=db;timeout=30""] +}"; + + var options = new JsonFormatterOptions(); + options.Settings.Converters.Add(new TransientFaultExceptionConverter()); + + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(json))) + { + var formatter = new JsonFormatter(options); + var exception = formatter.Deserialize(stream); + + Console.WriteLine(exception.Message); + Console.WriteLine($"Evidence - Attempts: {exception.Evidence.Attempts}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.DynamicJsonConverter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.DynamicJsonConverter.md new file mode 100644 index 00000000..7a59eb41 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.DynamicJsonConverter.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.Extensions.Text.Json.DynamicJsonConverter +example: +- *content +--- + +```csharp +using System; +using System.Text.Json; +using Cuemon.Extensions.Text.Json; + +namespace Cuemon.Extensions.Text.Json; + +public class DynamicJsonConverterExample +{ + public void Demonstrate() + { + var options = new JsonSerializerOptions(); + options.Converters.Add(DynamicJsonConverter.Create( + writer: (utf8Writer, value, _) => utf8Writer.WriteStringValue(value.ToString()), + reader: (ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions jsonOptions) => Version.Parse(reader.GetString()) + )); + + var version = new Version("5.0.0"); + string json = JsonSerializer.Serialize(version, options); + Console.WriteLine(json); + + var deserialized = JsonSerializer.Deserialize("\"6.0.0\"", options); + Console.WriteLine(deserialized); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Formatters.JsonFormatter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Formatters.JsonFormatter.md new file mode 100644 index 00000000..543ef3fc --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Formatters.JsonFormatter.md @@ -0,0 +1,48 @@ +--- +uid: Cuemon.Extensions.Text.Json.Formatters.JsonFormatter +example: +- *content +--- + +The following example demonstrates how to use `JsonFormatter` to serialize and deserialize objects to and from JSON. + +```csharp +using System; +using System.IO; +using Cuemon; +using Cuemon.IO; +using Cuemon.Extensions.Text.Json.Formatters; + +namespace MyApp.Examples; + +public record Product(int Id, string Name, decimal Price); + +public class Example +{ + public void Run() + { + // Create a JsonFormatter with default settings + var formatter = new JsonFormatter(); + + // Serialize an object to a stream + var product = new Product(1, "Wireless Mouse", 29.99m); + using var jsonStream = formatter.Serialize(product, typeof(Product)); + + // Read the JSON string (leave the stream open for reuse) + Console.WriteLine("Serialized JSON:"); + Console.WriteLine(Decorator.Enclose(jsonStream).ToEncodedString(o => o.LeaveOpen = true)); + + // Reset position and deserialize from the same stream + jsonStream.Position = 0; + var deserialized = (Product)formatter.Deserialize(jsonStream, typeof(Product)); + Console.WriteLine($"Deserialized: Id={deserialized.Id}, Name={deserialized.Name}, Price={deserialized.Price}"); + + // Use static convenience methods + using var json = JsonFormatter.SerializeObject(product); + json.Position = 0; + Console.WriteLine($"Static round-trip: {JsonFormatter.DeserializeObject(json).Name}"); + + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Formatters.JsonFormatterOptions.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Formatters.JsonFormatterOptions.md new file mode 100644 index 00000000..c715b926 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Formatters.JsonFormatterOptions.md @@ -0,0 +1,73 @@ +--- +uid: Cuemon.Extensions.Text.Json.Formatters.JsonFormatterOptions +example: +- *content +--- + +The following example demonstrates how to configure and use it with the JSON formatter to serialize objects. + +```csharp +using System; +using System.IO; +using System.Text.Json; +using System.Text.Json.Serialization; +using Cuemon.Diagnostics; +using Cuemon.Extensions.Text.Json.Formatters; + +namespace MyApp.Examples; + +public class JsonFormatterOptionsExample +{ + public void SerializeWithCustomOptions() + { + // Create options with custom JSON serializer settings + var options = new JsonFormatterOptions + { + Settings = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + PropertyNameCaseInsensitive = true + }, + SensitivityDetails = FaultSensitivityDetails.None + }; + + // Add custom converters + options.Settings.Converters.Add(new JsonStringEnumConverter()); + + var formatter = new JsonFormatter(options); + var payload = new { UserName = "johndoe", Email = "john@example.com", Age = 30 }; + + using (var stream = formatter.Serialize(payload)) + using (var reader = new StreamReader(stream)) + { + string json = reader.ReadToEnd(); + Console.WriteLine(json); + // Output: + // { + // "userName": "johndoe", + // "email": "john@example.com", + // "age": 30 + // } + } + } + + public void ConfigureDefaultMediaType() + { + // Access the default media type for JSON + Console.WriteLine(JsonFormatterOptions.DefaultMediaType); // "application/json" + + // DefaultConverters are applied automatically at static initialization + Console.WriteLine($"Default converters configured: {JsonFormatterOptions.DefaultConverters != null}"); // true + } + + public void ValidateOptions() + { + var options = new JsonFormatterOptions(); + // ValidateOptions throws InvalidOperationException if Settings is null + options.ValidateOptions(); + Console.WriteLine("Options are valid."); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonNamingPolicyExtensions.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonNamingPolicyExtensions.md new file mode 100644 index 00000000..d7f27607 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonNamingPolicyExtensions.md @@ -0,0 +1,41 @@ +--- +uid: Cuemon.Extensions.Text.Json.JsonNamingPolicyExtensions +example: +- *content +--- + +The following example demonstrates applying a naming policy to a property name using the extension method. + +```csharp +using System; +using System.Text.Json; +using Cuemon.Extensions.Text.Json; + +namespace MyApp.Examples; + +public class JsonNamingPolicyExtensionsExample +{ + public static void Main() + { + // Apply camelCase naming policy + JsonNamingPolicy camelCase = JsonNamingPolicy.CamelCase; + string camelName = camelCase.DefaultOrConvertName("OrderDate"); + Console.WriteLine(camelName); // Output: "orderDate" + + // When policy is null, the name is returned unaltered + string unchanged = ((JsonNamingPolicy)null).DefaultOrConvertName("OrderDate"); + Console.WriteLine(unchanged); // Output: "OrderDate" + + // Useful when working with configurable naming policies + JsonSerializerOptions options = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + + string configuredName = options.PropertyNamingPolicy.DefaultOrConvertName("ShippingAddress"); + Console.WriteLine(configuredName); // Output: "shippingAddress" + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonSerializerOptionsExtensions.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonSerializerOptionsExtensions.md new file mode 100644 index 00000000..1284e554 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonSerializerOptionsExtensions.md @@ -0,0 +1,47 @@ +--- +uid: Cuemon.Extensions.Text.Json.JsonSerializerOptionsExtensions +example: +- *content +--- + +The following example demonstrates cloning and applying property naming policies using the and extension methods. + +```csharp +using System; +using System.Text.Json; +using Cuemon.Extensions.Text.Json; + +namespace MyApp.Examples; + +public class JsonSerializerOptionsExtensionsExample +{ + public static void Main() + { + // Create base options with a camelCase naming policy + var baseOptions = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = true + }; + + // Clone the options and override the WriteIndented setting + JsonSerializerOptions cloned = baseOptions.Clone(options => + { + options.WriteIndented = false; + }); + Console.WriteLine($"Original WriteIndented: {baseOptions.WriteIndented}"); // True + Console.WriteLine($"Cloned WriteIndented: {cloned.WriteIndented}"); // False + + // SetPropertyName converts property names according to the naming policy + string propertyName = baseOptions.SetPropertyName("OrderDate"); + Console.WriteLine($"Converted property name: {propertyName}"); // Output: "orderDate" + + // When no naming policy is set, the name is returned unaltered + var plainOptions = new JsonSerializerOptions(); + string unchanged = plainOptions.SetPropertyName("OrderDate"); + Console.WriteLine($"Unchanged property name: {unchanged}"); // Output: "OrderDate" + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonReaderFunc`1.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonReaderFunc`1.md new file mode 100644 index 00000000..07461cdc --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonReaderFunc`1.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.Extensions.Text.Json.Utf8JsonReaderFunc`1 +example: +- *content +--- + +The following example demonstrates how a can deserialize a value inside a dynamic JSON converter. + +```csharp +using System; +using System.Text.Json; +using Cuemon.Extensions.Text.Json; + +namespace MyApp.Examples; + +public static class Utf8JsonReaderFuncExample +{ + public static void Demonstrate() + { + Utf8JsonReaderFunc reader = (ref Utf8JsonReader jsonReader, Type _, JsonSerializerOptions __) => + Guid.Parse(jsonReader.GetString()); + + var converter = DynamicJsonConverter.Create(reader: reader); + var result = JsonSerializer.Deserialize("\"11111111-2222-3333-4444-555555555555\"", new JsonSerializerOptions + { + Converters = { converter } + }); + + Console.WriteLine(result); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonWriterAction`1.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonWriterAction`1.md new file mode 100644 index 00000000..dc5472f2 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonWriterAction`1.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.Extensions.Text.Json.Utf8JsonWriterAction`1 +example: +- *content +--- + +The following example demonstrates how a can serialize a value inside a dynamic JSON converter. + +```csharp +using System; +using System.Text.Json; +using Cuemon.Extensions.Text.Json; + +namespace MyApp.Examples; + +public static class Utf8JsonWriterActionExample +{ + public static void Demonstrate() + { + Utf8JsonWriterAction writer = (jsonWriter, value, _) => + jsonWriter.WriteStringValue(value.ToString("D")); + + var converter = DynamicJsonConverter.Create(writer: writer); + var json = JsonSerializer.Serialize(Guid.Parse("11111111-2222-3333-4444-555555555555"), new JsonSerializerOptions + { + Converters = { converter } + }); + + Console.WriteLine(json); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonWriterExtensions.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonWriterExtensions.md new file mode 100644 index 00000000..a4c635d1 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonWriterExtensions.md @@ -0,0 +1,60 @@ +--- +uid: Cuemon.Extensions.Text.Json.Utf8JsonWriterExtensions +example: +- *content +--- + +The following example demonstrates writing a dynamic object to JSON using the extension method. + +```csharp +using System; +using System.IO; +using System.Text; +using System.Text.Json; +using Cuemon.Extensions.Text.Json; + +namespace MyApp.Examples; + +public class Utf8JsonWriterExtensionsExample +{ + public class Person + { + public string Name { get; set; } + public int Age { get; set; } + public string City { get; set; } + + public static void Main() + { + var person = new Person + { + Name = "John Doe", + Age = 42, + City = "Copenhagen" + }; + + var options = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + WriteIndented = true + }; + + using var stream = new MemoryStream(); + using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions { Indented = true }); + + // Write the object directly to the Utf8JsonWriter + writer.WriteObject(person, options); + writer.Flush(); + + string json = Encoding.UTF8.GetString(stream.ToArray()); + Console.WriteLine(json); + // Output: + // { + // "name": "John Doe", + // "age": 42, + // "city": "Copenhagen" + // } + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Text.StringExtensions.md b/.docfx/api/types/Cuemon.Extensions.Text.StringExtensions.md new file mode 100644 index 00000000..3da4170d --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Text.StringExtensions.md @@ -0,0 +1,68 @@ +--- +uid: Cuemon.Extensions.Text.StringExtensions +example: +- *content +--- + +The following example demonstrates how to encode strings between different character encodings using StringExtensions, with support for fallback handling and ASCII sanitization. + +```csharp +using System; +using System.Text; +using Cuemon.Extensions.Text; +using Cuemon.Text; + +namespace MyApp.Text +{ + public class StringExtensionsExample + { + public void Demonstrate() + { + // ToEncodedString - encodes a string to a different encoding with fallback handling + var withSpecialChars = "Café au lait: 2,50 €"; + + // Default: uses ExceptionFallback, will throw for unrepresentable chars + var encoded = withSpecialChars.ToEncodedString(o => + { + o.TargetEncoding = Encoding.UTF8; + }); + Console.WriteLine(encoded); // "Café au lait: 2,50 €" + + // Convert to ASCII with replacement fallback + var asciiResult = withSpecialChars.ToEncodedString(o => + { + o.TargetEncoding = Encoding.ASCII; + o.EncoderFallback = new EncoderReplacementFallback("?"); + }); + Console.WriteLine(asciiResult); // "Caf? au lait: 2,50 ?" + + // Convert to Windows-1252 (Western European) + var win1252 = withSpecialChars.ToEncodedString(o => + { + o.TargetEncoding = Encoding.GetEncoding(1252); + o.EncoderFallback = new EncoderReplacementFallback("?"); + }); + Console.WriteLine(win1252); // preserves most of the special chars + + // ToAsciiEncodedString - quick ASCII conversion + var asciiQuick = withSpecialChars.ToAsciiEncodedString(); + Console.WriteLine(asciiQuick); // "Cafe au lait: 2,50 " + // Uses EncoderReplacementFallback("") by default, so unsupported chars are removed silently + + // ToAsciiEncodedString with custom encoding options + var asciiCustom = withSpecialChars.ToAsciiEncodedString(o => + { + o.Preamble = PreambleSequence.Remove; + o.Encoding = Encoding.UTF8; + }); + Console.WriteLine(asciiCustom); // same result, no BOM + + // Practical example: sanitize user input to safe ASCII + var userInput = "Hello World — 2025 ©"; + var sanitized = userInput.ToAsciiEncodedString(); + Console.WriteLine(sanitized); // "Hello World 2025 " (em dash and copyright removed) + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Threading.Tasks.TaskExtensions.md b/.docfx/api/types/Cuemon.Extensions.Threading.Tasks.TaskExtensions.md new file mode 100644 index 00000000..a759985d --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Threading.Tasks.TaskExtensions.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.Extensions.Threading.Tasks.TaskExtensions +example: +- *content +--- + +The following example demonstrates how to await a task with or without flowing the captured synchronization context. + +```csharp +using System; +using System.Threading.Tasks; +using Cuemon.Extensions.Threading.Tasks; + +namespace MyApp.Examples +{ + public static class TaskExtensionsExample + { + public static async Task DemonstrateAsync() + { + await Task.Delay(10).ContinueWithCapturedContext(); + await Task.Delay(10).ContinueWithSuppressedContext(); + + var captured = await Task.FromResult(42).ContinueWithCapturedContext(); + var suppressed = await Task.FromResult(42).ContinueWithSuppressedContext(); + + Console.WriteLine(captured); + Console.WriteLine(suppressed); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.TimeSpanExtensions.md b/.docfx/api/types/Cuemon.Extensions.TimeSpanExtensions.md new file mode 100644 index 00000000..c7177859 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.TimeSpanExtensions.md @@ -0,0 +1,33 @@ +--- +uid: Cuemon.Extensions.TimeSpanExtensions +example: +- *content +--- + +The following example demonstrates how to use the extension methods to round, floor, and ceiling values, and to retrieve high-resolution time units. + +```csharp +using System; +using Cuemon; +using Cuemon.Extensions; + +namespace MyApp.Examples; + +public static class TimeSpanExtensionsExample +{ + public static void Demonstrate() + { + var hour = TimeSpan.FromHours(1); + var duration = TimeSpan.FromMinutes(280); + var shortDuration = TimeSpan.FromMinutes(45); + + Console.WriteLine(hour.GetTotalNanoseconds()); + Console.WriteLine(hour.GetTotalMicroseconds()); + Console.WriteLine(duration.Floor(1, TimeUnit.Hours)); + Console.WriteLine(duration.Ceiling(1, TimeUnit.Hours)); + Console.WriteLine(shortDuration.Round(TimeSpan.FromHours(1), VerticalDirection.Up)); + Console.WriteLine(shortDuration.Round(30, TimeUnit.Minutes, VerticalDirection.Down)); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.TypeExtensions.md b/.docfx/api/types/Cuemon.Extensions.TypeExtensions.md new file mode 100644 index 00000000..d6f1a537 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.TypeExtensions.md @@ -0,0 +1,47 @@ +--- +uid: Cuemon.Extensions.TypeExtensions +example: +- *content +--- + +The following example demonstrates how to use the to inspect types with concise extension methods. + +```csharp +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using Cuemon.Extensions; + +namespace MyApp.Examples; + +public static class TypeExtensionsExample +{ + public static void Demonstrate() + { + Type listType = typeof(IList); + Type dictionaryType = typeof(ConcurrentDictionary); + Type comparerType = typeof(StringComparer); + Type nullableInt = typeof(int?); + + Console.WriteLine(listType.ToFriendlyName()); + Console.WriteLine(listType.ToFriendlyName(options => options.FullName = true)); + Console.WriteLine(typeof(string).ToTypeCode()); + Console.WriteLine(listType.HasEnumerableImplementation()); + Console.WriteLine(typeof(string).HasComparableImplementation()); + Console.WriteLine(dictionaryType.HasDictionaryImplementation()); + Console.WriteLine(comparerType.HasEqualityComparerImplementation()); + Console.WriteLine(comparerType.HasComparerImplementation()); + Console.WriteLine(typeof(KeyValuePair).HasKeyValuePairImplementation()); + Console.WriteLine(nullableInt.IsNullable()); + Console.WriteLine(typeof(Stream).IsComplex()); + Console.WriteLine(typeof(int).IsSimple()); + Console.WriteLine(typeof(int).GetDefaultValue()); + Console.WriteLine(typeof(FileStream).HasTypes(typeof(Stream))); + Console.WriteLine(typeof(List<>).HasInterfaces(typeof(IEnumerable<>))); + Console.WriteLine(typeof(string).HasAttributes(typeof(SerializableAttribute))); + Console.WriteLine(new { Name = "sample", Value = 42 }.GetType().HasAnonymousCharacteristics()); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.VerticalDirection.md b/.docfx/api/types/Cuemon.Extensions.VerticalDirection.md new file mode 100644 index 00000000..291b062c --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.VerticalDirection.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.Extensions.VerticalDirection +example: +- *content +--- + +The following example demonstrates how to use the enum to indicate vertical positioning. + +```csharp +using System; +using Cuemon.Extensions; + +namespace MyApp.Examples; + +public static class VerticalDirectionExample +{ + public static void Demonstrate() + { + var upward = VerticalDirection.Up; + var downward = (VerticalDirection)Enum.Parse(typeof(VerticalDirection), "Down"); + + Console.WriteLine($"{upward} = {(int)upward}"); + Console.WriteLine($"{downward} = {(int)downward}"); + Console.WriteLine(default(VerticalDirection)); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Wrapper.md b/.docfx/api/types/Cuemon.Extensions.Wrapper.md new file mode 100644 index 00000000..a47e4e22 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Wrapper.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.Extensions.Wrapper +example: +- *content +--- + +```csharp +using System; +using Cuemon; +using Cuemon.Extensions; + +namespace Cuemon.Extensions; + +public class WrapperExample +{ + public void Demonstrate() + { + var wrapped = new Wrapper(42); + Console.WriteLine(wrapped.Instance); + Console.WriteLine(wrapped.InstanceType); + + string parsed = Wrapper.ParseInstance(wrapped); + Console.WriteLine(parsed); + + int asInt = wrapped.InstanceAs(); + Console.WriteLine(asInt); + + var wrappedString = new Wrapper("Hello, World!"); + Console.WriteLine(Wrapper.ParseInstance(wrappedString)); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Wrapper`1.md b/.docfx/api/types/Cuemon.Extensions.Wrapper`1.md new file mode 100644 index 00000000..bc89ed9e --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Wrapper`1.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.Extensions.Wrapper`1 +example: +- *content +--- + +The following example demonstrates how to use to wrap an object with optional member reference metadata. + +```csharp +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Reflection; +using Cuemon.Extensions; + +namespace MyApp.Examples; + +public static class WrapperExample +{ + private sealed class WrapperExampleModel + { + public string Name { get; set; } = string.Empty; + } + + public static void Demonstrate() + { + PropertyInfo nameProperty = typeof(WrapperExampleModel).GetProperty(nameof(WrapperExampleModel.Name), BindingFlags.Public | BindingFlags.Instance); + var answer = new Wrapper(42, nameProperty); + answer.Data["category"] = "number"; + + var fromText = new Wrapper("42"); + var bytes = new Wrapper(new byte[] { 1, 2, 3, 4 }); + var type = new Wrapper(typeof(Dictionary)); + + Console.WriteLine(answer.Instance); + Console.WriteLine(answer.MemberReference?.Name); + Console.WriteLine(answer.InstanceAs(CultureInfo.InvariantCulture)); + Console.WriteLine(fromText.InstanceAs()); + Console.WriteLine(answer.Data["category"]); + Console.WriteLine(Wrapper.ParseInstance(bytes)); + Console.WriteLine(type.ToString()); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.ByteArrayExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.ByteArrayExtensions.md new file mode 100644 index 00000000..30bca4eb --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Xml.ByteArrayExtensions.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Extensions.Xml.ByteArrayExtensions +example: +- *content +--- + +The following example demonstrates how to convert a byte array to an using the class. + +```csharp +using System; +using System.Text; +using System.Xml; +using Cuemon.Extensions.Xml; + +namespace MyApp.Examples; + +public class ByteArrayExtensionsExample +{ + public void Demonstrate() + { + byte[] xmlData = Encoding.UTF8.GetBytes("Value"); + + // Convert the byte array to an XmlReader + using (XmlReader reader = xmlData.ToXmlReader()) + { + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + Console.WriteLine(reader.Name); + +}}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.DateTimeExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.DateTimeExtensions.md new file mode 100644 index 00000000..18bbbbc6 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Xml.DateTimeExtensions.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Extensions.Xml.DateTimeExtensions +example: +- *content +--- + +The following example demonstrates how to format DateTime values as XML strings using DateTimeExtensions, supporting UTC, local, round-trip, and unspecified serialization modes. + +```csharp +using System; +using System.Xml; +using Cuemon.Extensions.Xml; + +namespace MyApp.Xml +{ + public class DateTimeExtensionsExample + { + public void Demonstrate() + { + DateTime utcNow = DateTime.UtcNow; + + // Format as XML UTC string (appends "Z" for UTC) + string xmlUtc = utcNow.ToString(XmlDateTimeSerializationMode.Utc); + Console.WriteLine(xmlUtc); + // Output: 2026-06-16T12:34:56.789Z + + // Convert local time to XML local string (includes offset) + DateTime localNow = DateTime.Now; + string xmlLocal = localNow.ToString(XmlDateTimeSerializationMode.Local); + Console.WriteLine(xmlLocal); + // Output: 2026-06-16T14:34:56.789+02:00 + + // Round-trip format preserves the Kind information + string xmlRoundtrip = utcNow.ToString(XmlDateTimeSerializationMode.RoundtripKind); + Console.WriteLine(xmlRoundtrip); + // Output: 2026-06-16T12:34:56.789Z + + // Unspecified mode drops any time zone info + string xmlUnspecified = utcNow.ToString(XmlDateTimeSerializationMode.Unspecified); + Console.WriteLine(xmlUnspecified); + // Output: 2026-06-16T12:34:56.789 + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.HierarchyExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.HierarchyExtensions.md new file mode 100644 index 00000000..40d9fe22 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Xml.HierarchyExtensions.md @@ -0,0 +1,57 @@ +--- +uid: Cuemon.Extensions.Xml.HierarchyExtensions +example: +- *content +--- + +The following example demonstrates how to inspect and query XML serialization metadata such as qualified entity names, enumerable detection, and XML ignore attributes using HierarchyExtensions. + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Serialization; +using Cuemon.Extensions.Runtime.Serialization; +using Cuemon.Extensions.Xml; +using Cuemon.Xml.Serialization; + +namespace DocExamples; + +public static class HierarchyExtensionsExample +{ + public static void Demonstrate() + { + var documentNodes = new HierarchySerializer(new CatalogDocument()).Nodes.GetChildren().ToList(); + var idNode = documentNodes.Single(node => node.MemberReference?.Name == nameof(CatalogDocument.Id)); + var tagsNode = documentNodes.Single(node => node.MemberReference?.Name == nameof(CatalogDocument.Tags)); + + var ignoredNodes = new HierarchySerializer(new IgnoredDocument()).Nodes.GetChildren().ToList(); + var hiddenNode = ignoredNodes.Single(node => node.MemberReference?.Name == nameof(IgnoredDocument.Hidden)); + var overrideEntity = new XmlQualifiedEntity("Override"); + + Console.WriteLine(idNode.GetXmlQualifiedEntity().LocalName); + Console.WriteLine(idNode.GetXmlQualifiedEntity(overrideEntity).LocalName); + Console.WriteLine(tagsNode.IsNodeEnumerable()); + Console.WriteLine(hiddenNode.HasXmlIgnoreAttribute()); + + var reordered = new[] { tagsNode, idNode }.OrderByXmlAttributes().ToList(); + Console.WriteLine(reordered[0].MemberReference?.Name); + } + + private sealed class CatalogDocument + { + [XmlAttribute] + public Guid Id { get; } = Guid.Empty; + + public List Tags { get; } = new() { "xml", "docfx" }; + } + + private sealed class IgnoredDocument + { + [XmlIgnore] + public string Hidden => "internal"; + + public string Visible => "public"; + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.Linq.StringExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.Linq.StringExtensions.md new file mode 100644 index 00000000..a059f82e --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Xml.Linq.StringExtensions.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.Extensions.Xml.Linq.StringExtensions +example: +- *content +--- + +The following example demonstrates how to parse XML strings into using the class. + +```csharp +using System; +using System.Xml.Linq; +using Cuemon.Extensions.Xml.Linq; + +namespace MyApp.Examples; + +public class StringExtensionsExample +{ + public void Demonstrate() + { + string xml = "Value"; + + // Try to parse the XML string into an XElement + if (xml.TryParseXElement(out XElement element)) + { + Console.WriteLine(element.Name); // root + Console.WriteLine(element.Element("item")?.Value); // Value + + // Check if a string is valid XML + bool isValid = xml.IsXmlString(); + Console.WriteLine(isValid); // True + + // Invalid XML returns false + string invalid = ""; + bool isInvalid = invalid.IsXmlString(); + Console.WriteLine(isInvalid); // False + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.Serialization.Converters.XmlConverterExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.Serialization.Converters.XmlConverterExtensions.md new file mode 100644 index 00000000..6c1e282a --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Xml.Serialization.Converters.XmlConverterExtensions.md @@ -0,0 +1,67 @@ +--- +uid: Cuemon.Extensions.Xml.Serialization.Converters.XmlConverterExtensions +example: +- *content +--- + +The following example registers built-in and custom XML converters, then reuses the configured list through . + +```csharp +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using Cuemon.Diagnostics; +using Cuemon.Extensions.Xml.Serialization.Converters; +using Cuemon.Xml.Serialization; +using Cuemon.Xml.Serialization.Converters; + +namespace DocExamples; + +public static class XmlConverterExtensionsExample +{ + public static void Demonstrate() + { + IList converters = new List(); + + converters.InsertXmlConverter( + 0, + (writer, value, entity) => writer.WriteElementString(entity?.LocalName ?? "Value", value), + (reader, objectType) => reader.ReadElementContentAsString(), + objectType => objectType == typeof(string), + new XmlQualifiedEntity("String")); + + converters.AddXmlConverter( + (writer, value, entity) => writer.WriteElementString(entity?.LocalName ?? "Value", value.ToString()), + (reader, objectType) => reader.ReadElementContentAsInt(), + objectType => objectType == typeof(int), + new XmlQualifiedEntity("Int32")); + + converters.AddEnumerableConverter(); + converters.AddExceptionDescriptorConverter(options => options.SensitivityDetails = FaultSensitivityDetails.All); + converters.AddUriConverter(); + converters.AddDateTimeConverter(); + converters.AddTimeSpanConverter(); + converters.AddStringConverter(); + converters.AddExceptionConverter(includeStackTrace: true, includeData: true); + converters.AddFailureConverter(); + + var writerConverter = converters.FirstOrDefaultWriterConverter(typeof(Uri)); + var readerConverter = converters.FirstOrDefaultReaderConverter(typeof(string)); + + var serializerOptions = new XmlSerializerOptions(); + serializerOptions.Converters.Clear(); + foreach (var converter in converters) + { + serializerOptions.Converters.Add(converter); + } + + var serializer = XmlSerializer.Create(serializerOptions); + using var stream = serializer.Serialize(new Uri("https://example.com/feed.xml"), typeof(Uri)); + using var xml = new StreamReader(stream); + + Console.WriteLine(writerConverter is not null && readerConverter is not null); + Console.WriteLine(xml.ReadToEnd()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.Serialization.XmlSerializerOptionsExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.Serialization.XmlSerializerOptionsExtensions.md new file mode 100644 index 00000000..c2584a76 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Xml.Serialization.XmlSerializerOptionsExtensions.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Extensions.Xml.Serialization.XmlSerializerOptionsExtensions +example: +- *content +--- + +The following example demonstrates how to apply custom to the default settings using the class. + +```csharp +using System; +using System.Text; +using System.Xml; +using Cuemon.Extensions.Xml.Serialization; +using Cuemon.Xml.Serialization; + +namespace MyApp.Examples; + +public class XmlSerializerOptionsExtensionsExample +{ + public void Demonstrate() + { + // Configure XmlSerializerOptions + var options = new XmlSerializerOptions + { + Reader = new XmlReaderSettings { IgnoreWhitespace = true }, + Writer = new XmlWriterSettings { Indent = true, Encoding = Encoding.UTF8 } + }; + + // Apply to default XmlConvert settings + options.ApplyToDefaultSettings(); + + // After this call, XmlConvert.DefaultSettings will reflect the options + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.StreamExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.StreamExtensions.md new file mode 100644 index 00000000..f1a15fc4 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Xml.StreamExtensions.md @@ -0,0 +1,63 @@ +--- +uid: Cuemon.Extensions.Xml.StreamExtensions +example: +- *content +--- + +The following example demonstrates how to work with XML data from streams using StreamExtensions, including creating XmlReaders, copying with indented formatting, detecting encoding, and removing namespace declarations. + +```csharp +using System; +using System.IO; +using System.Text; +using System.Xml; +using Cuemon.Extensions.Xml; + +namespace MyApp.Xml +{ + public class StreamExtensionsExample + { + public void Demonstrate() + { + var xml = "Value"; + var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + + // Convert an XML stream to an XmlReader + using (var reader = stream.ToXmlReader()) + { + while (reader.Read()) + { + if (reader.NodeType == XmlNodeType.Element) + { + Console.WriteLine(reader.Name); + + // Reset stream position for next demonstration + stream.Position = 0; + + // Copy an XML stream with specified writer settings (e.g., indented output) + using (var copy = stream.CopyXmlStream(o => o.Indent = true)) + { + var indentedXml = new StreamReader(copy).ReadToEnd(); + Console.WriteLine(indentedXml); // Indented XML + + stream.Position = 0; + + // Detect XML encoding from the stream + if (stream.TryDetectXmlEncoding(out var encoding)) + { + Console.WriteLine(encoding.EncodingName); // "Unicode (UTF-8)" + + stream.Position = 0; + + // Remove XML namespace declarations from the stream + using (var noNs = stream.RemoveXmlNamespaceDeclarations()) + { + var cleaned = new StreamReader(noNs).ReadToEnd(); + Console.WriteLine(cleaned); // Elements without namespace prefixes + + stream.Dispose(); + +}}}}}}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.StringExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.StringExtensions.md new file mode 100644 index 00000000..57e8f2e6 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Xml.StringExtensions.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Extensions.Xml.StringExtensions +example: +- *content +--- + +The following example demonstrates how to escape and unescape XML special characters, sanitize strings for use as XML element names, and remove invalid XML control characters using StringExtensions. + +```csharp +using System; +using Cuemon.Extensions.Xml; + +namespace MyApp.Xml +{ + public class StringExtensionsExample + { + public void Demonstrate() + { + // Escape XML special characters + var unsafeText = "Use & < > \" ' in XML"; + var escaped = unsafeText.EscapeXml(); + Console.WriteLine(escaped); // "Use & < > " ' in XML" + + // Unescape XML back to original text + var unescaped = escaped.UnescapeXml(); + Console.WriteLine(unescaped); // "Use & < > \" ' in XML" + + // Sanitize a string for use as an XML element name + var invalidName = "1st Element Name!"; + var sanitizedName = invalidName.SanitizeXmlElementName(); + Console.WriteLine(sanitizedName); // "_st_Element_Name_" + + // Sanitize XML element text (remove control characters except \t, \n, \r) + var invalidText = "Valid text \x00 with \x01 control chars"; + var sanitizedText = invalidText.SanitizeXmlElementText(); + Console.WriteLine(sanitizedText); // "Valid text with control chars" + + // Sanitize XML element text with CDATA section rules (discourages "]]>" sequence) + var cdataText = "text with ]]> inside"; + var sanitizedCdata = cdataText.SanitizeXmlElementText(cdataSection: true); + Console.WriteLine(sanitizedCdata); // "text with ]] inside" + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.UriExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.UriExtensions.md new file mode 100644 index 00000000..1689974b --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Xml.UriExtensions.md @@ -0,0 +1,48 @@ +--- +uid: Cuemon.Extensions.Xml.UriExtensions +example: +- *content +--- + +The following example demonstrates how to create an XmlReader from a file URI using UriExtensions, with configurable reader settings for comment handling and DTD processing. + +```csharp +using System; +using System.IO; +using System.Text; +using System.Xml; +using Cuemon.Extensions.Xml; + +namespace DocExamples; + +public static class UriExtensionsExample +{ + public static void Demonstrate() + { + var xml = "42"; + var filePath = Path.Combine(AppContext.BaseDirectory, "settings.xml"); + File.WriteAllText(filePath, xml, Encoding.UTF8); + + try + { + using var reader = new Uri(filePath).ToXmlReader(settings => + { + settings.IgnoreComments = true; + settings.DtdProcessing = DtdProcessing.Ignore; + }); + + if (reader.MoveToFirstElement()) + { + Console.WriteLine(reader.LocalName); + } + } + finally + { + if (File.Exists(filePath)) + { + File.Delete(filePath); + } + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.XmlCopyOptions.md b/.docfx/api/types/Cuemon.Extensions.Xml.XmlCopyOptions.md new file mode 100644 index 00000000..36636703 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Xml.XmlCopyOptions.md @@ -0,0 +1,63 @@ +--- +uid: Cuemon.Extensions.Xml.XmlCopyOptions +example: +- *content +--- + +The following example demonstrates how to use to configure settings when copying XML content. + +```csharp +using System; +using System.IO; +using System.Xml; +using Cuemon.Extensions.Xml; + +namespace MyApp.Examples; + +public class XmlCopyOptionsExample +{ + public void CopyXmlWithCustomSettings() + { + // Configure writer settings for indentation and encoding + var copyOptions = new XmlCopyOptions + { + WriterSettings = settings => + { + settings.Indent = true; + settings.IndentChars = " "; + settings.OmitXmlDeclaration = false; + settings.NewLineOnAttributes = false; + } + }; + + // Use the options to configure an XmlWriter during a copy operation + string input = @"text"; + + using (var reader = XmlReader.Create(new StringReader(input))) + using (var writer = XmlWriter.Create(Console.Out, ConfigureWriter(copyOptions))) + { + writer.WriteNode(reader, false); + } + // Output: + // + // + // text + // + } + + private static XmlWriterSettings ConfigureWriter(XmlCopyOptions options) + { + var settings = new XmlWriterSettings(); + options.WriterSettings?.Invoke(settings); + return settings; + } + + public void UseDefaults() + { + // Default options have null WriterSettings (no custom configuration) + var options = new XmlCopyOptions(); + Console.WriteLine($"WriterSettings: {(options.WriterSettings == null ? "null (no customization)" : "configured")}"); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.XmlReaderExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.XmlReaderExtensions.md new file mode 100644 index 00000000..b892b491 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Xml.XmlReaderExtensions.md @@ -0,0 +1,62 @@ +--- +uid: Cuemon.Extensions.Xml.XmlReaderExtensions +example: +- *content +--- + +The following example demonstrates how to navigate, read, chunk, and convert XML data using XmlReaderExtensions, including moving to the first element, building hierarchy trees, and streaming XML content. + +```csharp +using System; +using System.IO; +using System.Linq; +using System.Xml; +using Cuemon.Extensions.Xml; + +namespace DocExamples; + +public static class XmlReaderExtensionsExample +{ + private const string XmlDocument = "FirstSecond"; + + public static void Demonstrate() + { + Console.WriteLine(GetRootName()); + Console.WriteLine(DescribeHierarchy()); + Console.WriteLine(ReadFirstChunk()); + Console.WriteLine(CopyXml()); + } + + private static string GetRootName() + { + using var xmlReader = XmlReader.Create(new StringReader(XmlDocument)); + return xmlReader.MoveToFirstElement() ? xmlReader.LocalName : string.Empty; + } + + private static string DescribeHierarchy() + { + using var xmlReader = XmlReader.Create(new StringReader(XmlDocument)); + var hierarchy = xmlReader.ToHierarchy(); + var childNames = string.Join(", ", hierarchy.GetChildren().Select(child => child.Instance.Name)); + return $"{hierarchy.Instance.Name}: {childNames}"; + } + + private static string ReadFirstChunk() + { + using var xmlReader = XmlReader.Create(new StringReader(XmlDocument)); + using var firstChunk = xmlReader.Chunk(1, settings => settings.Indent = true).First(); + + firstChunk.MoveToFirstElement(); + return firstChunk.ReadOuterXml(); + } + + private static string CopyXml() + { + using var xmlReader = XmlReader.Create(new StringReader(XmlDocument)); + using var xmlStream = xmlReader.ToStream(); + using var streamReader = new StreamReader(xmlStream); + + return streamReader.ReadToEnd(); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.XmlWriterExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.XmlWriterExtensions.md new file mode 100644 index 00000000..52c81334 --- /dev/null +++ b/.docfx/api/types/Cuemon.Extensions.Xml.XmlWriterExtensions.md @@ -0,0 +1,71 @@ +--- +uid: Cuemon.Extensions.Xml.XmlWriterExtensions +example: +- *content +--- + +The following example writes XML directly to an by combining object serialization, qualified element names, and conditional wrapper elements. + +```csharp +using System; +using System.IO; +using System.Xml; +using Cuemon.Extensions.Xml; +using Cuemon.Xml.Serialization; + +namespace DocExamples; + +public static class XmlWriterExtensionsExample +{ + public static void Demonstrate() + { + Console.WriteLine(WriteException()); + Console.WriteLine(WriteStandaloneElement()); + Console.WriteLine(WriteWrappedException()); + Console.WriteLine(WriteRootElement()); + } + + private static string WriteException() + { + var output = new StringWriter(); + using var writer = XmlWriter.Create(output, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }); + writer.WriteObject(new InvalidOperationException()); + writer.Flush(); + return output.ToString(); + } + + private static string WriteStandaloneElement() + { + var output = new StringWriter(); + using var writer = XmlWriter.Create(output, new XmlWriterSettings { OmitXmlDeclaration = true }); + writer.WriteStartElement(new XmlQualifiedEntity("Cuemon")); + writer.WriteEndElement(); + writer.Flush(); + return output.ToString(); + } + + private static string WriteWrappedException() + { + var output = new StringWriter(); + using var writer = XmlWriter.Create(output, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }); + writer.WriteEncapsulatingElementWhenNotNull(new InvalidOperationException(), new XmlQualifiedEntity("MyWrappedElement"), (nestedWriter, exception) => + { + nestedWriter.WriteObject(exception); + }); + writer.Flush(); + return output.ToString(); + } + + private static string WriteRootElement() + { + var output = new StringWriter(); + using var writer = XmlWriter.Create(output, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }); + writer.WriteXmlRootElement(new InvalidOperationException(), (nestedWriter, exception, rootEntity) => + { + nestedWriter.WriteObject(exception); + }, new XmlQualifiedEntity("Root", "cuemon")); + writer.Flush(); + return output.ToString(); + } +} +``` diff --git a/.docfx/api/types/Cuemon.FormattingOptions.md b/.docfx/api/types/Cuemon.FormattingOptions.md new file mode 100644 index 00000000..81da4427 --- /dev/null +++ b/.docfx/api/types/Cuemon.FormattingOptions.md @@ -0,0 +1,33 @@ +--- +uid: Cuemon.FormattingOptions +example: +- *content +--- + +The following example demonstrates how to configure a with a custom format provider to control numeric formatting. + +```csharp +using System; +using System.Globalization; +using Cuemon; + +namespace MyApp.Examples; + +public class FormattingOptionsExample +{ + public void Demonstrate() + { + var options = new FormattingOptions + { + FormatProvider = new CultureInfo("da-DK") + }; + + var value = 1234.56; + var formatted = value.ToString("N2", options.FormatProvider); + + Console.WriteLine(formatted); // Output depends on the culture (e.g., "1.234,56" for da-DK) + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.FuncFactory`2.md b/.docfx/api/types/Cuemon.FuncFactory`2.md new file mode 100644 index 00000000..10ef58cf --- /dev/null +++ b/.docfx/api/types/Cuemon.FuncFactory`2.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.FuncFactory`2 +example: +- *content +--- + +The following example demonstrates how to use to encapsulate a function delegate and its arguments together for deferred execution. + +```csharp +using System; +using Cuemon; + +namespace Contoso.Formatting; + +public sealed class FuncFactoryExample +{ + public static void Run() + { + var factory = new FuncFactory, string>( + tuple => $"{tuple.Arg1}-{tuple.Arg2:D3}", + new MutableTuple("Item", 7)); + + string result = factory.ExecuteMethod(); + var clone = (FuncFactory, string>)factory.Clone(); + + Console.WriteLine(result); + Console.WriteLine(clone.ExecuteMethod()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Generate.md b/.docfx/api/types/Cuemon.Generate.md new file mode 100644 index 00000000..b2ef35e8 --- /dev/null +++ b/.docfx/api/types/Cuemon.Generate.md @@ -0,0 +1,50 @@ +--- +uid: Cuemon.Generate +example: +- *content +--- + +The following example demonstrates how to use `Generate` to produce numeric ranges, random numbers, random strings, hash codes, and structured object portrayals. + +```csharp +using System; +using System.Collections.Generic; + +namespace Cuemon; + +public class GenerateExample +{ + public void Demonstrate() + { + // Generate a range of values using a generator function + IEnumerable numbers = Generate.RangeOf(5, i => i * 10); + Console.WriteLine(string.Join(", ", numbers)); // 0, 10, 20, 30, 40 + + // Generate a random integer in a specific range + int randomValue = Generate.RandomNumber(1, 101); + Console.WriteLine($"Random between 1 and 100: {randomValue}"); + + // Generate a random alphanumeric string + string randomStr = Generate.RandomString(12); + Console.WriteLine($"Random 12-char string: {randomStr}"); + + // Generate a random string from custom character buckets + string customRandom = Generate.RandomString(8, "ABCDEF", "123456"); + Console.WriteLine($"Custom random string: {customRandom}"); + + // Generate a fixed string of repeated characters + string separator = Generate.FixedString('-', 20); + Console.WriteLine(separator); // -------------------- + + // Compute hash codes from convertible values + int hash32 = Generate.HashCode32(42, "hello", true); + long hash64 = Generate.HashCode64(42, "hello", true); + Console.WriteLine($"32-bit hash: {hash32}, 64-bit hash: {hash64}"); + + // Generate a structured portrayal of an object + var person = new { Name = "Alice", Age = 30 }; + string portrayal = Generate.ObjectPortrayal(person); + Console.WriteLine(portrayal); // shows property names and values + } +} +``` diff --git a/.docfx/api/types/Cuemon.Globalization.StatisticalRegionInfo.md b/.docfx/api/types/Cuemon.Globalization.StatisticalRegionInfo.md new file mode 100644 index 00000000..022125fa --- /dev/null +++ b/.docfx/api/types/Cuemon.Globalization.StatisticalRegionInfo.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.Globalization.StatisticalRegionInfo +example: +- *content +--- + +The following example demonstrates how to use via the class to retrieve UN M.49 region data. + +```csharp +using System; +using System.Linq; +using Cuemon.Globalization; + +namespace MyApp.Examples; + +public class StatisticalRegionInfoExample +{ + public void Demonstrate() + { + // Get United States by its UN M.49 code + StatisticalRegionInfo usa = World.GetCountry("840"); + + if (usa != null) + { + Console.WriteLine($"Name: {usa.Name}"); + Console.WriteLine($"Code: {usa.Code}"); + Console.WriteLine($"ISO Alpha-2: {usa.IsoAlpha2}"); + Console.WriteLine($"ISO Alpha-3: {usa.IsoAlpha3}"); + Console.WriteLine($"Kind: {usa.Kind}"); + Console.WriteLine($"Parent: {usa.Parent?.Name}"); + + // List all European countries + var europe = World.GetStatisticalRegion("150"); + if (europe != null) + { + Console.WriteLine($"\nCountries in {europe.Name}:"); + foreach (var country in europe.Countries.Take(5)) + { + Console.WriteLine($" - {country.Name} ({country.IsoAlpha2})"); + +}}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Globalization.StatisticalRegionKind.md b/.docfx/api/types/Cuemon.Globalization.StatisticalRegionKind.md new file mode 100644 index 00000000..6838b583 --- /dev/null +++ b/.docfx/api/types/Cuemon.Globalization.StatisticalRegionKind.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.Globalization.StatisticalRegionKind +example: +- *content +--- + +The following example demonstrates how to use to categorize geographic regions according to the UN M.49 standard. + +```csharp +using System; +using Cuemon.Globalization; + +namespace MyApp.Examples; + +public class StatisticalRegionKindExample +{ + public void Demonstrate() + { + var regionKind = StatisticalRegionKind.CountryOrTerritory; + + switch (regionKind) + { + case StatisticalRegionKind.World: + Console.WriteLine("The entire world (code 001)."); + break; + case StatisticalRegionKind.Region: + Console.WriteLine("A major geographic region or continent."); + break; + case StatisticalRegionKind.Subregion: + Console.WriteLine("A subdivision of a region (e.g., Western Europe)."); + break; + case StatisticalRegionKind.IntermediateRegion: + Console.WriteLine("An intermediate grouping of subregions."); + break; + case StatisticalRegionKind.CountryOrTerritory: + Console.WriteLine("An individual country or territory (leaf node)."); + break; + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Globalization.World.md b/.docfx/api/types/Cuemon.Globalization.World.md new file mode 100644 index 00000000..b77562e1 --- /dev/null +++ b/.docfx/api/types/Cuemon.Globalization.World.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Globalization.World +example: +- *content +--- + +```csharp +using System; +using System.Globalization; +using System.Linq; +using Cuemon.Globalization; + +namespace Cuemon.Globalization; + +public class WorldExample +{ + public void Demonstrate() + { + var regions = World.Regions.ToList(); + Console.WriteLine($"Number of regions: {regions.Count}"); + + var statisticalRegions = World.StatisticalRegions.ToList(); + Console.WriteLine($"Statistical regions: {statisticalRegions.Count}"); + + var country = World.GetStatisticalRegion("840"); + Console.WriteLine($"United States M.49: {country?.Name}"); + + var cultures = World.GetCultures(new RegionInfo("US")); + foreach (var culture in cultures) + { + Console.WriteLine($"Culture: {culture.DisplayName}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.GuidFormats.md b/.docfx/api/types/Cuemon.GuidFormats.md new file mode 100644 index 00000000..74e8863d --- /dev/null +++ b/.docfx/api/types/Cuemon.GuidFormats.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.GuidFormats +example: +- *content +--- + +The following example demonstrates how to use the flags enum to control which GUID formats are accepted during parsing. + +```csharp +using System; +using Cuemon; // for GuidFormats +using Cuemon.Text; // for ParserFactory, GuidStringOptions + +namespace MyApp.Examples; + +public class GuidFormatsExample +{ + public void Demonstrate() + { + var parser = ParserFactory.FromGuid(); + + // Accept only digit (D) and brace (B) formats + Guid g1 = parser.Parse("12345678-1234-1234-1234-123456789abc", + o => o.Formats = GuidFormats.D | GuidFormats.B); + Console.WriteLine(g1); // 12345678-1234-1234-1234-123456789abc + + Guid g2 = parser.Parse("{12345678-1234-1234-1234-123456789abc}", + o => o.Formats = GuidFormats.D | GuidFormats.B); + Console.WriteLine(g2); + + // TryParse with number format (N) - using Hyphens, so it would fail + bool ok = parser.TryParse("12345678123412341234123456789abc", out Guid g3, + o => o.Formats = GuidFormats.N); + Console.WriteLine(ok); // True - only N is selected and input has no hyphens + + // Fail: brace format but only D selected + ok = parser.TryParse("{12345678-1234-1234-1234-123456789abc}", out Guid g4, + o => o.Formats = GuidFormats.D); + Console.WriteLine(ok); // False + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.IO.AsyncDisposableOptions.md b/.docfx/api/types/Cuemon.IO.AsyncDisposableOptions.md new file mode 100644 index 00000000..ca32a77d --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.AsyncDisposableOptions.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.IO.AsyncDisposableOptions +example: +- *content +--- + +The following example demonstrates how to configure `AsyncDisposableOptions` to control whether a disposable resource is left open after an async operation. + +```csharp +using System; +using System.IO; +using System.Threading.Tasks; +using Cuemon.IO; + +namespace MyApp.Examples; + +public class AsyncDisposableOptionsExample +{ + public static async Task Main() + { + var options = new AsyncDisposableOptions + { + LeaveOpen = true + }; + + var stream = new MemoryStream(); + // Use options.LeaveOpen to decide disposal behavior + if (!options.LeaveOpen) + { + stream.Dispose(); + + Console.WriteLine("LeaveOpen: {0}", options.LeaveOpen); + Console.WriteLine("Stream still open: {0}", stream.CanWrite); + + // Output: + // LeaveOpen: True + // Stream still open: True + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.IO.AsyncStreamCompressionOptions.md b/.docfx/api/types/Cuemon.IO.AsyncStreamCompressionOptions.md new file mode 100644 index 00000000..e34e05a4 --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.AsyncStreamCompressionOptions.md @@ -0,0 +1,57 @@ +--- +uid: Cuemon.IO.AsyncStreamCompressionOptions +example: +- *content +--- + +The following example demonstrates how to configure AsyncStreamCompressionOptions to control compression level and buffer size when compressing stream data asynchronously. + +```csharp +using System; +using System.IO; +using System.IO.Compression; +using System.Text; +using System.Threading.Tasks; +using Cuemon.IO; + +namespace MyApp.IO +{ + public class AsyncStreamCompressionOptionsExample + { + public async Task DemonstrateAsync() + { + // Default compression: Optimal balance of speed and size + var defaultOptions = new AsyncStreamCompressionOptions(); + Console.WriteLine($"Default level: {defaultOptions.Level}"); // Optimal + Console.WriteLine($"Default buffer size: {defaultOptions.BufferSize}"); // 81920 + + // Fastest compression for CPU-sensitive scenarios + var fastOptions = new AsyncStreamCompressionOptions + { + Level = CompressionLevel.Fastest, + BufferSize = 4096 + }; + + // Compress data using the configured options + byte[] original = Encoding.UTF8.GetBytes("This is sample data that will be compressed using AsyncStreamCompressionOptions."); + using var source = new MemoryStream(original); + using var compressed = new MemoryStream(); + + using (var deflateStream = new DeflateStream(compressed, fastOptions.Level, leaveOpen: true)) + { + await source.CopyToAsync(deflateStream, fastOptions.BufferSize); + + Console.WriteLine($"Original size: {original.Length} bytes"); + Console.WriteLine($"Compressed size: {compressed.Length} bytes"); + + // No compression level for testing or passthrough scenarios + var noCompressionOptions = new AsyncStreamCompressionOptions + { + Level = CompressionLevel.NoCompression + }; + Console.WriteLine($"No compression level: {noCompressionOptions.Level}"); + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.IO.AsyncStreamCopyOptions.md b/.docfx/api/types/Cuemon.IO.AsyncStreamCopyOptions.md new file mode 100644 index 00000000..0d876111 --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.AsyncStreamCopyOptions.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.IO.AsyncStreamCopyOptions +example: +- *content +--- + +The following example demonstrates how to configure AsyncStreamCopyOptions to control buffer size and stream lifetime when copying data asynchronously between streams. + +```csharp +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Cuemon; +using Cuemon.IO; + +namespace Contoso.FileTransfers; + +public sealed class AsyncStreamCopyOptionsExample +{ + public static async Task RunAsync() + { + var options = new AsyncStreamCopyOptions + { + BufferSize = 4096, + LeaveOpen = true + }; + + using var source = new MemoryStream(Encoding.UTF8.GetBytes("Copy me asynchronously.")); + using var destination = new MemoryStream(); + + await Decorator.Enclose(source).CopyStreamAsync(destination, options.BufferSize, changePosition: true, ct: CancellationToken.None); + + byte[] copied = await Decorator.Enclose(destination).ToByteArrayAsync(setup => + { + setup.BufferSize = options.BufferSize; + setup.LeaveOpen = options.LeaveOpen; + }); + + Console.WriteLine(Encoding.UTF8.GetString(copied)); + } +} +``` diff --git a/.docfx/api/types/Cuemon.IO.AsyncStreamEncodingOptions.md b/.docfx/api/types/Cuemon.IO.AsyncStreamEncodingOptions.md new file mode 100644 index 00000000..e339a063 --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.AsyncStreamEncodingOptions.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.IO.AsyncStreamEncodingOptions +example: +- *content +--- + +The following example demonstrates how to configure `AsyncStreamEncodingOptions` when reading text from a stream asynchronously. + +```csharp +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Cuemon.IO; +using Cuemon.Text; + +namespace MyApp.Examples; + +public class AsyncStreamEncodingOptionsExample +{ + public static async Task Main() + { + var options = new AsyncStreamEncodingOptions + { + Encoding = Encoding.UTF8, + Preamble = PreambleSequence.Remove, + LeaveOpen = false + }; + + string text = "Hello, AsyncStreamEncodingOptions!"; + byte[] bytes = Encoding.UTF8.GetBytes(text); + + using var stream = new MemoryStream(bytes); + using var reader = new StreamReader(stream, options.Encoding); + + string result = await reader.ReadToEndAsync(); + Console.WriteLine(result); + + // Output: + // Hello, AsyncStreamEncodingOptions! + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.IO.AsyncStreamReaderOptions.md b/.docfx/api/types/Cuemon.IO.AsyncStreamReaderOptions.md new file mode 100644 index 00000000..03b87c45 --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.AsyncStreamReaderOptions.md @@ -0,0 +1,50 @@ +--- +uid: Cuemon.IO.AsyncStreamReaderOptions +example: +- *content +--- + +The following example demonstrates how to configure AsyncStreamReaderOptions to control encoding, preamble handling, and buffer size when reading stream content asynchronously. + +```csharp +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Cuemon; +using Cuemon.IO; +using Cuemon.Text; + +namespace Contoso.Imports; + +public sealed class AsyncStreamReaderOptionsExample +{ + public static async Task RunAsync() + { + byte[] payload = Encoding.UTF8.GetPreamble() + .Concat(Encoding.UTF8.GetBytes("Hej Cuemon")) + .ToArray(); + + using var stream = new MemoryStream(payload); + + var options = new AsyncStreamReaderOptions + { + BufferSize = 4096, + Encoding = EncodingOptions.DefaultEncoding, + Preamble = PreambleSequence.Remove, + LeaveOpen = true + }; + + string text = await Decorator.Enclose(stream).ToEncodedStringAsync(setup => + { + setup.BufferSize = options.BufferSize; + setup.Encoding = options.Encoding; + setup.Preamble = options.Preamble; + setup.LeaveOpen = options.LeaveOpen; + }); + + Console.WriteLine($"{options.Encoding.WebName}:{text}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.IO.BufferWriterOptions.md b/.docfx/api/types/Cuemon.IO.BufferWriterOptions.md new file mode 100644 index 00000000..348433c0 --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.BufferWriterOptions.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.IO.BufferWriterOptions +example: +- *content +--- + +The following example demonstrates how to configure `BufferWriterOptions` and use it with an `IBufferWriter` to produce a string. + +```csharp +using System; +using System.Buffers; +using System.Text; +using Cuemon.IO; +using Cuemon.Text; + +namespace MyApp.Examples; + +public class BufferWriterOptionsExample +{ + public static void Main() + { + var options = new BufferWriterOptions + { + BufferSize = 1024, + Encoding = Encoding.UTF8, + Preamble = PreambleSequence.Remove + }; + + var writer = new ArrayBufferWriter(options.BufferSize); + byte[] data = Encoding.UTF8.GetBytes("Hello, BufferWriterOptions!"); + writer.Write(data); + + string result = Encoding.UTF8.GetString(writer.WrittenSpan); + Console.WriteLine(result); + + // Output: + // Hello, BufferWriterOptions! + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.IO.FileInfoOptions.md b/.docfx/api/types/Cuemon.IO.FileInfoOptions.md new file mode 100644 index 00000000..bce6b1de --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.FileInfoOptions.md @@ -0,0 +1,61 @@ +--- +uid: Cuemon.IO.FileInfoOptions +example: +- *content +--- + +The following example demonstrates how to configure FileInfoOptions to control the number of bytes read from a file, useful for reading headers or file signatures. + +```csharp +using System; +using System.IO; +using Cuemon.IO; + +namespace MyApp.IO +{ + public class FileInfoOptionsExample + { + public void Demonstrate() + { + // Default options: BytesToRead = 0 (read entire file) + var defaultOptions = new FileInfoOptions(); + Console.WriteLine($"Default bytes to read: {defaultOptions.BytesToRead}"); // 0 + + // Read only the first 100 bytes of a file + var headerOptions = new FileInfoOptions + { + BytesToRead = 100 + }; + + // Read only the first 16 bytes (e.g., for file signature detection) + var signatureOptions = new FileInfoOptions + { + BytesToRead = 16 + }; + + string tempFile = Path.GetTempFileName(); + try + { + File.WriteAllText(tempFile, new string('A', 1000)); + + // Demonstrate how BytesToRead limits the data read + using var fileStream = File.OpenRead(tempFile); + byte[] buffer = new byte[headerOptions.BytesToRead]; + int bytesRead = fileStream.Read(buffer, 0, headerOptions.BytesToRead); + Console.WriteLine($"Requested {headerOptions.BytesToRead} bytes, read {bytesRead} bytes"); + } + finally + { + File.Delete(tempFile); + } + + // BytesToRead of 0 means no limit + var noLimitOptions = new FileInfoOptions + { + BytesToRead = 0 + }; + Console.WriteLine($"BytesToRead = 0 means no limit: {noLimitOptions.BytesToRead}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.IO.StreamCompressionOptions.md b/.docfx/api/types/Cuemon.IO.StreamCompressionOptions.md new file mode 100644 index 00000000..852958ab --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.StreamCompressionOptions.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.IO.StreamCompressionOptions +example: +- *content +--- + +The following example demonstrates how to configure StreamCompressionOptions to control the compression level when compressing stream data. + +```csharp +using System; +using System.IO; +using System.IO.Compression; +using System.Text; +using Cuemon.IO; + +namespace MyApp.IO +{ + public class StreamCompressionOptionsExample + { + public void Demonstrate() + { + // Default options: Optimal compression level + var defaultOptions = new StreamCompressionOptions(); + Console.WriteLine($"Default compression level: {defaultOptions.Level}"); // Optimal + + // Fastest compression (less CPU, larger output) + var fastOptions = new StreamCompressionOptions + { + Level = CompressionLevel.Fastest + }; + + // No compression (for testing) + var noCompression = new StreamCompressionOptions + { + Level = CompressionLevel.NoCompression + }; + + // Compress some data + var originalData = Encoding.UTF8.GetBytes("This is a test string that will be compressed."); + using var source = new MemoryStream(originalData); + using var compressed = new MemoryStream(); + using (var deflateStream = new DeflateStream(compressed, fastOptions.Level, leaveOpen: true)) + { + source.CopyTo(deflateStream); + + Console.WriteLine($"Original size: {originalData.Length} bytes"); + Console.WriteLine($"Compressed size: {compressed.Length} bytes"); + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.IO.StreamCopyOptions.md b/.docfx/api/types/Cuemon.IO.StreamCopyOptions.md new file mode 100644 index 00000000..20933f23 --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.StreamCopyOptions.md @@ -0,0 +1,54 @@ +--- +uid: Cuemon.IO.StreamCopyOptions +example: +- *content +--- + +The following example demonstrates how to configure StreamCopyOptions to control buffer size and whether the source stream remains open after copying. + +```csharp +using System; +using System.IO; +using System.Text; +using Cuemon; +using Cuemon.IO; + +namespace MyApp.IO; + +public class StreamCopyOptionsExample +{ + public void Demonstrate() + { + // Create and use StreamCopyOptions directly + var customOptions = new StreamCopyOptions { BufferSize = 4096, LeaveOpen = true }; + Console.WriteLine($"Buffer size: {customOptions.BufferSize}, Leave open: {customOptions.LeaveOpen}"); + + // Create a memory stream with some data + var source = new MemoryStream(Encoding.UTF8.GetBytes("Hello, StreamCopyOptions!")); + + // Convert the stream to a byte array using custom StreamCopyOptions + byte[] bytes = Decorator.Enclose(source).ToByteArray(setup => + { + setup.BufferSize = 4096; + setup.LeaveOpen = true; + }); + + Console.WriteLine($"Read {bytes.Length} bytes"); // 26 + Console.WriteLine(Encoding.UTF8.GetString(bytes)); // Hello, StreamCopyOptions! + Console.WriteLine($"Source stream is still open: {source.CanRead}"); // True + + // Without LeaveOpen, the source stream is automatically disposed after reading + var temp = new MemoryStream(Encoding.UTF8.GetBytes("Temporary data.")); + byte[] tempBytes = Decorator.Enclose(temp).ToByteArray(); // disposes 'temp' + Console.WriteLine(Encoding.UTF8.GetString(tempBytes)); // Temporary data. + Console.WriteLine($"Stream was disposed: {!temp.CanRead}"); // True + + // Using default options (BufferSize = 81920, LeaveOpen = false) + var data = new MemoryStream(Encoding.UTF8.GetBytes("Default options.")); + byte[] result = Decorator.Enclose(data).ToByteArray(); + Console.WriteLine(Encoding.UTF8.GetString(result)); // Default options. + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.IO.StreamDecoratorExtensions.md b/.docfx/api/types/Cuemon.IO.StreamDecoratorExtensions.md new file mode 100644 index 00000000..cc3ac468 --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.StreamDecoratorExtensions.md @@ -0,0 +1,130 @@ +--- +uid: Cuemon.IO.StreamDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the extension methods for stream operations including conversion, compression, and copying. + +```csharp +using System; +using Cuemon; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Cuemon; +using Cuemon.IO; + +namespace MyApp.IO; + +public class StreamDecoratorExtensionsExample +{ + public async Task DemonstrateAsync() + { + // ---- InvokeToByteArray: convert stream to byte array ---- + var source0 = new MemoryStream(Encoding.UTF8.GetBytes("Invoke test.")); + Decorator.Enclose(source0).InvokeToByteArray(); + + // ---- ToByteArray: convert stream to byte array ---- + var source1 = new MemoryStream(Encoding.UTF8.GetBytes("Hello, World!")); + byte[] bytes = Decorator.Enclose(source1).ToByteArray(); + Console.WriteLine($"Byte array length: {bytes.Length}"); // 13 + + // ---- ToByteArrayAsync: async version ---- + var source2 = new MemoryStream(Encoding.UTF8.GetBytes("Async bytes.")); + byte[] asyncBytes = await Decorator.Enclose(source2).ToByteArrayAsync(); + Console.WriteLine($"Async bytes length: {asyncBytes.Length}"); // 11 + + // ---- ToEncodedString: stream to string ---- + var source3 = new MemoryStream(Encoding.UTF8.GetBytes("Read me as text.")); + string text = Decorator.Enclose(source3).ToEncodedString(setup => + { + setup.LeaveOpen = true; + }); + Console.WriteLine(text); // Read me as text. + + // ---- ToEncodedStringAsync: async stream to string ---- + source3.Position = 0; + string textAsync = await Decorator.Enclose(source3).ToEncodedStringAsync(setup => + { + setup.LeaveOpen = true; + }); + Console.WriteLine(textAsync); // Read me as text. + + // ---- CopyStreamAsync: async copy to destination stream ---- + var source4 = new MemoryStream(Encoding.UTF8.GetBytes("Copy me.")); + using var destination = new MemoryStream(); + await Decorator.Enclose(source4).CopyStreamAsync(destination, bufferSize: 8192, changePosition: true); + Console.WriteLine($"Destination length: {destination.Length}"); // 8 + + // ---- CopyStream: synchronous copy ---- + var source4b = new MemoryStream(Encoding.UTF8.GetBytes("Sync copy.")); + using var dest4b = new MemoryStream(); + Decorator.Enclose(source4b).CopyStream(dest4b); + Console.WriteLine($"Sync copy length: {dest4b.Length}"); // 9 + + // ---- CompressGZip / DecompressGZip ---- + var source5 = new MemoryStream(Encoding.UTF8.GetBytes("GZip compress this.")); + using var gzipCompressed = Decorator.Enclose(source5).CompressGZip(); + Console.WriteLine($"GZip compressed size: {gzipCompressed.Length}"); + gzipCompressed.Position = 0; + var gzipDecompressed = Decorator.Enclose(gzipCompressed).DecompressGZip(); + var gzipText = await Decorator.Enclose(gzipDecompressed).ToEncodedStringAsync(); + Console.WriteLine(gzipText); // GZip compress this. + + // ---- CompressGZipAsync / DecompressGZipAsync ---- + var source5b = new MemoryStream(Encoding.UTF8.GetBytes("Async GZip test.")); + var gzipCompressedAsync = await Decorator.Enclose(source5b).CompressGZipAsync(); + var gzipDecompressedAsync = await Decorator.Enclose(gzipCompressedAsync).DecompressGZipAsync(); + var gzipAsyncText = await Decorator.Enclose(gzipDecompressedAsync).ToEncodedStringAsync(); + Console.WriteLine(gzipAsyncText); // Async GZip test. + + // ---- CompressDeflate / DecompressDeflate (sync) ---- + var source6 = new MemoryStream(Encoding.UTF8.GetBytes("Deflate test.")); + using var deflated = Decorator.Enclose(source6).CompressDeflate(); + deflated.Position = 0; + var deflatedResult = Decorator.Enclose(deflated).DecompressDeflate(); + var deflateText = await Decorator.Enclose(deflatedResult).ToEncodedStringAsync(); + Console.WriteLine(deflateText); // Deflate test. + + // ---- CompressDeflateAsync / DecompressDeflateAsync ---- + var source6b = new MemoryStream(Encoding.UTF8.GetBytes("Async Deflate.")); + var deflatedAsync = await Decorator.Enclose(source6b).CompressDeflateAsync(); + var deflatedDecompAsync = await Decorator.Enclose(deflatedAsync).DecompressDeflateAsync(); + var deflateAsyncText = await Decorator.Enclose(deflatedDecompAsync).ToEncodedStringAsync(); + Console.WriteLine(deflateAsyncText); // Async Deflate. + + // ---- ToByteArrayAsync / ToEncodedStringAsync (async byte/string conversion) ---- + var sourceBytes = new MemoryStream(Encoding.UTF8.GetBytes("Async byte conversion.")); + var bytesAsync = await Decorator.Enclose(sourceBytes).ToByteArrayAsync(); + Console.WriteLine(bytesAsync.Length); // 22 + + sourceBytes.Position = 0; + var strAsync = await Decorator.Enclose(sourceBytes).ToEncodedStringAsync(); + Console.WriteLine(strAsync); // Async byte conversion. + + // ---- CompressBrotli / DecompressBrotli (sync, netstandard2.1+ or net9.0+) ---- + var source7 = new MemoryStream(Encoding.UTF8.GetBytes("Brotli test.")); + var brotliCompressed = Decorator.Enclose(source7).CompressBrotli(); + brotliCompressed.Position = 0; + var brotliDecompressed = Decorator.Enclose(brotliCompressed).DecompressBrotli(); + var brotliText = await Decorator.Enclose(brotliDecompressed).ToEncodedStringAsync(); + Console.WriteLine(brotliText); // Brotli test. + + // ---- CompressBrotliAsync / DecompressBrotliAsync ---- + var source7b = new MemoryStream(Encoding.UTF8.GetBytes("Async Brotli.")); + var brotliCompressedAsync = await Decorator.Enclose(source7b).CompressBrotliAsync(); + var brotliDecompressedAsync = await Decorator.Enclose(brotliCompressedAsync).DecompressBrotliAsync(); + var brotliAsyncText = await Decorator.Enclose(brotliDecompressedAsync).ToEncodedStringAsync(); + Console.WriteLine(brotliAsyncText); // Async Brotli. + + // ---- WriteAllAsync: write bytes to stream ---- + var target = new MemoryStream(); + byte[] data = Encoding.UTF8.GetBytes("Write this."); + await Decorator.Enclose(target).WriteAllAsync(data); + Console.WriteLine($"Written bytes: {target.Length}"); // 10 + + } +} + +``` diff --git a/.docfx/api/types/Cuemon.IO.StreamEncodingOptions.md b/.docfx/api/types/Cuemon.IO.StreamEncodingOptions.md new file mode 100644 index 00000000..9bf9c91e --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.StreamEncodingOptions.md @@ -0,0 +1,63 @@ +--- +uid: Cuemon.IO.StreamEncodingOptions +example: +- *content +--- + +The following example demonstrates how to configure StreamEncodingOptions for preamble handling and encoding detection when reading stream content as strings. + +```csharp +using System; +using System.IO; +using System.Text; +using Cuemon; +using Cuemon.IO; +using Cuemon.Text; + +namespace MyApp.IO; + +public class StreamEncodingOptionsExample +{ + public void Demonstrate() + { + // Directly instantiate and use StreamEncodingOptions + var defaultOptions = new StreamEncodingOptions(); + Console.WriteLine($"Default preamble handling: {defaultOptions.Preamble}"); + + // Create a stream with UTF-32 encoded content including a BOM + var text = "Hello with BOM!"; + var preamble = Encoding.UTF32.GetPreamble(); + var encoded = Encoding.UTF32.GetBytes(text); + + var stream = new MemoryStream(preamble.Length + encoded.Length); + stream.Write(preamble, 0, preamble.Length); + stream.Write(encoded, 0, encoded.Length); + stream.Position = 0; + + // Read the stream as a string using StreamReaderOptions (which inherits StreamEncodingOptions) + // This auto-detects the encoding from the BOM and removes the preamble from the output + string result = Decorator.Enclose(stream).ToEncodedString(setup => + { + setup.Encoding = EncodingOptions.DefaultEncoding; // auto-detect from BOM + setup.Preamble = PreambleSequence.Remove; // strip the BOM from output + setup.LeaveOpen = true; // keep stream open for reuse + }); + + Console.WriteLine($"Read: {result}"); // Hello with BOM! + + // Read again, this time keeping the BOM preamble + stream.Position = 0; + string withBom = Decorator.Enclose(stream).ToEncodedString(setup => + { + setup.Encoding = Encoding.UTF32; + setup.Preamble = PreambleSequence.Keep; + setup.LeaveOpen = false; // let the extension dispose the stream + }); + + Console.WriteLine($"With BOM length: {withBom.Length}"); // includes BOM bytes + Console.WriteLine($"Stream disposed: {!stream.CanRead}"); // True + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.IO.StreamFactory.md b/.docfx/api/types/Cuemon.IO.StreamFactory.md new file mode 100644 index 00000000..a25f8649 --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.StreamFactory.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.IO.StreamFactory +example: +- *content +--- + +The following example demonstrates how to create instances using . + +```csharp +using System; +using System.IO; +using System.Text; +using Cuemon.IO; +using Cuemon.Text; + +namespace MyApp.Examples; + +public static class StreamFactoryExample +{ + public static void Demonstrate() + { + // Create a stream by writing to a StreamWriter + Stream stream = StreamFactory.Create(writer => + { + writer.Write("Hello, StreamFactory!"); + }); + + Console.WriteLine($"Stream length: {stream.Length}"); + Console.WriteLine($"Stream position: {stream.Position}"); + + using var reader = new StreamReader(stream); + string content = reader.ReadToEnd(); + Console.WriteLine(content); + + // Create a stream with encoding options + Stream utf32Stream = StreamFactory.Create(writer => + { + writer.Write("UTF-32 encoded content"); + }, options => + { + options.Encoding = Encoding.UTF32; + options.Preamble = PreambleSequence.Remove; + }); + + using var utf32Reader = new StreamReader(utf32Stream, Encoding.UTF32); + Console.WriteLine(utf32Reader.ReadToEnd()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.IO.StreamReaderOptions.md b/.docfx/api/types/Cuemon.IO.StreamReaderOptions.md new file mode 100644 index 00000000..010448cc --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.StreamReaderOptions.md @@ -0,0 +1,55 @@ +--- +uid: Cuemon.IO.StreamReaderOptions +example: +- *content +--- + +The following example demonstrates how to configure StreamReaderOptions to control encoding, preamble handling, and buffer size when reading from streams. + +```csharp +using System; +using System.IO; +using System.Text; +using Cuemon.IO; +using Cuemon.Text; + +namespace MyApp.IO +{ + public class StreamReaderOptionsExample + { + public void Demonstrate() + { + // Default options: UTF-8 without BOM, 81920 buffer + var defaultOptions = new StreamReaderOptions(); + Console.WriteLine($"Default encoding: {defaultOptions.Encoding.EncodingName}"); // UTF-8 + Console.WriteLine($"Default preamble: {defaultOptions.Preamble}"); // Remove + Console.WriteLine($"Default buffer size: {defaultOptions.BufferSize}"); // 81920 + + // Read a UTF-32 file with a smaller buffer + var utf32Options = new StreamReaderOptions + { + Encoding = Encoding.UTF32, + Preamble = PreambleSequence.Keep, + BufferSize = 4096 + }; + + // Create a StreamReader using these options + byte[] data = Encoding.UTF32.GetBytes("Hello, World!"); + using var stream = new MemoryStream(data); + using var reader = new StreamReader(stream, utf32Options.Encoding, false, utf32Options.BufferSize); + + string content = reader.ReadToEnd(); + Console.WriteLine($"Read content: {content}"); + + // Options for reading with explicit BOM handling + var bomOptions = new StreamReaderOptions + { + Encoding = Encoding.UTF8, + Preamble = PreambleSequence.Keep + }; + Console.WriteLine($"BOM preamble: {bomOptions.Preamble}"); // Keep + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.IO.StreamWriterOptions.md b/.docfx/api/types/Cuemon.IO.StreamWriterOptions.md new file mode 100644 index 00000000..ead733c5 --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.StreamWriterOptions.md @@ -0,0 +1,57 @@ +--- +uid: Cuemon.IO.StreamWriterOptions +example: +- *content +--- + +The following example demonstrates how to configure StreamWriterOptions to control encoding, preamble handling, buffer size, and formatting when writing to streams. + +```csharp +using System; +using System.Globalization; +using System.IO; +using Cuemon; +using Cuemon.IO; +using Cuemon.Text; + +namespace Contoso.Reporting; + +public sealed class StreamWriterOptionsExample +{ + public static void Run() + { + var options = new StreamWriterOptions + { + AutoFlush = true, + BufferSize = 256, + Encoding = EncodingOptions.DefaultEncoding, + Preamble = PreambleSequence.Remove, + FormatProvider = CultureInfo.InvariantCulture, + NewLine = "\n" + }; + + using Stream stream = StreamFactory.Create(writer => + { + string formatted = string.Format(options.FormatProvider, "Value: {0:F2}", Math.PI); + writer.WriteLine(formatted); + }, setup => + { + setup.AutoFlush = options.AutoFlush; + setup.BufferSize = options.BufferSize; + setup.Encoding = options.Encoding; + setup.Preamble = options.Preamble; + setup.FormatProvider = options.FormatProvider; + setup.NewLine = options.NewLine; + }); + + string output = Decorator.Enclose(stream).ToEncodedString(setup => + { + setup.Encoding = options.Encoding; + setup.Preamble = options.Preamble; + setup.LeaveOpen = true; + }); + + Console.WriteLine(output.Trim()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.IO.TextReaderDecoratorExtensions.md b/.docfx/api/types/Cuemon.IO.TextReaderDecoratorExtensions.md new file mode 100644 index 00000000..5a849fd3 --- /dev/null +++ b/.docfx/api/types/Cuemon.IO.TextReaderDecoratorExtensions.md @@ -0,0 +1,54 @@ +--- +uid: Cuemon.IO.TextReaderDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to copy content from one TextReader to a TextWriter asynchronously using TextReaderDecoratorExtensions, with configurable buffer sizes. + +```csharp +using System.Text; +using System; +using System.IO; +using System.Threading.Tasks; +using Cuemon; +using Cuemon.IO; + +namespace MyApp.IO +{ + public class TextReaderDecoratorExtensionsExample + { + public async Task DemonstrateAsync() + { + string source = "Line 1\nLine 2\nLine 3\n"; + + // Copy content from a TextReader to a TextWriter asynchronously + using var reader = new StringReader(source); + using var writer = new StringWriter(); + + await Decorator.Enclose(reader).CopyToAsync(writer); + + string result = writer.ToString(); + Console.WriteLine(result); // "Line 1\nLine 2\nLine 3\n" + + // Use a custom buffer size + using var readerSmallBuffer = new StringReader(source); + using var writerSmallBuffer = new StringWriter(); + + await Decorator.Enclose(readerSmallBuffer).CopyToAsync(writerSmallBuffer, bufferSize: 1024); + + string resultSmallBuffer = writerSmallBuffer.ToString(); + Console.WriteLine(resultSmallBuffer); // "Line 1\nLine 2\nLine 3\n" + + // Copy between different TextReader/TextWriter types + using var streamReader = new StreamReader(new MemoryStream( + Encoding.UTF8.GetBytes("Stream content"))); + using var stringWriter = new StringWriter(); + + await Decorator.Enclose(streamReader).CopyToAsync(stringWriter); + Console.WriteLine(stringWriter.ToString()); // "Stream content" + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.IntegerDecoratorExtensions.md b/.docfx/api/types/Cuemon.IntegerDecoratorExtensions.md new file mode 100644 index 00000000..fb4b2f45 --- /dev/null +++ b/.docfx/api/types/Cuemon.IntegerDecoratorExtensions.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.IntegerDecoratorExtensions +example: +- *content +--- + +The following example shows how to extend `int` with `IntegerDecoratorExtensions` methods to clamp integer values to a minimum bound via the decorator pattern. + +```csharp +using System; +using Cuemon; + +namespace MyApp.Numeric +{ + public class IntegerDecoratorExtensionsExample + { + public void Demonstrate() + { + // Wrap an int with Decorator.Enclose to access the Max extension + int value = 42; + int minimum = 100; + + // Returns the larger of the wrapped value and the specified minimum + int result = Decorator.Enclose(value).Max(minimum); + Console.WriteLine(result); // Output: 100 + + // When the wrapped value is larger than the minimum + value = 500; + result = Decorator.Enclose(value).Max(minimum); + Console.WriteLine(result); // Output: 500 + + // Works with any int expression + result = Decorator.Enclose(-10).Max(0); + Console.WriteLine(result); // Output: 0 + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Messaging.CorrelationToken.md b/.docfx/api/types/Cuemon.Messaging.CorrelationToken.md new file mode 100644 index 00000000..dce7a575 --- /dev/null +++ b/.docfx/api/types/Cuemon.Messaging.CorrelationToken.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.Messaging.CorrelationToken +example: +- *content +--- + +The following example shows how to create one correlation identifier and pass it through related work. + +```csharp +using System; +using Cuemon.Messaging; + +namespace MyApp.Examples; + +public static class CorrelationTokenExample +{ + public static void Demonstrate() + { + var generated = new CorrelationToken(); + var provided = new CorrelationToken("order-2026-0001"); + + Console.WriteLine(generated.CorrelationId.Length == 32); + Console.WriteLine(provided.ToString()); + Console.WriteLine(AttachToMessage("InventoryReserved", provided)); + } + + private static string AttachToMessage(string messageType, ICorrelationToken token) + { + return $"{messageType}:{token.CorrelationId}"; + } +} +``` diff --git a/.docfx/api/types/Cuemon.Messaging.RequestToken.md b/.docfx/api/types/Cuemon.Messaging.RequestToken.md new file mode 100644 index 00000000..8adf952a --- /dev/null +++ b/.docfx/api/types/Cuemon.Messaging.RequestToken.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Messaging.RequestToken +example: +- *content +--- + +The following example demonstrates how to use to uniquely identify an individual request within a system. + +```csharp +using System; +using Cuemon.Messaging; + +namespace MyApp.Examples; + +public class RequestTokenExample +{ + public void Demonstrate() + { + // Each request gets its own unique ID + var request1 = new RequestToken(); + var request2 = new RequestToken(); + + Console.WriteLine($"Request 1 ID: {request1}"); + Console.WriteLine($"Request 2 ID: {request2}"); + Console.WriteLine($"Are they different? {request1.RequestId != request2.RequestId}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.MutableTuple.md b/.docfx/api/types/Cuemon.MutableTuple.md new file mode 100644 index 00000000..42972998 --- /dev/null +++ b/.docfx/api/types/Cuemon.MutableTuple.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.MutableTuple +example: +- *content +--- + +The following example demonstrates how to create and use and its generic variants to store and pass multiple values without creating a custom class. + +```csharp +using System; +using Cuemon; + +namespace Contoso.Workflow; + +public sealed class MutableTupleExample +{ + public static void Run() + { + MutableTuple empty = new MutableTuple(); + var pair = new MutableTuple("Alice", 30); + + pair.Arg2 = 31; + + object[] values = pair.ToArray("verified"); + var clone = (MutableTuple)pair.Clone(); + + Console.WriteLine($"Empty: {empty.IsEmpty}"); + Console.WriteLine($"{clone.Arg1}:{clone.Arg2}"); + Console.WriteLine($"Array length: {values.Length}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.MutableTuple`1.md b/.docfx/api/types/Cuemon.MutableTuple`1.md new file mode 100644 index 00000000..b1346a04 --- /dev/null +++ b/.docfx/api/types/Cuemon.MutableTuple`1.md @@ -0,0 +1,24 @@ +--- +uid: Cuemon.MutableTuple`1 +example: +- *content +--- + +```csharp +using System; +using Cuemon; + +namespace MyApp.Data; + +public class MutableTupleExample +{ + public void Demonstrate() + { + var tuple = new MutableTuple("example"); + Console.WriteLine(tuple.Arg1); // "example" + + tuple.Arg1 = "updated"; + Console.WriteLine(tuple.Arg1); // "updated" + } +} +``` diff --git a/.docfx/api/types/Cuemon.Net.ByteArrayDecoratorExtensions.md b/.docfx/api/types/Cuemon.Net.ByteArrayDecoratorExtensions.md new file mode 100644 index 00000000..5bb012b0 --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.ByteArrayDecoratorExtensions.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.Net.ByteArrayDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to URL-encode byte array data using ByteArrayDecoratorExtensions, with support for partial encoding and custom character encoding options. + +```csharp +using System; +using System.Text; +using Cuemon; +using Cuemon.Net; +using Cuemon.Text; + +namespace MyApp.Net +{ + public class ByteArrayDecoratorExtensionsExample + { + public void Demonstrate() + { + // Create bytes containing characters that need URL encoding + byte[] data = Encoding.UTF8.GetBytes("hello world & more "); + + // URL-encode the bytes with default position (0) and length (all) + byte[] encoded = Decorator.Enclose(data).UrlEncode(); + string encodedString = Encoding.ASCII.GetString(encoded); + Console.WriteLine(encodedString); // "hello+world+%26+more+%3cstuff%3e" + + // Encode only a portion of the byte array + byte[] partial = Encoding.UTF8.GetBytes("a & b & c"); + byte[] encodedPartial = Decorator.Enclose(partial).UrlEncode(position: 0, bytesToRead: 5); + string partialString = Encoding.ASCII.GetString(encodedPartial); + Console.WriteLine(partialString); // "a+%26+b" (only first 5 bytes encoded) + + // Encode with custom encoding options + byte[] utf32Data = Encoding.UTF32.GetBytes("hello"); + byte[] utf32Encoded = Decorator.Enclose(utf32Data).UrlEncode(0, utf32Data.Length, o => + { + o.Encoding = Encoding.UTF32; + }); + + // Handle empty byte arrays + byte[] empty = Array.Empty(); + byte[] emptyEncoded = Decorator.Enclose(empty).UrlEncode(); + Console.WriteLine(emptyEncoded.Length); // 0 + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Net.Collections.Specialized.NameValueCollectionDecoratorExtensions.md b/.docfx/api/types/Cuemon.Net.Collections.Specialized.NameValueCollectionDecoratorExtensions.md new file mode 100644 index 00000000..3fd9b4d1 --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.Collections.Specialized.NameValueCollectionDecoratorExtensions.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.Net.Collections.Specialized.NameValueCollectionDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the `ToString` extension method to convert a `NameValueCollection` into a URI query string. + +```csharp +using System; +using System.Collections.Specialized; +using Cuemon; +using Cuemon.Net; +using Cuemon.Net.Collections.Specialized; + +namespace MyApp.Examples; + +public class NameValueCollectionDecoratorExtensionsExample +{ + public static void Main() + { + var nvc = new NameValueCollection + { + ["name"] = "John Doe", + ["city"] = "Copenhagen", + ["country"] = "Denmark" + }; + + // Convert to URL query string with ampersand separator and URL encoding. + string queryString = Decorator.Enclose(nvc).ToString(FieldValueSeparator.Ampersand, urlEncode: true); + Console.WriteLine(queryString); + + // Output: + // ?name=John%20Doe&city=Copenhagen&country=Denmark + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Net.FieldValueSeparator.md b/.docfx/api/types/Cuemon.Net.FieldValueSeparator.md new file mode 100644 index 00000000..fb325f1b --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.FieldValueSeparator.md @@ -0,0 +1,33 @@ +--- +uid: Cuemon.Net.FieldValueSeparator +example: +- *content +--- + +The following example demonstrates how to use to specify the separator for query string key-value pairs. + +```csharp +using System; +using Cuemon.Net; + +namespace MyApp.Examples; + +public class FieldValueSeparatorExample +{ + public void Demonstrate() + { + var separator = FieldValueSeparator.Ampersand; + + switch (separator) + { + case FieldValueSeparator.Ampersand: + Console.WriteLine("Using & separator for query string parameters (default)."); + break; + case FieldValueSeparator.Semicolon: + Console.WriteLine("Using ; separator for query string parameters."); + break; + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpAuthenticationSchemes.md b/.docfx/api/types/Cuemon.Net.Http.HttpAuthenticationSchemes.md new file mode 100644 index 00000000..1397cc2b --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.Http.HttpAuthenticationSchemes.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Net.Http.HttpAuthenticationSchemes +example: +- *content +--- + +```csharp +using System; +using System.Net.Http.Headers; +using System.Text; +using Cuemon.Net.Http; + +namespace MyApp.Examples; + +public static class HttpAuthenticationSchemesExample +{ + public static void Demonstrate() + { + // Use scheme constants to construct Authorization headers + string basic = HttpAuthenticationSchemes.Basic; + string bearer = HttpAuthenticationSchemes.Bearer; + string digest = HttpAuthenticationSchemes.Digest; + + Console.WriteLine($"Basic: {basic}"); + Console.WriteLine($"Bearer: {bearer}"); + Console.WriteLine($"Digest: {digest}"); + + // Example: create a Basic authentication header value + string credentials = Convert.ToBase64String( + Encoding.UTF8.GetBytes("user:password")); + string authHeader = $"{basic} {credentials}"; + Console.WriteLine($"Authorization: {authHeader}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpDependency.md b/.docfx/api/types/Cuemon.Net.Http.HttpDependency.md new file mode 100644 index 00000000..94b40ec8 --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.Http.HttpDependency.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.Net.Http.HttpDependency +example: +- *content +--- + +The following example demonstrates how to monitor an HTTP resource for changes using HttpDependency, which wraps an HttpWatcher to detect modifications via ETag and Last-Modified headers. + +```csharp +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Cuemon.Net.Http; + +namespace MyApp.Net +{ + public class HttpDependencyExample + { + public async Task DemonstrateAsync() + { + // Create an HttpWatcher that monitors changes to a URI resource + var watcherFactory = new Lazy(() => + { + var location = new Uri("https://example.com/api/status"); + return new HttpWatcher(location, o => + { + o.ReadResponseBody = false; // use HEAD requests (checks ETag/Last-Modified) + o.Period = TimeSpan.FromSeconds(30); + }); + }); + + // Create a dependency that wraps the watcher + var dependency = new HttpDependency(watcherFactory); + + // Subscribe to change notifications + dependency.DependencyChanged += (sender, args) => + { + Console.WriteLine($"Resource changed at: {args.UtcLastModified}"); + }; + + // Start monitoring + await dependency.StartAsync(); + + // The watcher will poll the URI every 30 seconds + // and raise DependencyChanged when a change is detected + + Console.WriteLine("Monitoring started. Press any key to stop..."); + Console.ReadKey(); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpHeaderNames.md b/.docfx/api/types/Cuemon.Net.Http.HttpHeaderNames.md new file mode 100644 index 00000000..450e5487 --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.Http.HttpHeaderNames.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Net.Http.HttpHeaderNames +example: +- *content +--- + +The following example demonstrates how to use constants when working with HTTP request and response headers. + +```csharp +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Cuemon.Net.Http; + +namespace MyApp.Examples; + +public static class HttpHeaderNamesExample +{ + public static async Task DemonstrateAsync() + { + using var client = new HttpClient(); + using var request = new HttpRequestMessage(HttpMethod.Get, "https://example.com"); + + // Set request headers using the constants + request.Headers.Add(HttpHeaderNames.Accept, "application/json"); + request.Headers.Add(HttpHeaderNames.Authorization, "Bearer token123"); + request.Headers.Add(HttpHeaderNames.UserAgent, "MyApp/1.0"); + request.Headers.Add(HttpHeaderNames.AcceptEncoding, "gzip"); + + Console.WriteLine("Request headers configured:"); + foreach (var header in request.Headers) + { + Console.WriteLine($" {header.Key}: {string.Join(", ", header.Value)}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpManager.md b/.docfx/api/types/Cuemon.Net.Http.HttpManager.md new file mode 100644 index 00000000..5f98eb3c --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.Http.HttpManager.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.Net.Http.HttpManager +example: +- *content +--- + +The following example demonstrates how to use with a custom in-memory HTTP handler. + +```csharp +using System; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Cuemon.Net.Http; + +namespace MyApp.Examples; + +public static class HttpManagerExample +{ + public static async Task DemonstrateAsync() + { + using var manager = new HttpManager(() => new HttpClient(new EchoHandler(), false)); + using var response = await manager.HttpGetAsync(new Uri("https://example.com/health")); + + Console.WriteLine(response.StatusCode); + Console.WriteLine(manager.Timeout > TimeSpan.Zero); + } + + private sealed class EchoHandler : HttpMessageHandler + { + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK) + { + RequestMessage = request, + Content = new StringContent("OK") + }); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpManagerOptions.md b/.docfx/api/types/Cuemon.Net.Http.HttpManagerOptions.md new file mode 100644 index 00000000..2a094848 --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.Http.HttpManagerOptions.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Net.Http.HttpManagerOptions +example: +- *content +--- + +The following example demonstrates how to configure before passing them to . + +```csharp +using System; +using System.Net.Http; +using Cuemon.Net.Http; + +namespace MyApp.Examples; + +public static class HttpManagerOptionsExample +{ + public static void Demonstrate() + { + var options = new HttpManagerOptions + { + Timeout = TimeSpan.FromSeconds(10), + HandlerFactory = () => new HttpClientHandler(), + DefaultRequestHeaders = + { + ["X-Correlation-Id"] = "docs-123" + } + }; + + options.ValidateOptions(); + + Console.WriteLine(options.Timeout.TotalSeconds); + Console.WriteLine(options.DefaultRequestHeaders["X-Correlation-Id"]); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpMethodConverter.md b/.docfx/api/types/Cuemon.Net.Http.HttpMethodConverter.md new file mode 100644 index 00000000..f97e2b7f --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.Http.HttpMethodConverter.md @@ -0,0 +1,23 @@ +--- +uid: Cuemon.Net.Http.HttpMethodConverter +example: +- *content +--- + +```csharp +using System; +using System.Net.Http; +using Cuemon.Net.Http; + +namespace MyApp.Examples; + +public static class HttpMethodConverterExample +{ + public static void Demonstrate() + { + HttpMethod get = HttpMethod.Get; + HttpMethods result = HttpMethodConverter.ToHttpMethod(get); + Console.WriteLine(result); // Get + } +} +``` diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpMethods.md b/.docfx/api/types/Cuemon.Net.Http.HttpMethods.md new file mode 100644 index 00000000..9a512a0c --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.Http.HttpMethods.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.Net.Http.HttpMethods +example: +- *content +--- + +The following example demonstrates how to combine and test flags. + +```csharp +using System; +using Cuemon.Net.Http; + +namespace MyApp.Examples; + +public static class HttpMethodsExample +{ + public static void Demonstrate() + { + var allowedMethods = HttpMethods.Get | HttpMethods.Post | HttpMethods.Head; + + Console.WriteLine(allowedMethods.HasFlag(HttpMethods.Get)); + Console.WriteLine(allowedMethods.HasFlag(HttpMethods.Delete)); + Console.WriteLine(allowedMethods & ~HttpMethods.Head); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpRequestOptions.md b/.docfx/api/types/Cuemon.Net.Http.HttpRequestOptions.md new file mode 100644 index 00000000..1f4029dd --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.Http.HttpRequestOptions.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Net.Http.HttpRequestOptions +example: +- *content +--- + +The following example demonstrates how to configure and send an HTTP request using `HttpRequestOptions` with the `HttpManager`. + +```csharp +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Cuemon.Net.Http; +using HttpRequestOptions = Cuemon.Net.Http.HttpRequestOptions; + +namespace Examples; + +public class HttpRequestExample +{ + public async Task SendRequestAsync() + { + // Direct instantiation of HttpRequestOptions + var requestOptions = new HttpRequestOptions(); + requestOptions.Request.Method = HttpMethod.Get; + + using var manager = new HttpManager(); + using var response = await manager.HttpAsync( + new Uri("https://api.example.com/data"), + o => + { + o.Request.Method = HttpMethod.Get; + o.Request.Headers.Add("Accept", "application/json"); + }); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpWatcher.md b/.docfx/api/types/Cuemon.Net.Http.HttpWatcher.md new file mode 100644 index 00000000..2917aba3 --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.Http.HttpWatcher.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Net.Http.HttpWatcher +example: +- *content +--- + +The following example demonstrates how to configure an for a remote URI and inspect its active monitoring settings. + +```csharp +using System; +using Cuemon.Net.Http; + +namespace MyApp.Examples; + +public static class HttpWatcherExample +{ + public static void Demonstrate() + { + var watcher = new HttpWatcher(new Uri("https://example.com/feed"), options => + { + options.ReadResponseBody = true; + options.Period = TimeSpan.FromSeconds(10); + }); + + Console.WriteLine(watcher.Location); + Console.WriteLine(watcher.ReadResponseBody); + Console.WriteLine(watcher.HashFactory != null); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpWatcherOptions.md b/.docfx/api/types/Cuemon.Net.Http.HttpWatcherOptions.md new file mode 100644 index 00000000..75e719cc --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.Http.HttpWatcherOptions.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Net.Http.HttpWatcherOptions +example: +- *content +--- + +The following example demonstrates how to configure before creating an . + +```csharp +using System; +using System.Net.Http; +using Cuemon.Net.Http; +using Cuemon.Security; + +namespace MyApp.Examples; + +public static class HttpWatcherOptionsExample +{ + public static void Demonstrate() + { + var options = new HttpWatcherOptions + { + ClientFactory = () => new HttpClient(new HttpClientHandler(), false), + HashFactory = () => new CyclicRedundancyCheck64(), + ReadResponseBody = true, + Period = TimeSpan.FromSeconds(5) + }; + + options.ValidateOptions(); + + Console.WriteLine(options.ReadResponseBody); + Console.WriteLine(options.Period.TotalSeconds); + Console.WriteLine(options.ClientFactory().GetType().Name); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Net.Mail.MailDistributor.md b/.docfx/api/types/Cuemon.Net.Mail.MailDistributor.md new file mode 100644 index 00000000..1f9fe2fe --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.Mail.MailDistributor.md @@ -0,0 +1,33 @@ +--- +uid: Cuemon.Net.Mail.MailDistributor +example: +- *content +--- + +The following example demonstrates how to construct a and skip delivery through a filter when you only want to validate a message batch. + +```csharp +using System; +using System.Net.Mail; +using System.Threading.Tasks; +using Cuemon.Net.Mail; + +namespace MyApp.Examples; + +public static class MailDistributorExample +{ + public static async Task DemonstrateAsync() + { + var distributor = new MailDistributor(() => new SmtpClient("smtp.example.com", 25), deliverySize: 10); + using var mail = new MailMessage("sender@example.com", "receiver@example.com") + { + Subject = "Docs sample", + Body = "This message is filtered out before delivery." + }; + + await distributor.SendOneAsync(mail, _ => false); + + Console.WriteLine("Delivery skipped by filter."); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Net.QueryStringCollection.md b/.docfx/api/types/Cuemon.Net.QueryStringCollection.md new file mode 100644 index 00000000..8c21b300 --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.QueryStringCollection.md @@ -0,0 +1,56 @@ +--- +uid: Cuemon.Net.QueryStringCollection +example: +- *content +--- + +The following example demonstrates how to create, parse, and manipulate URI query string parameters using QueryStringCollection, with support for URL decoding and cloning. + +```csharp +using System; +using System.Linq; +using Cuemon.Net; + +namespace MyApp.Net +{ + public static class QueryStringCollectionExamples + { + public static void Demonstrate() + { + // Create an empty query string collection and add parameters. + var qsc = new QueryStringCollection(); + qsc.Add("search", "dotnet"); + qsc.Add("page", "2"); + qsc.Add("sort", "name"); + Console.WriteLine("Query string: {0}", qsc); // search=dotnet&page=2&sort=name + + // Create from an existing URI query string. + var fromUrl = new QueryStringCollection("?category=books&author=tolkien"); + Console.WriteLine("Parsed query: {0}", fromUrl); // category=books&author=tolkien + + // Create with URL decoding enabled. + var encoded = new QueryStringCollection("q=hello%20world&lang=en", urlDecode: true); + Console.WriteLine("Decoded 'q': {0}", encoded["q"]); // hello world + + // Iterate over key-value pairs. + Console.WriteLine("Parameters:"); + foreach (var pair in fromUrl) + { + Console.WriteLine(" {0} = {1}", pair.Key, pair.Value); + + // Use AllKeys from the base NameValueCollection. + Console.WriteLine("Keys: {0}", string.Join(", ", qsc.AllKeys)); + + // Clone a QueryStringCollection. + var clone = new QueryStringCollection(qsc); + clone["page"] = "3"; + Console.WriteLine("Original page: {0}", qsc["page"]); // 2 + Console.WriteLine("Cloned page: {0}", clone["page"]); // 3 + + // Count entries. + Console.WriteLine("Count: {0}", qsc.Count); + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Net.StringDecoratorExtensions.md b/.docfx/api/types/Cuemon.Net.StringDecoratorExtensions.md new file mode 100644 index 00000000..9815c7a8 --- /dev/null +++ b/.docfx/api/types/Cuemon.Net.StringDecoratorExtensions.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.Net.StringDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to URL-encode and URL-decode strings using StringDecoratorExtensions, with support for custom encodings. + +```csharp +using System; +using Cuemon; +using System.Text; +using Cuemon.Net; +using Cuemon.Text; + +namespace MyApp.Net +{ + public class StringDecoratorExtensionsExample + { + public void Demonstrate() + { + // URL-encode a string with special characters + string raw = "hello world & some "; + + // Invoke UrlEncode extension method + string encoded = Decorator.Enclose(raw).UrlEncode(); + Console.WriteLine(encoded); // "hello+world+%26+some+%3cstuff%3e" + + // Also invoke as static method via the Cuemon.Net.StringDecoratorExtensions type + string encodedStatic = Cuemon.Net.StringDecoratorExtensions.UrlEncode(Decorator.Enclose(raw)); + Console.WriteLine(encodedStatic); // "hello+world+%26+some+%3cstuff%3e" + + // URL-decode the encoded string back + string decoded = Decorator.Enclose(encoded).UrlDecode(); + Console.WriteLine(decoded); // "hello world & some " + + // Invoke UrlDecode as static method via the Cuemon.Net.StringDecoratorExtensions type + string decodedStatic = Cuemon.Net.StringDecoratorExtensions.UrlDecode(Decorator.Enclose(encoded)); + Console.WriteLine(decodedStatic); // "hello world & some " + + // Encode with a specific encoding + string encodedUtf8 = Decorator.Enclose("a=b&c=d").UrlEncode(o => + { + o.Encoding = Encoding.UTF8; + }); + Console.WriteLine(encodedUtf8); // "a%3db%26c%3dd" + + } + } +} + +``` diff --git a/.docfx/api/types/Cuemon.ObjectDecoratorExtensions.md b/.docfx/api/types/Cuemon.ObjectDecoratorExtensions.md new file mode 100644 index 00000000..d7693aea --- /dev/null +++ b/.docfx/api/types/Cuemon.ObjectDecoratorExtensions.md @@ -0,0 +1,65 @@ +--- +uid: Cuemon.ObjectDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the extension methods to convert object types and traverse hierarchical structures through the pattern. + +```csharp +using System; +using System.Collections.Generic; +using System.Globalization; +using Cuemon; + +namespace DocExamples +{ + public static class ObjectDecoratorExamples + { + public static void Main() + { + // Convert a string to an integer + object input = "42"; + int result = Decorator.Enclose(input).ChangeType(); + Console.WriteLine($"Converted string to int: {result} (type: {result.GetType().Name})"); + + // Convert a string to DateTime (UTC) + object dateInput = "2024-01-15T10:30:00Z"; + DateTime dateResult = Decorator.Enclose(dateInput).ChangeType(); + Console.WriteLine($"Converted to DateTime: {dateResult} (Kind: {dateResult.Kind})"); + + // Convert with a fallback value + object invalidInput = "not-a-number"; + int fallbackResult = Decorator.Enclose(invalidInput).ChangeTypeOrDefault(42); + Console.WriteLine($"Conversion with fallback: {fallbackResult}"); + + // Convert a string to an enum + object enumInput = "Ascending"; + var enumResult = Decorator.Enclose(enumInput).ChangeType(); + Console.WriteLine($"Converted to SortOrder: {enumResult}"); + + // Traverse a hierarchical tree structure + var grandchild = new TreeNode { Name = "Grandchild" }; + var child1 = new TreeNode { Name = "Child1", Children = { grandchild } }; + var child2 = new TreeNode { Name = "Child2" }; + var root = new TreeNode { Name = "Root", Children = { child1, child2 } }; + + var allNodes = Decorator.Enclose(root).TraverseWhileNotEmpty(node => node.Children); + foreach (var node in allNodes) + { + Console.WriteLine($"Visited: {node.Name}"); + } + + var property = typeof(TreeNode).GetProperty(nameof(TreeNode.Name)); + var resolvedName = Decorator.Enclose((object)root).DefaultPropertyValueResolver(property); + Console.WriteLine($"Resolved property value: {resolvedName}"); + } + + private class TreeNode + { + public string Name { get; set; } + public List Children { get; } = new List(); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.ObjectFormattingOptions.md b/.docfx/api/types/Cuemon.ObjectFormattingOptions.md new file mode 100644 index 00000000..4038470f --- /dev/null +++ b/.docfx/api/types/Cuemon.ObjectFormattingOptions.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.ObjectFormattingOptions +example: +- *content +--- + +The following example demonstrates how to use to customize the conversion of an object to a different type via . + +```csharp +using System; +using System.Globalization; +using Cuemon; + +namespace MyApp.Examples; + +public class ObjectFormattingOptionsExample +{ + public void Demonstrate() + { + // Direct instantiation of ObjectFormattingOptions + var options = new ObjectFormattingOptions + { + FormatProvider = new CultureInfo("da-DK") + }; + + var value = "1234.56"; + + // Convert the string to a double using Danish formatting + var result = Decorator.Enclose((object)value) + .ChangeType(o => + { + o.FormatProvider = new CultureInfo("da-DK"); + }); + + Console.WriteLine(result); // Output: 1234.56 + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.ObjectPortrayalOptions.md b/.docfx/api/types/Cuemon.ObjectPortrayalOptions.md new file mode 100644 index 00000000..a095638b --- /dev/null +++ b/.docfx/api/types/Cuemon.ObjectPortrayalOptions.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.ObjectPortrayalOptions +example: +- *content +--- + +The following example demonstrates how to use with to produce a human-readable property dump of an object. + +```csharp +using System; +using Cuemon; + +namespace Contoso.Diagnostics; + +public sealed class ObjectPortrayalOptionsExample +{ + public static void Run() + { + var options = new ObjectPortrayalOptions + { + BypassOverrideCheck = true, + Delimiter = "; ", + NullValue = "(none)" + }; + + var profile = new SampleProfile { Name = "Alice", Nickname = null }; + + string portrayal = Generate.ObjectPortrayal(profile, setup => + { + setup.BypassOverrideCheck = options.BypassOverrideCheck; + setup.Delimiter = options.Delimiter; + setup.NullValue = options.NullValue; + }); + + Console.WriteLine(portrayal); + } + + private sealed class SampleProfile + { + public string Name { get; set; } + + public string Nickname { get; set; } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Patterns.md b/.docfx/api/types/Cuemon.Patterns.md new file mode 100644 index 00000000..a3a55399 --- /dev/null +++ b/.docfx/api/types/Cuemon.Patterns.md @@ -0,0 +1,46 @@ +--- +uid: Cuemon.Patterns +example: +- *content +--- + +The following example demonstrates how to use the class to safely invoke delegates, configure options via the Options pattern, and guard against fatal exceptions. + +```csharp +using System; +using System.Threading; +using Cuemon; +using Cuemon.Threading; + +namespace Contoso.Infrastructure; + +public sealed class PatternsExample +{ + public static void Run() + { + var options = Patterns.Configure(setup => + { + setup.CancellationToken = CancellationToken.None; + }); + + var profile = Patterns.CreateInstance(instance => + { + instance.Name = "health"; + }); + + bool wroteMessage = Patterns.TryInvoke(() => Console.WriteLine(profile.Name)); + int fallbackPort = Patterns.InvokeOrDefault(() => int.Parse("not-a-number"), -1); + bool recoverable = Patterns.IsRecoverableException(new InvalidOperationException("Transient.")); + + Console.WriteLine($"Token can cancel: {options.CancellationToken.CanBeCanceled}"); + Console.WriteLine($"TryInvoke succeeded: {wroteMessage}"); + Console.WriteLine($"Fallback port: {fallbackPort}"); + Console.WriteLine($"Recoverable: {recoverable}"); + } + + private sealed class EndpointProfile + { + public string Name { get; set; } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Reflection.ActivatorFactory.md b/.docfx/api/types/Cuemon.Reflection.ActivatorFactory.md new file mode 100644 index 00000000..7b582a12 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.ActivatorFactory.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.Reflection.ActivatorFactory +example: +- *content +--- + +```csharp +using System; +using System.Text; +using Cuemon.Reflection; + +namespace Cuemon.Reflection; + +public class ActivatorFactoryExample +{ + public void Demonstrate() + { + var sb = ActivatorFactory.CreateInstance(); + sb.Append("Hello from activator"); + Console.WriteLine(sb.ToString()); + + var dt = ActivatorFactory.CreateInstance(2025, 12, 1); + Console.WriteLine($"Created: {dt:yyyy-MM-dd}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Reflection.ActivatorOptions.md b/.docfx/api/types/Cuemon.Reflection.ActivatorOptions.md new file mode 100644 index 00000000..177acde8 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.ActivatorOptions.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Reflection.ActivatorOptions +example: +- *content +--- + +The following example demonstrates how to use with to customize object creation with specific binding flags. + +```csharp +using System; +using System.Reflection; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public class ActivatorOptionsExample +{ + public void Demonstrate() + { + // Direct instantiation of ActivatorOptions + var options = new ActivatorOptions + { + Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance + }; + + // Create a Uri instance using a factory with explicit binding flags + var uri = ActivatorFactory.CreateInstance("http://example.com", o => + { + o.Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance; + }); + + Console.WriteLine(uri.Host); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Reflection.AssemblyContext.md b/.docfx/api/types/Cuemon.Reflection.AssemblyContext.md new file mode 100644 index 00000000..3fed62d1 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.AssemblyContext.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.Reflection.AssemblyContext +example: +- *content +--- + +```csharp +using System; +using System.Linq; +using Cuemon.Reflection; + +namespace Cuemon.Reflection; + +public class AssemblyContextExample +{ + public void Demonstrate() + { + var assemblies = AssemblyContext.GetCurrentDomainAssemblies(options => + { + options.AssemblyFilter = a => a.FullName?.StartsWith("Cuemon") == true; + }); + + foreach (var assembly in assemblies) + { + Console.WriteLine($"Assembly: {assembly.GetName().Name}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Reflection.AssemblyContextOptions.md b/.docfx/api/types/Cuemon.Reflection.AssemblyContextOptions.md new file mode 100644 index 00000000..e7b00e4c --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.AssemblyContextOptions.md @@ -0,0 +1,72 @@ +--- +uid: Cuemon.Reflection.AssemblyContextOptions +example: +- *content +--- + +The following example demonstrates how to configure to control which assemblies are returned by . + +```csharp +using System; +using System.Linq; +using System.Reflection; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public class AssemblyContextOptionsExample +{ + public void FilterAssemblies() + { + // Configure to include only assemblies whose name contains "Cuemon" + // and exclude the current assembly from results + var assemblies = AssemblyContext.GetCurrentDomainAssemblies(o => + { + o.AssemblyFilter = assembly => + assembly.FullName.StartsWith("Cuemon", StringComparison.Ordinal); + + o.ReferencedAssemblyFilter = assemblyName => + assemblyName.FullName.StartsWith("Cuemon", StringComparison.Ordinal); + + o.IncludeReferencedAssemblies = true; + + // Remove the default exclusion of Cuemon.Core + o.ExcludedAssemblies.Clear(); + }); + + foreach (var assembly in assemblies) + { + Console.WriteLine(assembly.GetName().Name); + } + } + + public void UseDefaults() + { + // Default options exclude System and Microsoft assemblies + var options = new AssemblyContextOptions(); + Console.WriteLine($"IncludeReferencedAssemblies: {options.IncludeReferencedAssemblies}"); // true + Console.WriteLine($"AssemblyFilter: {(options.AssemblyFilter != null ? "set" : "null")}"); + Console.WriteLine($"ReferencedAssemblyFilter: {(options.ReferencedAssemblyFilter != null ? "set" : "null")}"); + Console.WriteLine($"ExcludedAssemblies count: {options.ExcludedAssemblies.Count}"); + } + + public void GetCuemonAssemblies() + { + // Get all Cuemon assemblies in the current domain + var cuemonAssemblies = AssemblyContext.GetCurrentDomainAssemblies(o => + { + o.AssemblyFilter = a => a.FullName.StartsWith("Cuemon", StringComparison.Ordinal); + o.ReferencedAssemblyFilter = an => an.FullName.StartsWith("Cuemon", StringComparison.Ordinal); + o.IncludeReferencedAssemblies = true; + o.ExcludedAssemblies.Clear(); + }); + + Console.WriteLine($"Found {cuemonAssemblies.Count} Cuemon assemblies:"); + foreach (var asm in cuemonAssemblies) + { + Console.WriteLine($" - {asm.GetName().Name} v{asm.GetName().Version}"); + } + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Reflection.AssemblyDecoratorExtensions.md b/.docfx/api/types/Cuemon.Reflection.AssemblyDecoratorExtensions.md new file mode 100644 index 00000000..f0f654ec --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.AssemblyDecoratorExtensions.md @@ -0,0 +1,63 @@ +--- +uid: Cuemon.Reflection.AssemblyDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the to inspect assemblies and load embedded resources via the decorator pattern. + +```csharp +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using Cuemon; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + + // Get the entry assembly to inspect + var assembly = Assembly.GetExecutingAssembly(); + var decorator = Decorator.Enclose(assembly); + + // Check if it's a debug build + bool isDebug = decorator.IsDebugBuild(); // true in Debug config, false in Release + + // Get version information + var asmVersion = decorator.GetAssemblyVersion(); // from AssemblyVersionAttribute + var fileVersion = decorator.GetFileVersion(); // from AssemblyFileVersionAttribute + var productVersion = decorator.GetProductVersion(); // from AssemblyInformationalVersionAttribute + + Console.WriteLine($"Assembly version: {asmVersion}"); + Console.WriteLine($"File version: {fileVersion}"); + Console.WriteLine($"Product version: {productVersion}"); + + // Get types from the assembly, optionally filtered + var allTypes = decorator.GetTypes(); // all types in the assembly + var filteredByNamespace = decorator.GetTypes(namespaceFilter: "Cuemon.Reflection"); // types in a specific namespace + var filteredByInterface = decorator.GetTypes(typeFilter: typeof(IDisposable)); // types implementing IDisposable + + // Load embedded manifest resources (partial name match) + var resources = decorator.GetManifestResources("config", ManifestResourceMatch.ContainsName); + foreach (var resource in resources) + { + using var reader = new StreamReader(resource.Value); + string content = reader.ReadToEnd(); + Console.WriteLine($"Resource '{resource.Key}': {content.Length} chars"); + + // Find resources by file extension + var jsonFiles = decorator.GetManifestResources(".json", ManifestResourceMatch.Extension); + + // Get a resource by exact name + var singleResource = decorator.GetManifestResources("MyApp.Resources.data.xml", ManifestResourceMatch.Name); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Reflection.ManifestResourceMatch.md b/.docfx/api/types/Cuemon.Reflection.ManifestResourceMatch.md new file mode 100644 index 00000000..8744e8ef --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.ManifestResourceMatch.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.Reflection.ManifestResourceMatch +example: +- *content +--- + +The following example demonstrates how to use to specify how to locate embedded assembly resources. + +```csharp +using System; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public class ManifestResourceMatchExample +{ + public void Demonstrate() + { + var match = ManifestResourceMatch.Extension; + + switch (match) + { + case ManifestResourceMatch.Name: + Console.WriteLine("Match by exact resource name."); + break; + case ManifestResourceMatch.ContainsName: + Console.WriteLine("Match by partial name match."); + break; + case ManifestResourceMatch.Extension: + Console.WriteLine("Match by file extension (e.g., .json)."); + break; + case ManifestResourceMatch.ContainsExtension: + Console.WriteLine("Match by partial extension match."); + break; + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Reflection.MemberArgument.md b/.docfx/api/types/Cuemon.Reflection.MemberArgument.md new file mode 100644 index 00000000..141e62d9 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.MemberArgument.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.Reflection.MemberArgument +example: +- *content +--- + +The following example demonstrates how to create and use MemberArgument instances to represent method parameters and their values, with priority support for ordering. + +```csharp +using System; +using Cuemon.Reflection; + +namespace MyApp.Reflection +{ + public static class MemberArgumentExamples + { + public static void Demonstrate() + { + // Create a MemberArgument to represent a method parameter and its value. + var arg = new MemberArgument("id", 42); + Console.WriteLine("Name: {0}", arg.Name); // id + Console.WriteLine("Value: {0}", arg.Value); // 42 + Console.WriteLine("Priority: {0}", arg.Priority); // 0 + + // Create arguments for use with MemberParser rehydration. + var args = new[] + { + new MemberArgument("name", "Widget"), + new MemberArgument("price", 19.99m), + new MemberArgument("quantity", 100) + }; + + // Priority can control the order of processing. + args[0].Priority = 2; + args[1].Priority = 1; + args[2].Priority = 0; + + foreach (var a in args) + { + Console.WriteLine("{0} = {1} (priority {2})", a.Name, a.Value, a.Priority); + + // Update a value after creation. + var updatable = new MemberArgument("status", "pending"); + updatable.Value = "shipped"; + updatable.Priority = 5; + Console.WriteLine("Updated: {0}", updatable); // [status, shipped, 5] + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Reflection.MemberArgumentDecoratorExtensions.md b/.docfx/api/types/Cuemon.Reflection.MemberArgumentDecoratorExtensions.md new file mode 100644 index 00000000..0a826291 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.MemberArgumentDecoratorExtensions.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.Reflection.MemberArgumentDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to reconstruct an exception from a recorded member argument stack using the class accessed through the class. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public class MemberArgumentDecoratorExtensionsExample +{ + public Exception ReconstructException() + { + // Simulate a recorded stack of member arguments representing an exception chain + var stack = new Stack>(); + + var innerArgs = new List + { + new MemberArgument("type", typeof(InvalidOperationException)), + new MemberArgument("message", "Inner operation failed.") + }; + stack.Push(innerArgs); + + var outerArgs = new List + { + new MemberArgument("type", typeof(ArgumentException)), + new MemberArgument("message", "Outer argument error."), + new MemberArgument("paramName", "myParam"), + }; + stack.Push(outerArgs); + + // Reconstruct the exception chain from the recorded arguments + return Decorator.Enclose(stack).CreateException(); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Reflection.MemberInfoDecoratorExtensions.md b/.docfx/api/types/Cuemon.Reflection.MemberInfoDecoratorExtensions.md new file mode 100644 index 00000000..1b1af982 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.MemberInfoDecoratorExtensions.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.Reflection.MemberInfoDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to check whether a MemberInfo has one or more custom attributes using MemberInfoDecoratorExtensions. + +```csharp +using System; +using System.ComponentModel; +using System.Reflection; +using Cuemon; +using Cuemon.Reflection; + +namespace MyApp.Reflection +{ + public class MemberInfoDecoratorExtensionsExample + { + public void Demonstrate() + { + // Get a MemberInfo for a method + MemberInfo demoMethod = typeof(MemberInfoDecoratorExtensionsExample) + .GetMethod(nameof(Demonstrate)); + + // Check if the method has a specific attribute + bool hasObsolete = Decorator.Enclose(demoMethod) + .HasAttribute(typeof(ObsoleteAttribute)); + Console.WriteLine($"Has ObsoleteAttribute: {hasObsolete}"); // False + + // Check for multiple attributes at once + bool hasAny = Decorator.Enclose(demoMethod) + .HasAttribute(typeof(ObsoleteAttribute), typeof(EditorBrowsableAttribute)); + Console.WriteLine($"Has Obsolete or EditorBrowsable: {hasAny}"); // False + + // A member with an attribute + MemberInfo deprecatedMethod = typeof(MemberInfoDecoratorExtensionsExample) + .GetMethod(nameof(OldMethod)); + + bool isDeprecated = Decorator.Enclose(deprecatedMethod) + .HasAttribute(typeof(ObsoleteAttribute)); + Console.WriteLine($"OldMethod has ObsoleteAttribute: {isDeprecated}"); // True + } + + [Obsolete("Use Demonstrate instead.")] + public void OldMethod() + { + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Reflection.MemberParser.md b/.docfx/api/types/Cuemon.Reflection.MemberParser.md new file mode 100644 index 00000000..a0dc30e7 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.MemberParser.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.Reflection.MemberParser +example: +- *content +--- + +The following example shows how to hydrate a type from named reflection arguments. + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public static class MemberParserExample +{ + public static void Demonstrate() + { + var arguments = new List + { + new("sku", "SKU-42"), + new("price", 19.95m), + new("stock", 12) + }; + + var parser = new MemberParser(typeof(CatalogItem), arguments); + var item = (CatalogItem)parser.CreateInstance(ctor => ctor.GetParameters().Length == 2); + + Console.WriteLine(item.Sku); + Console.WriteLine(item.Price); + Console.WriteLine(item.Stock); + Console.WriteLine(string.Join(", ", parser.ProcessedMemberArguments.Select(argument => argument.Name))); + } +} + +public sealed class CatalogItem +{ + public CatalogItem(string sku, decimal price) + { + Sku = sku; + Price = price; + } + + public string Sku { get; } + + public decimal Price { get; } + + public int Stock { get; set; } +} +``` diff --git a/.docfx/api/types/Cuemon.Reflection.MemberReflection.md b/.docfx/api/types/Cuemon.Reflection.MemberReflection.md new file mode 100644 index 00000000..44e352b4 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.MemberReflection.md @@ -0,0 +1,47 @@ +--- +uid: Cuemon.Reflection.MemberReflection +example: +- *content +--- + +The following example demonstrates how to use to create custom for reflection-based member discovery. + +```csharp +using System; +using System.Reflection; +using Cuemon.Reflection; // for MemberReflection, MemberReflectionOptions + +namespace MyApp.Examples; + +public class MemberReflectionExample +{ + public void Demonstrate() + { + // Create flags to find only public instance members (excluding inherited) + BindingFlags flags = new MemberReflection( + excludePrivate: true, + excludeStatic: true, + excludeInheritancePath: true); + Console.WriteLine(flags); + // Output: Instance, Public, DeclaredOnly + + // Use the static CreateFlags factory method + BindingFlags allFlags = MemberReflection.CreateFlags(); + Console.WriteLine(allFlags); + // Output: Instance, Static, Public, NonPublic + + // Configure via MemberReflectionOptions + BindingFlags customFlags = MemberReflection.CreateFlags(o => + { + o.ExcludePrivate = true; + o.ExcludeStatic = true; + }); + + // Use with reflection + var members = typeof(string).GetMembers(customFlags); + Console.WriteLine(members.Length); // Number of public instance members on string + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Reflection.MemberReflectionOptions.md b/.docfx/api/types/Cuemon.Reflection.MemberReflectionOptions.md new file mode 100644 index 00000000..3719d97f --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.MemberReflectionOptions.md @@ -0,0 +1,57 @@ +--- +uid: Cuemon.Reflection.MemberReflectionOptions +example: +- *content +--- + +The following example demonstrates how to use when generating a public API inventory for . + +```csharp +using System; +using System.Linq; +using System.Reflection; +using Cuemon; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public static class MemberReflectionOptionsExample +{ + public static void Demonstrate() + { + BindingFlags publicInstanceFlags = MemberReflection.CreateFlags(options => + { + options.ExcludePrivate = true; + options.ExcludeStatic = true; + }); + + var publicDateSpanMembers = typeof(DateSpan) + .GetMembers(publicInstanceFlags) + .Select(member => member.Name) + .Distinct() + .OrderBy(name => name) + .Take(8); + + Console.WriteLine(string.Join(", ", publicDateSpanMembers)); + + BindingFlags declaredOnlyFlags = MemberReflection.CreateFlags(options => + { + options.ExcludePrivate = true; + options.ExcludeStatic = true; + options.ExcludeInheritancePath = true; + }); + + Console.WriteLine(typeof(DateSpan).GetMethods(publicInstanceFlags).Length); + Console.WriteLine(typeof(DateSpan).GetMethods(declaredOnlyFlags).Length); + + var documentedOptions = new MemberReflectionOptions + { + ExcludePrivate = true, + ExcludeStatic = true, + ExcludeInheritancePath = true + }; + + Console.WriteLine($"{documentedOptions.ExcludePrivate}/{documentedOptions.ExcludeStatic}/{documentedOptions.ExcludeInheritancePath}/{documentedOptions.ExcludePublic}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Reflection.MethodBaseOptions.md b/.docfx/api/types/Cuemon.Reflection.MethodBaseOptions.md new file mode 100644 index 00000000..21964272 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.MethodBaseOptions.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.Reflection.MethodBaseOptions +example: +- *content +--- + +The following example shows how to store method lookup rules in `MethodBaseOptions` and apply them during reflection. + +```csharp +using System; +using System.Linq; +using System.Reflection; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public static class MethodBaseOptionsExample +{ + public static void Demonstrate() + { + var options = new MethodBaseOptions + { + Flags = BindingFlags.Instance | BindingFlags.Public, + Comparison = StringComparison.OrdinalIgnoreCase, + Types = new[] { typeof(decimal), typeof(decimal) } + }; + + MethodInfo method = ResolveMethod(typeof(PricingEngine), "applydiscount", options); + + Console.WriteLine(method == null ? "not found" : method.Name); + Console.WriteLine(options.Flags); + Console.WriteLine(string.Join(", ", options.Types.Select(type => type.Name))); + } + + private static MethodInfo ResolveMethod(Type source, string name, MethodBaseOptions options) + { + return source.GetMethods(options.Flags).FirstOrDefault(method => + method.Name.Equals(name, options.Comparison) && + method.GetParameters().Select(parameter => parameter.ParameterType) + .SequenceEqual(options.Types ?? Array.Empty())); + } +} + +public sealed class PricingEngine +{ + public decimal ApplyDiscount(decimal subtotal, decimal discount) + { + return subtotal - discount; + } +} +``` diff --git a/.docfx/api/types/Cuemon.Reflection.MethodDescriptor.md b/.docfx/api/types/Cuemon.Reflection.MethodDescriptor.md new file mode 100644 index 00000000..609c1355 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.MethodDescriptor.md @@ -0,0 +1,61 @@ +--- +uid: Cuemon.Reflection.MethodDescriptor +example: +- *content +--- + +The following example demonstrates how to create a MethodDescriptor from a MethodInfo, inspect its parameters, append runtime arguments, and merge parameter signatures with values. + +```csharp +using System; +using System.Linq; +using System.Reflection; +using Cuemon.Reflection; + +namespace MyApp.Reflection +{ + public static class MethodDescriptorExamples + { + public static void Demonstrate() + { + // Create a MethodDescriptor from a MethodInfo. + MethodInfo methodInfo = typeof(string).GetMethod("IndexOf", + new[] { typeof(string), typeof(StringComparison) }); + var descriptor = new MethodDescriptor(methodInfo); + + Console.WriteLine("Caller: {0}", descriptor.Caller.FullName); // System.String + Console.WriteLine("Method: {0}", descriptor.MethodName); // IndexOf + Console.WriteLine("Signature: {0}", descriptor.ToString(true)); + // Output: System.String.IndexOf(String value, StringComparison comparisonType) + + // List all parameters. + Console.WriteLine("Parameters:"); + foreach (var param in descriptor.Parameters) + { + Console.WriteLine(" {0} {1}", param.ParameterType.Name, param.ParameterName); + + // Append runtime arguments for debugging or logging. + descriptor.AppendRuntimeArguments("Hello", StringComparison.OrdinalIgnoreCase); + Console.WriteLine("Runtime arguments:"); + foreach (var kvp in descriptor.RuntimeArguments) + { + Console.WriteLine(" {0} = {1}", kvp.Key, kvp.Value); + + // Static factory method. + var fromFactory = MethodDescriptor.Create( + typeof(Math).GetMethod("Max", new[] { typeof(int), typeof(int) })); + Console.WriteLine("Factory: {0}", fromFactory.ToString(false)); + + // Merge parameters with runtime values. + var merged = MethodDescriptor.MergeParameters( + new[] { + new ParameterSignature(typeof(string), "input"), + new ParameterSignature(typeof(int), "count") + }, + "test", 3); + Console.WriteLine("Merged: input={0}, count={1}", merged["input"], merged["count"]); + +}}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Reflection.MethodInfoDecoratorExtensions.md b/.docfx/api/types/Cuemon.Reflection.MethodInfoDecoratorExtensions.md new file mode 100644 index 00000000..828b1f83 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.MethodInfoDecoratorExtensions.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.Reflection.MethodInfoDecoratorExtensions +example: +- *content +--- + +The following example shows how to detect whether a reflected method overrides a base implementation. + +```csharp +using System; +using System.Reflection; +using Cuemon; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public static class MethodInfoDecoratorExtensionsExample +{ + public static void Demonstrate() + { + MethodInfo baseMethod = typeof(PricingCalculator).GetMethod(nameof(PricingCalculator.Calculate))!; + MethodInfo derivedMethod = typeof(RegionalPricingCalculator).GetMethod(nameof(PricingCalculator.Calculate))!; + MethodInfo localMethod = typeof(RegionalPricingCalculator).GetMethod(nameof(RegionalPricingCalculator.FormatRegion))!; + + Console.WriteLine(Decorator.Enclose(baseMethod).IsOverridden()); + Console.WriteLine(Decorator.Enclose(derivedMethod).IsOverridden()); + Console.WriteLine(Decorator.Enclose(localMethod).IsOverridden()); + } +} + +public class PricingCalculator +{ + public virtual decimal Calculate(decimal subtotal) + { + return subtotal; + } +} + +public sealed class RegionalPricingCalculator : PricingCalculator +{ + public override decimal Calculate(decimal subtotal) + { + return subtotal * 1.25m; + } + + public string FormatRegion() + { + return "EU"; + } +} +``` diff --git a/.docfx/api/types/Cuemon.Reflection.MethodSignature.md b/.docfx/api/types/Cuemon.Reflection.MethodSignature.md new file mode 100644 index 00000000..ec03029f --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.MethodSignature.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Reflection.MethodSignature +example: +- *content +--- + +The following example shows how to capture lightweight method metadata for logging or retry evidence. + +```csharp +using System; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public static class MethodSignatureExample +{ + public static void Demonstrate() + { + var signature = new MethodSignature( + typeof(PaymentGateway).FullName ?? nameof(PaymentGateway), + nameof(PaymentGateway.Authorize), + new[] { typeof(string).Name, typeof(decimal).Name }, + new object[] { "INV-42", 19.95m }); + + Console.WriteLine(signature.ToString()); + Console.WriteLine(string.Join(", ", signature.Parameters ?? Array.Empty())); + Console.WriteLine(signature.Arguments?.Length ?? 0); + } +} + +public sealed class PaymentGateway +{ + public void Authorize(string orderId, decimal amount) + { + } +} +``` diff --git a/.docfx/api/types/Cuemon.Reflection.ParameterSignature.md b/.docfx/api/types/Cuemon.Reflection.ParameterSignature.md new file mode 100644 index 00000000..ea46735e --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.ParameterSignature.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.Reflection.ParameterSignature +example: +- *content +--- + +The following example demonstrates how to use to extract parameter information from a method. + +```csharp +using System; +using System.Linq; +using System.Reflection; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public class ParameterSignatureExample +{ + public void Demonstrate() + { + MethodInfo method = typeof(string).GetMethod("IndexOf", new[] { typeof(string), typeof(StringComparison) }); + + if (method != null) + { + var signatures = ParameterSignature.Parse(method).ToList(); + + foreach (var signature in signatures) + { + Console.WriteLine($"Parameter: {signature.ParameterName}, Type: {signature.ParameterType.Name}"); + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Reflection.PropertyInfoDecoratorExtensions.md b/.docfx/api/types/Cuemon.Reflection.PropertyInfoDecoratorExtensions.md new file mode 100644 index 00000000..f910ec56 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.PropertyInfoDecoratorExtensions.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.Reflection.PropertyInfoDecoratorExtensions +example: +- *content +--- + +The following example shows how to inspect reflected properties for auto-property and override behavior. + +```csharp +using System; +using System.Reflection; +using Cuemon; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public static class PropertyInfoDecoratorExtensionsExample +{ + public static void Demonstrate() + { + PropertyInfo code = typeof(Product).GetProperty(nameof(Product.Code))!; + PropertyInfo label = typeof(Product).GetProperty(nameof(Product.Label))!; + PropertyInfo summary = typeof(FeaturedProduct).GetProperty(nameof(Product.Summary))!; + + Console.WriteLine(Decorator.Enclose(code).IsAutoProperty()); + Console.WriteLine(Decorator.Enclose(label).IsAutoProperty()); + Console.WriteLine(Decorator.Enclose(summary).IsOverridden()); + } +} + +public class Product +{ + public string Code { get; set; } = string.Empty; + + public string Label => $"Product:{Code}"; + + public virtual string Summary => "standard"; +} + +public sealed class FeaturedProduct : Product +{ + public override string Summary => "featured"; +} +``` diff --git a/.docfx/api/types/Cuemon.Reflection.TypeNameOptions.md b/.docfx/api/types/Cuemon.Reflection.TypeNameOptions.md new file mode 100644 index 00000000..78d984cc --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.TypeNameOptions.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.Reflection.TypeNameOptions +example: +- *content +--- + +The following example demonstrates how to use `TypeNameOptions` to control the friendly name output of a `Type`. + +```csharp +using System; +using Cuemon; +using Cuemon.Reflection; + +namespace Examples; + +public class TypeNameFormattingExample +{ + public void Demonstrate() + { + // Direct instantiation of TypeNameOptions + var options = new TypeNameOptions + { + FullName = true, + ExcludeGenericArguments = false + }; + + Type type = typeof(Console); + + string friendlyName = Decorator.Enclose(type).ToFriendlyName(o => + { + o.FullName = true; + o.ExcludeGenericArguments = false; + }); + // friendlyName == "System.Console" + + friendlyName = Decorator.Enclose(type).ToFriendlyName(o => + { + o.FullName = false; + }); + // friendlyName == "Console" + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Reflection.VersionResult.md b/.docfx/api/types/Cuemon.Reflection.VersionResult.md new file mode 100644 index 00000000..48c65b04 --- /dev/null +++ b/.docfx/api/types/Cuemon.Reflection.VersionResult.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.Reflection.VersionResult +example: +- *content +--- + +The following example demonstrates how to use to work with both numerical and semantic (alphanumeric) version strings. + +```csharp +using System; +using Cuemon.Reflection; + +namespace MyApp.Examples; + +public class VersionResultExample +{ + public void Demonstrate() + { + // Numerical version (parsable to System.Version) + var numeric = new VersionResult("1.2.3.4"); + Console.WriteLine($"Value: {numeric.Value}"); + Console.WriteLine($"HasAlphanumericVersion: {numeric.HasAlphanumericVersion}"); + Console.WriteLine($"IsSemanticVersion: {numeric.IsSemanticVersion()}"); + + // Semantic/alphanumeric version (not a pure numerical version) + var semantic = new VersionResult("2.0.0-beta.1"); + Console.WriteLine($"\nValue: {semantic.Value}"); + Console.WriteLine($"HasAlphanumericVersion: {semantic.HasAlphanumericVersion}"); + Console.WriteLine($"IsSemanticVersion: {semantic.IsSemanticVersion()}"); + + // Static helper check + var check = VersionResult.IsSemanticVersion("3.0.0-rc.1"); + Console.WriteLine($"\nIs '3.0.0-rc.1' semantic? {check}"); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Resilience.AsyncTransientOperationOptions.md b/.docfx/api/types/Cuemon.Resilience.AsyncTransientOperationOptions.md new file mode 100644 index 00000000..4bd0c193 --- /dev/null +++ b/.docfx/api/types/Cuemon.Resilience.AsyncTransientOperationOptions.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.Resilience.AsyncTransientOperationOptions +example: +- *content +--- + +The following example demonstrates how to configure retry options for an asynchronous transient operation with exponential backoff. + +```csharp +using System; +using System.Threading.Tasks; +using Cuemon.Resilience; + +namespace Examples; + +public class AsyncTransientOperationExample +{ + public async Task ExecuteWithRetryAsync() + { + // Direct instantiation of AsyncTransientOperationOptions + var transientOptions = new AsyncTransientOperationOptions + { + RetryAttempts = 3, + MaximumAllowedLatency = TimeSpan.FromSeconds(30) + }; + transientOptions.RetryStrategy = currentAttempt => TimeSpan.FromSeconds(Math.Pow(2, currentAttempt)); + transientOptions.DetectionStrategy = exception => exception is TimeoutException; + + var result = await TransientOperation.WithFuncAsync(async ct => + { + return await Task.FromResult(42); + }, o => + { + o.RetryAttempts = 3; + o.RetryStrategy = currentAttempt => TimeSpan.FromSeconds(Math.Pow(2, currentAttempt)); + o.MaximumAllowedLatency = TimeSpan.FromSeconds(30); + o.DetectionStrategy = exception => exception is TimeoutException; + }); + // result == 42 after up to 3 retries with exponential backoff + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Resilience.LatencyException.md b/.docfx/api/types/Cuemon.Resilience.LatencyException.md new file mode 100644 index 00000000..3682a07f --- /dev/null +++ b/.docfx/api/types/Cuemon.Resilience.LatencyException.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.Resilience.LatencyException +example: +- *content +--- + +The following example demonstrates how to wrap a timeout-related failure in a . + +```csharp +using System; +using Cuemon.Resilience; + +namespace MyApp.Examples; + +public static class LatencyExceptionExample +{ + public static void Demonstrate() + { + var timeout = new TimeoutException("The database query timed out after 10 seconds."); + var exception = new LatencyException("Order processing exceeded the configured latency threshold.", timeout); + + Console.WriteLine(exception.Message); + Console.WriteLine(exception.InnerException?.GetType().Name); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Resilience.TransientFaultEvidence.md b/.docfx/api/types/Cuemon.Resilience.TransientFaultEvidence.md new file mode 100644 index 00000000..523f440e --- /dev/null +++ b/.docfx/api/types/Cuemon.Resilience.TransientFaultEvidence.md @@ -0,0 +1,70 @@ +--- +uid: Cuemon.Resilience.TransientFaultEvidence +example: +- *content +--- + +The following example demonstrates how to create TransientFaultEvidence instances to capture retry attempt details, recovery wait times, and latency information for transient fault handling. + +```csharp +using System; +using Cuemon.Reflection; +using Cuemon.Resilience; + +namespace MyApp.Resilience +{ + public class TransientFaultEvidenceExamples + { + public static void CreateWithMethodSignature() + { + var descriptor = new MethodSignature( + "MyApp.Services.PaymentService", + "ProcessPayment", + new[] { "orderId", "amount" }, + new object[] { "ORD-12345", 99.99m } + ); + + var evidence = new TransientFaultEvidence( + attempts: 3, + recoveryWaitTime: TimeSpan.FromSeconds(2), + totalRecoveryWaitTime: TimeSpan.FromSeconds(5), + latency: TimeSpan.FromMilliseconds(1500), + descriptor: descriptor + ); + + Console.WriteLine(evidence.ToString()); + Console.WriteLine("Attempts: {0}", evidence.Attempts); + Console.WriteLine("Last recovery wait: {0}", evidence.RecoveryWaitTime); + Console.WriteLine("Total recovery wait: {0}", evidence.TotalRecoveryWaitTime); + Console.WriteLine("Latency: {0}", evidence.Latency); + Console.WriteLine("Descriptor: {0}", evidence.Descriptor); + } + + public static void EqualityComparison() + { + var desc = new MethodSignature("App.MyClass", "DoWork", new[] { "id" }, new object[] { 42 }); + + var evidence1 = new TransientFaultEvidence(2, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromMilliseconds(500), desc); + var evidence2 = new TransientFaultEvidence(2, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromMilliseconds(500), desc); + + Console.WriteLine("Equals: {0}", evidence1.Equals(evidence2)); + Console.WriteLine("HashCode same: {0}", evidence1.GetHashCode() == evidence2.GetHashCode()); + } + + public static void CreateWithMinimalInfo() + { + var descriptor = new MethodSignature("App.Service", "Execute", Array.Empty(), Array.Empty()); + + var evidence = new TransientFaultEvidence( + attempts: 1, + recoveryWaitTime: TimeSpan.Zero, + totalRecoveryWaitTime: TimeSpan.Zero, + latency: TimeSpan.FromMilliseconds(200), + descriptor: descriptor + ); + + Console.WriteLine("Attempts: {0}", evidence.Attempts); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Resilience.TransientFaultException.md b/.docfx/api/types/Cuemon.Resilience.TransientFaultException.md new file mode 100644 index 00000000..161d05e9 --- /dev/null +++ b/.docfx/api/types/Cuemon.Resilience.TransientFaultException.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Resilience.TransientFaultException +example: +- *content +--- + +The following example demonstrates how to construct a with retry evidence. + +```csharp +using System; +using System.Reflection; +using Cuemon.Reflection; +using Cuemon.Resilience; + +namespace MyApp.Examples; + +public static class TransientFaultExceptionExample +{ + public static void Demonstrate() + { + var evidence = new TransientFaultEvidence( + attempts: 5, + recoveryWaitTime: TimeSpan.FromSeconds(2), + totalRecoveryWaitTime: TimeSpan.FromSeconds(10), + latency: TimeSpan.FromSeconds(1), + descriptor: MethodDescriptor.Create(MethodBase.GetCurrentMethod()!)); + + var exception = new TransientFaultException("Operation failed after retries.", evidence); + + Console.WriteLine(exception.Message); + Console.WriteLine(exception.Evidence.Attempts); + Console.WriteLine(exception.Evidence.TotalRecoveryWaitTime); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Resilience.TransientOperation.md b/.docfx/api/types/Cuemon.Resilience.TransientOperation.md new file mode 100644 index 00000000..4f9c9fcd --- /dev/null +++ b/.docfx/api/types/Cuemon.Resilience.TransientOperation.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.Resilience.TransientOperation +example: +- *content +--- + +```csharp +using System; +using System.Net.Http; +using Cuemon.Resilience; + +namespace Cuemon.Resilience; + +public class TransientOperationExample +{ + public void Demonstrate() + { + var result = TransientOperation.WithFunc(() => + { + using var client = new HttpClient(); + return client.GetStringAsync("https://example.com").Result; + }, options => + { + options.RetryAttempts = 3; + options.RetryStrategy = attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)); + }); + + Console.WriteLine($"Response length: {result.Length}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Resilience.TransientOperationOptions.md b/.docfx/api/types/Cuemon.Resilience.TransientOperationOptions.md new file mode 100644 index 00000000..57698629 --- /dev/null +++ b/.docfx/api/types/Cuemon.Resilience.TransientOperationOptions.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Resilience.TransientOperationOptions +example: +- *content +--- + +The following example demonstrates how to configure for retry attempts, transient-fault detection, and latency limits. + +```csharp +using System; +using System.Net.Http; +using Cuemon.Resilience; + +namespace MyApp.Examples; + +public static class TransientOperationOptionsExample +{ + public static void Demonstrate() + { + var options = new TransientOperationOptions + { + RetryAttempts = 3, + RetryStrategy = attempt => TimeSpan.FromSeconds(Math.Pow(2, attempt)), + DetectionStrategy = exception => exception is HttpRequestException, + MaximumAllowedLatency = TimeSpan.FromSeconds(30) + }; + + options.ValidateOptions(); + + Console.WriteLine(options.RetryAttempts); + Console.WriteLine(options.EnableRecovery); + Console.WriteLine(options.MaximumAllowedLatency); + Console.WriteLine(options.DetectionStrategy(new HttpRequestException("Network timeout simulated."))); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Runtime.Caching.CacheEntry.md b/.docfx/api/types/Cuemon.Runtime.Caching.CacheEntry.md new file mode 100644 index 00000000..20dd5e37 --- /dev/null +++ b/.docfx/api/types/Cuemon.Runtime.Caching.CacheEntry.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.Runtime.Caching.CacheEntry +example: +- *content +--- + +The following example demonstrates how to register a cache entry with invalidation rules and inspect its expiration behavior. + +```csharp +using System; +using Cuemon.Runtime.Caching; + +namespace MyApp.Examples; + +public static class CacheEntryExample +{ + public static void Demonstrate() + { + var cache = new SlimMemoryCache(); + var entry = new CacheEntry("session", "cached-value", "docs"); + + cache.Add(entry, new CacheInvalidation(TimeSpan.FromSeconds(30))); + + Console.WriteLine(entry.CanExpire); + Console.WriteLine(entry.HasExpired(entry.Accessed.AddSeconds(31))); + Console.WriteLine(entry.ToString().Contains("Key=session")); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Runtime.Caching.CacheEntryEventArgs.md b/.docfx/api/types/Cuemon.Runtime.Caching.CacheEntryEventArgs.md new file mode 100644 index 00000000..277ce9a5 --- /dev/null +++ b/.docfx/api/types/Cuemon.Runtime.Caching.CacheEntryEventArgs.md @@ -0,0 +1,63 @@ +--- +uid: Cuemon.Runtime.Caching.CacheEntryEventArgs +example: +- *content +--- + +The following example demonstrates how is delivered when a dependency invalidates a cache entry. + +```csharp +using System; +using System.Threading.Tasks; +using Cuemon.Runtime; +using Cuemon.Runtime.Caching; + +namespace MyApp.Examples; + +public static class CacheEntryEventArgsExample +{ + public static void Demonstrate() + { + var cache = new SlimMemoryCache(); + var dependency = new DependencyStub(); + var entry = new CacheEntry("key", "value"); + CacheEntryEventArgs captured = null; + + entry.Expired += (_, e) => + { + captured = e; + Console.WriteLine(e.GetType().Name); + }; + + cache.Add(entry, new CacheInvalidation(new[] { dependency })); + dependency.SignalChanged(); + + Console.WriteLine(captured != null); + } + + private sealed class DependencyStub : IDependency + { + public event EventHandler DependencyChanged; + + public DateTime? UtcLastModified { get; private set; } + + public bool HasChanged { get; private set; } + + public void Start() + { + } + + public Task StartAsync() + { + return Task.CompletedTask; + } + + public void SignalChanged() + { + UtcLastModified = DateTime.UtcNow; + HasChanged = true; + DependencyChanged?.Invoke(this, new DependencyEventArgs(UtcLastModified.Value)); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Runtime.Caching.CacheInvalidation.md b/.docfx/api/types/Cuemon.Runtime.Caching.CacheInvalidation.md new file mode 100644 index 00000000..32970ede --- /dev/null +++ b/.docfx/api/types/Cuemon.Runtime.Caching.CacheInvalidation.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Runtime.Caching.CacheInvalidation +example: +- *content +--- + +The following example demonstrates how to use to define eviction policies for cache entries. + +```csharp +using System; +using Cuemon.Runtime.Caching; // for CacheInvalidation + +namespace MyApp.Examples; + +public class CacheInvalidationExample +{ + public void Demonstrate() + { + // Absolute expiration at a specific UTC time + var absolute = new CacheInvalidation(new DateTime(2025, 12, 31, 23, 59, 59, DateTimeKind.Utc)); + Console.WriteLine(absolute.UseAbsoluteExpiration); // True + Console.WriteLine(absolute.AbsoluteExpiration); // 12/31/2025 23:59:59 + Console.WriteLine(absolute.UseSlidingExpiration); // False + Console.WriteLine(absolute.UseDependency); // False + + // Sliding expiration (entry expires after 30 minutes of inactivity) + var sliding = new CacheInvalidation(TimeSpan.FromMinutes(30)); + Console.WriteLine(sliding.UseSlidingExpiration); // True + Console.WriteLine(sliding.SlidingExpiration); // 00:30:00 + Console.WriteLine(sliding.UseAbsoluteExpiration); // False + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Runtime.Caching.CachingManager.md b/.docfx/api/types/Cuemon.Runtime.Caching.CachingManager.md new file mode 100644 index 00000000..665901d2 --- /dev/null +++ b/.docfx/api/types/Cuemon.Runtime.Caching.CachingManager.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.Runtime.Caching.CachingManager +example: +- *content +--- + +```csharp +using System; +using Cuemon.Runtime.Caching; + +namespace Cuemon.Runtime.Caching; + +public class CachingManagerExample +{ + public void Demonstrate() + { + var cache = CachingManager.Cache; + var key = "myKey"; + var value = cache.Get(key); + if (value == null) + { + cache.Add(key, DateTime.UtcNow, TimeSpan.FromMinutes(5)); + } + value = cache.Get(key); + Console.WriteLine($"Cached value: {value}"); + + var sameValue = cache.Get(key); + Console.WriteLine($"Same instance? {value == sameValue}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Runtime.Caching.SlimMemoryCache.md b/.docfx/api/types/Cuemon.Runtime.Caching.SlimMemoryCache.md new file mode 100644 index 00000000..a87b612d --- /dev/null +++ b/.docfx/api/types/Cuemon.Runtime.Caching.SlimMemoryCache.md @@ -0,0 +1,65 @@ +--- +uid: Cuemon.Runtime.Caching.SlimMemoryCache +example: +- *content +--- + +The following example demonstrates how to use `SlimMemoryCache` to store and retrieve cached values with various expiration strategies. + +```csharp +using System; +using Cuemon.Runtime.Caching; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + + // Create a cache with automatic cleanup + var cache = new SlimMemoryCache(o => + { + o.EnableCleanup = true; + o.FirstSweep = TimeSpan.FromSeconds(30); + o.SucceedingSweep = TimeSpan.FromSeconds(10); + }); + + // Add an entry with absolute expiration + cache.Add("config", new { Theme = "Dark", Locale = "en-US" }, DateTime.UtcNow.AddMinutes(5)); + + // Add an entry with sliding expiration (resets on each access) + cache.Add("session", new { UserId = 42, Role = "Admin" }, TimeSpan.FromMinutes(20), "sessions"); + + Console.WriteLine($"Config: {cache["config"]}"); + + // Use TryGet for safe retrieval + if (cache.TryGet("session", "sessions", out var session)) + { + Console.WriteLine($"Session: {session}"); + + // Update an existing entry using the indexer + cache["config"] = new { Theme = "Light", Locale = "en-US" }; + Console.WriteLine($"Updated config: {cache["config"]}"); + + // Check if entry exists and remove it + if (cache.Contains("config")) + { + cache.Remove("config"); + Console.WriteLine("Config removed."); + + // Count entries within a namespace + cache.Add("item1", 100, DateTime.MaxValue, "data"); + cache.Add("item2", 200, DateTime.MaxValue, "data"); + Console.WriteLine($"Items in 'data' namespace: {cache.Count("data")}"); + + // Remove all entries from a namespace + cache.RemoveAll("data"); + Console.WriteLine($"After removal: {cache.Count("data")}"); + + cache.Dispose(); + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Runtime.Caching.SlimMemoryCacheOptions.md b/.docfx/api/types/Cuemon.Runtime.Caching.SlimMemoryCacheOptions.md new file mode 100644 index 00000000..b8e5a26c --- /dev/null +++ b/.docfx/api/types/Cuemon.Runtime.Caching.SlimMemoryCacheOptions.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.Runtime.Caching.SlimMemoryCacheOptions +example: +- *content +--- + +The following example demonstrates how to configure for sweep intervals and cache-key generation. + +```csharp +using System; +using Cuemon.Runtime.Caching; + +namespace MyApp.Examples; + +public static class SlimMemoryCacheOptionsExample +{ + public static void Demonstrate() + { + var options = new SlimMemoryCacheOptions + { + EnableCleanup = false, + FirstSweep = TimeSpan.FromSeconds(10), + SucceedingSweep = TimeSpan.FromSeconds(30), + KeyProvider = (key, ns) => key.Length + (ns == CacheEntry.NoScope ? 0 : ns.Length) + }; + + options.ValidateOptions(); + + Console.WriteLine(options.EnableCleanup); + Console.WriteLine(options.FirstSweep); + Console.WriteLine(options.KeyProvider("session", "docs")); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Runtime.DependencyEventArgs.md b/.docfx/api/types/Cuemon.Runtime.DependencyEventArgs.md new file mode 100644 index 00000000..39eb1583 --- /dev/null +++ b/.docfx/api/types/Cuemon.Runtime.DependencyEventArgs.md @@ -0,0 +1,61 @@ +--- +uid: Cuemon.Runtime.DependencyEventArgs +example: +- *content +--- + +The following example demonstrates how to create and use DependencyEventArgs to report the UTC timestamp of a dependency change event. + +```csharp +using System; +using Cuemon.Runtime; + +namespace MyApp.Runtime +{ + public class DependencyEventArgsExamples + { + public static void CreateEventArgs() + { + // Create event args with the UTC time of the last dependency change. + var args = new DependencyEventArgs(DateTime.UtcNow); + Console.WriteLine("Last modified (UTC): {0:O}", args.UtcLastModified); + } + + public static void CreateEventArgsWithPastTimestamp() + { + // Create event args with a specific past timestamp. + var lastWrite = new DateTime(2026, 6, 1, 12, 0, 0, DateTimeKind.Utc); + var args = new DependencyEventArgs(lastWrite); + Console.WriteLine("Last dependency change: {0:O}", args.UtcLastModified); + } + + public static void UseEmptySentinel() + { + // Use the static Empty sentinel to represent no change. + DependencyEventArgs args = DependencyEventArgs.Empty; + Console.WriteLine("Is empty: {0}", args.UtcLastModified == DateTime.MinValue); // true + } + + public static void RaiseDependencyEvent() + { + var monitor = new DependencyMonitor(); + monitor.DependencyChanged += (sender, args) => + { + Console.WriteLine("Dependency last changed at: {0:O}", args.UtcLastModified); + }; + + monitor.CheckForChanges(); + } + } + + public class DependencyMonitor + { + public event EventHandler DependencyChanged; + + public void CheckForChanges() + { + DependencyChanged?.Invoke(this, new DependencyEventArgs(DateTime.UtcNow)); + } + } +} +``` \ No newline at end of file diff --git a/.docfx/api/types/Cuemon.Runtime.FileDependency.md b/.docfx/api/types/Cuemon.Runtime.FileDependency.md new file mode 100644 index 00000000..3bdb3717 --- /dev/null +++ b/.docfx/api/types/Cuemon.Runtime.FileDependency.md @@ -0,0 +1,41 @@ +--- +uid: Cuemon.Runtime.FileDependency +example: +- *content +--- + +The following example shows how to defer file-watcher creation until a dependency starts monitoring. + +```csharp +using System; +using System.IO; +using System.Threading.Tasks; +using Cuemon.Runtime; + +namespace MyApp.Examples; + +public static class FileDependencyExample +{ + public static async Task DemonstrateAsync() + { + string filePath = Path.Combine(Environment.CurrentDirectory, "settings.json"); + File.WriteAllText(filePath, "{ }"); + + var lazyWatcher = new Lazy(() => new FileWatcher(filePath, false, options => + { + options.Period = TimeSpan.FromMilliseconds(500); + })); + + var dependency = new FileDependency(lazyWatcher, breakTieOnChanged: true); + dependency.DependencyChanged += static (_, e) => Console.WriteLine(e.UtcLastModified.ToString("O")); + + Console.WriteLine(lazyWatcher.IsValueCreated); + Console.WriteLine(dependency.BreakTieOnChanged); + + await dependency.StartAsync(); + + Console.WriteLine(lazyWatcher.IsValueCreated); + Console.WriteLine(dependency.HasChanged); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Runtime.FileWatcher.md b/.docfx/api/types/Cuemon.Runtime.FileWatcher.md new file mode 100644 index 00000000..9fb807ac --- /dev/null +++ b/.docfx/api/types/Cuemon.Runtime.FileWatcher.md @@ -0,0 +1,41 @@ +--- +uid: Cuemon.Runtime.FileWatcher +example: +- *content +--- + +The following example shows how to start a file watcher, observe change notifications, and pause signaling again. + +```csharp +using System; +using System.IO; +using System.Threading; +using Cuemon.Runtime; + +namespace MyApp.Examples; + +public static class FileWatcherExample +{ + public static void Demonstrate() + { + string filePath = Path.Combine(Environment.CurrentDirectory, "health.txt"); + File.WriteAllText(filePath, "ready"); + + using var watcher = new FileWatcher(filePath, readFile: true, options => + { + options.DueTime = TimeSpan.Zero; + options.Period = TimeSpan.FromSeconds(5); + options.DueTimeOnChanged = TimeSpan.FromMilliseconds(250); + }); + + watcher.Changed += static (_, e) => Console.WriteLine($"{e.UtcLastModified:O} ({e.Delayed.TotalMilliseconds} ms)"); + watcher.StartMonitoring(); + + Console.WriteLine(watcher.Path); + Console.WriteLine(watcher.ReadFile); + Console.WriteLine(watcher.UtcCreated.ToString("O")); + + watcher.ChangeSignaling(Timeout.InfiniteTimeSpan); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Runtime.Serialization.Formatters.Formatter.md b/.docfx/api/types/Cuemon.Runtime.Serialization.Formatters.Formatter.md new file mode 100644 index 00000000..8d38380d --- /dev/null +++ b/.docfx/api/types/Cuemon.Runtime.Serialization.Formatters.Formatter.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.Runtime.Serialization.Formatters.Formatter +example: +- *content +--- + +```csharp +using System; +using Cuemon.Runtime.Serialization.Formatters; + +namespace Cuemon.Runtime.Serialization.Formatters; + +public class FormatterExample +{ + public void Demonstrate() + { + var type = Formatter.GetType("System.DateTime, mscorlib"); + Console.WriteLine($"Resolved type: {type}"); + + if (Formatter.TryGetType("Cuemon.GuidStringOptions, Cuemon.Core", out var optionsType)) + { + Console.WriteLine($"Found type: {optionsType}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Runtime.WatcherEventArgs.md b/.docfx/api/types/Cuemon.Runtime.WatcherEventArgs.md new file mode 100644 index 00000000..d6b5dc2a --- /dev/null +++ b/.docfx/api/types/Cuemon.Runtime.WatcherEventArgs.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.Runtime.WatcherEventArgs +example: +- *content +--- + +The following example shows the information a watcher passes along when a resource change is raised. + +```csharp +using System; +using Cuemon.Runtime; + +namespace MyApp.Examples; + +public static class WatcherEventArgsExample +{ + public static void Demonstrate() + { + var immediate = new WatcherEventArgs(DateTime.UtcNow); + var postponed = new WatcherEventArgs(DateTime.UtcNow.AddSeconds(-5), TimeSpan.FromMilliseconds(250)); + var empty = WatcherEventArgs.Empty; + + Console.WriteLine(immediate.UtcLastModified.Kind); + Console.WriteLine(postponed.Delayed.TotalMilliseconds); + Console.WriteLine(empty.UtcLastModified == DateTime.MinValue); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Runtime.WatcherOptions.md b/.docfx/api/types/Cuemon.Runtime.WatcherOptions.md new file mode 100644 index 00000000..94094986 --- /dev/null +++ b/.docfx/api/types/Cuemon.Runtime.WatcherOptions.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.Runtime.WatcherOptions +example: +- *content +--- + +The following example demonstrates how to configure a `WatcherOptions` for a file system watcher. + +```csharp +using System; +using Cuemon.Runtime; + +namespace Examples; + +public class WatcherConfigurationExample +{ + public WatcherOptions ConfigureWatcher() + { + return new WatcherOptions + { + DueTime = TimeSpan.FromSeconds(5), + DueTimeOnChanged = TimeSpan.FromSeconds(2), + Period = TimeSpan.FromMinutes(1) + }; + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.AesCryptor.md b/.docfx/api/types/Cuemon.Security.Cryptography.AesCryptor.md new file mode 100644 index 00000000..2ab388de --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.AesCryptor.md @@ -0,0 +1,91 @@ +--- +uid: Cuemon.Security.Cryptography.AesCryptor +example: +- *content +--- + +The following example demonstrates how to encrypt and decrypt data using AES encryption with AesCryptor, including key generation, custom cipher modes, and padding options. + +```csharp +using System; +using System.Security.Cryptography; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Security +{ + public class AesCryptorExamples + { + public static void Demonstrate() + { + // Generate a 256-bit key and 128-bit initialization vector. + byte[] key = AesCryptor.GenerateKey(); + byte[] iv = AesCryptor.GenerateInitializationVector(); + + Console.WriteLine("Key length: {0} bytes ({1} bits)", key.Length, key.Length * 8); + Console.WriteLine("IV length: {0} bytes ({1} bits)", iv.Length, iv.Length * 8); + + // Create an AesCryptor instance with the generated key and IV. + var cryptor = new AesCryptor(key, iv); + + // Encrypt a secret message. + byte[] plaintext = Encoding.UTF8.GetBytes("This is a sensitive message that needs encryption."); + byte[] ciphertext = cryptor.Encrypt(plaintext); + + Console.WriteLine("Plaintext bytes: {0}", plaintext.Length); + Console.WriteLine("Ciphertext (base64): {0}", Convert.ToBase64String(ciphertext)); + + // Decrypt the ciphertext back to the original message. + byte[] decrypted = cryptor.Decrypt(ciphertext); + string roundtrip = Encoding.UTF8.GetString(decrypted); + + Console.WriteLine("Decrypted message: {0}", roundtrip); // matches original + + // Use explicit AES options (CBC mode, PKCS7 padding). + byte[] ciphertextExplicit = cryptor.Encrypt(plaintext, o => + { + o.Mode = CipherMode.CBC; + o.Padding = PaddingMode.PKCS7; + }); + + byte[] decryptedExplicit = cryptor.Decrypt(ciphertextExplicit, o => + { + o.Mode = CipherMode.CBC; + o.Padding = PaddingMode.PKCS7; + }); + + Console.WriteLine("Explicit options roundtrip: {0}", + Encoding.UTF8.GetString(decryptedExplicit) == roundtrip); // true + } + + public static void GenerateKeysWithCustomSize() + { + // Generate a 128-bit key explicitly. + byte[] key128 = AesCryptor.GenerateKey(o => o.Size = AesSize.Aes128); + Console.WriteLine("128-bit key length: {0} bytes", key128.Length); // 16 + + // Generate a 192-bit key. + byte[] key192 = AesCryptor.GenerateKey(o => o.Size = AesSize.Aes192); + Console.WriteLine("192-bit key length: {0} bytes", key192.Length); // 24 + + // Default is 256-bit. + byte[] key256 = AesCryptor.GenerateKey(); + Console.WriteLine("256-bit key length: {0} bytes", key256.Length); // 32 + } + + public static void UseDefaultConstructor() + { + // Default constructor generates a random key and IV. + var cryptor = new AesCryptor(); + + byte[] data = Encoding.UTF8.GetBytes("Hello, world!"); + byte[] encrypted = cryptor.Encrypt(data); + byte[] decrypted = cryptor.Decrypt(encrypted); + + Console.WriteLine("Default constructor roundtrip: {0}", + Encoding.UTF8.GetString(decrypted)); // Hello, world! + } + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.AesCryptorOptions.md b/.docfx/api/types/Cuemon.Security.Cryptography.AesCryptorOptions.md new file mode 100644 index 00000000..395dcf59 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.AesCryptorOptions.md @@ -0,0 +1,77 @@ +--- +uid: Cuemon.Security.Cryptography.AesCryptorOptions +example: +- *content +--- + +The following example demonstrates how to configure AesCryptorOptions to specify cipher mode and padding when performing AES encryption and decryption. + +```csharp +using System; +using System.Security.Cryptography; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Security; + +public class AesCryptorOptionsExample +{ + public void Demonstrate() + { + // Generate a key and initialization vector + byte[] key = AesCryptor.GenerateKey(); + byte[] iv = AesCryptor.GenerateInitializationVector(); + + // Create an AES cryptor with the key and IV + var cryptor = new AesCryptor(key, iv); + + // Encrypt data using default options (CBC mode, PKCS7 padding) + byte[] plaintext = Encoding.UTF8.GetBytes("Secret message."); + byte[] encrypted = cryptor.Encrypt(plaintext); + Console.WriteLine($"Encrypted ({encrypted.Length} bytes): {Convert.ToBase64String(encrypted)}"); + + // Decrypt with default options + byte[] decrypted = cryptor.Decrypt(encrypted); + Console.WriteLine($"Decrypted: {Encoding.UTF8.GetString(decrypted)}"); // Secret message. + + // Create options explicitly and copy settings via delegate + var defaultOptions = new AesCryptorOptions(); + defaultOptions.Mode = CipherMode.CBC; + defaultOptions.Padding = PaddingMode.PKCS7; + + // Encrypt with explicit cipher mode and padding via delegate from AesCryptorOptions + byte[] plaintext2 = Encoding.UTF8.GetBytes("Configured encryption."); + byte[] encrypted2 = cryptor.Encrypt(plaintext2, o => + { + o.Mode = defaultOptions.Mode; + o.Padding = defaultOptions.Padding; + }); + + // Decrypt using the same options + byte[] decrypted2 = cryptor.Decrypt(encrypted2, o => + { + o.Mode = defaultOptions.Mode; + o.Padding = defaultOptions.Padding; + }); + Console.WriteLine($"Decrypted: {Encoding.UTF8.GetString(decrypted2)}"); // Configured encryption. + + // Using ECB mode with Zeros padding (not recommended for production) + defaultOptions.Mode = CipherMode.ECB; + defaultOptions.Padding = PaddingMode.Zeros; + byte[] plaintext3 = Encoding.UTF8.GetBytes("Alternative mode."); + byte[] encrypted3 = cryptor.Encrypt(plaintext3, o => + { + o.Mode = defaultOptions.Mode; + o.Padding = defaultOptions.Padding; + }); + byte[] decrypted3 = cryptor.Decrypt(encrypted3, o => + { + o.Mode = defaultOptions.Mode; + o.Padding = defaultOptions.Padding; + }); + Console.WriteLine($"Decrypted: {Encoding.UTF8.GetString(decrypted3)}"); // Alternative mode. + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.AesKeyOptions.md b/.docfx/api/types/Cuemon.Security.Cryptography.AesKeyOptions.md new file mode 100644 index 00000000..9fc9dcc2 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.AesKeyOptions.md @@ -0,0 +1,67 @@ +--- +uid: Cuemon.Security.Cryptography.AesKeyOptions +example: +- *content +--- + +The following example demonstrates how to configure AesKeyOptions to specify the key size and custom random string provider when generating AES keys. + +```csharp +using System; +using Cuemon.Security.Cryptography; + +namespace MyApp.Security.Cryptography +{ + public class AesKeyOptionsExamples + { + public static void ConfigureKeySize() + { + // Default is AesSize.Aes256 (32 bytes). + var defaultOptions = new AesKeyOptions(); + Console.WriteLine("Default key size: {0}", defaultOptions.Size); // Aes256 + + // Generate a 128-bit key with AesKeyOptions. + byte[] key128 = AesCryptor.GenerateKey(o => + { + o.Size = AesSize.Aes128; + }); + Console.WriteLine("128-bit key length: {0} bytes", key128.Length); // 16 + + // Generate a 192-bit key. + byte[] key192 = AesCryptor.GenerateKey(o => + { + o.Size = AesSize.Aes192; + }); + Console.WriteLine("192-bit key length: {0} bytes", key192.Length); // 24 + + // Generate a 256-bit key explicitly. + byte[] key256 = AesCryptor.GenerateKey(o => + { + o.Size = AesSize.Aes256; + }); + Console.WriteLine("256-bit key length: {0} bytes", key256.Length); // 32 + } + + public static void CustomRandomStringProvider() + { + // Replace the default random string provider with a custom one. + // The provider is used internally when generating passphrase-based keys. + byte[] key = AesCryptor.GenerateKey(o => + { + o.Size = AesSize.Aes128; + o.RandomStringProvider = size => new string('X', size == AesSize.Aes128 ? 16 : size == AesSize.Aes192 ? 24 : 32); + }); + + Console.WriteLine("Custom provider key length: {0} bytes", key.Length); // 16 + } + + public static void InspectDefaultProperties() + { + var options = new AesKeyOptions(); + Console.WriteLine("Default size: {0}", options.Size); // Aes256 + Console.WriteLine("RandomStringProvider != null: {0}", options.RandomStringProvider != null); // true + } + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.AesSize.md b/.docfx/api/types/Cuemon.Security.Cryptography.AesSize.md new file mode 100644 index 00000000..ce8aa896 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.AesSize.md @@ -0,0 +1,48 @@ +--- +uid: Cuemon.Security.Cryptography.AesSize +example: +- *content +--- + +The following example demonstrates how to select AES key sizes using the AesSize enumeration when generating cryptographic keys. + +```csharp +using System; +using Cuemon.Security.Cryptography; + +namespace MyApp.Security; + +public class AesSizeExample +{ + public void Demonstrate() + { + // AesSize specifies the key size for the AES symmetric algorithm: + // Aes128 = 128-bit key (16 bytes) + // Aes192 = 192-bit key (24 bytes) + // Aes256 = 256-bit key (32 bytes, default) + + // Generate a 256-bit key (default when no options are specified) + byte[] defaultKey = AesCryptor.GenerateKey(); + Console.WriteLine($"Default key length: {defaultKey.Length} bytes"); // 32 + + // Generate a 128-bit key using AesSize.Aes128 + byte[] key128 = AesCryptor.GenerateKey(o => o.Size = AesSize.Aes128); + Console.WriteLine($"128-bit key length: {key128.Length} bytes"); // 16 + + // Generate a 192-bit key using AesSize.Aes192 + byte[] key192 = AesCryptor.GenerateKey(o => o.Size = AesSize.Aes192); + Console.WriteLine($"192-bit key length: {key192.Length} bytes"); // 24 + + // Generate a 256-bit key explicitly using AesSize.Aes256 + byte[] key256 = AesCryptor.GenerateKey(o => o.Size = AesSize.Aes256); + Console.WriteLine($"256-bit key length: {key256.Length} bytes"); // 32 + + // Compare enum values directly + AesSize size = AesSize.Aes256; + Console.WriteLine($"Selected size: {size}"); // Aes256 + Console.WriteLine($"Is Aes256 selected: {size == AesSize.Aes256}"); // True + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.HmacMessageDigest5.md b/.docfx/api/types/Cuemon.Security.Cryptography.HmacMessageDigest5.md new file mode 100644 index 00000000..47af1c38 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.HmacMessageDigest5.md @@ -0,0 +1,64 @@ +--- +uid: Cuemon.Security.Cryptography.HmacMessageDigest5 +example: +- *content +--- + +The following example demonstrates how to compute and verify HMAC-MD5 message authentication codes using HmacMessageDigest5, including tamper detection. + +```csharp +using System; +using System.Text; +using Cuemon.Security; +using Cuemon.Security.Cryptography; + +using Cuemon; +namespace MyApp.Security +{ + public static class HmacMessageDigest5Examples + { + public static void Demonstrate() + { + // Define a secret key (minimum 64 bytes recommended for HMAC-MD5). + byte[] secret = Encoding.UTF8.GetBytes( + "ThisIsASecretKeyThatShouldBeAtLeastSixtyFourBytesLongForBestResults1234567"); + + // Create an HMAC-MD5 instance with the secret. + var hmacMd5 = new HmacMessageDigest5(secret, null); + + // Compute the HMAC of a message. + byte[] message = Encoding.UTF8.GetBytes("Important: Transfer $100 to account 12345"); + HashResult hash = hmacMd5.ComputeHash(message); + + Console.WriteLine("HMAC-MD5 (hex): {0}", hash.ToHexadecimalString()); + Console.WriteLine("HMAC-MD5 (base64): {0}", hash.ToBase64String()); + + // Verify the HMAC by recomputing with the same secret. + var verifier = new HmacMessageDigest5(secret, null); + HashResult expected = verifier.ComputeHash(message); + bool isValid = hash.Equals(expected); + Console.WriteLine("HMAC valid: {0}", isValid); // true + + // Tampered message produces a different HMAC. + byte[] tampered = Encoding.UTF8.GetBytes("Important: Transfer $100 to account 99999"); + HashResult tamperedHash = hmacMd5.ComputeHash(tampered); + Console.WriteLine("Tampered HMAC matches: {0}", hash.Equals(tamperedHash)); // false + + // Compute HMAC from string directly (UTF-8 encoding by default). + HashResult fromString = hmacMd5.ComputeHash("Hello, HMAC!"); + Console.WriteLine("String HMAC: {0}", fromString); + } + + public static void DemonstrateWithOptions() + { + byte[] secret = Encoding.UTF8.GetBytes("my-secret-key"); + var hmacMd5 = new HmacMessageDigest5(secret, o => + { + o.ByteOrder = Endianness.LittleEndian; + }); + HashResult result = hmacMd5.ComputeHash(Encoding.UTF8.GetBytes("test data")); + Console.WriteLine("HMAC-MD5 (little-endian): {0}", result.ToHexadecimalString()); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm1.md b/.docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm1.md new file mode 100644 index 00000000..dd8644fa --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm1.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.Security.Cryptography.HmacSecureHashAlgorithm1 +example: +- *content +--- + +The following example demonstrates how to compute an HMAC-SHA1 hash with . + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public static class HmacSecureHashAlgorithm1Example +{ + public static void Demonstrate() + { + var algorithm = new HmacSecureHashAlgorithm1(CreateSecret(), null); + var result = algorithm.ComputeHash(Encoding.UTF8.GetBytes("Authenticate this message")); + + Console.WriteLine(result.GetBytes().Length); + Console.WriteLine(result.ToBase64String()); + } + + private static byte[] CreateSecret() => Encoding.UTF8.GetBytes("docs-secret-sha1"); +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm256.md b/.docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm256.md new file mode 100644 index 00000000..28e96f45 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm256.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.Security.Cryptography.HmacSecureHashAlgorithm256 +example: +- *content +--- + +The following example demonstrates how to compute an HMAC-SHA256 hash with . + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public static class HmacSecureHashAlgorithm256Example +{ + public static void Demonstrate() + { + var secret = Encoding.UTF8.GetBytes("unittest-secret"); + var payload = Encoding.UTF8.GetBytes("Authenticate this message"); + var algorithm = new HmacSecureHashAlgorithm256(secret, null); + var result = algorithm.ComputeHash(payload); + + Console.WriteLine(result.GetBytes().Length); + Console.WriteLine(result.ToHexadecimalString()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm384.md b/.docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm384.md new file mode 100644 index 00000000..b94f0964 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm384.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.Security.Cryptography.HmacSecureHashAlgorithm384 +example: +- *content +--- + +The following example demonstrates how to compute an HMAC-SHA384 hash with . + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public static class HmacSecureHashAlgorithm384Example +{ + public static void Demonstrate() + { + var secret = Encoding.UTF8.GetBytes("docs-secret-sha384"); + var algorithm = new HmacSecureHashAlgorithm384(secret, null); + var result = algorithm.ComputeHash(Encoding.UTF8.GetBytes("Payload for SHA-384")); + + Console.WriteLine(result.GetBytes().Length); + Console.WriteLine(result.ToBase64String()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm512.md b/.docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm512.md new file mode 100644 index 00000000..0758eedb --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.HmacSecureHashAlgorithm512.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.Security.Cryptography.HmacSecureHashAlgorithm512 +example: +- *content +--- + +The following example demonstrates how different payloads produce different HMAC-SHA512 values with . + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public static class HmacSecureHashAlgorithm512Example +{ + public static void Demonstrate() + { + var secret = Encoding.UTF8.GetBytes("docs-secret-sha512"); + var algorithm = new HmacSecureHashAlgorithm512(secret, null); + var first = algorithm.ComputeHash(Encoding.UTF8.GetBytes("first")); + var second = algorithm.ComputeHash(Encoding.UTF8.GetBytes("second")); + + Console.WriteLine(first.GetBytes().Length); + Console.WriteLine(!first.Equals(second)); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.KeyedCryptoAlgorithm.md b/.docfx/api/types/Cuemon.Security.Cryptography.KeyedCryptoAlgorithm.md new file mode 100644 index 00000000..c3989bc7 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.KeyedCryptoAlgorithm.md @@ -0,0 +1,70 @@ +--- +uid: Cuemon.Security.Cryptography.KeyedCryptoAlgorithm +example: +- *content +--- + +The following example demonstrates how to use the KeyedCryptoAlgorithm enumeration to select an HMAC algorithm (SHA-256, SHA-384, SHA-512, SHA-1, or MD5) for keyed hashing. + +```csharp +using System; +using System.Security.Cryptography; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Security +{ + public class KeyedCryptoAlgorithmExample + { + public void Demonstrate() + { + // KeyedCryptoAlgorithm specifies the HMAC algorithm to use. + // HmacMd5 = -2 (HMAC-MD5, 128 bits) + // HmacSha1 = -1 (HMAC-SHA1, 160 bits) + // HmacSha256 = 0 (HMAC-SHA256,256 bits) + // HmacSha384 = 1 (HMAC-SHA384,384 bits) + // HmacSha512 = 2 (HMAC-SHA512,512 bits) + + byte[] key = Encoding.UTF8.GetBytes("my-secret-key"); + byte[] data = Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog"); + + // HMAC-SHA256 (default/recommended) + using var hmacSha256 = new HMACSHA256(key); + byte[] hash256 = hmacSha256.ComputeHash(data); + Console.WriteLine($"HmacSha256: {BitConverter.ToString(hash256).Replace("-", "").ToLowerInvariant()}"); + + // HMAC-SHA384 + using var hmacSha384 = new HMACSHA384(key); + byte[] hash384 = hmacSha384.ComputeHash(data); + Console.WriteLine($"HmacSha384: {BitConverter.ToString(hash384).Replace("-", "").ToLowerInvariant()}"); + + // HMAC-SHA512 + using var hmacSha512 = new HMACSHA512(key); + byte[] hash512 = hmacSha512.ComputeHash(data); + Console.WriteLine($"HmacSha512: {BitConverter.ToString(hash512).Replace("-", "").ToLowerInvariant()}"); + + // HMAC-SHA1 + using var hmacSha1 = new HMACSHA1(key); + byte[] hashSha1 = hmacSha1.ComputeHash(data); + Console.WriteLine($"HmacSha1: {BitConverter.ToString(hashSha1).Replace("-", "").ToLowerInvariant()}"); + + // Using KeyedCryptoAlgorithm to select algorithm dynamically + KeyedCryptoAlgorithm algorithm = KeyedCryptoAlgorithm.HmacSha384; + string algorithmName = algorithm switch + { + KeyedCryptoAlgorithm.HmacMd5 => "MD5", + KeyedCryptoAlgorithm.HmacSha1 => "SHA1", + KeyedCryptoAlgorithm.HmacSha256 => "SHA256", + KeyedCryptoAlgorithm.HmacSha384 => "SHA384", + KeyedCryptoAlgorithm.HmacSha512 => "SHA512", + _ => "SHA256" + }; + Console.WriteLine($"Selected HMAC algorithm: HMAC-{algorithmName}"); + + // Enum value comparison + Console.WriteLine($"HmacSha256 == 0: {KeyedCryptoAlgorithm.HmacSha256 == (KeyedCryptoAlgorithm)0}"); // True + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.KeyedHashFactory.md b/.docfx/api/types/Cuemon.Security.Cryptography.KeyedHashFactory.md new file mode 100644 index 00000000..1797aa0d --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.KeyedHashFactory.md @@ -0,0 +1,25 @@ +--- +uid: Cuemon.Security.Cryptography.KeyedHashFactory +example: +- *content +--- + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace Cuemon.Security.Cryptography; + +public class KeyedHashFactoryExample +{ + public void Demonstrate() + { + var secret = Encoding.UTF8.GetBytes("my-secret-key"); + var hmac = KeyedHashFactory.CreateHmacCryptoSha256(secret); + var input = "Message to authenticate"; + var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(input)); + Console.WriteLine($"HMAC-SHA256: {BitConverter.ToString(hash.To(bytes => bytes)).Replace("-", "")}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.MessageDigest5.md b/.docfx/api/types/Cuemon.Security.Cryptography.MessageDigest5.md new file mode 100644 index 00000000..3404b5fc --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.MessageDigest5.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.Security.Cryptography.MessageDigest5 +example: +- *content +--- + +The following example demonstrates how to compute an MD5 hash with . + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public static class MessageDigest5Example +{ + public static void Demonstrate() + { + var algorithm = new MessageDigest5(); + var result = algorithm.ComputeHash(Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog")); + + Console.WriteLine(MessageDigest5.BitSize); + Console.WriteLine(result.GetBytes().Length); + Console.WriteLine(result.ToHexadecimalString()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.SHA512256.md b/.docfx/api/types/Cuemon.Security.Cryptography.SHA512256.md new file mode 100644 index 00000000..5b3a2d11 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.SHA512256.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Security.Cryptography.SHA512256 +example: +- *content +--- + +The following example demonstrates how to use the low-level implementation directly through . + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public static class SHA512256Example +{ + public static void Demonstrate() + { + using var algorithm = new SHA512256(); + + var digest = algorithm.ComputeHash(Encoding.UTF8.GetBytes("Hello, world!")); + algorithm.Initialize(); + var secondDigest = algorithm.ComputeHash(Encoding.UTF8.GetBytes("Hello, world!")); + + Console.WriteLine(digest.Length); + Console.WriteLine(digest.Length == secondDigest.Length); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm1.md b/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm1.md new file mode 100644 index 00000000..6125a101 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm1.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.Security.Cryptography.SecureHashAlgorithm1 +example: +- *content +--- + +The following example demonstrates how to compute a SHA-1 hash with . + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public static class SecureHashAlgorithm1Example +{ + public static void Demonstrate() + { + var algorithm = new SecureHashAlgorithm1(); + var result = algorithm.ComputeHash(Encoding.UTF8.GetBytes("legacy-compatible digest")); + + Console.WriteLine(SecureHashAlgorithm1.BitSize); + Console.WriteLine(result.GetBytes().Length); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm256.md b/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm256.md new file mode 100644 index 00000000..b2ff5b3e --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm256.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.Security.Cryptography.SecureHashAlgorithm256 +example: +- *content +--- + +The following example demonstrates how to compute a SHA-256 hash with . + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public static class SecureHashAlgorithm256Example +{ + public static void Demonstrate() + { + var algorithm = new SecureHashAlgorithm256(); + var result = algorithm.ComputeHash(Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog")); + var repeated = algorithm.ComputeHash(Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog")); + + Console.WriteLine(SecureHashAlgorithm256.BitSize); + Console.WriteLine(result.GetBytes().Length); + Console.WriteLine(result.Equals(repeated)); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm384.md b/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm384.md new file mode 100644 index 00000000..ff31514c --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm384.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.Security.Cryptography.SecureHashAlgorithm384 +example: +- *content +--- + +The following example demonstrates how to compute a SHA-384 hash with . + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public static class SecureHashAlgorithm384Example +{ + public static void Demonstrate() + { + var algorithm = new SecureHashAlgorithm384(); + var result = algorithm.ComputeHash(Encoding.UTF8.GetBytes("Payload for SHA-384")); + + Console.WriteLine(SecureHashAlgorithm384.BitSize); + Console.WriteLine(result.GetBytes().Length); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm512.md b/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm512.md new file mode 100644 index 00000000..4d36a35e --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm512.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.Security.Cryptography.SecureHashAlgorithm512 +example: +- *content +--- + +The following example demonstrates how to compute a SHA-512 hash with . + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public static class SecureHashAlgorithm512Example +{ + public static void Demonstrate() + { + var algorithm = new SecureHashAlgorithm512(); + var result = algorithm.ComputeHash(Encoding.UTF8.GetBytes("Payload for SHA-512")); + + Console.WriteLine(SecureHashAlgorithm512.BitSize); + Console.WriteLine(result.ToBase64String()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm512256.md b/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm512256.md new file mode 100644 index 00000000..7d4e3f21 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.SecureHashAlgorithm512256.md @@ -0,0 +1,27 @@ +--- +uid: Cuemon.Security.Cryptography.SecureHashAlgorithm512256 +example: +- *content +--- + +The following example demonstrates how to compute a SHA-512/256 hash with . + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Examples; + +public static class SecureHashAlgorithm512256Example +{ + public static void Demonstrate() + { + var algorithm = new SecureHashAlgorithm512256(null); + var result = algorithm.ComputeHash(Encoding.UTF8.GetBytes("Payload for SHA-512/256")); + + Console.WriteLine(SecureHashAlgorithm512256.BitSize); + Console.WriteLine(result.GetBytes().Length); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedCryptoAlgorithm.md b/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedCryptoAlgorithm.md new file mode 100644 index 00000000..fd6e0a61 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedCryptoAlgorithm.md @@ -0,0 +1,62 @@ +--- +uid: Cuemon.Security.Cryptography.UnkeyedCryptoAlgorithm +example: +- *content +--- + +The following example demonstrates how to use the UnkeyedCryptoAlgorithm enumeration to select a hash algorithm (SHA-256, SHA-384, SHA-512, SHA-1, or MD5) for unkeyed hashing. + +```csharp +using System; +using System.Security.Cryptography; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace MyApp.Security +{ + public class UnkeyedCryptoAlgorithmExample + { + public void Demonstrate() + { + // UnkeyedCryptoAlgorithm specifies the hash algorithm to use. + // Md5 = -2 (MD5, 128 bits) + // Sha1 = -1 (SHA-1, 160 bits) + // Sha256 = 0 (SHA-256, 256 bits) + // Sha384 = 1 (SHA-384, 384 bits) + // Sha512 = 2 (SHA-512, 512 bits) + // Sha512Slash256 = 3 (SHA-512/256, 256 bits) + + byte[] data = Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog"); + + // SHA-256 (default/recommended) + using var sha256 = SHA256.Create(); + byte[] hash256 = sha256.ComputeHash(data); + Console.WriteLine($"Sha256: {BitConverter.ToString(hash256).Replace("-", "").ToLowerInvariant()}"); + + // SHA-384 + using var sha384 = SHA384.Create(); + byte[] hash384 = sha384.ComputeHash(data); + Console.WriteLine($"Sha384: {BitConverter.ToString(hash384).Replace("-", "").ToLowerInvariant()}"); + + // SHA-512 + using var sha512 = SHA512.Create(); + byte[] hash512 = sha512.ComputeHash(data); + Console.WriteLine($"Sha512: {BitConverter.ToString(hash512).Replace("-", "").ToLowerInvariant()}"); + + // SHA-1 + using var sha1 = SHA1.Create(); + byte[] hashSha1 = sha1.ComputeHash(data); + Console.WriteLine($"Sha1: {BitConverter.ToString(hashSha1).Replace("-", "").ToLowerInvariant()}"); + + // Using UnkeyedCryptoAlgorithm to select algorithm dynamically + UnkeyedCryptoAlgorithm algorithm = UnkeyedCryptoAlgorithm.Sha512; + Console.WriteLine($"Selected algorithm: {algorithm}"); // Sha512 + + // Enum value comparison + Console.WriteLine($"Sha256 == 0: {UnkeyedCryptoAlgorithm.Sha256 == (UnkeyedCryptoAlgorithm)0}"); // True + Console.WriteLine($"Bit size of Sha512: 512 bits"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedHashFactory.md b/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedHashFactory.md new file mode 100644 index 00000000..2dceb796 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedHashFactory.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.Security.Cryptography.UnkeyedHashFactory +example: +- *content +--- + +```csharp +using System; +using System.Text; +using Cuemon.Security.Cryptography; + +namespace Cuemon.Security.Cryptography; + +public class UnkeyedHashFactoryExample +{ + public void Demonstrate() + { + var sha256 = UnkeyedHashFactory.CreateCryptoSha256(); + var input = "Data to hash"; + var hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(input)); + Console.WriteLine($"SHA-256: {BitConverter.ToString(hash.GetBytes()).Replace("-", "")}"); + + var sha512 = UnkeyedHashFactory.CreateCryptoSha512(); + hash = sha512.ComputeHash(Encoding.UTF8.GetBytes(input)); + Console.WriteLine($"SHA-512: {BitConverter.ToString(hash.GetBytes()).Replace("-", "")}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.CyclicRedundancyCheck32.md b/.docfx/api/types/Cuemon.Security.CyclicRedundancyCheck32.md new file mode 100644 index 00000000..01c1c96f --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.CyclicRedundancyCheck32.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.Security.CyclicRedundancyCheck32 +example: +- *content +--- + +The following example shows how to compute a CRC-32 checksum with the common reflected configuration. + +```csharp +using System; +using System.Text; +using Cuemon; +using Cuemon.Security; + +namespace MyApp.Examples; + +public static class CyclicRedundancyCheck32Example +{ + public static void Demonstrate() + { + var checksum = new CyclicRedundancyCheck32(setup: options => + { + options.ByteOrder = Endianness.BigEndian; + options.ReflectInput = true; + options.ReflectOutput = true; + }); + + HashResult result = checksum.ComputeHash(Encoding.ASCII.GetBytes("123456789")); + + Console.WriteLine(result.ToHexadecimalString().ToLowerInvariant()); + Console.WriteLine(checksum.InitialValue); + Console.WriteLine(checksum.FinalXor); + + var alternate = new CyclicRedundancyCheck32(polynomial: 0xEDB88320, initialValue: 0xFFFFFFFF, finalXor: 0xFFFFFFFF); + Console.WriteLine(alternate.ComputeHash("Cuemon").ToBase64String()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.CyclicRedundancyCheck64.md b/.docfx/api/types/Cuemon.Security.CyclicRedundancyCheck64.md new file mode 100644 index 00000000..6650288b --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.CyclicRedundancyCheck64.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.Security.CyclicRedundancyCheck64 +example: +- *content +--- + +The following example demonstrates how to compute a 64-bit Cyclic Redundancy Check (CRC) checksum using the class. + +```csharp +using System; +using System.Text; +using Cuemon.Security; + +namespace MyApp.Examples; + +public class CyclicRedundancyCheck64Example +{ + public void Demonstrate() + { + // Create CRC-64 instance with default ECMA-182 polynomial + var crc64 = new CyclicRedundancyCheck64(); + + // Compute checksum from ASCII input + byte[] data = Encoding.ASCII.GetBytes("123456789"); + HashResult result = crc64.ComputeHash(data); + + // Display the checksum in hexadecimal + string hex = result.ToHexadecimalString(); + Console.WriteLine(hex); // 6c40df5f0b497347 + + // Create CRC-64 with custom polynomial + var customCrc = new CyclicRedundancyCheck64( + polynomial: 0x42F0E1EBA9EA3693, + initialValue: 0xFFFFFFFFFFFFFFFF, + finalXor: 0xFFFFFFFFFFFFFFFF); + + HashResult customResult = customCrc.ComputeHash(data); + Console.WriteLine(customResult.ToHexadecimalString()); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.CyclicRedundancyCheckAlgorithm.md b/.docfx/api/types/Cuemon.Security.CyclicRedundancyCheckAlgorithm.md new file mode 100644 index 00000000..15ee26fb --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.CyclicRedundancyCheckAlgorithm.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.Security.CyclicRedundancyCheckAlgorithm +example: +- *content +--- + +The following example demonstrates how to use the enum to select a specific CRC algorithm variant. + +```csharp +using System; +using Cuemon.Security; // for CyclicRedundancyCheckAlgorithm + +namespace MyApp.Examples; + +public class CyclicRedundancyCheckAlgorithmExample +{ + public void Demonstrate() + { + // Select commonly used CRC algorithms + CyclicRedundancyCheckAlgorithm crc32 = CyclicRedundancyCheckAlgorithm.Crc32; + CyclicRedundancyCheckAlgorithm crc32C = CyclicRedundancyCheckAlgorithm.Crc32C; + CyclicRedundancyCheckAlgorithm crc64 = CyclicRedundancyCheckAlgorithm.Crc64; + + Console.WriteLine(crc32); // Crc32 + Console.WriteLine(crc32C); // Crc32C + Console.WriteLine(crc64); // Crc64 + + // Switch on algorithm + string GetDescription(CyclicRedundancyCheckAlgorithm algo) => algo switch + { + CyclicRedundancyCheckAlgorithm.Crc32 => "CRC-32 (ISO-HDLC, PKZIP)", + CyclicRedundancyCheckAlgorithm.Crc32C => "CRC-32C (ISCSI, Castagnoli)", + CyclicRedundancyCheckAlgorithm.Crc64 => "CRC-64 (ECMA-182)", + _ => "Unknown" + }; + + Console.WriteLine(GetDescription(crc32C)); // CRC-32C (ISCSI, Castagnoli) + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.CyclicRedundancyCheckOptions.md b/.docfx/api/types/Cuemon.Security.CyclicRedundancyCheckOptions.md new file mode 100644 index 00000000..48189f4f --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.CyclicRedundancyCheckOptions.md @@ -0,0 +1,41 @@ +--- +uid: Cuemon.Security.CyclicRedundancyCheckOptions +example: +- *content +--- + +The following example shows how to reuse one `CyclicRedundancyCheckOptions` instance when configuring a checksum implementation. + +```csharp +using System; +using System.Text; +using Cuemon; +using Cuemon.Security; + +namespace MyApp.Examples; + +public static class CyclicRedundancyCheckOptionsExample +{ + public static void Demonstrate() + { + var options = new CyclicRedundancyCheckOptions + { + ByteOrder = Endianness.LittleEndian, + ReflectInput = true, + ReflectOutput = true + }; + + var checksum = new CyclicRedundancyCheck32(setup: configured => + { + configured.ByteOrder = options.ByteOrder; + configured.ReflectInput = options.ReflectInput; + configured.ReflectOutput = options.ReflectOutput; + }); + + Console.WriteLine(options.ByteOrder); + Console.WriteLine(options.ReflectInput); + Console.WriteLine(options.ReflectOutput); + Console.WriteLine(checksum.ComputeHash(Encoding.ASCII.GetBytes("123456789")).ToHexadecimalString()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.FowlerNollVo1024.md b/.docfx/api/types/Cuemon.Security.FowlerNollVo1024.md new file mode 100644 index 00000000..1eaf038c --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.FowlerNollVo1024.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Security.FowlerNollVo1024 +example: +- *content +--- + +The following example shows how to compute 1024-bit Fowler-Noll-Vo hashes for the same payload with different algorithms. + +```csharp +using System; +using System.Text; +using Cuemon; +using Cuemon.Security; + +namespace MyApp.Examples; + +public static class FowlerNollVo1024Example +{ + public static void Demonstrate() + { + var hasher = new FowlerNollVo1024(options => + { + options.Algorithm = FowlerNollVoAlgorithm.Fnv1a; + options.ByteOrder = Endianness.BigEndian; + }); + + HashResult orderHash = hasher.ComputeHash(Encoding.UTF8.GetBytes("order-42")); + + Console.WriteLine(hasher.Bits); + Console.WriteLine(orderHash.GetBytes().Length); + Console.WriteLine(orderHash.ToHexadecimalString()); + + var legacyHasher = new FowlerNollVo1024(options => options.Algorithm = FowlerNollVoAlgorithm.Fnv1); + Console.WriteLine(legacyHasher.ComputeHash("order-42").ToHexadecimalString()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.FowlerNollVo128.md b/.docfx/api/types/Cuemon.Security.FowlerNollVo128.md new file mode 100644 index 00000000..7788fcc1 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.FowlerNollVo128.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.Security.FowlerNollVo128 +example: +- *content +--- + +The following example demonstrates how to compute 128-bit FNV-1a and FNV-1 hash values using FowlerNollVo128, with configurable algorithm variant and byte order. + +```csharp +using System; +using System.Text; +using Cuemon; +using Cuemon.Security; + +namespace MyApp.Examples +{ + public class FowlerNollVo128Example + { + public void Demonstrate() + { + // Create a FNV-1a 128-bit hash (default algorithm). + var fnv = new FowlerNollVo128(); + + Console.WriteLine($"Bits: {fnv.Bits}"); // 128 + Console.WriteLine($"Algorithm: {fnv.Options.Algorithm}"); // Fnv1a + + // Compute hash of a UTF-8 encoded string. + var data = Encoding.UTF8.GetBytes("Hello, World!"); + var hash = fnv.ComputeHash(data); + + Console.WriteLine($"Hash (hex): {hash.ToHexadecimalString()}"); + Console.WriteLine($"Hash (b64): {hash.ToBase64String()}"); + + // Use FNV-1 instead of FNV-1a. + var fnv1 = new FowlerNollVo128(o => o.Algorithm = FowlerNollVoAlgorithm.Fnv1); + var hashFnv1 = fnv1.ComputeHash(data); + Console.WriteLine($"FNV-1 hash: {hashFnv1}"); + + // Little-endian byte order. + var fnvLe = new FowlerNollVo128(o => o.ByteOrder = Endianness.LittleEndian); + var hashLe = fnvLe.ComputeHash(data); + Console.WriteLine($"LE hash: {hashLe.ToHexadecimalString()}"); + + // Verify hash with the built-in offset basis for empty input. + var emptyHash = fnv.ComputeHash(Array.Empty()); + Console.WriteLine($"Offset basis hash: {emptyHash.ToHexadecimalString()}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.FowlerNollVo256.md b/.docfx/api/types/Cuemon.Security.FowlerNollVo256.md new file mode 100644 index 00000000..4e32baca --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.FowlerNollVo256.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.Security.FowlerNollVo256 +example: +- *content +--- + +The following example demonstrates how to compute 256-bit FNV-1a hash values using FowlerNollVo256, with configurable byte order and integer conversion. + +```csharp +using System; +using System.Numerics; +using System.Text; +using Cuemon; +using Cuemon.Security; + +namespace MyApp.Examples +{ + public class FowlerNollVo256Example + { + public void Demonstrate() + { + // Create a FNV-1a 256-bit hash (default algorithm). + var fnv = new FowlerNollVo256(); + + Console.WriteLine($"Bits: {fnv.Bits}"); // 256 + Console.WriteLine($"Algorithm: {fnv.Options.Algorithm}"); // Fnv1a + + // Compute hash of a UTF-8 encoded string. + var data = Encoding.UTF8.GetBytes("The quick brown fox jumps over the lazy dog"); + var hash = fnv.ComputeHash(data); + + Console.WriteLine($"Hash (hex): {hash.ToHexadecimalString()}"); + Console.WriteLine($"Hash (b64): {hash.ToBase64String()}"); + Console.WriteLine($"Hash length: {hash.GetBytes().Length} bytes"); + + // Configure byte order independently. + var fnvLe = new FowlerNollVo256(o => + { + o.ByteOrder = Endianness.LittleEndian; + }); + var hashLe = fnvLe.ComputeHash(data); + Console.WriteLine($"LE hash: {hashLe.ToHexadecimalString()}"); + + // Convert hash to an integer using the built-in converter. + var asBigInt = hash.To(b => new BigInteger(b)); + Console.WriteLine($"As integer: {asBigInt}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.FowlerNollVo32.md b/.docfx/api/types/Cuemon.Security.FowlerNollVo32.md new file mode 100644 index 00000000..14ce908e --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.FowlerNollVo32.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.Security.FowlerNollVo32 +example: +- *content +--- + +The following example demonstrates how to compute a 32-bit FNV-1a hash using the class. + +```csharp +using System; +using System.Text; +using Cuemon; // for Endianness +using Cuemon.Security; // for FowlerNollVo32 + +using Cuemon; +namespace MyApp.Examples; + +public class FowlerNollVo32Example +{ + public void Demonstrate() + { + var fnv = new FowlerNollVo32(); + + // Compute hash of a string + byte[] data = Encoding.UTF8.GetBytes("hello"); + var hash = fnv.ComputeHash(data); + + Console.WriteLine(hash.ToHexadecimalString()); // F970D0C7 (big-endian default) + Console.WriteLine(hash.ToBase64String()); // +XDQxw== + Console.WriteLine(fnv.Bits); // 32 + + // Configure for little-endian output + var fnvLe = new FowlerNollVo32(o => o.ByteOrder = Endianness.LittleEndian); + byte[] hashBytes = fnvLe.ComputeHash(data).GetBytes(); + Console.WriteLine(BitConverter.ToString(hashBytes)); // C7-D0-70-F9 + + // Use FNV-1 variant instead of FNV-1a + fnv.Options.Algorithm = FowlerNollVoAlgorithm.Fnv1; + hash = fnv.ComputeHash(data); + Console.WriteLine(hash.ToHexadecimalString()); // E973FD3B + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.FowlerNollVo512.md b/.docfx/api/types/Cuemon.Security.FowlerNollVo512.md new file mode 100644 index 00000000..c4cb2ba7 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.FowlerNollVo512.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.Security.FowlerNollVo512 +example: +- *content +--- + +The following example demonstrates how to compute 512-bit FNV-1a and FNV-1 hash values using FowlerNollVo512, with configurable algorithm variant and URL-safe Base64 output. + +```csharp +using System; +using System.Text; +using Cuemon; +using Cuemon.Security; + +namespace MyApp.Examples +{ + public class FowlerNollVo512Example + { + public void Demonstrate() + { + // Create a FNV-1a 512-bit hash (default algorithm). + var fnv = new FowlerNollVo512(); + + Console.WriteLine($"Bits: {fnv.Bits}"); // 512 + Console.WriteLine($"Algorithm: {fnv.Options.Algorithm}"); // Fnv1a + Console.WriteLine($"Offset basis: {fnv.OffsetBasis}"); + + // Compute hash of binary data. + var data = Encoding.UTF8.GetBytes("Cuemon FNV-512 example"); + var hash = fnv.ComputeHash(data); + + Console.WriteLine($"Hash (hex): {hash.ToHexadecimalString()}"); + Console.WriteLine($"Hash (base64): {hash.ToBase64String()}"); + + // Using FNV-1 algorithm. + var fnv1 = new FowlerNollVo512(o => o.Algorithm = FowlerNollVoAlgorithm.Fnv1); + var hashFnv1 = fnv1.ComputeHash(data); + Console.WriteLine($"FNV-1 hash: {hashFnv1.ToHexadecimalString()}"); + + // Raw bytes for further processing. + var bytes = hash.GetBytes(); + Console.WriteLine($"Byte length: {bytes.Length}"); // 64 (512 / 8) + + // URL-safe Base64 encoding. + var urlSafe = hash.ToUrlEncodedBase64String(); + Console.WriteLine($"URL-safe b64: {urlSafe}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.FowlerNollVo64.md b/.docfx/api/types/Cuemon.Security.FowlerNollVo64.md new file mode 100644 index 00000000..a2b532b2 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.FowlerNollVo64.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.Security.FowlerNollVo64 +example: +- *content +--- + +The following example demonstrates how to compute a 64-bit Fowler-Noll-Vo (FNV) hash using the class. + +```csharp +using System; +using System.Text; +using Cuemon.Security; + +using Cuemon; +namespace MyApp.Examples; + +public class FowlerNollVo64Example +{ + public void Demonstrate() + { + // Create FNV-1a 64-bit hash instance (default algorithm) + var fnv = new FowlerNollVo64(); + + // Compute hash from a string + byte[] data = Encoding.UTF8.GetBytes("hello"); + HashResult hash = fnv.ComputeHash(data); + + // Display the hash in hexadecimal format + Console.WriteLine(hash.ToHexadecimalString()); + + // Switch to FNV-1 algorithm + fnv.Options.Algorithm = FowlerNollVoAlgorithm.Fnv1; + HashResult hashFnv1 = fnv.ComputeHash(data); + Console.WriteLine(hashFnv1.ToHexadecimalString()); + + // Change byte order to little endian + fnv.Options.ByteOrder = Endianness.LittleEndian; + HashResult hashLe = fnv.ComputeHash(data); + Console.WriteLine(hashLe.ToHexadecimalString()); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.FowlerNollVoAlgorithm.md b/.docfx/api/types/Cuemon.Security.FowlerNollVoAlgorithm.md new file mode 100644 index 00000000..812f892e --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.FowlerNollVoAlgorithm.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.Security.FowlerNollVoAlgorithm +example: +- *content +--- + +The following example demonstrates how to use the `FowlerNollVoAlgorithm` enumeration to select between the FNV-1 and FNV-1a hash variants. + +```csharp +using System; +using Cuemon.Security; + +namespace MyApp.Examples; + +public class FowlerNollVoAlgorithmExample +{ + public static void Main() + { + FowlerNollVoAlgorithm[] variants = { FowlerNollVoAlgorithm.Fnv1, FowlerNollVoAlgorithm.Fnv1a }; + + foreach (var variant in variants) + { + string label = variant switch + { + FowlerNollVoAlgorithm.Fnv1 => "FNV-1 (original)", + FowlerNollVoAlgorithm.Fnv1a => "FNV-1a (recommended)", + _ => "Unknown" + }; + Console.WriteLine("{0} -> {1}", variant, label); + + // Output: + // Fnv1 -> FNV-1 (original) + // Fnv1a -> FNV-1a (recommended) + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.FowlerNollVoOptions.md b/.docfx/api/types/Cuemon.Security.FowlerNollVoOptions.md new file mode 100644 index 00000000..f83366d9 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.FowlerNollVoOptions.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.Security.FowlerNollVoOptions +example: +- *content +--- + +The following example demonstrates how to configure `FowlerNollVoOptions` with a specific algorithm and byte order, then use `FowlerNollVo32` to compute a hash. + +```csharp +using System.Text; +using System; +using Cuemon.Security; + +using Cuemon; +namespace MyApp.Examples; + +public class FowlerNollVoOptionsExample +{ + public static void Main() + { + // Create a FowlerNollVoOptions instance to configure the hash algorithm + var fnvOptions = new FowlerNollVoOptions(); + fnvOptions.Algorithm = FowlerNollVoAlgorithm.Fnv1a; + fnvOptions.ByteOrder = Endianness.LittleEndian; + + // Apply configuration through the setup delegate + var fnv32 = new FowlerNollVo32(o => + { + o.Algorithm = fnvOptions.Algorithm; + o.ByteOrder = fnvOptions.ByteOrder; + }); + + byte[] data = Encoding.UTF8.GetBytes("Hello, World!"); + HashResult hash = fnv32.ComputeHash(data); + + Console.WriteLine("FNV-1a 32-bit (little-endian): {0}", hash.ToHexadecimalString()); + + // Output: + // FNV-1a 32-bit (little-endian): 7b56c21a + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.HashFactory.md b/.docfx/api/types/Cuemon.Security.HashFactory.md new file mode 100644 index 00000000..2589f92a --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.HashFactory.md @@ -0,0 +1,32 @@ +--- +uid: Cuemon.Security.HashFactory +example: +- *content +--- + +```csharp +using System; +using System.Text; +using Cuemon.Security; + +namespace Cuemon.Security; + +public class HashFactoryExample +{ + public void Demonstrate() + { + var fnvHash = HashFactory.CreateFnv32(); + var input = "Hello World"; + var hash = fnvHash.ComputeHash(Encoding.UTF8.GetBytes(input)); + Console.WriteLine($"FNV-1a 32-bit: {BitConverter.ToString(hash.To(bytes => bytes)).Replace("-", "")}"); + + var crcHash = HashFactory.CreateCrc32(); + hash = crcHash.ComputeHash(Encoding.UTF8.GetBytes(input)); + Console.WriteLine($"CRC-32: {BitConverter.ToString(hash.To(bytes => bytes)).Replace("-", "")}"); + + var fnv256Hash = HashFactory.CreateFnv256(); + hash = fnv256Hash.ComputeHash(Encoding.UTF8.GetBytes(input)); + Console.WriteLine($"FNV-1a 256-bit: {BitConverter.ToString(hash.To(bytes => bytes)).Replace("-", "")}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Security.HashResult.md b/.docfx/api/types/Cuemon.Security.HashResult.md new file mode 100644 index 00000000..5a27d754 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.HashResult.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.Security.HashResult +example: +- *content +--- + +The following example demonstrates how to create a `HashResult` from a computed hash value and convert it to different string representations. + +```csharp +using System; +using Cuemon.Security; + +namespace MyApp.Examples; + +public class HashResultExample +{ + public static void Main() + { + // Simulate a computed hash value (e.g., from any hash algorithm). + byte[] hashBytes = { 0xdf, 0xfd, 0x60, 0x21, 0xbb, 0x2b, 0xd5, 0xb0, 0xaf, 0x67, 0x62, 0x90, 0x80, 0x9e, 0xc3, 0xa5, 0x31, 0x91, 0xdd, 0x81, 0xc7, 0xf7, 0x0a, 0x4b, 0x28, 0x68, 0x8a, 0x36, 0x21, 0x82, 0x98, 0x6f }; + + var hashResult = new HashResult(hashBytes); + + // Check if the hash has a value + Console.WriteLine("HasValue: {0}", hashResult.HasValue); + + // Convert to various string formats + Console.WriteLine("Hex: {0}", hashResult.ToHexadecimalString()); + Console.WriteLine("Base64: {0}", hashResult.ToBase64String()); + Console.WriteLine("Url-safe Base64: {0}", hashResult.ToUrlEncodedBase64String()); + + // Default ToString() returns hexadecimal + Console.WriteLine("ToString: {0}", hashResult.ToString()); + + // Output: + // HasValue: True + // Hex: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f + // Base64: 3/1gIbsr1bCvZ2KQgJ7DpTGR3YHH9wpLKGiKNiGCmG8= + // Url-safe Base64: 3_1gIbsr1bCvZ2KQgJ7DpTGR3YHH9wpLKGiKNiGCmG8= + // ToString: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Security.NonCryptoAlgorithm.md b/.docfx/api/types/Cuemon.Security.NonCryptoAlgorithm.md new file mode 100644 index 00000000..217deb93 --- /dev/null +++ b/.docfx/api/types/Cuemon.Security.NonCryptoAlgorithm.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.Security.NonCryptoAlgorithm +example: +- *content +--- + +The following example demonstrates how to use the `NonCryptoAlgorithm` enumeration to select a non-cryptographic hash algorithm. + +```csharp +using System; +using Cuemon.Security; + +namespace MyApp.Examples; + +public class NonCryptoAlgorithmExample +{ + public static void Main() + { + NonCryptoAlgorithm[] algorithms = + { + NonCryptoAlgorithm.Fnv32, + NonCryptoAlgorithm.Fnv64, + NonCryptoAlgorithm.Fnv128, + NonCryptoAlgorithm.Fnv256, + NonCryptoAlgorithm.Fnv512, + NonCryptoAlgorithm.Fnv1024 + }; + + foreach (var algo in algorithms) + { + Console.WriteLine("{0} (value: {1})", algo, (int)algo); + + // Output: + // Fnv32 (value: 0) + // Fnv64 (value: 1) + // Fnv128 (value: 2) + // Fnv256 (value: 3) + // Fnv512 (value: 4) + // Fnv1024 (value: 5) + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.SortOrder.md b/.docfx/api/types/Cuemon.SortOrder.md new file mode 100644 index 00000000..f951531e --- /dev/null +++ b/.docfx/api/types/Cuemon.SortOrder.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.SortOrder +example: +- *content +--- + +The following example demonstrates how to use the enum to indicate the direction of a sort operation in a custom comparer. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon; + +namespace Contoso.Search; + +public sealed class SortOrderExample +{ + public static void Run() + { + var names = new List { "Charlie", "Alice", "Bob" }; + + Apply(names, SortOrder.Ascending); + Console.WriteLine(string.Join(", ", names)); + + Apply(names, SortOrder.Descending); + Console.WriteLine(string.Join(", ", names)); + } + + private static void Apply(List names, SortOrder sortOrder) + { + names.Sort((left, right) => + { + int result = string.Compare(left, right, StringComparison.Ordinal); + return sortOrder == SortOrder.Descending ? -result : result; + }); + } +} +``` diff --git a/.docfx/api/types/Cuemon.StringDecoratorExtensions.md b/.docfx/api/types/Cuemon.StringDecoratorExtensions.md new file mode 100644 index 00000000..1ee9dde1 --- /dev/null +++ b/.docfx/api/types/Cuemon.StringDecoratorExtensions.md @@ -0,0 +1,65 @@ +--- +uid: Cuemon.StringDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the to manipulate strings via the decorator pattern. + +```csharp +using System; +using System.Globalization; +using System.IO; +using System.Text; +using Cuemon; +using Cuemon.Text; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + + string value = " Hello World! "; + var decorator = Decorator.Enclose(value); + + // Change casing via decorator + string lower = decorator.ToCasing(CasingMethod.LowerCase); // " hello world! " + string upper = decorator.ToCasing(CasingMethod.UpperCase); // " HELLO WORLD! " + string title = decorator.ToCasing(CasingMethod.TitleCase, new CultureInfo("en-US")); // " Hello World! " + + // Convert to byte array + byte[] bytes = decorator.ToByteArray(o => o.Encoding = Encoding.UTF8); + + // Convert to stream + using Stream stream = decorator.ToStream(o => o.Encoding = Encoding.UTF8); + + // Convert to URI + string url = "https://www.example.com"; + var uriDecorator = Decorator.Enclose(url); + Uri uri = uriDecorator.ToUri(); // https://www.example.com/ + + // Encoding conversions + string ascii = decorator.ToAsciiEncodedString(o => o.Encoding = Encoding.UTF8); // " Hello World! " (non-ASCII chars replaced with empty) + string encoded = decorator.ToEncodedString(o => + { + o.TargetEncoding = Encoding.ASCII; + o.EncoderFallback = new EncoderReplacementFallback("?"); + }); + + // StartsWith checks + bool starts = decorator.StartsWith(" Hello"); // true + bool startsIgnore = decorator.StartsWith(StringComparison.OrdinalIgnoreCase, "hello"); // true + bool startsAny = decorator.StartsWith("Hi", "Hello"); // true + + // Set difference + var helloDecorator = Decorator.Enclose("Hello World!"); + string diff = helloDecorator.Difference("Hello Universe!"); // "Universe!" + + // ContainsAny for characters + bool hasChar = decorator.ContainsAny('o', StringComparison.Ordinal); // true + bool hasChars = decorator.ContainsAny(StringComparison.Ordinal, 'x', 'y'); // false + } +} +``` diff --git a/.docfx/api/types/Cuemon.StringFactory.md b/.docfx/api/types/Cuemon.StringFactory.md new file mode 100644 index 00000000..a9737323 --- /dev/null +++ b/.docfx/api/types/Cuemon.StringFactory.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.StringFactory +example: +- *content +--- + +The following example demonstrates how to use `StringFactory` to generate hexadecimal, binary, URL-safe Base64, protocol-relative URL, and URI scheme strings from .NET data types. + +```csharp +using System; + +namespace Cuemon; + +public class StringFactoryExample +{ + public void Demonstrate() + { + // Convert bytes to hexadecimal string + byte[] binaryData = { 0x0F, 0xA0, 0x01 }; + string hex = StringFactory.CreateHexadecimal(binaryData); + Console.WriteLine(hex); // 0fa001 + + // Convert string to hexadecimal representation + string hexFromString = StringFactory.CreateHexadecimal("Hello"); + Console.WriteLine(hexFromString); // 48656c6c6f + + // Create binary digit string from bytes + string binary = StringFactory.CreateBinaryDigits(new byte[] { 0, 1, 255 }); + Console.WriteLine(binary); // 000000000000000111111111 + + // Create URL-safe Base64 string + string urlSafe = StringFactory.CreateUrlEncodedBase64(new byte[] { 251, 255 }); + Console.WriteLine(urlSafe); // -_8 + + // Create a protocol-relative URL (// prefix replaces https://) + string relativeUrl = StringFactory.CreateProtocolRelativeUrl( + new Uri("https://www.cuemon.net/about")); + Console.WriteLine(relativeUrl); // //www.cuemon.net/about + + // Get string representation of a URI scheme enum + string scheme = StringFactory.CreateUriScheme(UriScheme.Https); + Console.WriteLine(scheme); // https + } +} +``` diff --git a/.docfx/api/types/Cuemon.StringReplacePair.md b/.docfx/api/types/Cuemon.StringReplacePair.md new file mode 100644 index 00000000..3a3d04da --- /dev/null +++ b/.docfx/api/types/Cuemon.StringReplacePair.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.StringReplacePair +example: +- *content +--- + +The following example demonstrates how to use the struct to perform bulk string replacement and removal operations. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon; // for StringReplacePair + +namespace MyApp.Examples; + +public class StringReplacePairExample +{ + public void Demonstrate() + { + string input = "Hello World from Cuemon! Welcome to the World of .NET."; + + // Replace all occurrences of "World" with "Universe" (case-insensitive by default) + string result = StringReplacePair.ReplaceAll(input, "World", "Universe"); + Console.WriteLine(result); + // Output: Hello Universe from Cuemon! Welcome to the Universe of .NET. + + // Replace multiple pairs at once + var pairs = new StringReplacePair[] + { + new StringReplacePair("Hello", "Hi"), + new StringReplacePair("Cuemon", "Codebelt"), + new StringReplacePair(".NET", "dotnet") + }; + result = StringReplacePair.ReplaceAll(input, pairs); + Console.WriteLine(result); + // Output: Hi Universe from Codebelt! Welcome to the Universe of dotnet. + + // Remove specific words (case-sensitive ordinal comparison) + result = StringReplacePair.RemoveAll(input, StringComparison.Ordinal, "World", "Cuemon", "Welcome"); + Console.WriteLine(result); + // Output: Hello from ! to the of .NET. + + // Remove specific characters + result = StringReplacePair.RemoveAll(input, '.', '!'); + Console.WriteLine(result); + // Output: Hello World from Cuemon Welcome to the World of NET + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.SuccessfulValue.md b/.docfx/api/types/Cuemon.SuccessfulValue.md new file mode 100644 index 00000000..615b7cf9 --- /dev/null +++ b/.docfx/api/types/Cuemon.SuccessfulValue.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.SuccessfulValue +example: +- *content +--- + +The following example demonstrates how to use `SuccessfulValue` to represent a void operation that completed successfully, enabling consistent conditional-return patterns. + +```csharp +using System; +using Cuemon; + +namespace Contoso.Startup; + +public sealed class SuccessfulValueExample +{ + public static void Run() + { + ConditionalValue outcome = WarmUpCache(dependenciesReady: true); + + Console.WriteLine($"Succeeded: {outcome.Succeeded}"); + Console.WriteLine($"Failure is null: {outcome.Failure is null}"); + } + + private static ConditionalValue WarmUpCache(bool dependenciesReady) + { + if (!dependenciesReady) + { + return new UnsuccessfulValue(new InvalidOperationException("Dependencies are missing.")); + } + + return new SuccessfulValue(); + } +} +``` diff --git a/.docfx/api/types/Cuemon.SuccessfulValue`1.md b/.docfx/api/types/Cuemon.SuccessfulValue`1.md new file mode 100644 index 00000000..56d95f8e --- /dev/null +++ b/.docfx/api/types/Cuemon.SuccessfulValue`1.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.SuccessfulValue`1 +example: +- *content +--- + +The following example demonstrates how to use `SuccessfulValue` to represent a typed operation that completed successfully, pairing a result value with a success signal. + +```csharp +using System; +using Cuemon; + +namespace Contoso.Configuration; + +public sealed class SuccessfulValueOfTResultExample +{ + public static void Run() + { + ConditionalValue outcome = ParsePort("443"); + + Console.WriteLine($"Succeeded: {outcome.Succeeded}"); + Console.WriteLine($"Port: {outcome.Result}"); + } + + private static ConditionalValue ParsePort(string text) + { + if (int.TryParse(text, out int port)) + { + return new SuccessfulValue(port); + } + + return new UnsuccessfulValue(new FormatException("The port number is invalid.")); + } +} +``` diff --git a/.docfx/api/types/Cuemon.SystemSnapshots.md b/.docfx/api/types/Cuemon.SystemSnapshots.md new file mode 100644 index 00000000..07e35b8f --- /dev/null +++ b/.docfx/api/types/Cuemon.SystemSnapshots.md @@ -0,0 +1,45 @@ +--- +uid: Cuemon.SystemSnapshots +example: +- *content +--- + +The following example demonstrates how to use the `SystemSnapshots` flags enum to specify which system information categories to capture in a diagnostics snapshot. + +```csharp +using System; +using Cuemon; + +namespace MyApp.Examples +{ + public class SystemSnapshotsExample + { + public void Demonstrate() + { + // SystemSnapshots is a flags enum controlling which system + // information categories to capture. + + // Capture everything available. + var all = SystemSnapshots.CaptureAll; + Console.WriteLine($"CaptureAll = {all}"); // CaptureThreadInfo | CaptureProcessInfo | CaptureEnvironmentInfo + + // Capture only specific categories. + var minimal = SystemSnapshots.CaptureThreadInfo | SystemSnapshots.CaptureProcessInfo; + + // Test if a flag is set. + if (all.HasFlag(SystemSnapshots.CaptureEnvironmentInfo)) + { + Console.WriteLine("Environment info will be captured."); + + // Start with none and add incrementally. + var flags = SystemSnapshots.None; + flags |= SystemSnapshots.CaptureThreadInfo; + flags |= SystemSnapshots.CaptureProcessInfo; + + Console.WriteLine($"Flags: {flags}"); // CaptureThreadInfo | CaptureProcessInfo + Console.WriteLine($"Has thread info: {flags.HasFlag(SystemSnapshots.CaptureThreadInfo)}"); // True + +}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.TesterFuncFactory`3.md b/.docfx/api/types/Cuemon.TesterFuncFactory`3.md new file mode 100644 index 00000000..d21af876 --- /dev/null +++ b/.docfx/api/types/Cuemon.TesterFuncFactory`3.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.TesterFuncFactory`3 +example: +- *content +--- + +The following example demonstrates how to use `TesterFuncFactory` to encapsulate a tester function with its arguments for deferred execution with output extraction. + +```csharp +using System; +using Cuemon; + +namespace Contoso.Validation; + +public sealed class TesterFuncFactoryExample +{ + public static void Run() + { + var factory = new TesterFuncFactory, string, bool>( + (MutableTuple tuple, out string result) => + { + result = $"{tuple.Arg1},{tuple.Arg2},{tuple.Arg3}"; + return true; + }, + new MutableTuple(1, 2, 3)); + + bool success = factory.ExecuteMethod(out string output); + var clone = (TesterFuncFactory, string, bool>)factory.Clone(); + clone.ExecuteMethod(out string clonedOutput); + + Console.WriteLine($"Success: {success}"); + Console.WriteLine(output); + Console.WriteLine(clonedOutput); + } +} +``` diff --git a/.docfx/api/types/Cuemon.TesterFunc`2.md b/.docfx/api/types/Cuemon.TesterFunc`2.md new file mode 100644 index 00000000..3753c722 --- /dev/null +++ b/.docfx/api/types/Cuemon.TesterFunc`2.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.TesterFunc`2 +example: +- *content +--- + +The following example demonstrates the shared workflow for the family: call the delegate, capture the out value, and branch on the success result. + +```csharp +using System; +using Cuemon; + +namespace MyApp.Examples; + +public static class TesterFuncExample +{ + public static void Demonstrate() + { + TesterFunc tryReadPort = (out int port) => + { + var configuredPort = "8080"; + return int.TryParse(configuredPort, out port); + }; + + var success = tryReadPort(out var port); + + Console.WriteLine(success); + Console.WriteLine(port); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Text.AsyncEncodingOptions.md b/.docfx/api/types/Cuemon.Text.AsyncEncodingOptions.md new file mode 100644 index 00000000..2a719046 --- /dev/null +++ b/.docfx/api/types/Cuemon.Text.AsyncEncodingOptions.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Text.AsyncEncodingOptions +example: +- *content +--- + +The following example demonstrates how to configure `AsyncEncodingOptions` with a cancellation token for use in asynchronous encoding operations. + +```csharp +using System.Threading.Tasks; +using System.Text; +using System.Threading; +using Cuemon.Text; + +namespace MyApp.Examples; + +public class AsyncEncodingOptionsExample +{ + public void Demonstrate() + { + using var cts = new CancellationTokenSource(); + var options = new AsyncEncodingOptions + { + Encoding = Encoding.UTF8, + Preamble = PreambleSequence.Remove, + CancellationToken = cts.Token + }; + + // The options can be passed to async encoding methods + // that accept AsyncEncodingOptions. If cancellation is + // requested, the operation will be cancelled gracefully. + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Text.ByteOrderMark.md b/.docfx/api/types/Cuemon.Text.ByteOrderMark.md new file mode 100644 index 00000000..dc298d81 --- /dev/null +++ b/.docfx/api/types/Cuemon.Text.ByteOrderMark.md @@ -0,0 +1,33 @@ +--- +uid: Cuemon.Text.ByteOrderMark +example: +- *content +--- + +```csharp +using System; +using System.IO; +using System.Text; +using Cuemon.Text; + +namespace Cuemon.Text; + +public class ByteOrderMarkExample +{ + public void Demonstrate() + { + var utf8Bytes = new byte[] { 0xEF, 0xBB, 0xBF, 0x48, 0x65, 0x6C, 0x6C, 0x6F }; + var encoding = ByteOrderMark.Decode(utf8Bytes); + Console.WriteLine($"Detected encoding: {encoding.EncodingName}"); + + var bytes = ByteOrderMark.Remove(utf8Bytes, Encoding.UTF8); + Console.WriteLine($"BOM removed, remaining length: {bytes.Length}"); + + using var stream = new MemoryStream(utf8Bytes); + if (ByteOrderMark.TryDetectEncoding(stream, out var detected)) + { + Console.WriteLine($"Stream encoding: {detected.EncodingName}"); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Text.EncodingOptions.md b/.docfx/api/types/Cuemon.Text.EncodingOptions.md new file mode 100644 index 00000000..85a37a23 --- /dev/null +++ b/.docfx/api/types/Cuemon.Text.EncodingOptions.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.Text.EncodingOptions +example: +- *content +--- + +The following example demonstrates how to use to control encoding behavior, including preamble handling and encoding selection. + +```csharp +using System; +using System.Text; +using Cuemon.Text; // for EncodingOptions, PreambleSequence + +namespace MyApp.Examples; + +public class EncodingOptionsExample +{ + public void Demonstrate() + { + // Create options with UTF-8 encoding, removing the BOM preamble + var options = new EncodingOptions + { + Encoding = Encoding.UTF8, + Preamble = PreambleSequence.Remove + }; + Console.WriteLine(options.Encoding.EncodingName); // Unicode (UTF-8) + Console.WriteLine(options.Preamble); // Remove + + // Create options that keep the preamble + var preserveOptions = new EncodingOptions + { + Encoding = Encoding.Unicode, + Preamble = PreambleSequence.Keep + }; + Console.WriteLine(preserveOptions.Preamble); // Keep + + // Encoding property validates for null + // options.Encoding = null; // throws ArgumentNullException + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Text.EnumStringOptions.md b/.docfx/api/types/Cuemon.Text.EnumStringOptions.md new file mode 100644 index 00000000..0c2a5d3b --- /dev/null +++ b/.docfx/api/types/Cuemon.Text.EnumStringOptions.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.Text.EnumStringOptions +example: +- *content +--- + +The following example demonstrates how to configure `EnumStringOptions` to control case sensitivity when parsing an enum from a string using `ParserFactory.FromEnum`. + +```csharp +using System; +using Cuemon; +using Cuemon.Text; + +namespace MyApp.Examples; + +public class EnumStringOptionsExample +{ + public void Demonstrate() + { + // Direct instantiation of EnumStringOptions + var options = new EnumStringOptions + { + IgnoreCase = true + }; + + var parser = ParserFactory.FromEnum(); + + var result = (UriKind)parser.Parse("Relative", typeof(UriKind), o => + { + o.IgnoreCase = true; + }); + + Console.WriteLine(result); // outputs: Relative + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Text.FallbackEncodingOptions.md b/.docfx/api/types/Cuemon.Text.FallbackEncodingOptions.md new file mode 100644 index 00000000..94942552 --- /dev/null +++ b/.docfx/api/types/Cuemon.Text.FallbackEncodingOptions.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Text.FallbackEncodingOptions +example: +- *content +--- + +The following example demonstrates how to configure `FallbackEncodingOptions` to use exception fallbacks when encoding or decoding characters that are not supported by the target encoding. + +```csharp +using System.Text; +using Cuemon.Text; + +namespace MyApp.Examples; + +public class FallbackEncodingOptionsExample +{ + public void Demonstrate() + { + var options = new FallbackEncodingOptions + { + TargetEncoding = Encoding.ASCII, + EncoderFallback = EncoderFallback.ExceptionFallback, + DecoderFallback = DecoderFallback.ExceptionFallback, + Encoding = Encoding.UTF8, + Preamble = PreambleSequence.Remove + }; + + // The options are ready to be used with encoding operations + // that respect FallbackEncodingOptions. When an unsupported + // character is encountered, an EncoderFallbackException will be thrown. + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Text.GuidStringOptions.md b/.docfx/api/types/Cuemon.Text.GuidStringOptions.md new file mode 100644 index 00000000..b1439399 --- /dev/null +++ b/.docfx/api/types/Cuemon.Text.GuidStringOptions.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.Text.GuidStringOptions +example: +- *content +--- + +The following example demonstrates how to configure `GuidStringOptions` to restrict which GUID formats are accepted when parsing with `ParserFactory.FromGuid`. + +```csharp +using System; +using Cuemon; +using Cuemon.Text; + +namespace MyApp.Examples; + +public class GuidStringOptionsExample +{ + public void Demonstrate() + { + // Direct instantiation of GuidStringOptions + var options = new GuidStringOptions + { + Formats = GuidFormats.D + }; + + var parser = ParserFactory.FromGuid(); + var guidString = "{3f2504e0-4f89-41d3-9a0c-0305e82c3301}"; + + var result = parser.Parse(guidString, o => + { + o.Formats = GuidFormats.B; + }); + + Console.WriteLine(result); + // outputs: 3f2504e0-4f89-41d3-9a0c-0305e82c3301 + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Text.ParserFactory.md b/.docfx/api/types/Cuemon.Text.ParserFactory.md new file mode 100644 index 00000000..7669541b --- /dev/null +++ b/.docfx/api/types/Cuemon.Text.ParserFactory.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Text.ParserFactory +example: +- *content +--- + +```csharp +using System; +using Cuemon.Text; + +namespace Cuemon.Text; + +public class ParserFactoryExample +{ + public void Demonstrate() + { + var guidParser = ParserFactory.FromGuid(); + var result = guidParser.Parse("6B29FC40-CA47-1067-B31D-00DD010662DA"); + Console.WriteLine($"Parsed GUID: {result}"); + + var base64Parser = ParserFactory.FromBase64(); + var bytes = base64Parser.Parse("SGVsbG8gV29ybGQ="); + Console.WriteLine($"Base64 decoded bytes: {bytes.Length}"); + + var uriParser = ParserFactory.FromUri(); + var uri = uriParser.Parse("https://example.com/resource"); + Console.WriteLine($"Parsed URI: {uri}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Text.PreambleSequence.md b/.docfx/api/types/Cuemon.Text.PreambleSequence.md new file mode 100644 index 00000000..f7f014e2 --- /dev/null +++ b/.docfx/api/types/Cuemon.Text.PreambleSequence.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.Text.PreambleSequence +example: +- *content +--- + +The following example demonstrates how to use `PreambleSequence` with `EncodingOptions` to control whether byte order marks (BOM) are preserved or removed. + +```csharp +using System; +using System.Text; +using Cuemon.Text; + +namespace MyApp.Examples; + +public class PreambleSequenceExample +{ + public void Demonstrate() + { + var options = new EncodingOptions + { + Encoding = Encoding.UTF8, + Preamble = PreambleSequence.Keep + }; + + var preambleAction = options.Preamble; + var encoding = options.Encoding; + + Console.WriteLine(preambleAction); // outputs: Keep + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Text.ProtocolRelativeUriStringOptions.md b/.docfx/api/types/Cuemon.Text.ProtocolRelativeUriStringOptions.md new file mode 100644 index 00000000..a1e9acf3 --- /dev/null +++ b/.docfx/api/types/Cuemon.Text.ProtocolRelativeUriStringOptions.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.Text.ProtocolRelativeUriStringOptions +example: +- *content +--- + +The following example demonstrates how to configure ProtocolRelativeUriStringOptions to resolve protocol-relative URIs (such as //example.com/resource) by specifying the default protocol scheme. + +```csharp +using System; +using Cuemon; +using Cuemon.Text; + +namespace MyApp.Examples +{ + public class ProtocolRelativeUriStringOptionsExample + { + public void Demonstrate() + { + // Configure how a protocol-relative URI (e.g., "//example.com/resource") + // is resolved to an absolute URI by specifying the default protocol. + var options = new ProtocolRelativeUriStringOptions + { + Protocol = UriScheme.Https, + RelativeReference = Alphanumeric.NetworkPathReference + }; + + Console.WriteLine($"Protocol: {options.Protocol}"); + Console.WriteLine($"Relative reference: {options.RelativeReference}"); + + // Switch to HTTP for local development + options.Protocol = UriScheme.Http; + Console.WriteLine($"Updated protocol: {options.Protocol}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Text.Stem.md b/.docfx/api/types/Cuemon.Text.Stem.md new file mode 100644 index 00000000..b3f131d6 --- /dev/null +++ b/.docfx/api/types/Cuemon.Text.Stem.md @@ -0,0 +1,31 @@ +--- +uid: Cuemon.Text.Stem +example: +- *content +--- + +The following example demonstrates how to use `Stem` to build a URL path by attaching prefixes and suffixes without duplication. + +```csharp +using Cuemon.Text; + +namespace MyApp.Examples; + +public class StemExample +{ + public void Demonstrate() + { + var path = new Stem("api") + .AttachPrefix("/") + .AttachSuffix("/") + .AttachSuffix("v1") + .AttachSuffix("/") + .AttachSuffix("users"); + + var result = path.ToString(); + // result == "/api/v1/users" + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Text.UriStringOptions.md b/.docfx/api/types/Cuemon.Text.UriStringOptions.md new file mode 100644 index 00000000..3a392b5f --- /dev/null +++ b/.docfx/api/types/Cuemon.Text.UriStringOptions.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.Text.UriStringOptions +example: +- *content +--- + +The following example demonstrates how to configure UriStringOptions to validate and inspect URI properties including kind and allowed schemes. + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon; +using Cuemon.Text; + +namespace Contoso.Webhooks; + +public sealed class UriStringOptionsExample +{ + public static void Run() + { + var options = new UriStringOptions + { + Kind = UriKind.Absolute, + Schemes = new List { UriScheme.Https, UriScheme.Http } + }; + + options.ValidateOptions(); + + bool allowsHttps = options.Schemes.Contains(UriScheme.Https); + int knownSchemes = UriStringOptions.AllUriSchemes.Count(); + + Console.WriteLine($"Kind: {options.Kind}"); + Console.WriteLine($"Allows HTTPS: {allowsHttps}"); + Console.WriteLine($"Known schemes: {knownSchemes}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Threading.AdvancedParallelFactory.md b/.docfx/api/types/Cuemon.Threading.AdvancedParallelFactory.md new file mode 100644 index 00000000..0ed4b3f7 --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.AdvancedParallelFactory.md @@ -0,0 +1,24 @@ +--- +uid: Cuemon.Threading.AdvancedParallelFactory +example: +- *content +--- + +```csharp +using System; +using Cuemon.Threading; + +namespace Cuemon.Threading; + +public class AdvancedParallelFactoryExample +{ + public void Demonstrate() + { + var next = AdvancedParallelFactory.Iterator(5, AssignmentOperator.Addition, 3); + Console.WriteLine($"5 + 3 = {next}"); + + var isComplete = AdvancedParallelFactory.Condition(next, RelationalOperator.GreaterThanOrEqual, 8); + Console.WriteLine($"Is loop condition met? {isComplete}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Threading.AsyncActionFactory-1.md b/.docfx/api/types/Cuemon.Threading.AsyncActionFactory-1.md new file mode 100644 index 00000000..9aca2772 --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.AsyncActionFactory-1.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Threading.AsyncActionFactory`1 +example: +- *content +--- + +The following example demonstrates how to create and execute an for deferred asynchronous work with typed arguments. + +```csharp +using System; +using System.Threading; +using System.Threading.Tasks; +using Cuemon; +using Cuemon.Threading; + +namespace MyApp.Examples; + +public static class AsyncActionFactoryExample +{ + public static async Task DemonstrateAsync() + { + var factory = AsyncActionFactory.Create( + async (channel, retryCount, cancellationToken) => + { + await Task.Delay(10, cancellationToken).ConfigureAwait(false); + Console.WriteLine($"{channel}:{retryCount}"); + }, + "orders", + 3); + + await factory.ExecuteMethodAsync(CancellationToken.None); + + var clone = (AsyncActionFactory>)factory.Clone(); + await clone.ExecuteMethodAsync(CancellationToken.None); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Threading.AsyncActionFactory.md b/.docfx/api/types/Cuemon.Threading.AsyncActionFactory.md new file mode 100644 index 00000000..641bb3ff --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.AsyncActionFactory.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.Threading.AsyncActionFactory +example: +- *content +--- + +```csharp +using System; +using System.Threading; +using System.Threading.Tasks; +using Cuemon.Threading; + +namespace Cuemon.Threading; + +public class AsyncActionFactoryExample +{ + public async Task DemonstrateAsync() + { + var factory = AsyncActionFactory.Create(ct => + { + Console.WriteLine("Async operation executed"); + return Task.CompletedTask; + }); + await factory.ExecuteMethodAsync(CancellationToken.None); + + var factoryWithArg = AsyncActionFactory.Create(async (string msg, CancellationToken ct) => + { + await Task.Delay(10, ct); + Console.WriteLine(msg); + }, "Hello from async action"); + await factoryWithArg.ExecuteMethodAsync(CancellationToken.None); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory.md b/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory.md new file mode 100644 index 00000000..1200540c --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Threading.AsyncFuncFactory +example: +- *content +--- + +```csharp +using System; +using System.Threading; +using System.Threading.Tasks; +using Cuemon.Threading; + +namespace Cuemon.Threading; + +public class AsyncFuncFactoryExample +{ + public async Task DemonstrateAsync() + { + var factory = AsyncFuncFactory.Create(ct => + { + return Task.FromResult(42); + }); + var result = await factory.ExecuteMethodAsync(CancellationToken.None); + Console.WriteLine($"Result: {result}"); + + var factoryWithArg = AsyncFuncFactory.Create(async (int a, int b, CancellationToken ct) => + { + await Task.Delay(10, ct); + return a + b; + }, 3, 4); + var sum = await factoryWithArg.ExecuteMethodAsync(CancellationToken.None); + Console.WriteLine($"Sum: {sum}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory`2.md b/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory`2.md new file mode 100644 index 00000000..32ed914e --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory`2.md @@ -0,0 +1,49 @@ +--- +uid: Cuemon.Threading.AsyncFuncFactory`2 +example: +- *content +--- + +The following example demonstrates how to create and execute a function asynchronously using AsyncFuncFactory, with support for cloning for safe concurrent use. + +```csharp +using System; +using System.Threading; +using System.Threading.Tasks; +using Cuemon; +using Cuemon.Threading; + +namespace MyApp.Examples +{ + public class AsyncFuncFactoryExample + { + public async Task DemonstrateAsync() + { + // Create an AsyncFuncFactory that encapsulates a function taking + // two string arguments and returning an int. + var factory = AsyncFuncFactory.Create( + (string a, string b, CancellationToken ct) => + { + ct.ThrowIfCancellationRequested(); + return Task.FromResult(a.Length + b.Length); + }, + "Hello", + "World" + ); + + Console.WriteLine($"Has delegate: {factory.HasDelegate}"); // True + Console.WriteLine($"Delegate info: {factory.DelegateInfo?.Name}"); //
b__0_0 or similar + + // Execute the wrapped function asynchronously. + var result = await factory.ExecuteMethodAsync(CancellationToken.None); + Console.WriteLine($"Total length: {result}"); // 10 + + // Clone the factory for safe concurrent use. + var clone = (AsyncFuncFactory, int>)factory.Clone(); + var clonedResult = await clone.ExecuteMethodAsync(CancellationToken.None); + Console.WriteLine($"Cloned result: {clonedResult}"); // 10 + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Threading.AsyncOptions.md b/.docfx/api/types/Cuemon.Threading.AsyncOptions.md new file mode 100644 index 00000000..e33fca7b --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.AsyncOptions.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.Threading.AsyncOptions +example: +- *content +--- + +The following example demonstrates how to configure AsyncOptions to provide a cancellation token for asynchronous operations. + +```csharp +using System; +using System.Threading; +using System.Threading.Tasks; +using Cuemon.Threading; + +namespace Contoso.BackgroundJobs; + +public sealed class AsyncOptionsExample +{ + public static async Task RunAsync() + { + var defaults = new AsyncOptions(); + Console.WriteLine(defaults.CancellationToken == CancellationToken.None); + + using var cts = new CancellationTokenSource(); + var options = new AsyncOptions + { + CancellationTokenProvider = () => cts.Token + }; + + cts.Cancel(); + + try + { + await Task.Delay(10, options.CancellationToken); + } + catch (OperationCanceledException) + { + Console.WriteLine("Cancelled as expected."); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Threading.AsyncPatterns.md b/.docfx/api/types/Cuemon.Threading.AsyncPatterns.md new file mode 100644 index 00000000..6c1a5cc3 --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.AsyncPatterns.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.Threading.AsyncPatterns +example: +- *content +--- + +The following example demonstrates how to use `AsyncPatterns` for safe disposal of `IDisposable` resources (CA2000) in asynchronous workflows. + +```csharp +using System; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Cuemon.Threading; + +namespace Contoso.Streaming; + +public sealed class AsyncPatternsExample +{ + public static async Task RunAsync() + { + var result = await AsyncPatterns.SafeInvokeAsync( + () => new MemoryStream(), + async (stream, ct) => + { + byte[] buffer = Encoding.UTF8.GetBytes("Cuemon"); + await stream.WriteAsync(buffer, 0, buffer.Length, ct); + stream.Position = 0; + return stream; + }, + ct: CancellationToken.None); + + using (result) + using (var reader = new StreamReader(result, Encoding.UTF8, true, 1024, true)) + { + Console.WriteLine(await reader.ReadToEndAsync()); + } + + Console.WriteLine(ReferenceEquals(AsyncPatterns.Use, AsyncPatterns.Use)); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Threading.AsyncRunOptions.md b/.docfx/api/types/Cuemon.Threading.AsyncRunOptions.md new file mode 100644 index 00000000..31570027 --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.AsyncRunOptions.md @@ -0,0 +1,44 @@ +--- +uid: Cuemon.Threading.AsyncRunOptions +example: +- *content +--- + +The following example demonstrates how to use to configure timeout and retry delay for an asynchronous operation. + +```csharp +using System; +using System.Threading; +using System.Threading.Tasks; +using Cuemon.Threading; // for AsyncRunOptions + +namespace MyApp.Examples; + +public class AsyncRunOptionsExample +{ + public async Task DemonstrateAsync() + { + var options = new AsyncRunOptions + { + Timeout = TimeSpan.FromSeconds(30), + Delay = TimeSpan.FromMilliseconds(500) + }; + Console.WriteLine(options.Timeout); // 00:00:30 + Console.WriteLine(options.Delay); // 00:00:00.5000000 + + // Use with cancellation support + var withCancellation = new AsyncRunOptions + { + Timeout = TimeSpan.FromSeconds(10), + CancellationToken = new CancellationTokenSource(5000).Token + }; + + // Defaults: timeout 5s, delay 100ms + var defaults = new AsyncRunOptions(); + Console.WriteLine(defaults.Timeout); // 00:00:05 + Console.WriteLine(defaults.Delay); // 00:00:00.1000000 + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Threading.AsyncTaskFactoryOptions.md b/.docfx/api/types/Cuemon.Threading.AsyncTaskFactoryOptions.md new file mode 100644 index 00000000..a1247cf9 --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.AsyncTaskFactoryOptions.md @@ -0,0 +1,43 @@ +--- +uid: Cuemon.Threading.AsyncTaskFactoryOptions +example: +- *content +--- + +The following example demonstrates how to configure `AsyncTaskFactoryOptions` to control task creation options and scheduler when using `AdvancedParallelFactory.For`. + +```csharp +using System; +using System.Threading.Tasks; +using Cuemon; +using Cuemon.Threading; + +namespace MyApp.Examples; + +public class AsyncTaskFactoryOptionsExample +{ + public void Demonstrate() + { + // Direct instantiation of AsyncTaskFactoryOptions + var factoryOptions = new AsyncTaskFactoryOptions + { + CreationOptions = TaskCreationOptions.None, + PartitionSize = 2 + }; + + var rules = new ForLoopRuleset(0, 10, 1); + + AdvancedParallelFactory.For(rules, i => + { + Console.WriteLine($"Processing item {i}"); + }, o => + { + o.CreationOptions = TaskCreationOptions.None; + o.Scheduler = TaskScheduler.Default; + o.PartitionSize = 2; + }); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Threading.AsyncWorkloadOptions.md b/.docfx/api/types/Cuemon.Threading.AsyncWorkloadOptions.md new file mode 100644 index 00000000..1984a0e2 --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.AsyncWorkloadOptions.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.Threading.AsyncWorkloadOptions +example: +- *content +--- + +The following example demonstrates how to configure `AsyncWorkloadOptions` to control the partition size when processing items in parallel with `AdvancedParallelFactory.ForAsync`. + +```csharp +using System; +using System.Threading; +using System.Threading.Tasks; +using Cuemon; +using Cuemon.Threading; + +namespace MyApp.Examples; + +public class AsyncWorkloadOptionsExample +{ + public async Task DemonstrateAsync() + { + // Direct instantiation of AsyncWorkloadOptions + var workloadOptions = new AsyncWorkloadOptions + { + PartitionSize = 4 + }; + + var rules = new ForLoopRuleset(0, 20, 1); + + await AdvancedParallelFactory.ForAsync(rules, (i, ct) => + { + Console.WriteLine($"Processing item {i}"); + return Task.CompletedTask; + }, o => + { + o.PartitionSize = 4; + }); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Threading.Awaiter.md b/.docfx/api/types/Cuemon.Threading.Awaiter.md new file mode 100644 index 00000000..1f942a57 --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.Awaiter.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Threading.Awaiter +example: +- *content +--- + +```csharp +using System; +using System.Threading.Tasks; +using Cuemon.Threading; + +namespace Cuemon.Threading; + +public class AwaiterExample +{ + public async Task DemonstrateAsync() + { + var attempt = 0; + var result = await Awaiter.RunUntilSuccessfulOrTimeoutAsync(() => + { + attempt++; + if (attempt < 3) + { + return Task.FromResult(new UnsuccessfulValue()); + } + return Task.FromResult(new SuccessfulValue()); + }, options => + { + options.Timeout = TimeSpan.FromSeconds(5); + options.Delay = TimeSpan.FromMilliseconds(100); + }); + + Console.WriteLine($"Succeeded after {attempt} attempts: {result.Succeeded}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Threading.ForLoopRuleset`1.md b/.docfx/api/types/Cuemon.Threading.ForLoopRuleset`1.md new file mode 100644 index 00000000..0a6649f1 --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.ForLoopRuleset`1.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.Threading.ForLoopRuleset`1 +example: +- *content +--- + +The following example demonstrates how to define a for-loop ruleset using ForLoopRuleset with configurable start, end, step, relational operator, and assignment operator. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon; +using Cuemon.Threading; + +namespace Contoso.Scheduling; + +public sealed class ForLoopRulesetExample +{ + public static void Run() + { + var rules = new ForLoopRuleset( + from: 0, + to: 5, + step: 1, + relation: RelationalOperator.LessThanOrEqual, + assignment: AssignmentOperator.Addition); + + var values = new List(); + int current = rules.From; + + while (rules.Condition(current, rules.Relation, rules.To)) + { + values.Add(current); + current = rules.Iterator(current, rules.Assignment, rules.Step); + } + + Console.WriteLine(string.Join(", ", values)); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Threading.ParallelFactory.md b/.docfx/api/types/Cuemon.Threading.ParallelFactory.md new file mode 100644 index 00000000..3b817497 --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.ParallelFactory.md @@ -0,0 +1,29 @@ +--- +uid: Cuemon.Threading.ParallelFactory +example: +- *content +--- + +```csharp +using System; +using Cuemon.Threading; + +namespace Cuemon.Threading; + +public class ParallelFactoryExample +{ + public void Demonstrate() + { + ParallelFactory.For(0, 5, i => + { + Console.WriteLine($"Processing iteration {i}"); + }); + + var items = new[] { "apple", "banana", "cherry" }; + ParallelFactory.ForEach(items, item => + { + Console.WriteLine($"Processing {item}"); + }); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Threading.RelationalOperator.md b/.docfx/api/types/Cuemon.Threading.RelationalOperator.md new file mode 100644 index 00000000..a6f09343 --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.RelationalOperator.md @@ -0,0 +1,30 @@ +--- +uid: Cuemon.Threading.RelationalOperator +example: +- *content +--- + +The following example demonstrates how to use `RelationalOperator` with `ForLoopRuleset` and `AdvancedParallelFactory` to perform parallel work. + +```csharp +using System; +using Cuemon; +using Cuemon.Threading; + +namespace MyApp.Examples; + +public class RelationalOperatorExample +{ + public void Demonstrate() + { + var rules = new ForLoopRuleset(0, 10, 2, RelationalOperator.LessThan); + + AdvancedParallelFactory.For(rules, i => + { + Console.WriteLine($"Processing iteration: {i}"); + }); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Threading.TimerFactory.md b/.docfx/api/types/Cuemon.Threading.TimerFactory.md new file mode 100644 index 00000000..4382ead7 --- /dev/null +++ b/.docfx/api/types/Cuemon.Threading.TimerFactory.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.Threading.TimerFactory +example: +- *content +--- + +```csharp +using System; +using System.Threading; +using Cuemon.Threading; + +namespace Cuemon.Threading; + +public class TimerFactoryExample +{ + public void Demonstrate() + { + using var timer = TimerFactory.CreateNonCapturingTimer( + state => Console.WriteLine("Timer ticked"), + null, + TimeSpan.FromSeconds(1), + TimeSpan.FromSeconds(2)); + + Console.WriteLine("Timer started (1s delay, 2s interval)"); + Thread.Sleep(5000); + } +} +``` diff --git a/.docfx/api/types/Cuemon.TimeRange.md b/.docfx/api/types/Cuemon.TimeRange.md new file mode 100644 index 00000000..65428edd --- /dev/null +++ b/.docfx/api/types/Cuemon.TimeRange.md @@ -0,0 +1,41 @@ +--- +uid: Cuemon.TimeRange +example: +- *content +--- + +The following example demonstrates how to use to represent a range between two values. + +```csharp +using System; +using Cuemon; // for TimeRange + +namespace MyApp.Examples; + +public class TimeRangeExample +{ + public void Demonstrate() + { + // Define working hours (09:00 to 17:30) + var workDay = new TimeRange( + TimeSpan.FromHours(9), + TimeSpan.FromHours(17.5)); + + Console.WriteLine($"Start: {workDay.Start}"); // 09:00:00 + Console.WriteLine($"End: {workDay.End}"); // 17:30:00 + Console.WriteLine($"Duration: {workDay.Duration}"); // 08:30:00 + + // Use inherited formatting + Console.WriteLine(workDay.ToString("g", null)); + // Output: A duration of 00.08:30:00 between 09:00:00 and 17:30:00. + + // Create a short break range + var lunchBreak = new TimeRange( + TimeSpan.FromHours(12), + TimeSpan.FromHours(13)); + Console.WriteLine(lunchBreak.Duration); // 01:00:00 + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.TimeUnit.md b/.docfx/api/types/Cuemon.TimeUnit.md new file mode 100644 index 00000000..27e2e878 --- /dev/null +++ b/.docfx/api/types/Cuemon.TimeUnit.md @@ -0,0 +1,40 @@ +--- +uid: Cuemon.TimeUnit +example: +- *content +--- + +The following example demonstrates how to use the enum to convert a numeric value into a . + +```csharp +using System; +using Cuemon; // for Decorator and ToTimeSpan + +using Cuemon; +namespace MyApp.Examples; + +public class TimeUnitExample +{ + public void Demonstrate() + { + double value = 2.5; + + TimeSpan days = Decorator.Enclose(value).ToTimeSpan(TimeUnit.Days); + Console.WriteLine(days); // 2.12:00:00 + + TimeSpan hours = Decorator.Enclose(value).ToTimeSpan(TimeUnit.Hours); + Console.WriteLine(hours); // 02:30:00 + + TimeSpan minutes = Decorator.Enclose(value).ToTimeSpan(TimeUnit.Minutes); + Console.WriteLine(minutes); // 00:02:30 + + TimeSpan seconds = Decorator.Enclose(value).ToTimeSpan(TimeUnit.Seconds); + Console.WriteLine(seconds); // 00:00:02.5000000 + + TimeSpan ticks = Decorator.Enclose(50000000.0).ToTimeSpan(TimeUnit.Ticks); + Console.WriteLine(ticks); // 00:00:05 + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Tweaker.md b/.docfx/api/types/Cuemon.Tweaker.md new file mode 100644 index 00000000..c29b9e93 --- /dev/null +++ b/.docfx/api/types/Cuemon.Tweaker.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Tweaker +example: +- *content +--- + +The following example demonstrates how to use `Tweaker` to apply inline transformations on values and objects: adjusting with a converter, altering in-place, and changing between types. + +```csharp +using System; +using System.Collections.Generic; + +namespace Cuemon; + +public class TweakerExample +{ + public void Demonstrate() + { + // Adjust: transform a value using a converter function + int doubled = Tweaker.Adjust(21, x => x * 2); + Console.WriteLine(doubled); // 42 + + // Alter: modify an object in-place via an action delegate + var list = new List { "a", "b", "c" }; + Tweaker.Alter(list, lst => lst.Add("d")); + Console.WriteLine(string.Join(", ", list)); // a, b, c, d + + // Change: convert a value to a different type + string asString = Tweaker.Change(42, x => x.ToString()); + Console.WriteLine(asString); // 42 + + // Adjust with null converter returns the original value unchanged + int same = Tweaker.Adjust(10, null as Func); + Console.WriteLine(same); // 10 + } +} +``` diff --git a/.docfx/api/types/Cuemon.TypeArgumentException.md b/.docfx/api/types/Cuemon.TypeArgumentException.md new file mode 100644 index 00000000..c6e42567 --- /dev/null +++ b/.docfx/api/types/Cuemon.TypeArgumentException.md @@ -0,0 +1,50 @@ +--- +uid: Cuemon.TypeArgumentException +example: +- *content +--- + +The following example demonstrates how to throw and catch a when a generic type argument does not satisfy expected constraints at runtime. + +```csharp +using System; +using System.IO; +using Cuemon; + +namespace Contoso.DependencyInjection; + +public sealed class TypeArgumentExceptionExample +{ + public static void Run() + { + IDisposable disposable = Create(); + disposable.Dispose(); + + try + { + Create(); + } + catch (TypeArgumentException ex) + { + Console.WriteLine($"{ex.ParamName}: {ex.Message}"); + } + } + + private static TService Create() + where TImplementation : class, new() + { + if (!typeof(TService).IsAssignableFrom(typeof(TImplementation))) + { + throw new TypeArgumentException( + nameof(TImplementation), + $"{typeof(TImplementation).Name} must implement {typeof(TService).Name}."); + } + + return (TService)(object)new TImplementation(); + } + + private sealed class Widget + { + } +} +``` diff --git a/.docfx/api/types/Cuemon.TypeArgumentOutOfRangeException.md b/.docfx/api/types/Cuemon.TypeArgumentOutOfRangeException.md new file mode 100644 index 00000000..081b81c1 --- /dev/null +++ b/.docfx/api/types/Cuemon.TypeArgumentOutOfRangeException.md @@ -0,0 +1,54 @@ +--- +uid: Cuemon.TypeArgumentOutOfRangeException +example: +- *content +--- + +The following example demonstrates how to throw a when an enum-based type argument is outside the valid range. + +```csharp +using System; +using Cuemon; + +namespace Contoso.Logging; + +public sealed class TypeArgumentOutOfRangeExceptionExample +{ + public static void Run() + { + LogLevel parsed = ParseEnum("Warning"); + Console.WriteLine(parsed); + + try + { + ParseEnum("1"); + } + catch (TypeArgumentOutOfRangeException ex) + { + Console.WriteLine($"{ex.ParamName}: {ex.ActualValue}"); + } + } + + private static TEnum ParseEnum(string text) + where TEnum : struct + { + if (!typeof(TEnum).IsEnum) + { + throw new TypeArgumentOutOfRangeException( + nameof(TEnum), + typeof(TEnum), + "Type arguments must be enum types."); + } + + return (TEnum)Enum.Parse(typeof(TEnum), text, ignoreCase: true); + } + + private enum LogLevel + { + Debug, + Information, + Warning, + Error + } +} +``` diff --git a/.docfx/api/types/Cuemon.TypeDecoratorExtensions.md b/.docfx/api/types/Cuemon.TypeDecoratorExtensions.md new file mode 100644 index 00000000..4ce9783e --- /dev/null +++ b/.docfx/api/types/Cuemon.TypeDecoratorExtensions.md @@ -0,0 +1,115 @@ +--- +uid: Cuemon.TypeDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the to generate a reflection report before loading a plugin type. + +```csharp +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using Cuemon; + +namespace Contoso.Reflection; + +public sealed class TypeDecoratorExtensionsExample +{ + public static void Run() + { + var orderType = Decorator.Enclose(typeof(AuditedOrder)); + var streamType = Decorator.Enclose(typeof(Stream)); + + var propertyNames = orderType.GetAllProperties().Select(property => property.Name).OrderBy(name => name).ToArray(); + var fieldNames = orderType.GetAllFields().Select(field => field.Name).OrderBy(name => name).ToArray(); + var eventNames = orderType.GetAllEvents().Select(@event => @event.Name).OrderBy(name => name).ToArray(); + var methodNames = orderType + .GetAllMethods() + .Where(method => method.DeclaringType == typeof(AuditedOrder) && !method.IsSpecialName) + .Select(method => method.Name) + .Distinct() + .OrderBy(name => name) + .ToArray(); + var orderOnlyProperties = orderType.GetRuntimePropertiesExceptOf().Select(property => property.Name).OrderBy(name => name).ToArray(); + + bool hasTypes = Decorator.Enclose(typeof(FileStream)).HasTypes(typeof(Stream)); + bool hasInterfaces = Decorator.Enclose(typeof(List<>)).HasInterfaces(typeof(IEnumerable<>)); + bool hasAttribute = orderType.HasAttribute(typeof(DataContractAttribute), typeof(DataMemberAttribute)); + bool hasComparable = Decorator.Enclose(typeof(string)).HasComparableImplementation(); + bool hasComparer = Decorator.Enclose(typeof(StringComparer)).HasComparerImplementation(); + bool hasDictionary = Decorator.Enclose(typeof(ReadOnlyDictionary)).HasDictionaryImplementation(); + bool hasEqualityComparer = Decorator.Enclose(typeof(StringComparer)).HasEqualityComparerImplementation(); + bool hasEnumerable = Decorator.Enclose(typeof(ConcurrentBag)).HasEnumerableImplementation(); + bool hasKeyValuePair = Decorator.Enclose(typeof(KeyValuePair)).HasKeyValuePairImplementation(); + bool isNullable = Decorator.Enclose(typeof(int?)).IsNullable(); + bool hasAnonymousCharacteristics = Decorator.Enclose(new { ReferenceNumber = "PO-42" }.GetType()).HasAnonymousCharacteristics(); + bool hasDefaultCtor = Decorator.Enclose(typeof(MemoryStream)).HasDefaultConstructor(); + bool isComplex = streamType.IsComplex(); + + object defaultValue = Decorator.Enclose(typeof(Guid)).GetDefaultValue(); + string friendlyName = Decorator.Enclose(typeof(IList)).ToFriendlyName(); + MethodBase publishMethod = orderType.MatchMember(nameof(AuditedOrder.Publish)); + + bool inheritedIncludesObject = streamType.GetInheritedTypes().Contains(typeof(object)); + bool derivedIncludesMemoryStream = streamType.GetDerivedTypes().Contains(typeof(MemoryStream)); + bool hierarchyIncludesFileStream = streamType.GetHierarchyTypes().Contains(typeof(FileStream)); + + var loop = LinkedNode.CreateLoop(); + bool hasCircularReference = Decorator.Enclose(typeof(LinkedNode)).HasCircularReference(loop, maxDepth: 1); + + Console.WriteLine(string.Join(", ", propertyNames)); + Console.WriteLine(string.Join(", ", fieldNames)); + Console.WriteLine(string.Join(", ", eventNames)); + Console.WriteLine(string.Join(", ", methodNames)); + Console.WriteLine(string.Join(", ", orderOnlyProperties)); + Console.WriteLine($"{hasTypes}, {hasInterfaces}, {hasAttribute}"); + Console.WriteLine($"{hasComparable}, {hasComparer}, {hasDictionary}, {hasEqualityComparer}, {hasEnumerable}, {hasKeyValuePair}"); + Console.WriteLine($"{isNullable}, {hasAnonymousCharacteristics}, {hasDefaultCtor}, {isComplex}"); + Console.WriteLine(defaultValue); + Console.WriteLine(friendlyName); + Console.WriteLine(publishMethod.Name); + Console.WriteLine($"{inheritedIncludesObject}, {derivedIncludesMemoryStream}, {hierarchyIncludesFileStream}, {hasCircularReference}"); + } +} + +[DataContract] +public sealed class AuditedOrder : TrackedEntity +{ + public string PublicNote; + + [DataMember] + public string ReferenceNumber { get; set; } = string.Empty; + + public string Status { get; set; } = string.Empty; + + public event EventHandler Published; + + public void Publish() + { + Published?.Invoke(this, EventArgs.Empty); + } +} + +public abstract class TrackedEntity +{ + public DateTime CreatedAt { get; set; } +} + +public sealed class LinkedNode +{ + public LinkedNode Next { get; set; } + + public static LinkedNode CreateLoop() + { + var node = new LinkedNode(); + node.Next = node; + return node; + } +} +``` diff --git a/.docfx/api/types/Cuemon.UnsuccessfulValue.md b/.docfx/api/types/Cuemon.UnsuccessfulValue.md new file mode 100644 index 00000000..37b93778 --- /dev/null +++ b/.docfx/api/types/Cuemon.UnsuccessfulValue.md @@ -0,0 +1,38 @@ +--- +uid: Cuemon.UnsuccessfulValue +example: +- *content +--- + +The following example demonstrates how to use `UnsuccessfulValue` to represent a void operation that failed with an exception, providing a consistent way to signal failure without throwing. + +```csharp +using System; +using Cuemon; + +namespace Contoso.Connections; + +public sealed class UnsuccessfulValueExample +{ + public static void Run() + { + ConditionalValue outcome = OpenConnection(null); + + Console.WriteLine($"Succeeded: {outcome.Succeeded}"); + Console.WriteLine($"Failure: {outcome.Failure?.GetType().Name}"); + } + + private static ConditionalValue OpenConnection(string connectionString) + { + try + { + Validator.ThrowIfNullOrWhitespace(connectionString); + return new SuccessfulValue(); + } + catch (Exception ex) + { + return new UnsuccessfulValue(ex); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.UnsuccessfulValue`1.md b/.docfx/api/types/Cuemon.UnsuccessfulValue`1.md new file mode 100644 index 00000000..c938ce36 --- /dev/null +++ b/.docfx/api/types/Cuemon.UnsuccessfulValue`1.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.UnsuccessfulValue`1 +example: +- *content +--- + +The following example demonstrates how to use `UnsuccessfulValue` to represent a typed operation that failed, carrying both the exception and a default result value. + +```csharp +using System; +using Cuemon; + +namespace Contoso.Calculations; + +public sealed class UnsuccessfulValueOfTResultExample +{ + public static void Run() + { + ConditionalValue outcome = Divide(10, 0); + + Console.WriteLine($"Succeeded: {outcome.Succeeded}"); + Console.WriteLine($"Result: {outcome.Result}"); + Console.WriteLine($"Failure: {outcome.Failure?.GetType().Name}"); + } + + private static ConditionalValue Divide(int dividend, int divisor) + { + if (divisor == 0) + { + return new UnsuccessfulValue(new DivideByZeroException("Cannot divide by zero."), -1); + } + + return new SuccessfulValue(dividend / divisor); + } +} +``` diff --git a/.docfx/api/types/Cuemon.UriScheme.md b/.docfx/api/types/Cuemon.UriScheme.md new file mode 100644 index 00000000..1cdefb3d --- /dev/null +++ b/.docfx/api/types/Cuemon.UriScheme.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.UriScheme +example: +- *content +--- + +The following example demonstrates how to use `UriScheme` with `StringFactory.CreateUriScheme` to generate URI scheme strings. + +```csharp +using Cuemon; +using System; + +namespace MyApp.Examples; + +public class UriSchemeExample +{ + public void Demonstrate() + { + var httpsScheme = StringFactory.CreateUriScheme(UriScheme.Https); + var ftpScheme = StringFactory.CreateUriScheme(UriScheme.Ftp); + + Console.WriteLine(httpsScheme); // outputs: https:// + Console.WriteLine(ftpScheme); // outputs: ftp:// + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Validator.md b/.docfx/api/types/Cuemon.Validator.md new file mode 100644 index 00000000..c6c0f709 --- /dev/null +++ b/.docfx/api/types/Cuemon.Validator.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.Validator +example: +- *content +--- + +The following example demonstrates how to use the `Validator` class to guard against null, empty, and invalid arguments using precondition checks. + +```csharp +using System; +using System.Collections.Generic; +using System.Linq; +using Cuemon; + +namespace Contoso.Routing; + +public sealed class ValidatorExample +{ + public static void Run() + { + string endpoint = NormalizeEndpoint("https://api.cuemon.net", new[] { "v1", "health" }); + Console.WriteLine(endpoint); + } + + private static string NormalizeEndpoint(string endpoint, IEnumerable segments) + { + Validator.ThrowIfNullOrWhitespace(endpoint); + Validator.ThrowIfSequenceNullOrEmpty(segments); + Validator.ThrowIfNotUri(endpoint, UriKind.Absolute); + + return string.Join("/", new[] { endpoint.TrimEnd('/') }.Concat(segments)); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Xml.HierarchyDecoratorExtensions.md b/.docfx/api/types/Cuemon.Xml.HierarchyDecoratorExtensions.md new file mode 100644 index 00000000..51214694 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.HierarchyDecoratorExtensions.md @@ -0,0 +1,57 @@ +--- +uid: Cuemon.Xml.HierarchyDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to inspect XML-related metadata on a hierarchy node with . + +```csharp +using System; +using Cuemon; +using Cuemon.Extensions.Runtime; +using Cuemon.Xml; +using System.Collections.Generic; +using System.Linq; +using System.Xml.Serialization; + +namespace MyApp.Examples; + +public static class HierarchyDecoratorExtensionsExample +{ + public static void Demonstrate() + { + var hierarchy = new Hierarchy(); + var root = hierarchy.Add(new Person { Name = "Alice" }); + var child = root.Add(new Address { City = "Paris" }); + + var decorator = Decorator.Enclose((IHierarchy)child); + var rootDecorator = Decorator.Enclose((IHierarchy)root); + var qualifiedEntity = decorator.GetXmlQualifiedEntity(); + var hasRoot = rootDecorator.TryGetXmlRootAttribute(out _); + var hasElement = decorator.TryGetXmlElementAttribute(out _); + var hasText = decorator.TryGetXmlTextAttribute(out _); + var hasAttribute = decorator.TryGetXmlAttributeAttribute(out _); + var ordered = Decorator.Enclose((IEnumerable>)new[] { root, child }).OrderByXmlAttributes().ToList(); + + Console.WriteLine(qualifiedEntity.LocalName); + Console.WriteLine(hasRoot); + Console.WriteLine(hasElement || hasText || hasAttribute); + Console.WriteLine(decorator.IsNodeEnumerable()); + Console.WriteLine(decorator.HasXmlIgnoreAttribute()); + Console.WriteLine(ordered.Count); + } + + [XmlRoot("person")] + private sealed class Person + { + public string Name { get; set; } + } + + private sealed class Address + { + public string City { get; set; } + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Xml.Linq.StringDecoratorExtensions.md b/.docfx/api/types/Cuemon.Xml.Linq.StringDecoratorExtensions.md new file mode 100644 index 00000000..608e805c --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Linq.StringDecoratorExtensions.md @@ -0,0 +1,60 @@ +--- +uid: Cuemon.Xml.Linq.StringDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to validate and parse XML strings into XElement objects using StringDecoratorExtensions, with support for load options and whitespace preservation. + +```csharp +using System; +using System.Xml.Linq; +using Cuemon; +using Cuemon.Xml.Linq; + +namespace MyApp.Xml +{ + public class StringDecoratorExtensionsExample + { + public void Demonstrate() + { + // Valid XML string + var validXml = "value"; + + // Check if the string is valid XML + var isValid = Decorator.Enclose(validXml).IsXmlString(); + Console.WriteLine($"Is valid XML: {isValid}"); // True + + // Try to parse the XML string into an XElement + if (Decorator.Enclose(validXml).TryParseXElement(out var element)) + { + Console.WriteLine($"Root element: {element.Name}"); + Console.WriteLine($"Inner XML: {element}"); + + // Navigate the parsed XElement + var item = element.Element("item"); + Console.WriteLine($"Item id attribute: {item?.Attribute("id")?.Value}"); + Console.WriteLine($"Item value: {item?.Value}"); + + // Invalid XML string + var invalidXml = "not xml at all"; + var isInvalid = Decorator.Enclose(invalidXml).IsXmlString(); + Console.WriteLine($"Is valid XML: {isInvalid}"); // False + + // TryParse will return false for invalid XML + if (!Decorator.Enclose(invalidXml).TryParseXElement(out var badElement)) + { + Console.WriteLine("Could not parse invalid XML."); + Console.WriteLine($"Result is null: {badElement == null}"); // True + + // TryParse with load options + var xmlWithWhitespace = " value "; + if (Decorator.Enclose(xmlWithWhitespace) + .TryParseXElement(LoadOptions.PreserveWhitespace, out var preserveElement)) + { + Console.WriteLine($"Preserved whitespace element: '{preserveElement}'"); + +}}}}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.Converters.DefaultXmlConverter.md b/.docfx/api/types/Cuemon.Xml.Serialization.Converters.DefaultXmlConverter.md new file mode 100644 index 00000000..8c7e5741 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.Converters.DefaultXmlConverter.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.Xml.Serialization.Converters.DefaultXmlConverter +example: +- *content +--- + +The following example demonstrates how can serialize and deserialize a simple XML value. + +```csharp +using System; +using System.Collections.Generic; +using System.IO; +using Cuemon.Xml.Serialization; +using Cuemon.Xml.Serialization.Converters; +using System.Xml; + +namespace MyApp.Examples; + +public static class DefaultXmlConverterExample +{ + public static void Demonstrate() + { + var converter = new DefaultXmlConverter(new XmlQualifiedEntity("String"), new List()); + + using var buffer = new MemoryStream(); + using (var writer = XmlWriter.Create(buffer, new XmlWriterSettings { OmitXmlDeclaration = true })) + { + converter.WriteXml(writer, "Hello World"); + } + + buffer.Position = 0; + using var reader = XmlReader.Create(buffer); + var value = (string)converter.ReadXml(reader, typeof(string)); + + Console.WriteLine(value); + Console.WriteLine(converter.CanConvert(typeof(string))); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.Converters.ExceptionConverter.md b/.docfx/api/types/Cuemon.Xml.Serialization.Converters.ExceptionConverter.md new file mode 100644 index 00000000..67389155 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.Converters.ExceptionConverter.md @@ -0,0 +1,89 @@ +--- +uid: Cuemon.Xml.Serialization.Converters.ExceptionConverter +example: +- *content +--- + +The following example demonstrates how to serialize an to XML and deserialize it back using the . + +```csharp +using System; +using System.IO; +using System.Text; +using System.Xml; +using Cuemon.Xml.Serialization; +using Cuemon.Xml.Serialization.Converters; +using Cuemon.Xml.Serialization.Formatters; + +namespace MyApp.Examples; + +public class ExceptionConverterExample +{ + public void SerializeExceptionWithStackTrace() + { + // Create an exception with inner exception and custom data + var inner = new ArgumentNullException("connectionString", "Value cannot be null."); + var outer = new InvalidOperationException("Failed to connect to the database.", inner); + outer.Data["Server"] = "db01.prod.example.com"; + + // Configure the XML formatter with ExceptionConverter including stack trace and data + var options = new XmlFormatterOptions(); + options.Settings.Converters.Add(new ExceptionConverter(includeStackTrace: true, includeData: true)); + + // Serialize to XML + var formatter = new XmlFormatter(options); + using (var stream = formatter.Serialize(outer)) + using (var reader = new StreamReader(stream, Encoding.UTF8)) + { + string xml = reader.ReadToEnd(); + Console.WriteLine(xml); + // The output resembles: + // + // + // ... + // Failed to connect to the database. + // + // at ExceptionConverterExample.SerializeExceptionWithStackTrace() ... + // + // + // db01.prod.example.com + // + // ... + // + } + } + + public void DeserializeExceptionFromXml() + { + string xml = @" + + MyApp + Something went wrong. +"; + + var converter = new ExceptionConverter(); + using (var reader = XmlReader.Create(new StringReader(xml))) + { + var restored = converter.ReadXml(typeof(InvalidOperationException), reader); + Console.WriteLine(restored.GetType().Name); // "InvalidOperationException" + Console.WriteLine(restored.Message); // "Something went wrong." + } + } + + public void SerializeWithoutStackTraceAndData() + { + var exception = new TimeoutException("The operation timed out."); + var options = new XmlFormatterOptions(); + options.Settings.Converters.Add(new ExceptionConverter()); // defaults: false, false + + var formatter = new XmlFormatter(options); + using (var stream = formatter.Serialize(exception)) + using (var reader = new StreamReader(stream, Encoding.UTF8)) + { + string xml = reader.ReadToEnd(); + // Stack trace and Data are excluded from the output + Console.WriteLine(xml); + } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.Converters.FailureConverter.md b/.docfx/api/types/Cuemon.Xml.Serialization.Converters.FailureConverter.md new file mode 100644 index 00000000..68b4a6bc --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.Converters.FailureConverter.md @@ -0,0 +1,51 @@ +--- +uid: Cuemon.Xml.Serialization.Converters.FailureConverter +example: +- *content +--- + +The following example demonstrates how to serialize a object to XML using the . + +```csharp +using System; +using System.IO; +using Cuemon.Diagnostics; +using Cuemon.Xml.Serialization; +using Cuemon.Xml.Serialization.Converters; +using Cuemon.Xml.Serialization.Formatters; + +namespace MyApp.Examples; + +public class FailureConverterExample +{ + public void SerializeFailureToXml() + { + // Create a Failure from an exception + var exception = new InvalidOperationException("The requested resource was not found.") + { + Source = "MyApi" + }; + var failure = new Failure(exception, FaultSensitivityDetails.None); + + // Configure the XML formatter with the FailureConverter + var options = new XmlFormatterOptions(); + options.Settings.Converters.Add(new FailureConverter()); + + // Serialize to XML + var formatter = new XmlFormatter(options); + using (var stream = formatter.Serialize(failure)) + using (var reader = new StreamReader(stream)) + { + string xml = reader.ReadToEnd(); + Console.WriteLine(xml); + // The output resembles: + // + // + // MyApi + // The requested resource was not found. + // + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.Converters.XmlConverterDecoratorExtensions.md b/.docfx/api/types/Cuemon.Xml.Serialization.Converters.XmlConverterDecoratorExtensions.md new file mode 100644 index 00000000..493ad45e --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.Converters.XmlConverterDecoratorExtensions.md @@ -0,0 +1,53 @@ +--- +uid: Cuemon.Xml.Serialization.Converters.XmlConverterDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to register and query XML converters with . + +```csharp +using System; +using System.Collections.Generic; +using Cuemon; +using Cuemon.Diagnostics; +using Cuemon.Xml.Serialization.Converters; + +namespace MyApp.Examples; + +public static class XmlConverterDecoratorExtensionsExample +{ + public static void Demonstrate() + { + var converters = new List(); + var decorator = Decorator.Enclose((IList)converters); + + decorator.AddDateTimeConverter(); + decorator.AddTimeSpanConverter(); + decorator.AddStringConverter(); + decorator.AddUriConverter(); + decorator.AddEnumerableConverter(); + decorator.AddExceptionConverter(false, false); + decorator.AddFailureConverter(); + decorator.AddExceptionDescriptorConverter(options => options.SensitivityDetails = FaultSensitivityDetails.All); + decorator.AddXmlConverter( + (writer, version, qe) => + { + writer.WriteStartElement(qe?.LocalName ?? "Version"); + writer.WriteString(version.ToString()); + writer.WriteEndElement(); + }, + (reader, type) => Version.Parse(reader.ReadElementContentAsString()) + ); + decorator.InsertXmlConverter(0); + + var writerConverter = decorator.FirstOrDefaultWriterConverter(typeof(Version)); + var readerConverter = decorator.FirstOrDefaultReaderConverter(typeof(Uri)); + + Console.WriteLine(writerConverter != null); + Console.WriteLine(readerConverter != null); + Console.WriteLine(converters.Count); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverter.md b/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverter.md new file mode 100644 index 00000000..9ec00211 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverter.md @@ -0,0 +1,37 @@ +--- +uid: Cuemon.Xml.Serialization.DynamicXmlConverter +example: +- *content +--- + +```csharp +using System; +using System.IO; +using System.Xml; +using Cuemon.Xml.Serialization; + +namespace Cuemon.Xml.Serialization; + +public class DynamicXmlConverterExample +{ + public void Demonstrate() + { + var converter = DynamicXmlConverter.Create( + writer: (w, value, entity) => + { + w.WriteElementString("Value", value.ToString()); + }, + reader: (r, type) => + { + r.ReadToDescendant("Value"); + return int.Parse(r.ReadElementContentAsString()); + }); + + using var sw = new StringWriter(); + using var writer = XmlWriter.Create(sw); + converter.WriteXml(writer, 42); + writer.Flush(); + Console.WriteLine(sw.ToString()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverterCore.md b/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverterCore.md new file mode 100644 index 00000000..ccc80dc5 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverterCore.md @@ -0,0 +1,99 @@ +--- +uid: Cuemon.Xml.Serialization.DynamicXmlConverterCore +example: +- *content +--- + +The following example demonstrates how to create a custom XML converter using DynamicXmlConverterCore, with read and write delegates for serializing and deserializing objects to and from XML. + +```csharp +using System; +using System.IO; +using System.Xml; +using Cuemon.Xml.Serialization; + +namespace MyApp.Xml +{ + public static class DynamicXmlConverterCoreExamples + { + public static void Demonstrate() + { + // Use the DynamicXmlConverter factory to create a converter for a custom type. + // This converter knows how to read and write instances of Person to/from XML. + DynamicXmlConverterCore converter = (DynamicXmlConverterCore)DynamicXmlConverter.Create( + writer: (xmlWriter, person, element) => + { + xmlWriter.WriteStartElement(element?.LocalName ?? "Person"); + xmlWriter.WriteElementString("FirstName", person.FirstName); + xmlWriter.WriteElementString("LastName", person.LastName); + xmlWriter.WriteElementString("Age", person.Age.ToString()); + xmlWriter.WriteEndElement(); + }, + reader: (xmlReader, type) => + { + var person = new Person(); + xmlReader.ReadStartElement(); + person.FirstName = xmlReader.ReadElementContentAsString("FirstName", ""); + person.LastName = xmlReader.ReadElementContentAsString("LastName", ""); + person.Age = xmlReader.ReadElementContentAsInt("Age", ""); + xmlReader.ReadEndElement(); + return person; + }); + + converter.RootName = new XmlQualifiedEntity("Person"); + + // The returned converter is an XmlConverter instance. + Console.WriteLine("Can convert Person: {0}", converter.CanConvert(typeof(Person))); + Console.WriteLine("Can read: {0}", converter.CanRead); // true + Console.WriteLine("Can write: {0}", converter.CanWrite); // true + + // Write a Person instance to XML. + var person = new Person { FirstName = "John", LastName = "Doe", Age = 30 }; + var xml = new StringWriter(); + using (var xmlWriter = XmlWriter.Create(xml, new XmlWriterSettings { Indent = true })) + { + converter.WriteXml(xmlWriter, person); + } + Console.WriteLine(xml.ToString()); + + // Read the Person back from XML. + using (var xmlReader = XmlReader.Create(new StringReader(xml.ToString()))) + { + var deserialized = (Person)converter.ReadXml(xmlReader, typeof(Person)); + Console.WriteLine("Deserialized: {0} {1}, Age {2}", + deserialized.FirstName, deserialized.LastName, deserialized.Age); + } + } + + public static void DemonstrateWriteOnly() + { + // Create a write-only converter (no reader delegate). + var writeOnly = DynamicXmlConverter.Create( + writer: (w, p, e) => + { + w.WriteStartElement(e?.LocalName ?? "Person"); + w.WriteAttributeString("name", p.FirstName + " " + p.LastName); + w.WriteEndElement(); + }); + + Console.WriteLine("Can read: {0}", writeOnly.CanRead); // false + Console.WriteLine("Can write: {0}", writeOnly.CanWrite); // true + + var person = new Person { FirstName = "Jane", LastName = "Smith", Age = 25 }; + var xml = new StringWriter(); + using (var xmlWriter = XmlWriter.Create(xml)) + { + writeOnly.WriteXml(xmlWriter, person); + } + Console.WriteLine(xml.ToString()); + } + } + + public class Person + { + public string FirstName { get; set; } + public string LastName { get; set; } + public int Age { get; set; } + } +} +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlSerializable.md b/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlSerializable.md new file mode 100644 index 00000000..c33d0f43 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlSerializable.md @@ -0,0 +1,35 @@ +--- +uid: Cuemon.Xml.Serialization.DynamicXmlSerializable +example: +- *content +--- + +```csharp +using System; +using System.IO; +using System.Xml; +using System.Xml.Serialization; +using Cuemon.Xml.Serialization; + +namespace Cuemon.Xml.Serialization; + +public class DynamicXmlSerializableExample +{ + public void Demonstrate() + { + var data = new { Name = "Alice", Score = 95 }; + var serializable = DynamicXmlSerializable.Create(data, + writer: (w, src) => + { + w.WriteElementString("Name", src.Name); + w.WriteElementString("Score", src.Score.ToString()); + }); + + using var sw = new StringWriter(); + using var writer = XmlWriter.Create(sw); + serializable.WriteXml(writer); + writer.Flush(); + Console.WriteLine(sw.ToString()); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.Formatters.XmlFormatter.md b/.docfx/api/types/Cuemon.Xml.Serialization.Formatters.XmlFormatter.md new file mode 100644 index 00000000..3d3261a9 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.Formatters.XmlFormatter.md @@ -0,0 +1,41 @@ +--- +uid: Cuemon.Xml.Serialization.Formatters.XmlFormatter +example: +- *content +--- + +The following example demonstrates how to serialize an object with . + +```csharp +using System; +using System.IO; +using Cuemon.Xml.Serialization.Formatters; + +namespace MyApp.Examples; + +public static class XmlFormatterExample +{ + public static void Demonstrate() + { + var formatter = new XmlFormatter(); + var person = new Person { Name = "John Doe", Age = 42 }; + + using var stream = formatter.Serialize(person, typeof(Person)); + stream.Position = 0; + + using var reader = new StreamReader(stream); + var xml = reader.ReadToEnd(); + + Console.WriteLine(xml.Contains("John Doe")); + Console.WriteLine(xml.Contains("42")); + } + + private sealed class Person + { + public string Name { get; set; } + + public int Age { get; set; } + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.Formatters.XmlFormatterOptions.md b/.docfx/api/types/Cuemon.Xml.Serialization.Formatters.XmlFormatterOptions.md new file mode 100644 index 00000000..22f6875f --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.Formatters.XmlFormatterOptions.md @@ -0,0 +1,52 @@ +--- +uid: Cuemon.Xml.Serialization.Formatters.XmlFormatterOptions +example: +- *content +--- + +The following example demonstrates how to configure XmlFormatterOptions for custom media types, fault sensitivity details, and synchronization with XmlConvert settings. + +```csharp +using System; +using System.Collections.Generic; +using System.Net.Http.Headers; +using Cuemon.Diagnostics; +using Cuemon.Xml.Serialization.Formatters; + +namespace MyApp.Examples +{ + public class XmlFormatterOptionsExample + { + public void Demonstrate() + { + // Configure XmlFormatter with custom settings. + var options = new XmlFormatterOptions + { + SynchronizeWithXmlConvert = true, + SensitivityDetails = FaultSensitivityDetails.None + }; + + // Customize the supported media types. + options.SupportedMediaTypes = new List + { + XmlFormatterOptions.DefaultMediaType, + new MediaTypeHeaderValue("text/xml"), + new MediaTypeHeaderValue("application/problem+xml") + }; + + Console.WriteLine($"Default media type: {XmlFormatterOptions.DefaultMediaType}"); // application/xml + Console.WriteLine($"Supported types: {options.SupportedMediaTypes.Count}"); // 3 + Console.WriteLine($"Synchronize: {options.SynchronizeWithXmlConvert}"); // True + + // Validate before use. + options.ValidateOptions(); + Console.WriteLine("Options are valid."); + + // Use with a formatter. + var formatter = new XmlFormatter(options); + Console.WriteLine($"Formatter created with {formatter.GetType().Name}."); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.XmlConvert.md b/.docfx/api/types/Cuemon.Xml.Serialization.XmlConvert.md new file mode 100644 index 00000000..05552204 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.XmlConvert.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.Xml.Serialization.XmlConvert +example: +- *content +--- + +```csharp +using System; +using System.Text; +using System.Xml; +using Cuemon.Xml.Serialization; + +namespace Cuemon.Xml.Serialization; + +public class XmlConvertExample +{ + public void Demonstrate() + { + XmlConvert.DefaultSettings = () => new XmlSerializerOptions + { + Writer = new XmlWriterSettings { Encoding = Encoding.UTF8, IndentChars = Cuemon.Alphanumeric.Tab } + }; + + var settings = XmlConvert.DefaultSettings(); + Console.WriteLine($"Default encoding: {settings.Writer.Encoding.EncodingName}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.XmlQualifiedEntity.md b/.docfx/api/types/Cuemon.Xml.Serialization.XmlQualifiedEntity.md new file mode 100644 index 00000000..b1b2b2f3 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.XmlQualifiedEntity.md @@ -0,0 +1,62 @@ +--- +uid: Cuemon.Xml.Serialization.XmlQualifiedEntity +example: +- *content +--- + +The following example demonstrates how to create XmlQualifiedEntity instances from local names, namespaces, prefixes, and XML serialization attributes to control element naming. + +```csharp +using System; +using System.Xml.Serialization; +using Cuemon.Xml.Serialization; + +namespace MyApp.Xml +{ + public class XmlQualifiedEntityExample + { + public void Demonstrate() + { + // Create an entity from local name only + var entity1 = new XmlQualifiedEntity("Order"); + Console.WriteLine($"LocalName: {entity1.LocalName}"); // Order + Console.WriteLine($"Namespace: {entity1.Namespace}"); // (null) + Console.WriteLine($"Prefix: {entity1.Prefix}"); // (null) + + // Create an entity with local name and namespace + var entity2 = new XmlQualifiedEntity("Order", "http://example.com/orders"); + Console.WriteLine($"LocalName: {entity2.LocalName}, Namespace: {entity2.Namespace}"); + + // Create an entity with prefix, local name, and namespace + var entity3 = new XmlQualifiedEntity("o", "Order", "http://example.com/orders"); + Console.WriteLine($"Prefix: {entity3.Prefix}, LocalName: {entity3.LocalName}, Namespace: {entity3.Namespace}"); + + // Create from XmlRootAttribute + var rootAttr = new XmlRootAttribute("PurchaseOrder"); + var fromRoot = new XmlQualifiedEntity(rootAttr); + Console.WriteLine($"From XmlRoot: {fromRoot.LocalName} (Namespace: {fromRoot.Namespace})"); + Console.WriteLine($"HasXmlRootDecoration: {fromRoot.HasXmlRootDecoration}"); // True + + // Create from XmlElementAttribute + var elemAttr = new XmlElementAttribute("LineItem"); + var fromElement = new XmlQualifiedEntity(elemAttr); + Console.WriteLine($"From XmlElement: {fromElement.LocalName}"); + Console.WriteLine($"HasXmlElementDecoration: {fromElement.HasXmlElementDecoration}"); // True + + // Create from XmlAttributeAttribute + var attr = new XmlAttributeAttribute("Quantity"); + var fromAttribute = new XmlQualifiedEntity(attr); + Console.WriteLine($"From XmlAttribute: {fromAttribute.LocalName}"); + Console.WriteLine($"HasXmlAttributeDecoration: {fromAttribute.HasXmlAttributeDecoration}"); // True + + // Use with XmlSerializerOptions to set a custom root name + var options = new XmlSerializerOptions + { + RootName = new XmlQualifiedEntity("CustomRoot", "http://example.com/schema") + }; + Console.WriteLine($"Options root name: {options.RootName.LocalName}"); + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.XmlSerializer.md b/.docfx/api/types/Cuemon.Xml.Serialization.XmlSerializer.md new file mode 100644 index 00000000..dfb2957a --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.XmlSerializer.md @@ -0,0 +1,50 @@ +--- +uid: Cuemon.Xml.Serialization.XmlSerializer +example: +- *content +--- + +The following example demonstrates how to serialize and deserialize a simple object with . + +```csharp +using System; +using Cuemon.Xml.Serialization; + +namespace MyApp.Examples; + +public static class XmlSerializerExample +{ + public static void Demonstrate() + { + var serializer = XmlSerializer.Create(new XmlSerializerOptions + { + RootName = new XmlQualifiedEntity("Order") + }); + + var order = new Order + { + Id = 1001, + Customer = "John Doe", + Total = 299.99m + }; + + using var stream = serializer.Serialize(order, typeof(Order)); + stream.Position = 0; + + var deserialized = serializer.Deserialize(stream); + + Console.WriteLine(deserialized.Customer); + Console.WriteLine(deserialized.Total); + } + + private sealed class Order + { + public int Id { get; set; } + + public string Customer { get; set; } + + public decimal Total { get; set; } + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.XmlSerializerOptions.md b/.docfx/api/types/Cuemon.Xml.Serialization.XmlSerializerOptions.md new file mode 100644 index 00000000..bbd023fc --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.XmlSerializerOptions.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.Xml.Serialization.XmlSerializerOptions +example: +- *content +--- + +The following example demonstrates how to configure for custom root names and XML reader/writer settings. + +```csharp +using System; +using System.Xml; +using Cuemon.Xml.Serialization; + +namespace MyApp.Examples; + +public static class XmlSerializerOptionsExample +{ + public static void Demonstrate() + { + var options = new XmlSerializerOptions + { + RootName = new XmlQualifiedEntity("Invoice"), + FlattenCollectionItems = true, + Reader = new XmlReaderSettings { DtdProcessing = DtdProcessing.Ignore }, + Writer = new XmlWriterSettings { Indent = true } + }; + + Console.WriteLine(options.RootName.LocalName); + Console.WriteLine(options.FlattenCollectionItems); + Console.WriteLine(options.Writer.Indent); + Console.WriteLine(options.Converters.Count); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.XmlSerializerOptionsDecoratorExtensions.md b/.docfx/api/types/Cuemon.Xml.Serialization.XmlSerializerOptionsDecoratorExtensions.md new file mode 100644 index 00000000..51c4f909 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.Serialization.XmlSerializerOptionsDecoratorExtensions.md @@ -0,0 +1,36 @@ +--- +uid: Cuemon.Xml.Serialization.XmlSerializerOptionsDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the `ApplyToDefaultSettings` extension method to apply `XmlSerializerOptions` to the global `XmlConvert.DefaultSettings`. + +```csharp +using System; +using System.Xml; +using Cuemon; +using Cuemon.Xml.Serialization; + +namespace MyApp.Examples; + +public class XmlSerializerOptionsDecoratorExtensionsExample +{ + public static void Main() + { + var options = new XmlSerializerOptions + { + Writer = new XmlWriterSettings { Indent = true, IndentChars = " " }, + RootName = new XmlQualifiedEntity("CustomRoot") + }; + + // Apply the options as the default XmlWriterSettings globally. + Decorator.Enclose(options).ApplyToDefaultSettings(); + + // When running XmlConvert.EncodeName or similar, the default settings apply. + Console.WriteLine("Default settings applied successfully."); + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Xml.StreamDecoratorExtensions.md b/.docfx/api/types/Cuemon.Xml.StreamDecoratorExtensions.md new file mode 100644 index 00000000..e838f8b8 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.StreamDecoratorExtensions.md @@ -0,0 +1,39 @@ +--- +uid: Cuemon.Xml.StreamDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to create an from a stream and detect the XML encoding. + +```csharp +using System; +using System.IO; +using System.Text; +using System.Xml; +using Cuemon; +using Cuemon.Xml; + +namespace MyApp.Examples; + +public static class StreamDecoratorExtensionsExample +{ + public static void Demonstrate() + { + const string xml = "hello"; + + using var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + using XmlReader reader = Decorator.Enclose(stream).ToXmlReader(); + reader.MoveToContent(); + + Console.WriteLine(reader.LocalName); + + using var detectStream = new MemoryStream(Encoding.UTF8.GetBytes(xml)); + var detected = Decorator.Enclose(detectStream).TryDetectXmlEncoding(out var encoding); + + Console.WriteLine(detected); + Console.WriteLine(encoding.EncodingName); + } +} + +``` diff --git a/.docfx/api/types/Cuemon.Xml.StringDecoratorExtensions.md b/.docfx/api/types/Cuemon.Xml.StringDecoratorExtensions.md new file mode 100644 index 00000000..97d56a70 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.StringDecoratorExtensions.md @@ -0,0 +1,53 @@ +--- +uid: Cuemon.Xml.StringDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the XML `StringDecoratorExtensions` to escape, unescape, and sanitize XML strings through the `IDecorator` interface. + +```csharp +using System; +using Cuemon; +using Cuemon.Xml; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + + // Escape XML characters in a string + var raw = ""; + var escaped = Decorator.Enclose(raw).EscapeXml(); + Console.WriteLine($"Escaped: {escaped}"); + // Output: <hello & 'world' "test"> + + // Unescape back to original + var unescaped = Decorator.Enclose(escaped).UnescapeXml(); + Console.WriteLine($"Unescaped: {unescaped}"); + // Output: + + // Sanitize a string to be a valid XML element name + var invalidName = "123order-details!.xml"; + var sanitizedName = Decorator.Enclose(invalidName).SanitizeXmlElementName(); + Console.WriteLine($"Sanitized element name: {sanitizedName}"); + // Output: order-details.xml + + // Sanitize XML element text (remove control characters) + var textWithControlChars = "Hello\x0001\x0002World"; + var cleanText = Decorator.Enclose(textWithControlChars).SanitizeXmlElementText(); + Console.WriteLine($"Clean text: {cleanText}"); + // Output: HelloWorld + + // Sanitize with CDATA section rules (removes ]]> sequences) + var cdataText = "Some data with ]]> embedded"; + var safeCdata = Decorator.Enclose(cdataText).SanitizeXmlElementText(cdataSection: true); + Console.WriteLine($"Safe CDATA: {safeCdata}"); + // Output: Some data with embedded + +} +} + +``` diff --git a/.docfx/api/types/Cuemon.Xml.XPath.XPathDocumentFactory.md b/.docfx/api/types/Cuemon.Xml.XPath.XPathDocumentFactory.md new file mode 100644 index 00000000..003db799 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.XPath.XPathDocumentFactory.md @@ -0,0 +1,26 @@ +--- +uid: Cuemon.Xml.XPath.XPathDocumentFactory +example: +- *content +--- + +```csharp +using System; +using System.Xml.XPath; +using Cuemon.Xml.XPath; + +namespace Cuemon.Xml.XPath; + +public class XPathDocumentFactoryExample +{ + public void Demonstrate() + { + var xml = "Hello"; + var doc = XPathDocumentFactory.CreateDocument(xml); + + var navigator = doc.CreateNavigator(); + var value = navigator.SelectSingleNode("//item/text()")?.Value; + Console.WriteLine($"XPath result: {value}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Xml.XmlDocumentFactory.md b/.docfx/api/types/Cuemon.Xml.XmlDocumentFactory.md new file mode 100644 index 00000000..365c17ae --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.XmlDocumentFactory.md @@ -0,0 +1,28 @@ +--- +uid: Cuemon.Xml.XmlDocumentFactory +example: +- *content +--- + +```csharp +using System; +using System.Xml; +using Cuemon.Xml; + +namespace Cuemon.Xml; + +public class XmlDocumentFactoryExample +{ + public void Demonstrate() + { + var xml = ""; + var doc = XmlDocumentFactory.CreateDocument(xml); + + var root = doc.DocumentElement; + Console.WriteLine($"Root element: {root?.Name}"); + + var book = root?.SelectSingleNode("book"); + Console.WriteLine($"Title: {book?.Attributes?["title"]?.Value}"); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Xml.XmlEncodingOptions.md b/.docfx/api/types/Cuemon.Xml.XmlEncodingOptions.md new file mode 100644 index 00000000..26c6bfe9 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.XmlEncodingOptions.md @@ -0,0 +1,57 @@ +--- +uid: Cuemon.Xml.XmlEncodingOptions +example: +- *content +--- + +The following example demonstrates how to configure XmlEncodingOptions to control character encoding and XML declaration behavior when writing XML documents. + +```csharp +using System; +using System.IO; +using System.Text; +using System.Xml; +using Cuemon.Text; +using Cuemon.Xml; + +namespace MyApp.Examples +{ + public class XmlEncodingOptionsExample + { + public void Demonstrate() + { + // Configure XML encoding options. + var options = new XmlEncodingOptions + { + Encoding = Encoding.UTF8, + Preamble = EncodingOptions.DefaultPreambleSequence, + OmitXmlDeclaration = false + }; + + Console.WriteLine($"Encoding: {options.Encoding.WebName}"); // utf-8 + Console.WriteLine($"Omit XML declaration: {options.OmitXmlDeclaration}"); // False + + // Write XML with explicit encoding settings. + var settings = new XmlWriterSettings + { + Encoding = options.Encoding, + OmitXmlDeclaration = options.OmitXmlDeclaration, + Indent = true + }; + + using var writer = XmlWriter.Create(Stream.Null, settings); + writer.WriteStartDocument(); + writer.WriteStartElement("root"); + writer.WriteElementString("value", "Hello, World!"); + writer.WriteEndElement(); + writer.WriteEndDocument(); + writer.Flush(); + + // Omit the XML declaration. + options.OmitXmlDeclaration = true; + Console.WriteLine($"Omit XML declaration now: {options.OmitXmlDeclaration}"); // True + +}} +} + +``` diff --git a/.docfx/api/types/Cuemon.Xml.XmlReaderDecoratorExtensions.md b/.docfx/api/types/Cuemon.Xml.XmlReaderDecoratorExtensions.md new file mode 100644 index 00000000..f31da1b0 --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.XmlReaderDecoratorExtensions.md @@ -0,0 +1,42 @@ +--- +uid: Cuemon.Xml.XmlReaderDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to move to the first XML element, chunk a document, and build a hierarchy from an . + +```csharp +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; +using Cuemon; +using Cuemon.Xml; + +namespace MyApp.Examples; + +public static class XmlReaderDecoratorExtensionsExample +{ + public static void Demonstrate() + { + const string xml = ""; + + using var reader = XmlReader.Create(new StringReader(xml)); + var hasElement = Decorator.Enclose(reader).MoveToFirstElement(); + + Console.WriteLine(hasElement); + Console.WriteLine(reader.LocalName); + + using var chunkReader = XmlReader.Create(new StringReader(xml)); + var chunks = new List(Decorator.Enclose(chunkReader).Chunk(size: 2)); + + Console.WriteLine(chunks.Count); + + using var hierarchyReader = XmlReader.Create(new StringReader(xml)); + var hierarchy = Decorator.Enclose(hierarchyReader).ToHierarchy(); + + Console.WriteLine(hierarchy.Instance.Name); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Xml.XmlStreamFactory.md b/.docfx/api/types/Cuemon.Xml.XmlStreamFactory.md new file mode 100644 index 00000000..b7df7f4f --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.XmlStreamFactory.md @@ -0,0 +1,34 @@ +--- +uid: Cuemon.Xml.XmlStreamFactory +example: +- *content +--- + +```csharp +using System; +using System.IO; +using System.Xml; +using Cuemon.Xml; + +namespace Cuemon.Xml; + +public class XmlStreamFactoryExample +{ + public void Demonstrate() + { + using var stream = XmlStreamFactory.CreateStream(writer => + { + writer.WriteStartDocument(); + writer.WriteStartElement("Configuration"); + writer.WriteElementString("AppName", "MyApp"); + writer.WriteElementString("Version", "1.0"); + writer.WriteEndElement(); + writer.WriteEndDocument(); + }); + + using var reader = new StreamReader(stream); + var xml = reader.ReadToEnd(); + Console.WriteLine(xml); + } +} +``` diff --git a/.docfx/api/types/Cuemon.Xml.XmlWriterDecoratorExtensions.md b/.docfx/api/types/Cuemon.Xml.XmlWriterDecoratorExtensions.md new file mode 100644 index 00000000..5e08da4f --- /dev/null +++ b/.docfx/api/types/Cuemon.Xml.XmlWriterDecoratorExtensions.md @@ -0,0 +1,65 @@ +--- +uid: Cuemon.Xml.XmlWriterDecoratorExtensions +example: +- *content +--- + +The following example demonstrates how to use the to serialize objects directly to an via the decorator pattern. + +```csharp +using System; +using System.IO; +using System.Text; +using System.Xml; +using Cuemon; +using Cuemon.Xml; +using Cuemon.Xml.Serialization; + +namespace MyApp.Examples; + +public class Example +{ + public void Run() + { + + var writer = new StringWriter(); + var xmlWriter = XmlWriter.Create(writer, new XmlWriterSettings { Indent = true, Encoding = Encoding.UTF8, OmitXmlDeclaration = false }); + + var decorator = Decorator.Enclose(xmlWriter); + + // Write a root element and serialize an object + var person = new { FirstName = "John", LastName = "Doe", Age = 30 }; + decorator.WriteXmlRootElement(person, (w, value, rootEntity) => + { + decorator.WriteStartElement(rootEntity); // + decorator.WriteObject(value, typeof(object)); // serialized person content + decorator.WriteEncapsulatingElementIfNotNull("notes", new XmlQualifiedEntity("Notes"), (w2, notes) => + { + w2.WriteString(notes); // notes + }); + }); + + xmlWriter.Flush(); + string xml = writer.ToString(); + Console.WriteLine(xml); + + // Write an object directly without root element handling + var version = new Version(1, 0, 0, 0); + var xmlWriter2 = XmlWriter.Create(new StringWriter(), new XmlWriterSettings { Indent = true }); + var decorator2 = Decorator.Enclose(xmlWriter2); + decorator2.WriteObject(version, o => + { + o.Settings.RootName = new XmlQualifiedEntity("Version"); + }); + xmlWriter2.Flush(); + // + // 1 + // 0 + // 0 + // 0 + // + +} +} + +``` diff --git a/.docfx/api/types/System.Runtime.CompilerServices.CallerArgumentExpressionAttribute.md b/.docfx/api/types/System.Runtime.CompilerServices.CallerArgumentExpressionAttribute.md new file mode 100644 index 00000000..51d1af9d --- /dev/null +++ b/.docfx/api/types/System.Runtime.CompilerServices.CallerArgumentExpressionAttribute.md @@ -0,0 +1,36 @@ +--- +uid: System.Runtime.CompilerServices.CallerArgumentExpressionAttribute +example: +- *content +--- + +```csharp +using System; +using System.Runtime.CompilerServices; + +namespace System.Runtime.CompilerServices; + +public class CallerArgumentExpressionAttributeExample +{ + public void Demonstrate() + { + var attr = new CallerArgumentExpressionAttribute("condition"); + Console.WriteLine(attr.ParameterName); // "condition" + + var value = 42; + Validate(value > 0); + } + + public void Validate(bool condition, [CallerArgumentExpression("condition")] string expression = null) + { + if (!condition) + { + Console.WriteLine($"Assertion failed: {expression}"); + } + else + { + Console.WriteLine($"Assertion passed: {expression}"); + } + } +} +``` From 81fcd6545e721473a95f3a030f59876a3420a5d5 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Sat, 20 Jun 2026 11:06:43 +0200 Subject: [PATCH 5/8] =?UTF-8?q?=F0=9F=93=9D=20enhance=20type-level=20api?= =?UTF-8?q?=20documentation=20with=20examples?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expand type-level documentation across 220 public API classes, structs, interfaces, and extension methods with enhanced examples and improved descriptions. Update docfx.json to include type documentation in the published API reference build pipeline, enabling comprehensive type-level guidance alongside existing namespace documentation. --- .docfx/api/types/Cuemon.Alphanumeric.md | 2 ++ .../Cuemon.ArgumentReservedKeywordException.md | 2 ++ ...ication.Basic.BasicAuthenticationHandler.md | 2 +- ...ation.Digest.DigestAuthenticationHandler.md | 2 +- ...ntication.Hmac.HmacAuthenticationHandler.md | 2 +- ...aultDescriptorOptionsDecoratorExtensions.md | 2 +- ...tpExceptionDescriptorDecoratorExtensions.md | 18 +++++++++--------- ...riptorResponseHandlerDecoratorExtensions.md | 2 +- ...pNetCore.Diagnostics.HttpRequestEvidence.md | 2 +- ...spNetCore.Diagnostics.ServerTimingMetric.md | 2 +- ...Http.HeaderDictionaryDecoratorExtensions.md | 2 +- ...AspNetCore.Http.Headers.CacheableOptions.md | 2 ++ ....Headers.CorrelationIdentifierMiddleware.md | 2 ++ ...ttp.Headers.CorrelationIdentifierOptions.md | 2 ++ ...NetCore.Http.Headers.RetryConditionScope.md | 2 ++ ...Core.Http.HttpContextDecoratorExtensions.md | 2 +- ...AspNetCore.Http.PayloadTooLargeException.md | 2 +- ...re.Http.Throttling.MemoryThrottlingCache.md | 2 ++ ...AspNetCore.Http.Throttling.ThrottleQuota.md | 2 ++ ...ttp.Throttling.ThrottlingSentinelOptions.md | 2 ++ ...AspNetCore.Http.TooManyRequestsException.md | 2 +- ...ilters.Diagnostics.ServerTimingAttribute.md | 2 +- ...mon.AspNetCore.Mvc.ForbiddenObjectResult.md | 2 +- .../Cuemon.ByteArrayDecoratorExtensions.md | 2 +- .docfx/api/types/Cuemon.Calculator.md | 2 ++ .../types/Cuemon.CharDecoratorExtensions.md | 2 +- .../Cuemon.Collections.Generic.Arguments.md | 2 ++ ...ns.Generic.CollectionDecoratorExtensions.md | 2 ++ ...ns.Generic.DictionaryDecoratorExtensions.md | 2 ++ ...emon.Collections.Generic.DynamicComparer.md | 2 ++ ...lections.Generic.DynamicEqualityComparer.md | 2 ++ ...ections.Generic.EnumerableSizeComparer-1.md | 2 ++ ...llections.Generic.PaginationEnumerable-1.md | 2 ++ ...mon.Collections.Generic.PaginationList-1.md | 2 ++ ...on.Collections.Generic.PaginationOptions.md | 2 ++ ...lections.Generic.PartitionerCollection-1.md | 2 ++ ...lections.Generic.PartitionerEnumerable`1.md | 2 +- ....Collections.Generic.ReferenceComparer-1.md | 2 ++ .docfx/api/types/Cuemon.Condition.md | 2 +- .docfx/api/types/Cuemon.Convertible.md | 2 ++ .../types/Cuemon.Data.DataManagerOptions.md | 2 +- ...uemon.Data.DataReaderDecoratorExtensions.md | 2 +- .docfx/api/types/Cuemon.Data.DataStatement.md | 2 +- .../types/Cuemon.Data.DataStatementOptions.md | 2 +- .../types/Cuemon.Data.DataTransferColumn.md | 2 +- ...Cuemon.Data.DataTransferColumnCollection.md | 2 +- .../api/types/Cuemon.Data.DataTransferRow.md | 2 +- .../types/Cuemon.Data.DatabaseDependency.md | 2 +- .../api/types/Cuemon.Data.DatabaseWatcher.md | 2 +- .../api/types/Cuemon.Data.InOperatorResult.md | 2 +- ...emon.Data.Integrity.DataIntegrityFactory.md | 2 +- ....Integrity.EntityDataIntegrityValidation.md | 2 ++ .../types/Cuemon.Data.Integrity.EntityInfo.md | 2 ++ ...uemon.Data.Integrity.FileChecksumOptions.md | 2 ++ .docfx/api/types/Cuemon.Data.QueryFormat.md | 2 +- .../Cuemon.Data.SqlClient.SqlQueryBuilder.md | 2 +- ...uemon.Data.UniqueIndexViolationException.md | 2 +- .../api/types/Cuemon.Data.Xml.XmlDataReader.md | 2 ++ .docfx/api/types/Cuemon.DateSpan.md | 2 ++ .../Cuemon.DateTimeDecoratorExtensions.md | 2 +- .docfx/api/types/Cuemon.DateTimeRange.md | 2 +- .docfx/api/types/Cuemon.Decorator.md | 2 ++ .../Cuemon.DelegateDecoratorExtensions.md | 2 +- .docfx/api/types/Cuemon.DelimitedString.md | 2 ++ .../types/Cuemon.Diagnostics.FaultResolver.md | 2 +- .../types/Cuemon.Diagnostics.MemberEvidence.md | 2 +- .../types/Cuemon.Diagnostics.TimeMeasure.md | 2 +- .../Cuemon.Diagnostics.TimeMeasureProfiler.md | 2 +- ...Cuemon.Diagnostics.TimeMeasureProfiler`1.md | 2 +- .../types/Cuemon.DoubleDecoratorExtensions.md | 2 +- .../Cuemon.ExceptionDecoratorExtensions.md | 2 +- .docfx/api/types/Cuemon.ExceptionInsights.md | 2 ++ .../types/Cuemon.Extensions.ActionFactory.md | 2 ++ ...hentication.AuthorizationResponseHandler.md | 2 +- ...ns.AspNetCore.Http.HttpRequestExtensions.md | 2 +- ...s.AspNetCore.Http.HttpResponseExtensions.md | 2 +- ...p.Throttling.ServiceCollectionExtensions.md | 2 +- ...Core.Mvc.CacheableObjectResultExtensions.md | 2 +- ...NetCore.Mvc.Filters.MvcBuilderExtensions.md | 2 +- ....Mvc.Formatters.Xml.MvcBuilderExtensions.md | 2 +- ...NetCore.Mvc.ViewDataDictionaryExtensions.md | 2 +- ...Collections.Generic.CollectionExtensions.md | 2 +- ...Collections.Generic.DictionaryExtensions.md | 2 +- ...Collections.Generic.EnumerableExtensions.md | 2 +- ...sions.Collections.Generic.ListExtensions.md | 2 +- ...ions.Collections.Generic.QueueExtensions.md | 2 ++ ...ions.Collections.Generic.StackExtensions.md | 2 ++ ...ections.Specialized.DictionaryExtensions.md | 2 +- ...pecialized.NameValueCollectionExtensions.md | 2 +- .../Cuemon.Extensions.DateTimeExtensions.md | 2 +- ...ncyInjection.ServiceCollectionExtensions.md | 2 +- ...dencyInjection.ServiceProviderExtensions.md | 2 +- ...sions.DependencyInjection.TypeExtensions.md | 2 +- ...ns.Diagnostics.FileVersionInfoExtensions.md | 2 +- .../Cuemon.Extensions.DoubleExtensions.md | 2 +- .../Cuemon.Extensions.ExceptionExtensions.md | 2 +- .../api/types/Cuemon.Extensions.FuncFactory.md | 2 ++ ...sions.Globalization.RegionInfoExtensions.md | 2 +- ...lobalization.StatisticalRegionExtensions.md | 2 +- .../Cuemon.Extensions.Hosting.Environments.md | 2 ++ ...nsions.Hosting.HostEnvironmentExtensions.md | 2 +- ...Cuemon.Extensions.IO.ByteArrayExtensions.md | 2 +- .../Cuemon.Extensions.IO.StreamExtensions.md | 2 +- .../Cuemon.Extensions.IO.StringExtensions.md | 2 +- ...uemon.Extensions.IO.TextReaderExtensions.md | 2 +- ...on.Extensions.MethodDescriptorExtensions.md | 2 +- .../Cuemon.Extensions.MutableTupleFactory.md | 2 ++ ...uemon.Extensions.Net.ByteArrayExtensions.md | 2 +- ...emon.Extensions.Net.DictionaryExtensions.md | 2 +- ...n.Extensions.Net.Http.HttpManagerFactory.md | 2 ++ ...Cuemon.Extensions.Net.Http.UriExtensions.md | 2 +- ....Extensions.Net.HttpStatusCodeExtensions.md | 2 +- ...nsions.Net.NameValueCollectionExtensions.md | 2 +- .../Cuemon.Extensions.Net.StringExtensions.md | 2 +- .../Cuemon.Extensions.ObjectExtensions.md | 2 +- ...Extensions.Reflection.AssemblyExtensions.md | 2 +- ...tensions.Reflection.MemberInfoExtensions.md | 2 +- ...nsions.Reflection.PropertyInfoExtensions.md | 2 +- ...mon.Extensions.Reflection.TypeExtensions.md | 2 +- .../Cuemon.Extensions.Runtime.Hierarchy.md | 2 ++ ...ons.Runtime.HierarchyDecoratorExtensions.md | 2 +- ...untime.Serialization.HierarchySerializer.md | 2 +- .../Cuemon.Extensions.StringExtensions.md | 2 +- .../Cuemon.Extensions.TesterFuncFactory.md | 2 ++ ...s.Text.Json.Converters.DateTimeConverter.md | 2 +- ....Text.Json.Converters.ExceptionConverter.md | 2 +- ...erters.JsonConverterCollectionExtensions.md | 2 +- ...Text.Json.Converters.StringEnumConverter.md | 2 +- ...Json.Converters.StringFlagsEnumConverter.md | 2 +- ...verters.TransientFaultExceptionConverter.md | 2 +- ...xtensions.Text.Json.DynamicJsonConverter.md | 2 ++ ...ons.Text.Json.JsonNamingPolicyExtensions.md | 2 +- ...ext.Json.JsonSerializerOptionsExtensions.md | 2 +- ...sions.Text.Json.Utf8JsonWriterExtensions.md | 2 +- .../Cuemon.Extensions.Text.StringExtensions.md | 2 +- .../Cuemon.Extensions.TimeSpanExtensions.md | 2 +- .../types/Cuemon.Extensions.TypeExtensions.md | 2 +- .docfx/api/types/Cuemon.Extensions.Wrapper.md | 2 ++ ...Cuemon.Extensions.Xml.DateTimeExtensions.md | 2 +- ...uemon.Extensions.Xml.HierarchyExtensions.md | 2 +- ...zation.Converters.XmlConverterExtensions.md | 2 +- .../Cuemon.Extensions.Xml.StreamExtensions.md | 2 +- .../Cuemon.Extensions.Xml.StringExtensions.md | 2 +- .../Cuemon.Extensions.Xml.UriExtensions.md | 2 +- ...uemon.Extensions.Xml.XmlReaderExtensions.md | 2 +- ...uemon.Extensions.Xml.XmlWriterExtensions.md | 2 +- .docfx/api/types/Cuemon.Globalization.World.md | 2 ++ .../Cuemon.IO.AsyncStreamCompressionOptions.md | 2 +- .../types/Cuemon.IO.AsyncStreamCopyOptions.md | 2 +- .../Cuemon.IO.AsyncStreamEncodingOptions.md | 2 +- .../Cuemon.IO.AsyncStreamReaderOptions.md | 2 +- .docfx/api/types/Cuemon.IO.FileInfoOptions.md | 2 +- .../Cuemon.IO.StreamCompressionOptions.md | 2 +- .../api/types/Cuemon.IO.StreamCopyOptions.md | 2 +- .../Cuemon.IO.StreamDecoratorExtensions.md | 2 +- .../types/Cuemon.IO.StreamEncodingOptions.md | 2 +- .../api/types/Cuemon.IO.StreamReaderOptions.md | 2 +- .../api/types/Cuemon.IO.StreamWriterOptions.md | 2 +- .../Cuemon.IO.TextReaderDecoratorExtensions.md | 2 +- .../types/Cuemon.IntegerDecoratorExtensions.md | 2 +- .docfx/api/types/Cuemon.MutableTuple`1.md | 2 ++ .../Cuemon.Net.ByteArrayDecoratorExtensions.md | 2 +- ...uemon.Net.Http.HttpAuthenticationSchemes.md | 2 ++ .../types/Cuemon.Net.Http.HttpDependency.md | 2 +- .../api/types/Cuemon.Net.Http.HttpManager.md | 2 +- .../Cuemon.Net.Http.HttpMethodConverter.md | 2 ++ .../types/Cuemon.Net.QueryStringCollection.md | 2 +- .../Cuemon.Net.StringDecoratorExtensions.md | 2 +- .../types/Cuemon.ObjectDecoratorExtensions.md | 2 +- .../Cuemon.Reflection.ActivatorFactory.md | 2 ++ .../types/Cuemon.Reflection.AssemblyContext.md | 2 ++ ...n.Reflection.AssemblyDecoratorExtensions.md | 2 +- ...Reflection.MemberInfoDecoratorExtensions.md | 2 +- .../Cuemon.Reflection.MethodBaseOptions.md | 2 +- .../Cuemon.Reflection.MethodDescriptor.md | 2 +- ...Reflection.MethodInfoDecoratorExtensions.md | 2 +- ...flection.PropertyInfoDecoratorExtensions.md | 2 +- ...Cuemon.Resilience.TransientFaultEvidence.md | 2 +- .../Cuemon.Resilience.TransientOperation.md | 2 ++ .../Cuemon.Runtime.Caching.CachingManager.md | 2 ++ .../Cuemon.Runtime.Caching.SlimMemoryCache.md | 2 +- .../Cuemon.Runtime.DependencyEventArgs.md | 2 +- .../api/types/Cuemon.Runtime.FileDependency.md | 2 +- ...ntime.Serialization.Formatters.Formatter.md | 2 ++ .../Cuemon.Security.Cryptography.AesCryptor.md | 2 +- ...Security.Cryptography.HmacMessageDigest5.md | 2 +- ...curity.Cryptography.KeyedCryptoAlgorithm.md | 2 +- ...n.Security.Cryptography.KeyedHashFactory.md | 2 ++ ...rity.Cryptography.UnkeyedCryptoAlgorithm.md | 2 +- ...Security.Cryptography.UnkeyedHashFactory.md | 2 ++ .../api/types/Cuemon.Security.HashFactory.md | 2 ++ .../types/Cuemon.StringDecoratorExtensions.md | 2 +- .docfx/api/types/Cuemon.Text.ByteOrderMark.md | 2 ++ .docfx/api/types/Cuemon.Text.ParserFactory.md | 2 ++ ...Cuemon.Threading.AdvancedParallelFactory.md | 2 ++ .../Cuemon.Threading.AsyncActionFactory-1.md | 2 +- .../Cuemon.Threading.AsyncActionFactory.md | 2 ++ .../types/Cuemon.Threading.AsyncFuncFactory.md | 2 ++ .../Cuemon.Threading.AsyncFuncFactory`2.md | 2 +- .../types/Cuemon.Threading.AsyncPatterns.md | 2 +- .docfx/api/types/Cuemon.Threading.Awaiter.md | 2 ++ .../types/Cuemon.Threading.ParallelFactory.md | 2 ++ .../api/types/Cuemon.Threading.TimerFactory.md | 2 ++ .../types/Cuemon.TypeDecoratorExtensions.md | 2 +- .../Cuemon.Xml.HierarchyDecoratorExtensions.md | 2 +- ...uemon.Xml.Linq.StringDecoratorExtensions.md | 2 +- ...ialization.Converters.ExceptionConverter.md | 2 +- ...erialization.Converters.FailureConverter.md | 2 +- ...on.Xml.Serialization.DynamicXmlConverter.md | 2 ++ ...ml.Serialization.DynamicXmlConverterCore.md | 2 +- ...Xml.Serialization.DynamicXmlSerializable.md | 2 ++ .../Cuemon.Xml.Serialization.XmlConvert.md | 2 ++ ...mon.Xml.Serialization.XmlQualifiedEntity.md | 2 +- .../Cuemon.Xml.XPath.XPathDocumentFactory.md | 2 ++ .../api/types/Cuemon.Xml.XmlDocumentFactory.md | 2 ++ .../api/types/Cuemon.Xml.XmlStreamFactory.md | 2 ++ .../Cuemon.Xml.XmlWriterDecoratorExtensions.md | 2 +- ...rvices.CallerArgumentExpressionAttribute.md | 2 ++ .docfx/docfx.json | 8 ++++++-- 219 files changed, 300 insertions(+), 160 deletions(-) diff --git a/.docfx/api/types/Cuemon.Alphanumeric.md b/.docfx/api/types/Cuemon.Alphanumeric.md index 10f946fa..ed48ce78 100644 --- a/.docfx/api/types/Cuemon.Alphanumeric.md +++ b/.docfx/api/types/Cuemon.Alphanumeric.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to use the `Alphanumeric` class to access predefined character sets. It prints the available character ranges for digits, uppercase letters, hexadecimal characters, and punctuation marks. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.ArgumentReservedKeywordException.md b/.docfx/api/types/Cuemon.ArgumentReservedKeywordException.md index f1605534..e14046b9 100644 --- a/.docfx/api/types/Cuemon.ArgumentReservedKeywordException.md +++ b/.docfx/api/types/Cuemon.ArgumentReservedKeywordException.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to throw an `ArgumentReservedKeywordException` when a parameter value matches a reserved SQL keyword. It demonstrates the expected validation failure and how to catch the exception with access to the parameter name. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationHandler.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationHandler.md index b87bc0b1..9de0a35b 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationHandler.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Basic.BasicAuthenticationHandler.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to register `BasicAuthenticationHandler` with ASP.NET Core authentication services. +The following example demonstrates how to register `BasicAuthenticationHandler` with ASP.NET Core authentication services. It sets up a `ServiceCollection`, registers the handler with a custom authenticator callback that validates credentials against hardcoded values, and builds the service provider. The handler is then resolved from DI and its type name is written to the console, confirming the authentication pipeline wires up correctly. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationHandler.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationHandler.md index df61f0b8..54e9b9e4 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationHandler.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Digest.DigestAuthenticationHandler.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to register `DigestAuthenticationHandler` with ASP.NET Core authentication services. +The following example demonstrates how to register `DigestAuthenticationHandler` with ASP.NET Core authentication services. It configures DI with `INonceTracker`, registers a digest authentication scheme with a username/password lookup callback, and builds the service provider. The handler is resolved from DI and its type name is written to the console, verifying that digest authentication wiring is operational. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationHandler.md b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationHandler.md index 23f130d6..2ce4abc8 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationHandler.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Authentication.Hmac.HmacAuthenticationHandler.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to register `HmacAuthenticationHandler` with ASP.NET Core authentication services. +The following example demonstrates how to register `HmacAuthenticationHandler` with ASP.NET Core authentication services. It creates a `ServiceCollection`, registers the handler under a custom HMAC scheme with a client ID/secret authenticator callback, and builds the service provider. The handler is resolved from DI and its type name is written to the console, confirming that HMAC authentication configuration works end-to-end. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptionsDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptionsDecoratorExtensions.md index a42ca3f7..207d7705 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptionsDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.FaultDescriptorOptionsDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the `FaultDescriptorOptions` decorator extensions to try resolving an HTTP exception descriptor from a failure. +`FaultDescriptorOptionsDecoratorExtensions` provides extension methods on `Decorator.Enclose` for resolving HTTP exception descriptors from failure objects using `FaultDescriptorOptions`. This example creates a `FaultDescriptorOptions` instance and a `BadRequestException` as the failure input, then wraps the options with `Decorator.Enclose` and calls `TryResolveHttpExceptionDescriptor` with the failure and an `HttpContext`. The resolved descriptor's `StatusCode` is output as `400`, confirming the failure was correctly mapped to a `Bad Request` HTTP response. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorDecoratorExtensions.md index cc1a1a3a..76ed36d0 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to convert an `HttpExceptionDescriptor` to a `ProblemDetails` instance using the decorator extensions. +`HttpExceptionDescriptorDecoratorExtensions` provides extension methods on `Decorator.Enclose` for converting `HttpExceptionDescriptor` instances into ASP.NET Core `ProblemDetails` objects for structured API error responses. This example creates an `HttpExceptionDescriptor` from a `BadRequestException` with `CorrelationId`, `RequestId`, and `TraceId` set as context, then wraps it with `Decorator.Enclose` and calls `ToProblemDetails` with `FaultSensitivityDetails.None`. The resulting `ProblemDetails.Title` is printed to the console, showing the error output ready for serialization into an HTTP API response body. ```csharp using System; @@ -13,13 +13,13 @@ using Cuemon.AspNetCore.Http; using Cuemon.Diagnostics; using Microsoft.AspNetCore.Mvc; - namespace Cuemon.AspNetCore.Diagnostics; +namespace Cuemon.AspNetCore.Diagnostics; - public static class HttpExceptionDescriptorDecoratorExtensionsExample - { - public static void Demonstrate() - { - var descriptor = new HttpExceptionDescriptor(new BadRequestException()) +public static class HttpExceptionDescriptorDecoratorExtensionsExample +{ + public static void Demonstrate() + { + var descriptor = new HttpExceptionDescriptor(new BadRequestException()) { CorrelationId = "corr-42", RequestId = "req-42", @@ -28,6 +28,6 @@ using Microsoft.AspNetCore.Mvc; ProblemDetails problem = Decorator.Enclose(descriptor).ToProblemDetails(FaultSensitivityDetails.None); Console.WriteLine(problem.Title); - } - } + } +} ``` diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerDecoratorExtensions.md index b6aea346..0b2700b4 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpExceptionDescriptorResponseHandlerDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to register additional HTTP exception descriptor response handlers using the decorator pattern. +`HttpExceptionDescriptorResponseHandlerDecoratorExtensions` provides extension methods on `Decorator.Enclose` for registering additional response handlers that control how HTTP exception descriptors are serialized and returned. This example creates an initial `HttpExceptionDescriptorResponseHandler` for `application/json` with a `500 Internal Server Error` status, wraps a `List` containing it, and calls `AddResponseHandler` with an options delegate specifying a custom content type, `ContentFactory`, and `StatusCodeFactory`. After execution, the list contains both handlers configured for different response scenarios in the error pipeline. ```csharp using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpRequestEvidence.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpRequestEvidence.md index b5c725ee..420367ba 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpRequestEvidence.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.HttpRequestEvidence.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to capture HTTP request evidence, including headers, query parameters, form data, and the request body, for diagnostic purposes. +`HttpRequestEvidence` captures HTTP request diagnostic data including headers, query parameters, form data, and the request body for logging and debugging scenarios. This example sets up a `DefaultHttpContext` with a POST request to `https://api.example.com/orders`, including an `Authorization` header, `X-Trace-Id`, a `status=pending` query string, form data with `customerId=42`, and a captured request body. Key steps include constructing an `HttpRequestEvidence` from the request and supplying a custom body converter delegate that redacts sensitive values by replacing `"42"` with `"***"`. Console output displays each evidence property (location, method, headers, query, form, body, and redacted body). ```csharp using System; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingMetric.md b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingMetric.md index f3c721cb..e99fa942 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingMetric.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Diagnostics.ServerTimingMetric.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create `ServerTimingMetric` instances to record performance data for the Server-Timing header, supporting duration, description, and marker-only metrics. +`ServerTimingMetric` records performance data points for the HTTP `Server-Timing` header, supporting metrics with or without duration and description. This example constructs three metrics — `"db-query"` with 135.2ms duration and a description, `"cache-hit"` as a marker-only metric, and `"redis-get"` with a 3.7ms duration — then integrates them with `IServerTiming` via `AddServerTiming` to build a complete server-timing collection. Key steps include creating metrics with various constructor overloads and iterating the final list. Console output shows header-value strings such as `db-query;dur=135.2;desc="Customer order lookup"` and `cache-hit`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.HeaderDictionaryDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.HeaderDictionaryDecoratorExtensions.md index aac856e0..e8588b7a 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Http.HeaderDictionaryDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.HeaderDictionaryDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the decorator extensions to merge, sanitize, and update HTTP header dictionaries. +`HeaderDictionaryDecoratorExtensions` provides extension methods on `Decorator.Enclose` for merging, sanitizing, and updating `IHeaderDictionary` instances. This example creates a target `HeaderDictionary` with `"X-Existing"` and a source with both `"X-Existing"` and `"X-New"`, then calls `AddRange` to selectively add only non-existing headers. It also demonstrates `AddOrUpdateHeader` with control-character sanitization (removing `\r\n` from a value) and `AddOrUpdateHeaders` to copy `HttpResponseMessage` response headers into the target. Console output confirms `"X-Existing"` retains its original value, `"X-New"` is added, sanitized headers are cleaned to `"helloworld"`, and response headers are merged as `"alpha,beta"`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CacheableOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CacheableOptions.md index d1e9acda..6fd38f1e 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CacheableOptions.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CacheableOptions.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to configure `CacheableOptions` with cache-control and expiration headers. After validation, it prints whether each header type is enabled. + ```csharp using System; using Microsoft.Net.Http.Headers; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierMiddleware.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierMiddleware.md index 432de2b6..7335aab5 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierMiddleware.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierMiddleware.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to register `CorrelationIdentifierMiddleware` in the ASP.NET Core pipeline with a custom header name and correlation token. It then reads the correlation ID from an endpoint to confirm the middleware is working. + ```csharp using System.Threading.Tasks; using System; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierOptions.md index 52f1bb09..d5f4d9c4 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierOptions.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.CorrelationIdentifierOptions.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to configure `CorrelationIdentifierOptions` with a custom correlation token. After validation, it prints the token's correlation ID. + ```csharp using System; using Cuemon.Messaging; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RetryConditionScope.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RetryConditionScope.md index 13caf871..51c7afd9 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RetryConditionScope.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Headers.RetryConditionScope.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to use `RetryConditionScope` to choose the format of a Retry-After header. It compares delta-seconds and absolute-date scopes and prints the resulting header value. + ```csharp using System; using System.Net.Http.Headers; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.HttpContextDecoratorExtensions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.HttpContextDecoratorExtensions.md index e2182a08..e82a9d95 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Http.HttpContextDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.HttpContextDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the decorator extensions on `HttpContext` to invoke throttling sentinels, API key sentinels, user-agent sentinels, and write exception descriptor responses. +`HttpContextDecoratorExtensions` provides extension methods on `Decorator.Enclose` for invoking throttling sentinels, API key sentinels, user-agent sentinels, and writing exception descriptor responses on `HttpContext`. This example configures a `DefaultHttpContext` with `"X-Api-Key: secret-key"` and `"User-Agent: Cuemon Docs"` headers, sets up `ThrottlingSentinelOptions` with a quota of 2 requests per minute, `ApiKeySentinelOptions` with allowed keys, and `UserAgentSentinelOptions`. Key steps include calling `InvokeThrottlerSentinelAsync`, `InvokeApiKeySentinelAsync`, and `InvokeUserAgentSentinelAsync`, then writing a `400 Bad Request` exception descriptor response via `WriteExceptionDescriptorResponseAsync`. Console output confirms the final response status code. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.PayloadTooLargeException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.PayloadTooLargeException.md index e0630ae2..0d146682 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Http.PayloadTooLargeException.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.PayloadTooLargeException.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use to signal HTTP 413 Payload Too Large responses. +The following example demonstrates how to use to signal HTTP 413 Payload Too Large responses. It constructs the exception with default and custom messages, wraps an inner exception, and uses `TryParse` to resolve by status code. A payload-size guard check then creates the exception conditionally. Each variant writes status code, reason phrase, and message to the console, showing how to communicate request-entity-size violations. ```csharp using System.IO; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.MemoryThrottlingCache.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.MemoryThrottlingCache.md index a697c445..0e600376 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.MemoryThrottlingCache.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.MemoryThrottlingCache.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to create a `MemoryThrottlingCache`, add a throttle request for a client, and retrieve the request count from the cache. + ```csharp using System; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottleQuota.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottleQuota.md index 603563dd..478163c2 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottleQuota.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottleQuota.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to create `ThrottleQuota` instances using different time units and a `TimeSpan` directly. It then tracks request usage with `ThrottleRequest`, including incrementing and refreshing the window. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelOptions.md b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelOptions.md index 26e38583..82c8a4f6 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelOptions.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.Throttling.ThrottlingSentinelOptions.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to create default and custom `ThrottlingSentinelOptions` to configure rate-limiting behavior. It demonstrates setting the quota, context resolver, header names, and retry-after scope, then validates the configuration and prints the selected values. + ```csharp using System; using Cuemon.AspNetCore.Http.Headers; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Http.TooManyRequestsException.md b/.docfx/api/types/Cuemon.AspNetCore.Http.TooManyRequestsException.md index 945811ef..64788e0b 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Http.TooManyRequestsException.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Http.TooManyRequestsException.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use to signal HTTP 429 Too Many Requests responses. +The following example demonstrates how to use to signal HTTP 429 Too Many Requests responses. It creates instances with default and custom messages, wraps an inner exception, and resolves by status code via `TryParse`. A rate-limit simulation checks request count against a threshold, then sets the `Retry-After` header. Each variation outputs status code, message, and header values to the console, illustrating rate-limit enforcement patterns. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingAttribute.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingAttribute.md index be34491b..bae5015f 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingAttribute.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.ServerTimingAttribute.md @@ -4,7 +4,7 @@ example: - *content --- -The following example applies to a controller action and configures the attribute directly. +The following example applies to a controller action and configures the attribute directly. It instantiates the attribute with a name, description, threshold in milliseconds, and desired log level, then applies it declaratively to a `WeatherController` GET endpoint. The attribute outputs its configuration and confirms it implements `IFilterFactory`, demonstrating how to instrument ASP.NET Core endpoints with server-timing metrics. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.AspNetCore.Mvc.ForbiddenObjectResult.md b/.docfx/api/types/Cuemon.AspNetCore.Mvc.ForbiddenObjectResult.md index 3ce20409..ba69ed54 100644 --- a/.docfx/api/types/Cuemon.AspNetCore.Mvc.ForbiddenObjectResult.md +++ b/.docfx/api/types/Cuemon.AspNetCore.Mvc.ForbiddenObjectResult.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to return a 403 Forbidden response with a diagnostic payload using `ForbiddenObjectResult`, optionally overriding the status code. +`ForbiddenObjectResult` is an `ObjectResult` subclass that returns a `403 Forbidden` HTTP response with an optional diagnostic payload. This example creates a first result with an anonymous object containing `error` and `requiredRole` fields, then inspects its `StatusCode` (403) and `Value`. A second result demonstrates overriding the status code to `404 Not Found` to obscure resource existence when security through obscurity is preferred. Console output confirms the status code values and the diagnostic payload content. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.ByteArrayDecoratorExtensions.md b/.docfx/api/types/Cuemon.ByteArrayDecoratorExtensions.md index 0d405f67..730ebed3 100644 --- a/.docfx/api/types/Cuemon.ByteArrayDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.ByteArrayDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example shows how to extend `byte[]` with `ByteArrayDecoratorExtensions` methods to convert byte arrays into encoded strings and seekable streams. +`ByteArrayDecoratorExtensions` provides extension methods on `Decorator.Enclose` for converting byte arrays into strings, streams, and encoded text with configurable encoding. This example wraps a UTF-8 byte array and the ISO-8859-1-encoded `"Café"` bytes, then calls `ToEncodedString`, `ToStream`, and reads the stream via `StreamReader`. Key steps include setting encoding via the options delegate and verifying the stream is seekable and the correct length. Console output confirms the decoded strings match the original text, and the stream reports `Length = 13` with `CanSeek = True`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Calculator.md b/.docfx/api/types/Cuemon.Calculator.md index 5f423ed7..33d479f3 100644 --- a/.docfx/api/types/Cuemon.Calculator.md +++ b/.docfx/api/types/Cuemon.Calculator.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to use the `Calculator` class to perform basic arithmetic and bitwise operations. Each method call prints the computed result to the console. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.CharDecoratorExtensions.md b/.docfx/api/types/Cuemon.CharDecoratorExtensions.md index d27a35f8..066b57f1 100644 --- a/.docfx/api/types/Cuemon.CharDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.CharDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example shows how to extend `IEnumerable` with `CharDecoratorExtensions` methods to convert character sequences into single-character strings and back to a combined string. +`CharDecoratorExtensions` provides extension methods on `Decorator.Enclose` for converting between `IEnumerable` sequences and string collections. This example wraps the characters of `"Hello"` and calls `ToEnumerable` to split them into single-character strings, then `ToStringEquivalent` to rejoin them back into the original string. It also demonstrates the same round-trip with a `char[]` array of `'A'`, `'B'`, `'C'`. Console output confirms the split produces `"H, e, l, l, o"` and the rejoined result matches `"Hello"` and `"ABC"`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Collections.Generic.Arguments.md b/.docfx/api/types/Cuemon.Collections.Generic.Arguments.md index af3b775b..d934e2f2 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.Arguments.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.Arguments.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to use the `Arguments` class to create arrays and enumerables from argument lists. It shows array concatenation, single-element yielding, and object-based overloads. + ```csharp using System; using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Collections.Generic.CollectionDecoratorExtensions.md b/.docfx/api/types/Cuemon.Collections.Generic.CollectionDecoratorExtensions.md index 73d41ee2..bdd4b281 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.CollectionDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.CollectionDecoratorExtensions.md @@ -4,6 +4,8 @@ example: - *content --- +`CollectionDecoratorExtensions` provides extension methods on `Decorator.Enclose` for bulk-adding elements to `ICollection` instances using `AddRange`. This example wraps a `List` with `"apple", "banana"` and calls `AddRange` with individual `"cherry", "date", "elderberry"` arguments and an array `["fig", "grape"]` to insert them in a single operation. Key setup includes calling `Decorator.Enclose(list).AddRange(...)` to access the non-common extension methods. Console output lists all entries after both bulk insertions, confirming that `AddRange` accepts both parameterized and array overloads. + ```csharp using System; using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Collections.Generic.DictionaryDecoratorExtensions.md b/.docfx/api/types/Cuemon.Collections.Generic.DictionaryDecoratorExtensions.md index 57bdde21..019b27d3 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.DictionaryDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.DictionaryDecoratorExtensions.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates dictionary extension methods available through the `Decorator` wrapper. It shows get-or-fallback, try-add, add-or-update, copying, and depth-indexing operations, printing each result to the console. + ```csharp using System; using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Collections.Generic.DynamicComparer.md b/.docfx/api/types/Cuemon.Collections.Generic.DynamicComparer.md index 94614fb1..9f87e600 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.DynamicComparer.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.DynamicComparer.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to create custom `IComparer` instances using `DynamicComparer` with lambda expressions. It demonstrates sorting by string length and in descending order, printing each sorted array. + ```csharp using System; using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Collections.Generic.DynamicEqualityComparer.md b/.docfx/api/types/Cuemon.Collections.Generic.DynamicEqualityComparer.md index 5096e10e..878c9b81 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.DynamicEqualityComparer.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.DynamicEqualityComparer.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to create a case-insensitive `IEqualityComparer` using `DynamicEqualityComparer` with lambda expressions. It filters distinct values from a mixed-case word list and prints the result. + ```csharp using System; using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Collections.Generic.EnumerableSizeComparer-1.md b/.docfx/api/types/Cuemon.Collections.Generic.EnumerableSizeComparer-1.md index 507be584..a39d6900 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.EnumerableSizeComparer-1.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.EnumerableSizeComparer-1.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to compare the sizes of enumerable collections using `EnumerableSizeComparer`. It shows comparisons between collections of different and equal sizes, including null-value handling. + ```csharp using System; using System.Collections; diff --git a/.docfx/api/types/Cuemon.Collections.Generic.PaginationEnumerable-1.md b/.docfx/api/types/Cuemon.Collections.Generic.PaginationEnumerable-1.md index 5e09435e..52b0d8c3 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.PaginationEnumerable-1.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.PaginationEnumerable-1.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates lazy pagination of a string array using `PaginationEnumerable`. It shows how to access page 2 with 3 items per page and prints page metadata such as page count and navigation flags. + ```csharp using System; using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Collections.Generic.PaginationList-1.md b/.docfx/api/types/Cuemon.Collections.Generic.PaginationList-1.md index 2429a924..60ea3d6a 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.PaginationList-1.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.PaginationList-1.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates eager pagination of a customer list using `PaginationList`. It shows indexer-based access and page metadata such as total items, page count, and first/last page flags. + ```csharp using System; using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Collections.Generic.PaginationOptions.md b/.docfx/api/types/Cuemon.Collections.Generic.PaginationOptions.md index bf09a743..7e1a37a6 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.PaginationOptions.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.PaginationOptions.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to configure pagination options with a custom page size and number. It shows both lazy (`PaginationEnumerable`) and eager (`PaginationList`) pagination, printing page metadata and specific items. + ```csharp using System; using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Collections.Generic.PartitionerCollection-1.md b/.docfx/api/types/Cuemon.Collections.Generic.PartitionerCollection-1.md index d7d233d3..910a6622 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.PartitionerCollection-1.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.PartitionerCollection-1.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to partition a list of numbers into fixed-size groups using `PartitionerCollection`. It iterates through each partition and prints partition-level and collection-level metadata. + ```csharp using System; using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Collections.Generic.PartitionerEnumerable`1.md b/.docfx/api/types/Cuemon.Collections.Generic.PartitionerEnumerable`1.md index d83d2639..faba04d0 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.PartitionerEnumerable`1.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.PartitionerEnumerable`1.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use to iterate over a sequence in fixed-size partitions. +The following example demonstrates how to use to iterate over a sequence in fixed-size partitions. It wraps a sequence of 1000 integers with a partition size of 100, then processes partitions sequentially using `ToList` while tracking the remaining partitions via `HasPartitions`. A smaller string partitioner shows the same behavior with an uneven final batch. The example outputs partition counts and content to the console, verifying that batching works correctly. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Collections.Generic.ReferenceComparer-1.md b/.docfx/api/types/Cuemon.Collections.Generic.ReferenceComparer-1.md index ed4d50d6..cc476c78 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.ReferenceComparer-1.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.ReferenceComparer-1.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to compare objects by their inheritance depth using `ReferenceComparer`. It shows how objects with deeper inheritance chains are considered greater, including null-value comparisons. + ```csharp using System; using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Condition.md b/.docfx/api/types/Cuemon.Condition.md index f6d74073..8662372b 100644 --- a/.docfx/api/types/Cuemon.Condition.md +++ b/.docfx/api/types/Cuemon.Condition.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the `Condition` class to perform common validation checks, equality comparisons, conditional branching, and range assertions. +The following example demonstrates how to use the `Condition` class to perform common validation checks, equality comparisons, conditional branching, and range assertions. It exercises `AreEqual`, `AreNotEqual`, and `AreSame` for equality, `FlipFlop` and `TernaryIf` for conditional execution, and validation helpers such as `IsEmail`, `IsGuid`, `IsNumeric`, `IsPrime`, and `IsWithinRange`. An async flip-flop variant confirms the API works with task-based delegates. Each result is written to the console, illustrating the full validation utility surface. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Convertible.md b/.docfx/api/types/Cuemon.Convertible.md index 0d1001cc..26efd899 100644 --- a/.docfx/api/types/Cuemon.Convertible.md +++ b/.docfx/api/types/Cuemon.Convertible.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to convert common .NET types to byte arrays using `Convertible.GetBytes`. It demonstrates converting an integer and a string, then restoring the integer from its byte representation. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.Data.DataManagerOptions.md b/.docfx/api/types/Cuemon.Data.DataManagerOptions.md index 42934c77..030abd6b 100644 --- a/.docfx/api/types/Cuemon.Data.DataManagerOptions.md +++ b/.docfx/api/types/Cuemon.Data.DataManagerOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to configure `DataManagerOptions` with a connection string, reader behavior, and connection lifecycle settings. +`DataManagerOptions` configures connection strings, reader behavior, and connection lifecycle settings for use with `DataManager`. This example creates an options instance with `ConnectionString = "Data Source=app.db"`, `PreferredReaderBehavior` set to `SequentialAccess | CloseConnection`, and both `LeaveConnectionOpen` and `LeaveCommandOpen` set to `false`. After configuration, `ValidateOptions()` is called to confirm the settings are valid. Console output prints the connection string, reader behavior flag, and lifecycle settings. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.DataReaderDecoratorExtensions.md b/.docfx/api/types/Cuemon.Data.DataReaderDecoratorExtensions.md index d16430ed..72f5e309 100644 --- a/.docfx/api/types/Cuemon.Data.DataReaderDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Data.DataReaderDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the decorator extensions to convert an `IDataReader` to an encoded string, an async string, or a stream. +`DataReaderDecoratorExtensions` provides extension methods on `Decorator.Enclose` for converting `IDataReader` content into encoded strings or streams, both synchronously and asynchronously. This example creates a single-column DSV data source backed by `DsvDataReader` with three rows of data, then wraps it and calls `ToEncodedString`, `ToEncodedStringAsync`, and `ToStream`. Key steps include repositioning the underlying stream between conversions and using `DsvDataReader` as the input source. Console output shows the string representation of the data and the stream length. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.DataStatement.md b/.docfx/api/types/Cuemon.Data.DataStatement.md index 4d163b75..190814f8 100644 --- a/.docfx/api/types/Cuemon.Data.DataStatement.md +++ b/.docfx/api/types/Cuemon.Data.DataStatement.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create `DataStatement` instances for text queries, stored procedures, and parameterized commands. +`DataStatement` represents a database command with support for text queries, stored procedures, and parameterized commands. This example creates three different statements: a text query via implicit conversion from `"SELECT * FROM Product"`, a stored procedure `"dbo.GetOrdersByDate"` with a 120-second timeout configured through an options delegate, and a parameterized `UPDATE` command with two `IDataParameter` inputs (`@qty` and `@id`). Console output shows each statement's text, `CommandType`, timeout, parameter count, and parameter names. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.DataStatementOptions.md b/.docfx/api/types/Cuemon.Data.DataStatementOptions.md index 0aa1577d..a821da28 100644 --- a/.docfx/api/types/Cuemon.Data.DataStatementOptions.md +++ b/.docfx/api/types/Cuemon.Data.DataStatementOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to configure `DataStatementOptions` for text commands and stored procedures with custom timeout and parameters. +`DataStatementOptions` provides configuration for `DataStatement` instances including command type, timeout, and parameters. This example creates a text command option with a 30-second timeout and prints its `CommandType` and timeout values, then creates a stored procedure option with a 5-minute timeout and an empty `IDataParameter` array. After configuration, `ValidateOptions()` is called to confirm the stored procedure settings are valid. Console output displays the command type, timeout in seconds, and validation status. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.DataTransferColumn.md b/.docfx/api/types/Cuemon.Data.DataTransferColumn.md index 80ed9f97..2fff1d4f 100644 --- a/.docfx/api/types/Cuemon.Data.DataTransferColumn.md +++ b/.docfx/api/types/Cuemon.Data.DataTransferColumn.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use `DataTransferColumn` to inspect column metadata — name, ordinal, and data type — from a data reader. +`DataTransferColumn` provides column metadata such as ordinal position, name, and data type for fields retrieved from an `IDataReader`. This example builds a `DataTable` with `EmployeeId`, `FirstName`, `LastName`, and `HireDate` columns containing two sample rows, creates a data reader, and retrieves a `DataTransferColumnCollection` via `DataTransfer.GetColumns`. It iterates each column to display ordinal, name, and `DataType.Name`, accesses the `"FirstName"` column by name to get its ordinal, and calls `ToString()` on a column instance. Console output shows column metadata such as `[0] EmployeeId (Int32)` and confirms the column name string representation. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.DataTransferColumnCollection.md b/.docfx/api/types/Cuemon.Data.DataTransferColumnCollection.md index 09231a37..cd73a1c1 100644 --- a/.docfx/api/types/Cuemon.Data.DataTransferColumnCollection.md +++ b/.docfx/api/types/Cuemon.Data.DataTransferColumnCollection.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use `DataTransferColumnCollection` to access column metadata retrieved from a data reader, including lookup by name or ordinal. +`DataTransferColumnCollection` is a strongly typed collection of `DataTransferColumn` objects that provides access to column metadata by index and by name. This example creates a `DataTable` with `Id`, `Name`, and `Created` columns containing one data row, then retrieves the column collection via `DataTransfer.GetColumns` from the data reader. It accesses the first column by index, looks up the `"Name"` column by name to get its ordinal, and checks whether a missing column name returns `null`. Console output shows the column count, the first column's name and data type, and the missing-column lookup result. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.DataTransferRow.md b/.docfx/api/types/Cuemon.Data.DataTransferRow.md index 4fc3268c..0e4334f0 100644 --- a/.docfx/api/types/Cuemon.Data.DataTransferRow.md +++ b/.docfx/api/types/Cuemon.Data.DataTransferRow.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use `DataTransferRow` to access field values by index, column name, or column object, including type-safe access via generic methods. +`DataTransferRow` provides access to data reader field values by index, column name, or `DataTransferColumn` object, including type-safe access via generic methods and automatic `DBNull` to `null` conversion. This example creates a `DataTable` with `Id`, `Name`, `Created`, and `Notes` columns containing two rows (one with a `DBNull` note), then retrieves a `DataTransferRowCollection` via `DataTransfer.GetRows`. It accesses values using all three lookup approaches — `first[0]` by index, `first["Name"]` by column name, and `first[idCol]` by column object — and uses `As("Id")` for type-safe access. Console output confirms each value, shows `null` for the `DBNull` case, and displays the string representation of the row. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.DatabaseDependency.md b/.docfx/api/types/Cuemon.Data.DatabaseDependency.md index f9e5f99a..e1c70714 100644 --- a/.docfx/api/types/Cuemon.Data.DatabaseDependency.md +++ b/.docfx/api/types/Cuemon.Data.DatabaseDependency.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use to monitor a relational data source for changes and notify dependent objects. +The following example demonstrates how to use to monitor a relational data source for changes and notify dependent objects. It sets up a `Lazy` with a stub connection and a command that executes `SELECT COUNT(*) FROM Products`, then creates a `DatabaseDependency` with a change event handler that writes to the console. The dependency is started asynchronously, showing how to watch a relational data source for data-change notifications. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.DatabaseWatcher.md b/.docfx/api/types/Cuemon.Data.DatabaseWatcher.md index 6540a1a4..1cc03809 100644 --- a/.docfx/api/types/Cuemon.Data.DatabaseWatcher.md +++ b/.docfx/api/types/Cuemon.Data.DatabaseWatcher.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use `DatabaseWatcher` to monitor a database for data changes by comparing checksums over time. +`DatabaseWatcher` monitors a database for data changes by comparing checksums computed from `IDataReader` results over time. This example creates a `SampleDatabaseWatcher` subclass with an in-memory `InMemoryConnection` and a factory that returns a `DataTable`'s contents as a reader, then subscribes to the `Changed` event. Key steps include calling `SignalAsync` to capture the initial checksum, modifying the data table, and signaling again to detect the change. Console output shows the initial checksum value, the number of change signals raised (1), and the updated checksum that differs from the original, confirming modification detection. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.InOperatorResult.md b/.docfx/api/types/Cuemon.Data.InOperatorResult.md index fb83c533..de9e84a2 100644 --- a/.docfx/api/types/Cuemon.Data.InOperatorResult.md +++ b/.docfx/api/types/Cuemon.Data.InOperatorResult.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create an `InOperatorResult` by using a custom `InOperator` subclass and then access its arguments, parameters, and string representation. +The following example demonstrates how to create an `InOperatorResult` by using a custom `InOperator` subclass and then access its arguments, parameters, and string representation. The `IntInOperator` maps integer values to parameterized SQL-safe placeholders prefixed with `@p`. Calling `ToSafeResult` with three values produces an `InOperatorResult` whose arguments CSV and parameter metadata are written to the console, showing how to generate safe SQL IN clauses programmatically. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.Integrity.DataIntegrityFactory.md b/.docfx/api/types/Cuemon.Data.Integrity.DataIntegrityFactory.md index 2f6ffbb3..78b00baf 100644 --- a/.docfx/api/types/Cuemon.Data.Integrity.DataIntegrityFactory.md +++ b/.docfx/api/types/Cuemon.Data.Integrity.DataIntegrityFactory.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create an implementation from a file using . +The following example demonstrates how to create an implementation from a file using . It writes sample data to a temporary file, then calls `CreateIntegrity` with a custom converter that computes a CRC64 hash over the file content. The resulting checksum and file name are written to the console, showing how to verify file integrity with configurable hashing algorithms. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.Integrity.EntityDataIntegrityValidation.md b/.docfx/api/types/Cuemon.Data.Integrity.EntityDataIntegrityValidation.md index a440c6b8..07dd65e7 100644 --- a/.docfx/api/types/Cuemon.Data.Integrity.EntityDataIntegrityValidation.md +++ b/.docfx/api/types/Cuemon.Data.Integrity.EntityDataIntegrityValidation.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to create an `EntityInfo` with strong data integrity validation and create a `CacheValidator` that uses it. It demonstrates switching on the validation level and printing the resulting checksum. + ```csharp using System; using System.Text; diff --git a/.docfx/api/types/Cuemon.Data.Integrity.EntityInfo.md b/.docfx/api/types/Cuemon.Data.Integrity.EntityInfo.md index 70d122f4..7636d47d 100644 --- a/.docfx/api/types/Cuemon.Data.Integrity.EntityInfo.md +++ b/.docfx/api/types/Cuemon.Data.Integrity.EntityInfo.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates various ways to construct `EntityInfo` instances with timestamps and optional checksums for data integrity. It shows creation-only, created-and-modified, validated, and local-time normalization scenarios, printing the resulting values. + ```csharp using System; using Cuemon.Data.Integrity; diff --git a/.docfx/api/types/Cuemon.Data.Integrity.FileChecksumOptions.md b/.docfx/api/types/Cuemon.Data.Integrity.FileChecksumOptions.md index d41005be..299142a2 100644 --- a/.docfx/api/types/Cuemon.Data.Integrity.FileChecksumOptions.md +++ b/.docfx/api/types/Cuemon.Data.Integrity.FileChecksumOptions.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to configure `FileChecksumOptions` and create cache validators with different integrity methods for a file. It demonstrates default settings, combined validation, and strong validation with a limited byte read. + ```csharp using System; using System.IO; diff --git a/.docfx/api/types/Cuemon.Data.QueryFormat.md b/.docfx/api/types/Cuemon.Data.QueryFormat.md index 2fedda0b..45ac8303 100644 --- a/.docfx/api/types/Cuemon.Data.QueryFormat.md +++ b/.docfx/api/types/Cuemon.Data.QueryFormat.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the `QueryFormat` enumeration to control how query fragments — including delimited, quoted, and bracketed formats — are generated when building SQL queries. +`QueryFormat` is an enumeration that controls how `QueryBuilder.EncodeFragment` formats column and value fragments for SQL statement generation. This example calls `EncodeFragment` with `QueryFormat.Delimited` on column names (`"FirstName,LastName,Email"`), `DelimitedString` on string values (`"'John','Doe'"`), and `DelimitedSquareBracket` on identifiers (`"[FirstName],[LastName]"`). It also demonstrates the `distinct: true` option that removes duplicate values from the output. Console output shows each formatting style applied to the sample data, such as `FirstName,LastName,Email` for delimited and `[FirstName],[LastName]` for square-bracket delimited. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.SqlClient.SqlQueryBuilder.md b/.docfx/api/types/Cuemon.Data.SqlClient.SqlQueryBuilder.md index d4c3c1e4..bff22f43 100644 --- a/.docfx/api/types/Cuemon.Data.SqlClient.SqlQueryBuilder.md +++ b/.docfx/api/types/Cuemon.Data.SqlClient.SqlQueryBuilder.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use `SqlQueryBuilder` to generate SELECT, INSERT, UPDATE, DELETE, and EXISTS queries for SQL Server with table and column encapsulation, dirty reads, and read limits. +`SqlQueryBuilder` generates SQL Server-specific SELECT, INSERT, UPDATE, DELETE, and EXISTS queries from key and column mapping dictionaries. This example configures multiple `SqlQueryBuilder` instances for an `Employees` table with key column `EmployeeId` and optional columns `FirstName`, `LastName`, and `Email`. Settings include `EnableTableAndColumnEncapsulation` for bracket-delimited identifiers, `EnableDirtyReads` for `WITH(NOLOCK)`, and `EnableReadLimit` with `ReadLimit = 50` for `TOP 50`. Console output shows the generated SQL for each query type, such as `SELECT TOP 50 [EmployeeId],[FirstName],[LastName],[Email] FROM [Employees] WITH(NOLOCK) WHERE [EmployeeId]=@EmployeeId`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.UniqueIndexViolationException.md b/.docfx/api/types/Cuemon.Data.UniqueIndexViolationException.md index e48172f3..75b02133 100644 --- a/.docfx/api/types/Cuemon.Data.UniqueIndexViolationException.md +++ b/.docfx/api/types/Cuemon.Data.UniqueIndexViolationException.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use `UniqueIndexViolationException` to represent a unique index or unique constraint violation in a data source. +`UniqueIndexViolationException` represents a unique index or constraint violation error, with support for inner exceptions and parameterless construction. This example throws a new instance with a descriptive message about a duplicate key in `dbo.Users` and catches it to print the message. It also creates a wrapped exception with an inner `InvalidOperationException` as the cause, and demonstrates the default parameterless constructor with type name resolution via `GetType().Name`. Console output shows the exception messages and the resolved type name `UniqueIndexViolationException`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Data.Xml.XmlDataReader.md b/.docfx/api/types/Cuemon.Data.Xml.XmlDataReader.md index d837aed4..e8feb501 100644 --- a/.docfx/api/types/Cuemon.Data.Xml.XmlDataReader.md +++ b/.docfx/api/types/Cuemon.Data.Xml.XmlDataReader.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to read XML data as a tabular result set using `XmlDataReader`. It iterates through records, accesses fields by name, and prints row metadata such as depth and field count. + ```csharp using System; using System.IO; diff --git a/.docfx/api/types/Cuemon.DateSpan.md b/.docfx/api/types/Cuemon.DateSpan.md index 65262305..92e3fd57 100644 --- a/.docfx/api/types/Cuemon.DateSpan.md +++ b/.docfx/api/types/Cuemon.DateSpan.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to calculate the time span between two dates using `DateSpan`. It shows constructing a span, accessing years/months/days, parsing ISO 8601 date strings, and creating a span that defaults the end to today. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.DateTimeDecoratorExtensions.md b/.docfx/api/types/Cuemon.DateTimeDecoratorExtensions.md index c23f022b..66538667 100644 --- a/.docfx/api/types/Cuemon.DateTimeDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.DateTimeDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example shows how to extend `DateTime` with `DateTimeDecoratorExtensions` methods to perform Unix epoch conversions and adjust `DateTimeKind` without changing the underlying ticks. +`DateTimeDecoratorExtensions` provides extension methods for converting between `DateTime` and Unix epoch time and for switching `DateTimeKind` without altering the underlying ticks. This example retrieves the Unix epoch via `Decorator.Syntactic().GetUnixEpoch()`, converts `DateTime.UtcNow` to seconds since epoch with `ToUnixEpochTime`, and transforms `DateTimeKind` between `Utc`, `Local`, and `Unspecified` using `ToUtcKind`, `ToLocalKind`, and `ToDefaultKind`. Key setup includes creating UTC and local `DateTime` values, then verifying each kind-only transformation preserves the tick count. Console output shows the epoch value, Unix timestamp, and confirms `Kind` changes while `Ticks == localTime.Ticks` remains `True`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.DateTimeRange.md b/.docfx/api/types/Cuemon.DateTimeRange.md index d73699f7..b2467b64 100644 --- a/.docfx/api/types/Cuemon.DateTimeRange.md +++ b/.docfx/api/types/Cuemon.DateTimeRange.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use `DateTimeRange` to represent and query a range between two `DateTime` values, including duration, formatting, and equality comparison. +The following example demonstrates how to use `DateTimeRange` to represent and query a range between two `DateTime` values. It creates a range for January 2026, queries the start and end points, computes the duration, and tests equality against another range. Custom formatting and hash-code access are also shown. Each result is written to the console, confirming that date-range creation, comparison, and formatting behave as expected. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Decorator.md b/.docfx/api/types/Cuemon.Decorator.md index 3dc2a9da..efc5265b 100644 --- a/.docfx/api/types/Cuemon.Decorator.md +++ b/.docfx/api/types/Cuemon.Decorator.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to wrap values using `Decorator.Enclose` and related methods. It shows accessing the inner value, argument name, syntactic default, and raw (nullable) wrapping. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.DelegateDecoratorExtensions.md b/.docfx/api/types/Cuemon.DelegateDecoratorExtensions.md index 43d3d423..86330dbe 100644 --- a/.docfx/api/types/Cuemon.DelegateDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.DelegateDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example shows how to extend `Delegate` with `DelegateDecoratorExtensions` methods to resolve `MethodInfo` from a delegate instance through the decorator pattern. +`DelegateDecoratorExtensions` provides extension methods on `Decorator.Enclose` for resolving `MethodInfo` from delegate instances via reflection. This example creates a `Func add` delegate and an `Action greet` delegate, then calls `ResolveDelegateInfo` to retrieve their underlying `MethodInfo`, with optional fallback to the decorator wrapper when one parameter is null. Key steps include wrapping `null` as a fallback delegate and resolving `MethodInfo` from both the original and wrapped delegates. Console output prints the method name, declaring type name, and static status for each resolved method. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.DelimitedString.md b/.docfx/api/types/Cuemon.DelimitedString.md index 7dbc5892..85a6582f 100644 --- a/.docfx/api/types/Cuemon.DelimitedString.md +++ b/.docfx/api/types/Cuemon.DelimitedString.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to create a delimited string from an array of integers and split it back into parts using `DelimitedString`. The delimiter and string converter are configured through setup options. + ```csharp using System; using System.Globalization; diff --git a/.docfx/api/types/Cuemon.Diagnostics.FaultResolver.md b/.docfx/api/types/Cuemon.Diagnostics.FaultResolver.md index 468629b5..b158a475 100644 --- a/.docfx/api/types/Cuemon.Diagnostics.FaultResolver.md +++ b/.docfx/api/types/Cuemon.Diagnostics.FaultResolver.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use to register exception-to-descriptor mappings for structured error reporting. +`FaultResolver` registers exception-to-descriptor mappings for structured error reporting, using a validator predicate and a descriptor factory. This example registers a resolver that matches `ArgumentNullException` and produces an `ExceptionDescriptor` with code `"ERR_NULL_ARG"` and a message including the parameter name. It then tests resolution against both a matching `ArgumentNullException("value")` and a non-matching `InvalidOperationException`. Console output shows `True`, `ERR_NULL_ARG`, the descriptive message, the failure details (`"value"`), and `False` for the unmatched case where the result is `null`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Diagnostics.MemberEvidence.md b/.docfx/api/types/Cuemon.Diagnostics.MemberEvidence.md index 1db29101..4c674e89 100644 --- a/.docfx/api/types/Cuemon.Diagnostics.MemberEvidence.md +++ b/.docfx/api/types/Cuemon.Diagnostics.MemberEvidence.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to retrieve a instance from an that has been enriched with embedded insights to capture member signature and runtime parameter evidence for diagnostic purposes. +The following example demonstrates how to retrieve a instance from an that has been enriched with embedded insights. It throws an `ArgumentNullException` enriched via `ExceptionInsights.Embed` with the current method and runtime arguments, then catches and extracts the descriptor. The `MemberEvidence` is read from the descriptor's evidence dictionary, and its member signature and runtime parameter count are written to the console, showing how to capture diagnostic context at the point of failure. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Diagnostics.TimeMeasure.md b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasure.md index 73d664d9..7a22a2a5 100644 --- a/.docfx/api/types/Cuemon.Diagnostics.TimeMeasure.md +++ b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasure.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to profile actions and functions using . +The following example demonstrates how to profile actions and functions using . It profiles parameterless and parameterized actions via `WithAction`, profiles functions with return values via `WithFunc`, and configures a completion threshold. Each profiler's elapsed time and, where applicable, return value are written to the console, illustrating how to measure execution duration of synchronous delegates. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler.md b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler.md index e7d3fce1..4ee9c9b5 100644 --- a/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler.md +++ b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how returns instances for measured work. +`TimeMeasureProfiler` captures performance timing metrics for synchronous operations via the `TimeMeasure` API. This example calls `TimeMeasure.WithAction(() => Thread.Sleep(25))` to profile a 25ms sleep and `TimeMeasure.WithFunc(() => 42)` to profile a function returning a result. Key steps include checking the profiler's `Elapsed` time and `IsRunning` state, and accessing the `Result` of the function profiler. Console output confirms `Elapsed > TimeSpan.Zero` for both profilers, `IsRunning` is `False` after completion, and the function result is `42`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler`1.md b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler`1.md index 0ae8de4b..1ae0d34e 100644 --- a/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler`1.md +++ b/.docfx/api/types/Cuemon.Diagnostics.TimeMeasureProfiler`1.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use to time an operation that returns a value and access the result through . +`TimeMeasureProfiler` extends `TimeMeasureProfiler` by providing typed access to the result of a timed function via `TimeMeasure.WithFunc`. This example wraps a `Thread.Sleep(100)` followed by returning `42`, then inspects the profiler's `Result` (`42`), `Elapsed` (~100ms), `IsRunning` (`False`), and `Member` properties. Key setup includes capturing the profiler and checking each property after execution. Console output shows the result value, the elapsed duration, the running state, the member name, and the `ToString()` output like ` took 00:00:00.100 to execute.`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.DoubleDecoratorExtensions.md b/.docfx/api/types/Cuemon.DoubleDecoratorExtensions.md index 34502b68..08de594f 100644 --- a/.docfx/api/types/Cuemon.DoubleDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.DoubleDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example shows how to extend `double` with `DoubleDecoratorExtensions` methods to convert numeric values into `TimeSpan` instances using a specified `TimeUnit`. +`DoubleDecoratorExtensions` provides extension methods on `Decorator.Enclose` for converting `double` values into `TimeSpan` instances using the `ToTimeSpan` method with a specified `TimeUnit`. This example creates four `double` values representing 1.5 days, 90 minutes, 5000 milliseconds, and 2.5 hours, each wrapped with `Decorator.Enclose` and passed to `ToTimeSpan` with the matching time unit. Key setup includes choosing the correct `TimeUnit` enum value for each conversion. Console output shows `1.12:00:00` for 1.5 days, `01:30:00` for 90 minutes, `00:00:05` for 5000 milliseconds, and `02:30:00` for 2.5 hours. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.ExceptionDecoratorExtensions.md b/.docfx/api/types/Cuemon.ExceptionDecoratorExtensions.md index 2242ef4f..2c880029 100644 --- a/.docfx/api/types/Cuemon.ExceptionDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.ExceptionDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example shows how to extend `Exception` with `ExceptionDecoratorExtensions` methods to flatten nested exception hierarchies into a flat sequence. +`ExceptionDecoratorExtensions` provides extension methods on `Decorator.Enclose` for flattening deeply nested exception hierarchies into a flat sequence via the `Flatten` method. This example creates a three-level exception chain (`InvalidOperationException` → `ArgumentException` → `TimeoutException`) and an `AggregateException` containing two root-level exceptions. Key steps include wrapping each exception with `Decorator.Enclose`, calling `Flatten()`, and materializing the result with `ToList()`. Console output shows the flattened chain order (`InvalidOperationException -> ArgumentException -> TimeoutException`) and the aggregate exception count, confirming the full hierarchy is unwound without losing any exceptions. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.ExceptionInsights.md b/.docfx/api/types/Cuemon.ExceptionInsights.md index f6983a6f..ad7d466e 100644 --- a/.docfx/api/types/Cuemon.ExceptionInsights.md +++ b/.docfx/api/types/Cuemon.ExceptionInsights.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to enrich an exception with thread and environment information using `ExceptionInsights.Embed`. It catches an exception, embeds runtime parameters and system snapshots, then checks for the embedded insight data in the exception's Data dictionary. + ```csharp using System; using System.Reflection; diff --git a/.docfx/api/types/Cuemon.Extensions.ActionFactory.md b/.docfx/api/types/Cuemon.Extensions.ActionFactory.md index 3bb58fac..2a0ba262 100644 --- a/.docfx/api/types/Cuemon.Extensions.ActionFactory.md +++ b/.docfx/api/types/Cuemon.Extensions.ActionFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to create an `ActionFactory` from a callback with arguments and execute it. It shows both creating a factory with `Create` and invoking directly with `Invoke`. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandler.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandler.md index 4818ee15..60fd2c22 100644 --- a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandler.md +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Authentication.AuthorizationResponseHandler.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to construct `AuthorizationResponseHandler` with configured options and the required logger dependency. +The following example demonstrates how to construct `AuthorizationResponseHandler` with configured options and the required logger dependency. It registers `AuthorizationResponseHandlerOptions` with `FaultSensitivityDetails.All`, adds logging services, and builds the service provider. The handler is then created from the resolved `ILogger` and `IOptions` instances, and its type name is written to the console, confirming the dependency-injection wiring works correctly. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpRequestExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpRequestExtensions.md index c31d5b6b..f712a26d 100644 --- a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpRequestExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpRequestExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use HttpRequestExtensions to inspect HTTP request properties such as accepted MIME types, HTTP method checks, and client-side caching status using ETags and Last-Modified headers. +`HttpRequestExtensions` provides extension methods for `HttpRequest` that inspect accepted MIME types, HTTP method type, and client-side caching status. This example sets up a request with `Accept` header values (`text/html`, `application/json`, `*/*` with quality scores), `If-None-Match` with an ETag, and `If-Modified-Since` with a date, then calls `AcceptMimeTypesOrderedByQuality` to sort by q-value, `IsGetOrHeadMethod` to check the HTTP method, and `IsClientSideResourceCached` with both a `ChecksumBuilder` ETag and a `Last-Modified` date overload. Console output shows the sorted MIME types (`application/json, text/html, */*`), the method check results, and the cache state booleans. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpResponseExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpResponseExtensions.md index 8e98fe39..9ab34f2d 100644 --- a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpResponseExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.HttpResponseExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use HttpResponseExtensions to manage HTTP response headers such as ETag and Last-Modified, write response bodies, and transform HttpResponseMessage content into the ASP.NET Core response pipeline. +`HttpResponseExtensions` provides extension methods for `HttpResponse` to manage ETag and Last-Modified headers, write response bodies asynchronously, and transform `HttpResponseMessage` content into the ASP.NET Core response pipeline. This example calls `AddOrUpdateEntityTagHeader` with a `ChecksumBuilder` for ETag generation, `AddOrUpdateLastModifiedHeader` with a `2024-06-15T10:00:00Z` UTC date, `WriteBodyAsync` with a byte array delegate, and `OnStartingInvokeTransformer` to transfer an `HttpResponseMessage` with status `200 OK` and JSON content type. Each operation is demonstrated independently, with Console output confirming the header values and response modifications. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Throttling.ServiceCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Throttling.ServiceCollectionExtensions.md index 5b4b9109..22004483 100644 --- a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Throttling.ServiceCollectionExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Http.Throttling.ServiceCollectionExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to register throttling and rate-limiting services in an ASP.NET Core application using ServiceCollectionExtensions, including in-memory throttling cache and custom rate-limit sentinel options. +`ServiceCollectionExtensions` in the `Throttling` namespace registers rate-limiting services in an ASP.NET Core `IServiceCollection`. This example calls `AddMemoryThrottlingCache` and `AddThrottlingCache` to register in-memory and custom throttling cache implementations as singletons, then configures `ThrottlingSentinelOptions` with a `ContextResolver` that uses the remote IP address, a quota of `100` requests per minute, custom rate-limit header names (`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`), and `RetryAfter` header behavior in delta-seconds format. After this setup in `ConfigureServices`, the middleware pipeline can enforce the configured throttling rules for each client. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.CacheableObjectResultExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.CacheableObjectResultExtensions.md index af6bc617..04254c31 100644 --- a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.CacheableObjectResultExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.CacheableObjectResultExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example mirrors the cacheable object patterns covered by the unit tests: a payload can expose Last-Modified metadata, an ETag, or both headers at once. +The following example mirrors the cacheable object patterns covered by the unit tests: a payload can expose Last-Modified metadata, an ETag, or both at once. It calls `WithLastModifiedHeader`, `WithEntityTagHeader`, and `WithCacheableHeaders` in sequence on a `ProductDto`, each with timestamp and checksum provider callbacks. The resulting `ICacheableObjectResult` is read back to display the modified timestamp and entity-tag validation, showing how to attach HTTP caching headers to response payloads. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.MvcBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.MvcBuilderExtensions.md index fe0ffb7f..ed004635 100644 --- a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.MvcBuilderExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Filters.MvcBuilderExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example configures the MVC builder with the same option families covered by the unit tests: API-key enforcement, throttling, user-agent validation, fault descriptors, and cache headers. +The following example configures the MVC builder with the same option families covered by the unit tests: API-key enforcement, throttling, user-agent validation, fault descriptors, and cache headers. It chains `AddApiKeySentinelOptions`, `AddThrottlingSentinelOptions`, `AddUserAgentSentinelOptions`, `AddFaultDescriptorOptions`, and `AddHttpCacheableOptions` on the MVC builder. The resulting service count is written to the console, demonstrating how to register security, throttling, and caching middleware in a single fluent configuration. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcBuilderExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcBuilderExtensions.md index a9962c40..bb26fc69 100644 --- a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcBuilderExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.MvcBuilderExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to add XML serialization formatters to an MVC builder. +The following example demonstrates how to add XML serialization formatters to an MVC builder. It calls `AddXmlFormatters` with indentation enabled, then `AddXmlFormattersOptions` with indentation disabled, on the builder returned by `AddControllers`. Both calls configure the underlying `XmlWriter` settings, showing how to register and customize XML input/output formatters for ASP.NET Core API controllers. ```csharp using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml; diff --git a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.ViewDataDictionaryExtensions.md b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.ViewDataDictionaryExtensions.md index 54669ea0..694ddbc9 100644 --- a/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.ViewDataDictionaryExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.AspNetCore.Mvc.ViewDataDictionaryExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example follows the same pattern as the sample MVC app in the test project: controller actions populate breadcrumbs from the current model, and a shared Razor partial reads them back from . +The following example follows the same pattern as the sample MVC app in the test project: controller actions populate breadcrumbs from the current model, and a shared Razor partial reads them back from . Three `RegionController` actions call `AddBreadcrumbs` with a `RegionPageModel` that holds hierarchical labels. A `BreadcrumbPartial` class then retrieves the breadcrumbs via `GetBreadcrumbs` and projects each into a readable string, demonstrating hierarchical navigation-data propagation in ASP.NET Core MVC. ```csharp using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.CollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.CollectionExtensions.md index bec19afd..dda0843c 100644 --- a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.CollectionExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.CollectionExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to add a range of values to a collection and iterate it through a partitioner. +`CollectionExtensions` provides extension methods for `ICollection` including `AddRange` for bulk insertion and `ToPartitioner` for batched iteration. This example creates an empty `List`, calls `AddRange(1, 2, 3, 4)` to insert four integers at once, then creates a partitioner with `ToPartitioner(2)` to split elements into batches of two. Console output confirms the element count (`4`) and the partition count (`2`), demonstrating batch processing of collection contents. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.DictionaryExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.DictionaryExtensions.md index 54fba270..73747d35 100644 --- a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.DictionaryExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.DictionaryExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to populate, update, and query a dictionary through the available extension methods. +`DictionaryExtensions` provides extension methods for `IDictionary` including `CopyTo`, `TryAdd` with a predicate, `AddOrUpdate`, `GetValueOrDefault` with a factory fallback, and `TryGetValueOrFallback`. This example creates a source dictionary with `"alpha": 1` and `"beta": 2`, copies entries to a new dictionary via `CopyTo`, conditionally adds `"gamma": 3` only if the key does not exist, updates `"beta"` to `20`, retrieves `"delta"` with a fallback factory returning `42`, and resolves a missing key using `TryGetValueOrFallback`. Console output confirms the destination count, fallback values, and the formatted key-value pairs. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.EnumerableExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.EnumerableExtensions.md index e98c4224..27b9eef7 100644 --- a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.EnumerableExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.EnumerableExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to partition, reorder, paginate, and materialize a sequence by using the available enumerable extensions. +`EnumerableExtensions` provides extension methods for `IEnumerable` including chunking, shuffling, ordering, pagination, and materialization. This example starts with an `int[] { 4, 1, 3, 2 }` and applies `Chunk(2)` to split into batches, `Shuffle` with both random and deterministic seeds, `OrderAscending` and `OrderDescending` for sorted output, `RandomOrDefault` for element selection, and `Yield` to wrap a single value. It also demonstrates `ToDictionary` from `KeyValuePair` sequences, `ToPartitioner` for partitioned iteration, and `ToPagination`/`ToPaginationList` for page-based access. Console output confirms each operation's results, such as chunk count (`2`), sorted order (`1, 2, 3, 4`), and dictionary value for key `"beta"`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.ListExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.ListExtensions.md index 643f2b5e..6f44d443 100644 --- a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.ListExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.ListExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the extension methods to safely navigate and manipulate lists. +`ListExtensions` provides extension methods for `List` for safe navigation and manipulation including predicate-based removal, bounds checking, adjacent-element access, and conditional addition. This example creates a list of fruit names `["Apple", "Banana", "Cherry", "Date"]`, calls `Remove` with a predicate to delete `"Banana"`, checks whether index `5` exists with `HasIndex`, and retrieves adjacent elements using `Next(0)` and `Previous(2)` without throwing on out-of-bounds access. `TryAdd` conditionally adds `"Cherry"` (duplicate, returns `false`) and `"Elderberry"` (new, returns `true`). Console output confirms the removal, bounds-check results, neighbor values, and the success of each conditional addition. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.QueueExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.QueueExtensions.md index aa011221..194c6362 100644 --- a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.QueueExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.QueueExtensions.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to use `TryPeek` to safely inspect the front of a `Queue` without removing the item. It demonstrates that successive calls return the same element. + ```csharp using System; using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.StackExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.StackExtensions.md index ed80d412..7bfa8340 100644 --- a/.docfx/api/types/Cuemon.Extensions.Collections.Generic.StackExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Generic.StackExtensions.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to use `TryPop` to safely remove items from a `Stack`. It demonstrates popping until the stack is empty, after which `TryPop` returns `false` and sets the result to `null`. + ```csharp using System; using System.Collections.Generic; diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.DictionaryExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.DictionaryExtensions.md index 9ef03792..76704548 100644 --- a/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.DictionaryExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.DictionaryExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to convert a Dictionary with string array values into a NameValueCollection using DictionaryExtensions, with support for custom delimiters. +`DictionaryExtensions` in the `Specialized` namespace converts `Dictionary` into `NameValueCollection` instances, joining multi-valued keys with a configurable delimiter. This example creates a dictionary with `"colors": ["red", "green", "blue"]` and `"sizes": ["small", "large"]`, calls `ToNameValueCollection()` to produce a collection using the default comma delimiter, then calls `ToNameValueCollection` with a custom `";"` delimiter via an options delegate. Console output confirms that `"colors"` becomes `"red,green,blue"` with the default delimiter and `"red;green;blue"` with the custom semicolon delimiter. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.NameValueCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.NameValueCollectionExtensions.md index 19b9569e..f242f2da 100644 --- a/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.NameValueCollectionExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Collections.Specialized.NameValueCollectionExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use NameValueCollectionExtensions to check for key existence and convert a NameValueCollection into a dictionary with string array values. +`NameValueCollectionExtensions` provides extension methods for `NameValueCollection` including case-insensitive key lookup and conversion to `IDictionary`. This example creates a collection with `"name": "John Doe"` and `"tag": ["dotnet", "csharp"]` (duplicate key), then calls `ContainsKey("NAME")` to verify case-insensitive matching and `ToDictionary()` to materialize entries as a dictionary with string array values. It also demonstrates `ToDictionary` with a custom `";"` delimiter for splitting multi-valued entries. Console output confirms boolean key-lookup results, the individual array elements `"dotnet"` and `"csharp"`, and the array length when using the custom delimiter. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.DateTimeExtensions.md b/.docfx/api/types/Cuemon.Extensions.DateTimeExtensions.md index fc4f62ca..d05d9778 100644 --- a/.docfx/api/types/Cuemon.Extensions.DateTimeExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.DateTimeExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates common `DateTime` extension methods for rounding, range checking, time-of-day classification, and timezone kind conversion. +`DateTimeExtensions` provides extension methods for `DateTime` including rounding, range checking, time-of-day classification, kind conversion, and Unix epoch round-tripping. This example creates UTC and local `DateTime` values and applies `Floor` to snap to the nearest hour, `Ceiling` to round up to the next hour, `IsWithinRange` for containment checks, and classification methods like `IsTimeOfDayMorning` and `IsTimeOfDayEvening`. It also converts between `DateTimeKind` values using `ToUtcKind`, `ToLocalKind`, and `ToDefaultKind`, and round-trips through Unix epoch seconds via `ToUnixEpochTime` and `FromUnixEpochTime`. Console output confirms each result, including the snapped timestamp, boolean range check, time-of-day flags, updated `Kind` values, and the restored timestamp. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceCollectionExtensions.md index e81097d9..ac6e7284 100644 --- a/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceCollectionExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceCollectionExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example registers a concrete handler once and lets `Add` forward both its typed service contract and its dependency-injection marker so the same scoped instance can be resolved through each public entry point. +`ServiceCollectionExtensions` provides registration methods for `IServiceCollection` that support multi-contract resolution, typed options, and bulk post-configuration. This example defines an `OrdersMessageHandler` implementing both `IMessageHandler` and `IDependencyInjectionMarker`, then registers it with various lifecycle options using `Add`, `TryAdd`, and `TryConfigure` overloads including scoped and singleton lifetimes. It also demonstrates `PostConfigureAllOf` for bulk configuration of options instances. After building the service provider and creating a scope, the concrete handler, typed contract, and marker are resolved and compared by reference. Console output confirms that all three resolve to the same instance and that `HandlerOptions.Label` is correctly set to `"post-configured"`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceProviderExtensions.md b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceProviderExtensions.md index c9db7fc6..8ee4c231 100644 --- a/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceProviderExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.ServiceProviderExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example wraps the built service provider and then uses `GetServiceDescriptors()` to inspect the registrations that were added to the container. +The following example wraps the built service provider and then uses `GetServiceDescriptors()` to inspect the registrations that were added to the container. It registers singleton and scoped services in a `ServiceCollection`, builds the provider, and wraps it in a `DelegatingServiceProvider`. The wrapped provider's descriptors are queried for the registered types, and the results are written to the console, showing how to introspect service registrations at runtime. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.DependencyInjection.TypeExtensions.md b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.TypeExtensions.md index c51028de..942983e5 100644 --- a/.docfx/api/types/Cuemon.Extensions.DependencyInjection.TypeExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.DependencyInjection.TypeExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example asks `TryGetDependencyInjectionMarker` whether a generic service type carries an `IDependencyInjectionMarker` contract and then reads the discovered marker type. +The following example asks `TryGetDependencyInjectionMarker` whether a generic service type carries an `IDependencyInjectionMarker` contract and then reads the discovered marker type. It tests a `DefaultService` that implements the marker interface, and a plain `string` type that does not. The boolean results and the resolved marker type are written to the console, demonstrating how to detect marker-interface contracts for DI service wiring at runtime. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Diagnostics.FileVersionInfoExtensions.md b/.docfx/api/types/Cuemon.Extensions.Diagnostics.FileVersionInfoExtensions.md index 089cb0be..cb8dd9b0 100644 --- a/.docfx/api/types/Cuemon.Extensions.Diagnostics.FileVersionInfoExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Diagnostics.FileVersionInfoExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use FileVersionInfoExtensions to extract structured product and file version information from an assembly's FileVersionInfo. +`FileVersionInfoExtensions` provides extension methods for `FileVersionInfo` to extract structured version information as `VersionResult` objects from an assembly's metadata. This example obtains the `FileVersionInfo` for the current assembly, then calls `ToProductVersion` to retrieve the NuGet/semantic version string and `ToFileVersion` to retrieve the file version string. Key steps include checking `IsSemanticVersion()` and `HasAlphanumericVersion` on the product version, and converting the file version to a `System.Version` via `ToVersion()`. Console output displays the assembly full name, original version strings, structured version results, and boolean flags for version characteristics. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.DoubleExtensions.md b/.docfx/api/types/Cuemon.Extensions.DoubleExtensions.md index ff938afb..2a6a48f5 100644 --- a/.docfx/api/types/Cuemon.Extensions.DoubleExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.DoubleExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use DoubleExtensions for numeric operations such as Unix epoch conversion, time span creation, factorial computation, and rounding to specified accuracy. +`DoubleExtensions` provides extension methods for `Double` covering Unix epoch conversion, time span creation, factorial computation, and precision rounding. This example starts with a Unix timestamp of `1617738277` and converts it to a local `DateTime` via `FromUnixEpochTime`, creates a `TimeSpan` from `3661` seconds using `ToTimeSpan`, computes `5!` using `Factorial`, and rounds `123456789.987654321` to the nearest thousand and million using `RoundOff`. Console output shows the resulting date (`O` format), the duration (`01:01:01`), the factorial value (`120`), and the rounded figures (`123457000` and `123000000`). ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.ExceptionExtensions.md b/.docfx/api/types/Cuemon.Extensions.ExceptionExtensions.md index ab376b25..af1edd4b 100644 --- a/.docfx/api/types/Cuemon.Extensions.ExceptionExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.ExceptionExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates flattening nested exception hierarchies using the extension method. +`ExceptionExtensions.Flatten` unwinds deeply nested exception hierarchies into a flat `IEnumerable` while preserving insertion order. This example constructs a four-level exception chain starting with an `InvalidOperationException("First")` containing `AmbiguousMatchException`, `OutOfMemoryException`, and an inner `AggregateException` with an `AccessViolationException`. Key setup includes building the nested exception tree and calling `Flatten()` to produce a flat sequence. Console output shows the count of `4` and each exception type name in order: `InvalidOperationException`, `AmbiguousMatchException`, `OutOfMemoryException`, `AccessViolationException`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.FuncFactory.md b/.docfx/api/types/Cuemon.Extensions.FuncFactory.md index 78d4846e..a818563f 100644 --- a/.docfx/api/types/Cuemon.Extensions.FuncFactory.md +++ b/.docfx/api/types/Cuemon.Extensions.FuncFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to create a `FuncFactory` from a delegate and execute it to produce a result. It shows both creating a factory with `Create` and invoking directly with `Invoke` using a mutable tuple. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.Extensions.Globalization.RegionInfoExtensions.md b/.docfx/api/types/Cuemon.Extensions.Globalization.RegionInfoExtensions.md index 0241131b..3f41519a 100644 --- a/.docfx/api/types/Cuemon.Extensions.Globalization.RegionInfoExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Globalization.RegionInfoExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use RegionInfoExtensions to retrieve the cultures associated with a specific geographic region. +`RegionInfoExtensions` provides extension methods for `RegionInfo` to enumerate all cultures associated with a geographic region via the `GetCultures` method. This example creates `RegionInfo` instances for `"US"` and `"JP"`, then calls `GetCultures()` on each to retrieve their associated culture collections. Key steps include iterating the culture results and printing the culture name and English name for each. Console output lists cultures such as `en-US` for the US and `ja-JP` for Japan, along with their English names. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Globalization.StatisticalRegionExtensions.md b/.docfx/api/types/Cuemon.Extensions.Globalization.StatisticalRegionExtensions.md index 7ea703f0..dd5ce612 100644 --- a/.docfx/api/types/Cuemon.Extensions.Globalization.StatisticalRegionExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Globalization.StatisticalRegionExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the to classify geographic regions using the UN M.49 standard. +`StatisticalRegionExtensions` provides extension methods for classifying geographic regions using the UN M.49 standard via the `World` class. This example retrieves `StatisticalRegion` instances for the world (`"001"`), Europe (`"150"`), Western Europe (`"155"`), Denmark (`"208"`), and the United States (`"840"`), then calls classification methods like `IsWorld`, `IsRegion`, `IsSubregion`, `IsCountryOrTerritory`, `IsArea`, and `HasIsoCodes`. It also traverses Denmark's hierarchy using `GetAncestors()` to show parent regions, finds the US by `RegionInfo`, and counts all countries via `world.Countries.Count()`. Console output confirms each classification, such as `True` for `denmark.IsCountryOrTerritory()` and the ancestor chain `Northern Europe → Europe → World`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Hosting.Environments.md b/.docfx/api/types/Cuemon.Extensions.Hosting.Environments.md index b9b41725..910c5ef1 100644 --- a/.docfx/api/types/Cuemon.Extensions.Hosting.Environments.md +++ b/.docfx/api/types/Cuemon.Extensions.Hosting.Environments.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to configure a .NET generic host to use the `Environments.LocalDevelopment` environment. The host is built and run with this environment setting. + ```csharp using Cuemon.Extensions.Hosting; using Microsoft.Extensions.Hosting; diff --git a/.docfx/api/types/Cuemon.Extensions.Hosting.HostEnvironmentExtensions.md b/.docfx/api/types/Cuemon.Extensions.Hosting.HostEnvironmentExtensions.md index 7210cfea..d652e4c6 100644 --- a/.docfx/api/types/Cuemon.Extensions.Hosting.HostEnvironmentExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Hosting.HostEnvironmentExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use HostEnvironmentExtensions to check if the current hosting environment is a local development or non-production environment. +`HostEnvironmentExtensions` provides extension methods for `IHostEnvironment` to check whether the current environment is a local development or non-production environment. This example takes an `IHostEnvironment` parameter and calls `IsLocalDevelopment()` to detect a developer machine and `IsNonProduction()` to check for any non-production environment. Key setup includes using these methods in conditional startup logic. Console output prints `"Running on a developer machine."` or `"Environment is not Production."` based on the check results. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.IO.ByteArrayExtensions.md b/.docfx/api/types/Cuemon.Extensions.IO.ByteArrayExtensions.md index f4aa97c9..308aa92e 100644 --- a/.docfx/api/types/Cuemon.Extensions.IO.ByteArrayExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.IO.ByteArrayExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to convert a byte array into a seekable MemoryStream using ByteArrayExtensions, with both synchronous and asynchronous overloads. +`ByteArrayExtensions` provides extension methods for converting `byte[]` into seekable `MemoryStream` instances, with both synchronous and asynchronous overloads. This example encodes `"Hello, World!"` into a UTF-8 byte array, then calls `ToStream()` and `ToStreamAsync()` to create streams, verifying that the synchronous stream has `Length = 13` and `CanSeek = True`. The content is read back with a `StreamReader` to confirm round-trip fidelity, and the asynchronous overload is demonstrated with a `CancellationToken`. Console output confirms the stream properties and that re-read content matches the original string. ```csharp using System.Threading; diff --git a/.docfx/api/types/Cuemon.Extensions.IO.StreamExtensions.md b/.docfx/api/types/Cuemon.Extensions.IO.StreamExtensions.md index b04346ad..e33dd9b0 100644 --- a/.docfx/api/types/Cuemon.Extensions.IO.StreamExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.IO.StreamExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to transform, compress, and decompress streams by invoking the available stream extensions. +`StreamExtensions` provides extension methods for `Stream` covering concatenation, encoding conversion, compression (GZip, Deflate, Brotli), and encoding detection. This example creates memory streams from `"Cue"` and `"mon"` and concatenates them with `Concat`, then converts the result to byte arrays, character arrays, and encoded strings both synchronously and asynchronously. It demonstrates compression round-trips for GZip, Deflate, and Brotli — each compressing a source stream, decompressing back, and reading the result — and also includes `TryDetectUnicodeEncoding` on a BOM-prefixed stream and `WriteAllAsync` for asynchronous writes. Console output confirms that all compressed round-trips preserve the original payload (`"gzip payload"`, `"deflate payload"`, `"brotli payload"`), that detected encoding is UTF-8, and that byte counts and string values agree across sync and async paths. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.IO.StringExtensions.md b/.docfx/api/types/Cuemon.Extensions.IO.StringExtensions.md index cc874295..1f6b25d1 100644 --- a/.docfx/api/types/Cuemon.Extensions.IO.StringExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.IO.StringExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to convert a string into a stream or text reader with . +`StringExtensions` in the `IO` namespace converts strings into `Stream` and `TextReader` instances for stream-based processing. This example starts with a JSON string `{"key":"value"}`, calls `ToStream` with a UTF-8 encoding configuration, `ToStreamAsync` for the asynchronous variant, and `ToTextReader` for direct text reader access. Key steps include verifying the stream has positive length, reading back the async stream's content with `ToEncodedStringAsync`, and reading the text reader content with `ReadToEnd`. Console output confirms the stream length is greater than zero, the async round-trip matches the original JSON, and the text reader reads the expected content. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.IO.TextReaderExtensions.md b/.docfx/api/types/Cuemon.Extensions.IO.TextReaderExtensions.md index 8cd86ddc..f02e220e 100644 --- a/.docfx/api/types/Cuemon.Extensions.IO.TextReaderExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.IO.TextReaderExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to read lines from a and copy its content asynchronously. +`TextReaderExtensions` provides extension methods for `TextReader` including `ReadAllLines`, `ReadAllLinesAsync`, and `CopyToAsync` for reading and copying text content. This example creates a multi-line string `"line one\nline two\nline three"`, converts it to a `TextReader` via `ToTextReader`, then calls `ReadAllLines` synchronously and `ReadAllLinesAsync` asynchronously to collect each line. It also uses `CopyToAsync` to write the reader content into a `StringWriter`. Console output confirms all three approaches produce the correct line count of `3` and that the copied content contains `"line two"`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.MethodDescriptorExtensions.md b/.docfx/api/types/Cuemon.Extensions.MethodDescriptorExtensions.md index bf1f1c8a..95af4685 100644 --- a/.docfx/api/types/Cuemon.Extensions.MethodDescriptorExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.MethodDescriptorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use MethodDescriptorExtensions to inspect a method's parameter information using the MethodDescriptor API. +`MethodDescriptorExtensions` provides extension methods for `MethodDescriptor` to inspect parameter information and method metadata. This example retrieves `MethodInfo` for `Console.WriteLine(string)` (which has a parameter) and `Guid.NewGuid()` (which has none), creates `MethodDescriptor` instances via `MethodDescriptor.Create`, then calls `HasParameters()` to check each for parameters. Key steps include resolving the method info via reflection and calling `HasParameters` on each descriptor. Console output confirms `True` for `WriteLine`, `False` for `NewGuid`, and displays the method name and caller name. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.MutableTupleFactory.md b/.docfx/api/types/Cuemon.Extensions.MutableTupleFactory.md index 1b03848b..7c6194d3 100644 --- a/.docfx/api/types/Cuemon.Extensions.MutableTupleFactory.md +++ b/.docfx/api/types/Cuemon.Extensions.MutableTupleFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to create mutable tuples with zero to five arguments using `MutableTupleFactory`. It shows accessing tuple values and constructing tuples of various sizes. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.Extensions.Net.ByteArrayExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.ByteArrayExtensions.md index d94bf03a..bc15af26 100644 --- a/.docfx/api/types/Cuemon.Extensions.Net.ByteArrayExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Net.ByteArrayExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to URL-encode byte array data for safe HTTP transmission using ByteArrayExtensions, with support for partial encoding and custom character encodings. +`ByteArrayExtensions` in the `Net` namespace URL-encodes byte arrays for safe HTTP transmission with support for partial encoding and custom character encodings. This example converts `"hello world"` to a UTF-8 byte array and calls `UrlEncode` to produce `hello%20world`, then demonstrates partial encoding of only the first five bytes (producing `hello`) and encoding with UTF-32 where each character is encoded as 4 bytes. Console output displays each encoded result, confirming that full encoding, partial ranges, and non-default encodings all produce correct percent-encoded output. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Net.DictionaryExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.DictionaryExtensions.md index 8fa7f22d..cb6c587c 100644 --- a/.docfx/api/types/Cuemon.Extensions.Net.DictionaryExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Net.DictionaryExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to build a query string from a dictionary of string arrays using DictionaryExtensions, with optional URL encoding. +`DictionaryExtensions` in the `Net` namespace converts `Dictionary` into URL query strings with optional percent-encoding. This example creates a dictionary with parameters `"search": ["dotnet"]`, `"page": ["1"]`, and `"tags": ["aspnet", "core"]`, then calls `ToQueryString()` to produce `search=dotnet&page=1&tags=aspnet&tags=core` and `ToQueryString(urlEncode: true)` for URL-encoded output. It also handles an empty dictionary that returns an empty string. Console output shows the raw query string, the encoded variant, and the empty-collection result `"Empty: ''"`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Net.Http.HttpManagerFactory.md b/.docfx/api/types/Cuemon.Extensions.Net.Http.HttpManagerFactory.md index c5e9cd81..73147ad5 100644 --- a/.docfx/api/types/Cuemon.Extensions.Net.Http.HttpManagerFactory.md +++ b/.docfx/api/types/Cuemon.Extensions.Net.Http.HttpManagerFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to create an HTTP manager using `HttpManagerFactory` with a custom `IHttpClientFactory`. It performs a GET request and prints the response content. + ```csharp using System; using System.Net.Http; diff --git a/.docfx/api/types/Cuemon.Extensions.Net.Http.UriExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.Http.UriExtensions.md index bd366a98..205da279 100644 --- a/.docfx/api/types/Cuemon.Extensions.Net.Http.UriExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Net.Http.UriExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to perform HTTP requests (GET, POST, PUT, DELETE, and more) directly on a Uri using UriExtensions, with support for media types and cancellation tokens. +`UriExtensions` provides HTTP extension methods directly on `Uri` covering GET, POST, PUT, DELETE, HEAD, OPTIONS, PATCH, and TRACE with support for custom headers, content types, and cancellation. This example assigns a stub `IHttpClientFactory` that returns a fixed `200 OK` response, then calls each HTTP method variant including `HttpGetAsync`, `HttpDeleteAsync`, `HttpPostAsync` with JSON content, `HttpPutAsync` with a stream body, `HttpPatchAsync`, `HttpTraceAsync`, and the generic `HttpAsync` overload for full `HttpRequestOptions` control with custom headers. It also demonstrates passing a `CancellationToken` with a timeout that triggers a `TaskCanceledException`. Console output confirms that each request returns `200 OK` and that cancellation is handled gracefully. ```csharp using System.Text; diff --git a/.docfx/api/types/Cuemon.Extensions.Net.HttpStatusCodeExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.HttpStatusCodeExtensions.md index 685107e0..2105600a 100644 --- a/.docfx/api/types/Cuemon.Extensions.Net.HttpStatusCodeExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Net.HttpStatusCodeExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the extension methods to classify HTTP status codes by range directly from values. +`HttpStatusCodeExtensions` provides extension methods for `HttpStatusCode` that classify status codes by HTTP range: informational (100–199), success (200–299), redirection (300–399), client error (400–499), and server error (500–599). This example evaluates `NotFound` (404), `OK` (200), `MovedPermanently` (301), `Forbidden` (403), `InternalServerError` (500), and `Continue` (100) using methods like `IsClientErrorStatusCode`, `IsSuccessStatusCode`, `IsRedirectionStatusCode`, and `IsServerErrorStatusCode`. Console output confirms each classification, such as `200 OK is success: True` and `404 NotFound is client error: True`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Net.NameValueCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.NameValueCollectionExtensions.md index ed3405d1..737f09a7 100644 --- a/.docfx/api/types/Cuemon.Extensions.Net.NameValueCollectionExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Net.NameValueCollectionExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to convert a NameValueCollection into a query string using NameValueCollectionExtensions, with optional URL encoding for safe HTTP transmission. +`NameValueCollectionExtensions` in the `Net` namespace converts `NameValueCollection` instances into URL query strings with optional percent-encoding. This example populates a collection with `"name": "John Doe"`, `"city": "Copenhagen"`, and duplicate key `"hobbies": ["reading", "coding"]`, then calls `ToQueryString()` to produce `name=John Doe&city=Copenhagen&hobbies=reading&hobbies=coding` and `ToQueryString(urlEncode: true)` where spaces become `+`. It also handles an empty collection that returns an empty string. Console output shows both query string variants and the empty result. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Net.StringExtensions.md b/.docfx/api/types/Cuemon.Extensions.Net.StringExtensions.md index d4a15a90..15145037 100644 --- a/.docfx/api/types/Cuemon.Extensions.Net.StringExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Net.StringExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to URL-encode and URL-decode strings directly using StringExtensions, with support for custom encodings and null-safe handling. +`StringExtensions` in the `Net` namespace provides URL-encoding and URL-decoding extension methods on `string` with custom encoding support and null-safe handling. This example encodes `"hello world"` to `"hello+world"`, decodes it back, encodes with UTF-32 where each character produces 4 bytes, and handles query-string special characters in `"name=Jane Doe&city=Copenhagen"` producing `"name%3dJane+Doe%26city%3dCopenhagen"`. It also demonstrates null input safety where `((string)null).UrlEncode()` returns `null`. Console output confirms each round-trip operation and the null-safe result. ```csharp using System.Text; diff --git a/.docfx/api/types/Cuemon.Extensions.ObjectExtensions.md b/.docfx/api/types/Cuemon.Extensions.ObjectExtensions.md index 3d1f92ee..93f30c05 100644 --- a/.docfx/api/types/Cuemon.Extensions.ObjectExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.ObjectExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the to wrap, convert, and adjust objects. +`ObjectExtensions` provides extension methods for type conversion with fallback (`As`), wrapper creation (`UseWrapper`), collection manipulation (`Adjust`, `Alter`), and delimited-string formatting. This example converts `"42"` to an `int`, handles `"not-a-number"` with a fallback of `99`, wraps a string with `UseWrapper` to attach metadata, adjusts a `List` by appending elements, and alters it in-place. Key steps include using the `As` method for safe casts, `UseWrapper` for attaching diagnostic data, and `Adjust`/`Alter` for immutable/mutable collection operations. Console output confirms each conversion result, the wrapper data value `"example"`, hash codes, and the delimited string `"1;2;3;4"`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Reflection.AssemblyExtensions.md b/.docfx/api/types/Cuemon.Extensions.Reflection.AssemblyExtensions.md index 51ede81b..577df48f 100644 --- a/.docfx/api/types/Cuemon.Extensions.Reflection.AssemblyExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Reflection.AssemblyExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to retrieve assembly version, file version, and product version information from an assembly using AssemblyExtensions. +`AssemblyExtensions` provides extension methods for `Assembly` to retrieve version information and debug-build status. This example obtains the entry assembly and calls `GetAssemblyVersion`, `GetFileVersion`, and `GetProductVersion` to read version attributes, then checks `HasAlphanumericVersion` and `IsSemanticVersion()` on the returned `SourceVersion` objects. It also calls `IsDebugBuild()` to determine whether the assembly was compiled in Debug configuration. Console output displays each version string (e.g., `1.0.0.0`), whether it has alphanumeric or semantic version characteristics, and the debug-build flag. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Reflection.MemberInfoExtensions.md b/.docfx/api/types/Cuemon.Extensions.Reflection.MemberInfoExtensions.md index fc968739..3f79f382 100644 --- a/.docfx/api/types/Cuemon.Extensions.Reflection.MemberInfoExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Reflection.MemberInfoExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates checking whether a member has specific custom attributes using the extension method. +`MemberInfoExtensions` provides extension methods for `MemberInfo` to check for the presence of one or more custom attributes via `HasAttributes`. This example defines a class with an `[Description]`-annotated property, an `[Obsolete]`-annotated field, and a regular property with no attributes, then iterates all public instance members calling `HasAttributes` with `DescriptionAttribute` and `ObsoleteAttribute` types. Console output shows each member name, its `MemberType`, and whether it carries any of the target attributes, demonstrating attribute-based filtering or validation of reflected members. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Reflection.PropertyInfoExtensions.md b/.docfx/api/types/Cuemon.Extensions.Reflection.PropertyInfoExtensions.md index fa887e2a..b8514589 100644 --- a/.docfx/api/types/Cuemon.Extensions.Reflection.PropertyInfoExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Reflection.PropertyInfoExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to detect whether a property uses an auto-implemented backing field. +`PropertyInfoExtensions` provides extension methods for `PropertyInfo` to detect auto-implemented properties via `IsAutoProperty`. This example defines a `Sample` class with an auto-property (`AutoProperty`) and a manually implemented property (`ManualProperty`) that uses a backing field with a null-guard in its setter, then retrieves both `PropertyInfo` instances via reflection and calls `IsAutoProperty` on each. Console output displays `True` for the auto-property and `False` for the manual one, confirming the extension correctly distinguishes compiler-generated get/set accessors from custom implementations. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Reflection.TypeExtensions.md b/.docfx/api/types/Cuemon.Extensions.Reflection.TypeExtensions.md index daf41ae2..c87b6531 100644 --- a/.docfx/api/types/Cuemon.Extensions.Reflection.TypeExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Reflection.TypeExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to inspect a type hierarchy and member set with . +`TypeExtensions` in the `Reflection` namespace provides methods for inspecting type hierarchies and enumerating members across the inheritance tree. This example uses `typeof(Stream)` to retrieve derived, inherited, and hierarchy types via `GetDerivedTypes`, `GetInheritedTypes`, and `GetHierarchyTypes`, then uses `TypeCatalog` (extending `BaseCatalog`) with `GetAllProperties`, `GetAllEvents`, `GetAllFields`, and `GetAllMethods` to enumerate members. It also demonstrates `GetRuntimePropertiesExceptOf` to exclude inherited properties, `GetEmbeddedResources` for assembly resource lookup, and `ToFullNameIncludingAssemblyName` for a fully qualified type name. Console output confirms member names, hierarchy inclusion (e.g., `Stream` in `GetHierarchyTypes`), and assembly-qualified type identity. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Runtime.Hierarchy.md b/.docfx/api/types/Cuemon.Extensions.Runtime.Hierarchy.md index 9823d73b..0ddecae9 100644 --- a/.docfx/api/types/Cuemon.Extensions.Runtime.Hierarchy.md +++ b/.docfx/api/types/Cuemon.Extensions.Runtime.Hierarchy.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to build and traverse a hierarchical tree structure using `Hierarchy`. It shows adding nodes, printing paths, searching for nodes with `Find`, and generating an object hierarchy from an anonymous type. + ```csharp using System; using System.Linq; diff --git a/.docfx/api/types/Cuemon.Extensions.Runtime.HierarchyDecoratorExtensions.md b/.docfx/api/types/Cuemon.Extensions.Runtime.HierarchyDecoratorExtensions.md index 4e38ff56..82a9aaab 100644 --- a/.docfx/api/types/Cuemon.Extensions.Runtime.HierarchyDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Runtime.HierarchyDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the to navigate a hierarchy, replace matching nodes, and materialize typed values from nodes. +`HierarchyDecoratorExtensions` provides extension methods on `Decorator.Enclose` for navigating, replacing, and materializing hierarchy trees built from `Hierarchy` nodes. This example builds a three-level string hierarchy (`root` → `child-one` → `grandchild`) and demonstrates root navigation, ancestor/descendant/sibling traversal, node replacement, and `DataPair` value extraction using typed formatters like `UseConvertibleFormatter`, `UseDateTimeFormatter`, and `UseGuidFormatter`. Key steps include using `Decorator.Enclose` to call methods such as `Root()`, `AncestorsAndSelf()`, `Replace()`, and `UseCollection()`. Console output confirms the root node name (`"root"`), ancestor chain (`"root > child-one"`), and typed values extracted from `DataPair` nodes. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Runtime.Serialization.HierarchySerializer.md b/.docfx/api/types/Cuemon.Extensions.Runtime.Serialization.HierarchySerializer.md index b886b195..93395a53 100644 --- a/.docfx/api/types/Cuemon.Extensions.Runtime.Serialization.HierarchySerializer.md +++ b/.docfx/api/types/Cuemon.Extensions.Runtime.Serialization.HierarchySerializer.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use to convert any object graph into a hierarchical node structure and display its path-based tree representation. +`HierarchySerializer` converts any object graph into a hierarchical node structure (`IHierarchy`) for inspection and path-based representation. This example creates a `ReportRoot` with a `Name` of `"alpha"` and a `ReportChild` with `Count = 7`, passes it to the `HierarchySerializer` constructor, and accesses the root node's instance type name, checks whether it has children, and prints the tree path representation via `ToString()`. Key steps include constructing a serializer from a plain object and reading the resulting node properties. Console output displays the `ReportRoot` type name, `True` for `HasChildren`, and a path-based tree showing `ReportRoot > ReportChild`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.StringExtensions.md b/.docfx/api/types/Cuemon.Extensions.StringExtensions.md index 9ca0cb4c..42d0df14 100644 --- a/.docfx/api/types/Cuemon.Extensions.StringExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.StringExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the extension methods to manipulate and inspect a string value. +`StringExtensions` provides a comprehensive set of extension methods for `string` covering trimming, casing, content inspection, encoding, parsing, and utility operations. This example applies `TrimAll` to remove whitespace, `ToCasing` with `LowerCase`, `UpperCase`, and `TitleCase` modes, and content checks like `IsEmailAddress`, `IsGuid`, `IsHex`, `IsNumeric`, and `IsBase64`. It also demonstrates encoding conversions (`ToByteArray`, `ToHexadecimal`, `FromBase64`, `FromUrlEncodedBase64`), enum parsing (`"Monday".ToEnum()`), delimited-string splitting (`SplitDelimited` with quoted fields), and utility operations such as `Count`, `Difference`, `JsEscape`, `Chunk`, `PrefixWith`, `SuffixWith`, and `ToGuid`. Console output confirms transformations like `" Hello, World! "` trimmed to `"Hello,World!"`, `"hello".SuffixWith(" world")` producing `"hello world"`, and `"Monday".ToEnum()` returning `DayOfWeek.Monday`. ```csharp using System.Text; diff --git a/.docfx/api/types/Cuemon.Extensions.TesterFuncFactory.md b/.docfx/api/types/Cuemon.Extensions.TesterFuncFactory.md index 9bff3609..f448270c 100644 --- a/.docfx/api/types/Cuemon.Extensions.TesterFuncFactory.md +++ b/.docfx/api/types/Cuemon.Extensions.TesterFuncFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to create a `TesterFuncFactory` from a TryParse-style delegate. It shows both a successful parse and a failure case, printing the parsed value or fallback accordingly. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.DateTimeConverter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.DateTimeConverter.md index 78eb65db..f81ce304 100644 --- a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.DateTimeConverter.md +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.DateTimeConverter.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to register and use the to serialize and deserialize values with a custom format and culture-specific formatting. +`DateTimeConverter` enables custom format and culture-aware serialization of `DateTime` values in `System.Text.Json`. This example registers the converter in `JsonSerializerOptions` with the French date format `"dd/MM/yyyy"` and `fr-FR` culture, then serializes a UTC `DateTime` (`2026-06-16`). The JSON output contains the date as `"16/06/2026"`. Deserializing the same JSON back to a `DateTime` and formatting it again with `"dd/MM/yyyy"` produces `"16/06/2026"`, confirming round-trip fidelity with culture-aware formatting. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.ExceptionConverter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.ExceptionConverter.md index 5218675b..ae7731a0 100644 --- a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.ExceptionConverter.md +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.ExceptionConverter.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to serialize an to JSON including its stack trace and data dictionary. +`ExceptionConverter` serializes `Exception` instances to JSON, including optional stack trace and `Data` dictionary content. This example configures `JsonSerializerOptions` with `WriteIndented = true` and adds the converter with `includeStackTrace: true` and `includeData: true`, then creates a nested `InvalidOperationException("Outer operation failed.")` with an inner `InvalidOperationException("Inner operation failed.")` and a `CorrelationId` data entry. The resulting JSON includes top-level fields (`Type`, `Source`, `Message`, `Stack`, `Data`) and a nested `Inner` section for the inner exception with its own `Type` and `Message`. Console output displays the complete JSON structure. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.JsonConverterCollectionExtensions.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.JsonConverterCollectionExtensions.md index 1fa0c612..69a8f23e 100644 --- a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.JsonConverterCollectionExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.JsonConverterCollectionExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the to configure a custom with specialized converters. +`JsonConverterCollectionExtensions` provides fluent extension methods for building a `List` with specialized converters and applying them to a `JsonFormatter`. This example calls `AddDateTimeConverter`, `AddStringEnumConverter`, `AddStringFlagsEnumConverter`, `AddExceptionConverter`, `AddFailureConverter`, `AddTransientFaultExceptionConverter`, and `AddDataPairConverter` to register each converter, then demonstrates `RemoveAllOf()` and `RemoveAllOf(typeof(TimeSpan))` to remove converters by type. The converter list is applied to a `JsonFormatter` with `CamelCase` naming policy to serialize an anonymous person object. Console output displays the resulting JSON with the configured formatting. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringEnumConverter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringEnumConverter.md index 9391952b..c25f320f 100644 --- a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringEnumConverter.md +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringEnumConverter.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the to serialize and deserialize non-flags enum values as their string representation rather than their underlying integer value. +`StringEnumConverter` serializes and deserializes non-flags enum values as their string names rather than underlying integer values in `System.Text.Json`. This example creates `JsonSerializerOptions` with `CamelCase` naming policy and adds the converter, then serializes an anonymous object with `DayOfWeek.Friday` and `UriKind.Relative`. The JSON output shows `"friday"` and `"relative"` instead of numeric values like `5` or `2`. Deserializing the JSON back into a typed `Payload` object confirms that the string values round-trip correctly to the original enum members, with `restored.Day` output as `Friday`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringFlagsEnumConverter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringFlagsEnumConverter.md index 854110ef..b508e948 100644 --- a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringFlagsEnumConverter.md +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.StringFlagsEnumConverter.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the to serialize and deserialize enum values decorated with as an array of strings. +`StringFlagsEnumConverter` serializes and deserializes `[Flags]` enum values as an array of active flag string names instead of a single integer. This example registers the converter in `JsonSerializerOptions`, then serializes `FileShare.Read | FileShare.Write` which produces the JSON array `["Read", "Write"]`. Deserializing the array back to a `FileShare` value restores the combined flags, and the output displays `Read, Write`, confirming round-trip correctness for flags enum values. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.TransientFaultExceptionConverter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.TransientFaultExceptionConverter.md index 2a332b13..4c57d0d2 100644 --- a/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.TransientFaultExceptionConverter.md +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Converters.TransientFaultExceptionConverter.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to serialize and deserialize a using the . +`TransientFaultExceptionConverter` serializes and deserializes `TransientFaultException` instances including their `TransientFaultEvidence` with attempt count, recovery wait times, latency, and method signature. This example creates a `TransientFaultException` with evidence (`Attempts = 3`, `RecoveryWaitTime = 2s`, etc.) and a method descriptor, then configures a `JsonFormatter` with the converter and serializes it to JSON. The deserialization part reads the JSON back through the same formatter, reconstructing the exception with its `Evidence` properties intact. Console output displays the round-tripped message (`"Failed to connect after 3 retries."`) and evidence attempt count (`3`). ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.DynamicJsonConverter.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.DynamicJsonConverter.md index 7a59eb41..cebad9a3 100644 --- a/.docfx/api/types/Cuemon.Extensions.Text.Json.DynamicJsonConverter.md +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.DynamicJsonConverter.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to register a custom JSON converter for the `Version` type using `DynamicJsonConverter`. It serializes a version to JSON and deserializes it back, printing each result. + ```csharp using System; using System.Text.Json; diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonNamingPolicyExtensions.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonNamingPolicyExtensions.md index d7f27607..253662b6 100644 --- a/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonNamingPolicyExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonNamingPolicyExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates applying a naming policy to a property name using the extension method. +`JsonNamingPolicyExtensions` provides the `DefaultOrConvertName` extension method that applies a `JsonNamingPolicy` to a property name or returns it unchanged when the policy is `null`. This example applies `JsonNamingPolicy.CamelCase` to `"OrderDate"`, producing `"orderDate"`, and demonstrates that a `null` policy returns the name unaltered. Key steps include calling `DefaultOrConvertName` directly on a policy instance and using it within a `JsonSerializerOptions` configuration. Console output confirms `"orderDate"` for the camelCase transformation and `"OrderDate"` for the null policy case, and `"shippingAddress"` when sourced from serializer options. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonSerializerOptionsExtensions.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonSerializerOptionsExtensions.md index 1284e554..eebc781b 100644 --- a/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonSerializerOptionsExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.JsonSerializerOptionsExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates cloning and applying property naming policies using the and extension methods. +`JsonSerializerOptionsExtensions` provides `Clone`, `SetPropertyName`, and `DefaultOrConvertName` extension methods for duplicating and transforming `JsonSerializerOptions` instances. This example creates base options with `CamelCase` and `WriteIndented = true`, clones them with `WriteIndented = false` via `Clone`, and demonstrates `SetPropertyName` which converts property names according to the naming policy. Key steps include passing a setup delegate to `Clone` to override specific settings without modifying the original. Console output confirms the original has `WriteIndented = True` while the clone has `False`, and `SetPropertyName("OrderDate")` returns `"orderDate"` under CamelCase or `"OrderDate"` when no policy is set. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonWriterExtensions.md b/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonWriterExtensions.md index a4c635d1..d784faed 100644 --- a/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonWriterExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Text.Json.Utf8JsonWriterExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates writing a dynamic object to JSON using the extension method. +`Utf8JsonWriterExtensions` provides the `WriteObject` extension method for serializing .NET objects directly into a `Utf8JsonWriter` stream. This example creates a `Person` instance with `Name`, `Age`, and `City` properties, configures `JsonSerializerOptions` with `CamelCase` naming and indented output, and calls `WriteObject` on a `Utf8JsonWriter` backed by a `MemoryStream`. Key steps include flushing the writer and reading the stream content as a UTF-8 string. Console output displays the formatted JSON with camelCase property names, such as `"name": "John Doe"`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Text.StringExtensions.md b/.docfx/api/types/Cuemon.Extensions.Text.StringExtensions.md index 3da4170d..0dcbaa94 100644 --- a/.docfx/api/types/Cuemon.Extensions.Text.StringExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Text.StringExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to encode strings between different character encodings using StringExtensions, with support for fallback handling and ASCII sanitization. +`StringExtensions` in the `Text` namespace provides encoding conversion between character encodings with custom fallback handling and ASCII sanitization. This example takes `"Café au lait: 2,50 €"` and converts it to UTF-8 (preserves all characters), ASCII with `EncoderReplacementFallback("?")` (replaces `é` and `€` with `?`), and Windows-1252 (preserves Western European characters). It also demonstrates `ToAsciiEncodedString` for quick ASCII sanitization that removes unsupported characters by default. Console output shows each encoded result, such as `"Caf? au lait: 2,50 ?"` for the ASCII replacement case and `"Cafe au lait: 2,50 "` for the quick ASCII sanitization. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.TimeSpanExtensions.md b/.docfx/api/types/Cuemon.Extensions.TimeSpanExtensions.md index c7177859..c8136791 100644 --- a/.docfx/api/types/Cuemon.Extensions.TimeSpanExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.TimeSpanExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the extension methods to round, floor, and ceiling values, and to retrieve high-resolution time units. +`TimeSpanExtensions` provides extension methods for `TimeSpan` including high-resolution unit queries (`GetTotalNanoseconds`, `GetTotalMicroseconds`) and interval snapping (`Floor`, `Ceiling`, `Round`). This example creates `TimeSpan.FromHours(1)` and `TimeSpan.FromMinutes(280)`, then calls `GetTotalNanoseconds` and `GetTotalMicroseconds` on the hour, `Floor(1, TimeUnit.Hours)` and `Ceiling(1, TimeUnit.Hours)` on 280 minutes, and `Round` on 45 minutes with both up and down directions. Console output shows the nanosecond and microsecond values, the floored/ceiling hours, and the rounded minutes. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.TypeExtensions.md b/.docfx/api/types/Cuemon.Extensions.TypeExtensions.md index d6f1a537..797fa1f2 100644 --- a/.docfx/api/types/Cuemon.Extensions.TypeExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.TypeExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the to inspect types with concise extension methods. +`TypeExtensions` provides extension methods for `Type` that simplify classification and metadata retrieval via methods like `ToFriendlyName`, `ToTypeCode`, and various `Has*`/`Is*` predicates. This example inspects `IList`, `ConcurrentDictionary`, `StringComparer`, `int?`, and anonymous types, calling `HasEnumerableImplementation`, `HasDictionaryImplementation`, `IsNullable`, `IsComplex`, `GetDefaultValue`, and `ToFriendlyName`. It also demonstrates `HasAnonymousCharacteristics` on an anonymous object, `HasTypes` for hierarchy checks, `HasInterfaces` for generic interface matching, and `HasAttributes` for attribute presence. Console output prints friendly type names like `IList`, boolean capability flags, and the default value `0` for `typeof(int)`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Wrapper.md b/.docfx/api/types/Cuemon.Extensions.Wrapper.md index a47e4e22..d3c9fe93 100644 --- a/.docfx/api/types/Cuemon.Extensions.Wrapper.md +++ b/.docfx/api/types/Cuemon.Extensions.Wrapper.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to wrap values using `Wrapper` to access the inner instance, its type, and a parsed string representation. It shows wrapping both an integer and a string value. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.DateTimeExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.DateTimeExtensions.md index 18bbbbc6..d91cd2aa 100644 --- a/.docfx/api/types/Cuemon.Extensions.Xml.DateTimeExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Xml.DateTimeExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to format DateTime values as XML strings using DateTimeExtensions, supporting UTC, local, round-trip, and unspecified serialization modes. +`DateTimeExtensions` in the `Xml` namespace formats `DateTime` values as XML strings using `XmlDateTimeSerializationMode` enum values. This example creates `DateTime.UtcNow` and `DateTime.Now`, then calls `ToString` with `XmlDateTimeSerializationMode.Utc` (appends `Z`), `Local` (includes timezone offset like `+02:00`), `RoundtripKind` (preserves `Kind` information), and `Unspecified` (omits timezone info). Console output for each mode shows how time zone information is represented or omitted, such as `2026-06-16T12:34:56.789Z` for UTC and `2026-06-16T14:34:56.789+02:00` for local. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.HierarchyExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.HierarchyExtensions.md index 40d9fe22..382253ae 100644 --- a/.docfx/api/types/Cuemon.Extensions.Xml.HierarchyExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Xml.HierarchyExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to inspect and query XML serialization metadata such as qualified entity names, enumerable detection, and XML ignore attributes using HierarchyExtensions. +`HierarchyExtensions` provides extension methods for inspecting XML serialization metadata on hierarchy nodes, including qualified entity names, enumerable detection, and XML ignore and ordering attributes. This example creates `HierarchySerializer` instances for `CatalogDocument` (with `[XmlAttribute]` on `Id` and a `List Tags` property) and `IgnoredDocument` (with `[XmlIgnore]` on `Hidden`), then calls `GetXmlQualifiedEntity`, `IsNodeEnumerable`, `HasXmlIgnoreAttribute`, and `OrderByXmlAttributes` on individual nodes. Console output shows the qualified entity local name, whether the node is enumerable, whether it has `[XmlIgnore]`, and the reordered element order. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.Serialization.Converters.XmlConverterExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.Serialization.Converters.XmlConverterExtensions.md index 6c1e282a..a667a3a7 100644 --- a/.docfx/api/types/Cuemon.Extensions.Xml.Serialization.Converters.XmlConverterExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Xml.Serialization.Converters.XmlConverterExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example registers built-in and custom XML converters, then reuses the configured list through . +`XmlConverterExtensions` provides extension methods for building a list of `XmlConverter` instances with both built-in and custom converters that can be reused through `XmlSerializer`. This example creates an `IList` and calls `InsertXmlConverter` to register a custom string converter at position 0, `AddXmlConverter` for an integer converter, and fluent methods like `AddEnumerableConverter`, `AddExceptionDescriptorConverter`, `AddUriConverter`, `AddDateTimeConverter`, `AddTimeSpanConverter`, `AddStringConverter`, `AddExceptionConverter`, and `AddFailureConverter`. It then uses `FirstOrDefaultWriterConverter` and `FirstOrDefaultReaderConverter` to query converters, applies them to `XmlSerializerOptions`, and serializes a `Uri` to XML. Console output confirms converter lookup results and displays the serialized XML. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.StreamExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.StreamExtensions.md index f1a15fc4..cacdb660 100644 --- a/.docfx/api/types/Cuemon.Extensions.Xml.StreamExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Xml.StreamExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to work with XML data from streams using StreamExtensions, including creating XmlReaders, copying with indented formatting, detecting encoding, and removing namespace declarations. +`StreamExtensions` in the `Xml` namespace provides stream-based XML operations including `XmlReader` creation, indented copying, encoding detection, and namespace removal. This example loads an XML string into a `MemoryStream` and demonstrates four operations: `ToXmlReader` to parse element names, `CopyXmlStream` with `Indent = true` for pretty-printed XML output, `TryDetectXmlEncoding` to identify `UTF-8` encoding, and `RemoveXmlNamespaceDeclarations` to strip namespace prefixes from elements. Each operation repositions the stream to `Position = 0` before proceeding. Console output shows element names (`root`, `item`), the indented XML, the detected encoding name (`Unicode (UTF-8)`), and the namespace-cleaned content. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.StringExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.StringExtensions.md index 57e8f2e6..330ad107 100644 --- a/.docfx/api/types/Cuemon.Extensions.Xml.StringExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Xml.StringExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to escape and unescape XML special characters, sanitize strings for use as XML element names, and remove invalid XML control characters using StringExtensions. +`StringExtensions` in the `Xml` namespace provides XML escaping, unescaping, element name sanitization, and control-character removal for text content. This example starts with `"Use & < > \" ' in XML"` and calls `EscapeXml` to produce `"Use & < > " ' in XML"`, then round-trips back with `UnescapeXml`. It also demonstrates `SanitizeXmlElementName` on `"1st Element Name!"` to replace leading digits and punctuation with underscores, and `SanitizeXmlElementText` to remove control characters except `\t`, `\n`, `\r`, with optional CDATA section protection that removes `"]]>"` sequences. Console output displays each transformation result. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.UriExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.UriExtensions.md index 1689974b..8e96e2b6 100644 --- a/.docfx/api/types/Cuemon.Extensions.Xml.UriExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Xml.UriExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create an XmlReader from a file URI using UriExtensions, with configurable reader settings for comment handling and DTD processing. +`UriExtensions` in the `Xml` namespace creates `XmlReader` instances from file URIs with configurable reader settings. This example writes a simple XML snippet to a temporary file, constructs a `Uri` pointing to it, and calls `ToXmlReader` with settings that ignore XML comments and disable DTD processing. After positioning the reader with `MoveToFirstElement`, the local element name is output as `"root"`. A `finally` block ensures the temporary file is deleted after the demonstration. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.XmlReaderExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.XmlReaderExtensions.md index b892b491..f94d5a40 100644 --- a/.docfx/api/types/Cuemon.Extensions.Xml.XmlReaderExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Xml.XmlReaderExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to navigate, read, chunk, and convert XML data using XmlReaderExtensions, including moving to the first element, building hierarchy trees, and streaming XML content. +`XmlReaderExtensions` provides extension methods for `XmlReader` including navigation, hierarchy building, chunked reading, and stream conversion. This example starts with an XML string containing `` and two `` elements, then demonstrates `MoveToFirstElement` to position at the first element, `ToHierarchy` to build a tree of element nodes with child names, `Chunk(1)` to stream only the first element as a new indented `XmlReader`, and `ToStream` to convert the entire reader content into a readable stream. Console output shows the root element name (`"root"`), a hierarchy description with child names, the outer XML of the first chunk (`First`), and the full XML content. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Extensions.Xml.XmlWriterExtensions.md b/.docfx/api/types/Cuemon.Extensions.Xml.XmlWriterExtensions.md index 52c81334..612969d5 100644 --- a/.docfx/api/types/Cuemon.Extensions.Xml.XmlWriterExtensions.md +++ b/.docfx/api/types/Cuemon.Extensions.Xml.XmlWriterExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example writes XML directly to an by combining object serialization, qualified element names, and conditional wrapper elements. +`XmlWriterExtensions` provides extension methods for `XmlWriter` including object serialization, qualified element names, conditional wrapping, and root element generation. This example creates an `XmlWriter` targeting a `StringWriter` with indented, declaration-free settings, then calls `WriteObject` to serialize an `InvalidOperationException`, `WriteStartElement` with an `XmlQualifiedEntity("Cuemon")` for a standalone element, `WriteEncapsulatingElementWhenNotNull` to conditionally wrap an exception in a `"MyWrappedElement"`, and `WriteXmlRootElement` to produce a `Root` element with a `"cuemon"` namespace URI. Console output displays four separate XML results showing the serialized exception, the standalone element, the wrapped exception, and the namespace-qualified root element. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Globalization.World.md b/.docfx/api/types/Cuemon.Globalization.World.md index b77562e1..b1702b13 100644 --- a/.docfx/api/types/Cuemon.Globalization.World.md +++ b/.docfx/api/types/Cuemon.Globalization.World.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to query global regions, statistical regions, and cultures using the `World` class. It prints region counts, looks up the United States by M.49 code, and enumerates cultures for a specific region. + ```csharp using System; using System.Globalization; diff --git a/.docfx/api/types/Cuemon.IO.AsyncStreamCompressionOptions.md b/.docfx/api/types/Cuemon.IO.AsyncStreamCompressionOptions.md index e34e05a4..e36d048d 100644 --- a/.docfx/api/types/Cuemon.IO.AsyncStreamCompressionOptions.md +++ b/.docfx/api/types/Cuemon.IO.AsyncStreamCompressionOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to configure AsyncStreamCompressionOptions to control compression level and buffer size when compressing stream data asynchronously. +`AsyncStreamCompressionOptions` configures compression level and buffer size for asynchronous stream compression operations. This example creates default options with `CompressionLevel.Optimal` and an `81920` buffer size, fast options with `CompressionLevel.Fastest` and a `4096` buffer for CPU-sensitive scenarios, and no-compression options for testing or passthrough use. Key steps include compressing sample data using `DeflateStream` with the configured options and comparing original vs. compressed byte sizes. Console output shows the default level (`Optimal`), buffer size, and the compression ratio between original and compressed sizes. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.IO.AsyncStreamCopyOptions.md b/.docfx/api/types/Cuemon.IO.AsyncStreamCopyOptions.md index 0d876111..27329a2c 100644 --- a/.docfx/api/types/Cuemon.IO.AsyncStreamCopyOptions.md +++ b/.docfx/api/types/Cuemon.IO.AsyncStreamCopyOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to configure AsyncStreamCopyOptions to control buffer size and stream lifetime when copying data asynchronously between streams. +`AsyncStreamCopyOptions` configures buffer size and stream lifetime for asynchronous stream copy operations. This example creates options with `BufferSize = 4096` and `LeaveOpen = true`, then copies UTF-8 string content from one `MemoryStream` to another using `Decorator.Enclose(source).CopyStreamAsync(destination, options.BufferSize, ...)`. The copied data is read back as a string and printed to confirm `"Copy me asynchronously."` was transferred intact, while the source stream remains open due to `LeaveOpen = true`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.IO.AsyncStreamEncodingOptions.md b/.docfx/api/types/Cuemon.IO.AsyncStreamEncodingOptions.md index e339a063..0a12ec22 100644 --- a/.docfx/api/types/Cuemon.IO.AsyncStreamEncodingOptions.md +++ b/.docfx/api/types/Cuemon.IO.AsyncStreamEncodingOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to configure `AsyncStreamEncodingOptions` when reading text from a stream asynchronously. +`AsyncStreamEncodingOptions` configures encoding, preamble handling, and stream lifetime when reading text from a stream asynchronously. This example creates options with `Encoding.UTF8`, `PreambleSequence.Remove` to strip the BOM from output, and `LeaveOpen = false`, then creates a `MemoryStream` with UTF-8 encoded text and reads the content using a `StreamReader` with the configured encoding. Console output displays `"Hello, AsyncStreamEncodingOptions!"`, confirming the text was read correctly with the configured encoding settings. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.IO.AsyncStreamReaderOptions.md b/.docfx/api/types/Cuemon.IO.AsyncStreamReaderOptions.md index 03b87c45..a87777b8 100644 --- a/.docfx/api/types/Cuemon.IO.AsyncStreamReaderOptions.md +++ b/.docfx/api/types/Cuemon.IO.AsyncStreamReaderOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to configure AsyncStreamReaderOptions to control encoding, preamble handling, and buffer size when reading stream content asynchronously. +`AsyncStreamReaderOptions` configures encoding, preamble handling, and buffer size for asynchronous stream reading operations. This example creates a `MemoryStream` with UTF-8 preamble bytes followed by `"Hej Cuemon"` text, sets up options with `PreambleSequence.Remove` to strip the BOM, `Encoding = EncodingOptions.DefaultEncoding` for auto-detection, and `BufferSize = 4096`, then calls `ToEncodedStringAsync` via the decorator pattern. Console output shows the encoding web name (`utf-8`) and the decoded text with the preamble stripped, confirming correct preamble handling. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.IO.FileInfoOptions.md b/.docfx/api/types/Cuemon.IO.FileInfoOptions.md index bce6b1de..e6d6a443 100644 --- a/.docfx/api/types/Cuemon.IO.FileInfoOptions.md +++ b/.docfx/api/types/Cuemon.IO.FileInfoOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to configure FileInfoOptions to control the number of bytes read from a file, useful for reading headers or file signatures. +`FileInfoOptions` controls the maximum number of bytes read from a file, useful for reading headers or file signatures. This example demonstrates default options where `BytesToRead = 0` means no limit, a 100-byte limit for reading file headers, and a 16-byte limit for file signature detection. A temporary file with 1000 `'A'` characters is created, then read with the 100-byte limit and the actual bytes read is reported. Console output shows the default `BytesToRead` value, the requested vs. actual bytes read, and confirms that `BytesToRead = 0` means no limit. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.IO.StreamCompressionOptions.md b/.docfx/api/types/Cuemon.IO.StreamCompressionOptions.md index 852958ab..120a8f5e 100644 --- a/.docfx/api/types/Cuemon.IO.StreamCompressionOptions.md +++ b/.docfx/api/types/Cuemon.IO.StreamCompressionOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to configure StreamCompressionOptions to control the compression level when compressing stream data. +`StreamCompressionOptions` configures the compression level for synchronous stream compression operations. This example creates default options with `CompressionLevel.Optimal`, fast options with `CompressionLevel.Fastest`, and no-compression options for testing, then compresses sample data using `DeflateStream` with the fastest level. Console output shows the default compression level (`Optimal`), the original byte size of sample text, and the compressed byte size after deflate compression, demonstrating the compression ratio achieved. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.IO.StreamCopyOptions.md b/.docfx/api/types/Cuemon.IO.StreamCopyOptions.md index 20933f23..1b03a3e2 100644 --- a/.docfx/api/types/Cuemon.IO.StreamCopyOptions.md +++ b/.docfx/api/types/Cuemon.IO.StreamCopyOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to configure StreamCopyOptions to control buffer size and whether the source stream remains open after copying. +`StreamCopyOptions` configures buffer size and whether the source stream remains open after synchronous copy operations. This example creates custom options with `BufferSize = 4096` and `LeaveOpen = true`, converts a `MemoryStream` to a byte array via the decorator pattern with these options, then confirms the source stream is still readable (`CanRead = True`). It also demonstrates the default behavior where `LeaveOpen = false` disposes the source stream after copying, showing `CanRead = False`. Console output displays the byte count (`26`), the decoded string (`"Hello, StreamCopyOptions!"`), and the stream's open/disposed state. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.IO.StreamDecoratorExtensions.md b/.docfx/api/types/Cuemon.IO.StreamDecoratorExtensions.md index cc3ac468..f7d29942 100644 --- a/.docfx/api/types/Cuemon.IO.StreamDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.IO.StreamDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the extension methods for stream operations including conversion, compression, and copying. +`StreamDecoratorExtensions` provides extension methods on `Decorator.Enclose` for stream operations including byte array conversion, string encoding, compression (GZip, Deflate, Brotli), and copying. This example creates multiple `MemoryStream` instances with sample text and demonstrates `ToByteArray` and `ToByteArrayAsync`, `ToEncodedString` and `ToEncodedStringAsync`, `CopyStream` and `CopyStreamAsync`, `CompressGZip`/`DecompressGZip`, `CompressDeflate`/`DecompressDeflate`, `CompressBrotli`/`DecompressBrotli`, and `WriteAllAsync` — all via the decorator pattern. Console output confirms each operation's result, such as byte array lengths, decompressed strings matching the original content, and stream copy sizes. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.IO.StreamEncodingOptions.md b/.docfx/api/types/Cuemon.IO.StreamEncodingOptions.md index 9bf9c91e..91151a77 100644 --- a/.docfx/api/types/Cuemon.IO.StreamEncodingOptions.md +++ b/.docfx/api/types/Cuemon.IO.StreamEncodingOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to configure StreamEncodingOptions for preamble handling and encoding detection when reading stream content as strings. +`StreamEncodingOptions` configures preamble handling and encoding detection when reading stream content as strings. This example creates a `MemoryStream` with UTF-32 encoded `"Hello with BOM!"` text including a BOM preamble, then reads it twice using the decorator pattern: first with `PreambleSequence.Remove` to strip the BOM (resulting text matches the original), then with `PreambleSequence.Keep` to preserve the BOM bytes in the output. Console output displays the decoded text (`"Hello with BOM!"`), the increased string length when BOM is kept, and confirms the stream is disposed after the second read. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.IO.StreamReaderOptions.md b/.docfx/api/types/Cuemon.IO.StreamReaderOptions.md index 010448cc..91aad888 100644 --- a/.docfx/api/types/Cuemon.IO.StreamReaderOptions.md +++ b/.docfx/api/types/Cuemon.IO.StreamReaderOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to configure StreamReaderOptions to control encoding, preamble handling, and buffer size when reading from streams. +`StreamReaderOptions` configures encoding, preamble handling, and buffer size for reading from streams via `StreamReader`. This example shows default options (UTF-8, `PreambleSequence.Remove`, `BufferSize = 81920`) and custom options for UTF-32 with `PreambleSequence.Keep` and `BufferSize = 4096`. A `StreamReader` is created using the custom options to read `"Hello, World!"` UTF-32 data from a `MemoryStream`, and the default preamble and buffer size values are also printed. Console output displays the default encoding name (`UTF-8`), preamble mode, buffer size, and the read content. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.IO.StreamWriterOptions.md b/.docfx/api/types/Cuemon.IO.StreamWriterOptions.md index ead733c5..3e99af9e 100644 --- a/.docfx/api/types/Cuemon.IO.StreamWriterOptions.md +++ b/.docfx/api/types/Cuemon.IO.StreamWriterOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to configure StreamWriterOptions to control encoding, preamble handling, buffer size, and formatting when writing to streams. +`StreamWriterOptions` configures encoding, preamble handling, buffer size, format provider, and newline style when writing to streams via `StreamWriter`. This example sets up options with `AutoFlush = true`, `BufferSize = 256`, `Encoding = EncodingOptions.DefaultEncoding`, `Preamble = PreambleSequence.Remove`, `FormatProvider = CultureInfo.InvariantCulture`, and `NewLine = "\n"`, then uses `StreamFactory.Create` with a writer delegate to format a string with `Math.PI` to two decimal places. The resulting stream is read back as a string via the decorator pattern. Console output displays the trimmed formatted output `"Value: 3.14"`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.IO.TextReaderDecoratorExtensions.md b/.docfx/api/types/Cuemon.IO.TextReaderDecoratorExtensions.md index 5a849fd3..b895920b 100644 --- a/.docfx/api/types/Cuemon.IO.TextReaderDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.IO.TextReaderDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to copy content from one TextReader to a TextWriter asynchronously using TextReaderDecoratorExtensions, with configurable buffer sizes. +`TextReaderDecoratorExtensions` provides extension methods on `Decorator.Enclose` for copying `TextReader` content to `TextWriter` instances asynchronously with configurable buffer sizes. This example creates a `StringReader` with three lines of text, copies to a `StringWriter` via `CopyToAsync`, and outputs the result. It also demonstrates a custom buffer size of `1024` for the copy operation and copying between different reader/writer types (`StreamReader` to `StringWriter`). Console output confirms the copied content matches the source for all three scenarios. ```csharp using System.Text; diff --git a/.docfx/api/types/Cuemon.IntegerDecoratorExtensions.md b/.docfx/api/types/Cuemon.IntegerDecoratorExtensions.md index fb4b2f45..590a0eb8 100644 --- a/.docfx/api/types/Cuemon.IntegerDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.IntegerDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example shows how to extend `int` with `IntegerDecoratorExtensions` methods to clamp integer values to a minimum bound via the decorator pattern. +`IntegerDecoratorExtensions` provides extension methods on `Decorator.Enclose` for clamping integer values to a minimum bound using the `Max` extension method. This example wraps `int` values of `42`, `500`, and `-10`, then calls `Max` with a minimum threshold of `100` or `0`. Key setup includes comparing the wrapped value against the minimum and returning the larger of the two. Console output shows `100` for `42.Max(100)`, `500` for `500.Max(100)` (pass-through), and `0` for `(-10).Max(0)`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.MutableTuple`1.md b/.docfx/api/types/Cuemon.MutableTuple`1.md index b1346a04..b741931d 100644 --- a/.docfx/api/types/Cuemon.MutableTuple`1.md +++ b/.docfx/api/types/Cuemon.MutableTuple`1.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to create a single-argument `MutableTuple` and access its value. It demonstrates both reading and updating the `Arg1` property. + ```csharp using System; using Cuemon; diff --git a/.docfx/api/types/Cuemon.Net.ByteArrayDecoratorExtensions.md b/.docfx/api/types/Cuemon.Net.ByteArrayDecoratorExtensions.md index 5bb012b0..a25fa4db 100644 --- a/.docfx/api/types/Cuemon.Net.ByteArrayDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Net.ByteArrayDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to URL-encode byte array data using ByteArrayDecoratorExtensions, with support for partial encoding and custom character encoding options. +`ByteArrayDecoratorExtensions` in the `Net` namespace provides URL-encoding extension methods on `Decorator.Enclose` for byte arrays with partial encoding and custom encoding support. This example creates UTF-8 bytes from `"hello world & more "` and calls `UrlEncode` with default parameters producing `"hello+world+%26+more+%3cstuff%3e"`, then demonstrates partial encoding on the first 5 bytes of `"a & b & c"` producing `"a+%26+b"`. It also shows custom UTF-32 encoding and empty array handling where `Array.Empty()` returns an encoded array of length `0`. Console output displays each encoded result. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpAuthenticationSchemes.md b/.docfx/api/types/Cuemon.Net.Http.HttpAuthenticationSchemes.md index 1397cc2b..739d8e9c 100644 --- a/.docfx/api/types/Cuemon.Net.Http.HttpAuthenticationSchemes.md +++ b/.docfx/api/types/Cuemon.Net.Http.HttpAuthenticationSchemes.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to use the `HttpAuthenticationSchemes` constants to construct HTTP Authorization headers. It prints each scheme name and creates a Basic authentication header value. + ```csharp using System; using System.Net.Http.Headers; diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpDependency.md b/.docfx/api/types/Cuemon.Net.Http.HttpDependency.md index 94b40ec8..fd75eed8 100644 --- a/.docfx/api/types/Cuemon.Net.Http.HttpDependency.md +++ b/.docfx/api/types/Cuemon.Net.Http.HttpDependency.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to monitor an HTTP resource for changes using HttpDependency, which wraps an HttpWatcher to detect modifications via ETag and Last-Modified headers. +`HttpDependency` wraps an `HttpWatcher` to monitor an HTTP resource for changes, detecting modifications via ETag and Last-Modified headers. This example creates a `Lazy` that monitors `https://example.com/api/status` with HEAD requests at 30-second intervals, then constructs an `HttpDependency` from the factory and subscribes to the `DependencyChanged` event. Key steps include calling `StartAsync` to begin monitoring and handling the `DependencyChanged` event to react to changes. Console output prints the UTC timestamp when a resource change is detected. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpManager.md b/.docfx/api/types/Cuemon.Net.Http.HttpManager.md index 5f98eb3c..019c9ed6 100644 --- a/.docfx/api/types/Cuemon.Net.Http.HttpManager.md +++ b/.docfx/api/types/Cuemon.Net.Http.HttpManager.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use with a custom in-memory HTTP handler. +`HttpManager` provides HTTP operation methods backed by a configurable `IHttpClientFactory`. This example creates an `HttpManager` with a custom `EchoHandler` that returns `200 OK` for all requests, then calls `HttpGetAsync` on a test URI. Key setup includes passing a factory delegate that returns `HttpClient` instances backed by the echo handler. Console output confirms the response status code (`OK`) and that `Timeout` is greater than `TimeSpan.Zero`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Net.Http.HttpMethodConverter.md b/.docfx/api/types/Cuemon.Net.Http.HttpMethodConverter.md index f97e2b7f..d2cb8a13 100644 --- a/.docfx/api/types/Cuemon.Net.Http.HttpMethodConverter.md +++ b/.docfx/api/types/Cuemon.Net.Http.HttpMethodConverter.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to convert a `System.Net.Http.HttpMethod` to the corresponding `HttpMethods` enum value using `HttpMethodConverter`. It converts the GET method and prints the result. + ```csharp using System; using System.Net.Http; diff --git a/.docfx/api/types/Cuemon.Net.QueryStringCollection.md b/.docfx/api/types/Cuemon.Net.QueryStringCollection.md index 8c21b300..1dd39f2b 100644 --- a/.docfx/api/types/Cuemon.Net.QueryStringCollection.md +++ b/.docfx/api/types/Cuemon.Net.QueryStringCollection.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create, parse, and manipulate URI query string parameters using QueryStringCollection, with support for URL decoding and cloning. +`QueryStringCollection` provides creation, parsing, and manipulation of URI query string parameters, extending `NameValueCollection` with URL decoding support. This example creates an empty collection and adds `"search"`, `"page"`, and `"sort"` parameters, parses an existing query string (`"?category=books&author=tolkien"`) with and without URL decoding, and iterates key-value pairs. It also demonstrates cloning the collection and modifying the clone independently to verify they are separate instances. Console output shows the query string representation, decoded values, keys, clone independence, and entry counts. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Net.StringDecoratorExtensions.md b/.docfx/api/types/Cuemon.Net.StringDecoratorExtensions.md index 9815c7a8..0b64e1f1 100644 --- a/.docfx/api/types/Cuemon.Net.StringDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Net.StringDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to URL-encode and URL-decode strings using StringDecoratorExtensions, with support for custom encodings. +`StringDecoratorExtensions` in the `Net` namespace provides URL-encoding and URL-decoding extension methods on `Decorator.Enclose` for strings with custom encoding support. This example encodes `"hello world & some "` via `UrlEncode` producing `"hello+world+%26+some+%3cstuff%3e"`, decodes it back to the original via `UrlDecode`, and also demonstrates calling the static methods directly on `Cuemon.Net.StringDecoratorExtensions.UrlEncode`. Custom encoding with UTF-8 on `"a=b&c=d"` produces `"a%3db%26c%3dd"`. Console output confirms each encode and decode operation's round-trip behavior. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.ObjectDecoratorExtensions.md b/.docfx/api/types/Cuemon.ObjectDecoratorExtensions.md index d7693aea..58f3138c 100644 --- a/.docfx/api/types/Cuemon.ObjectDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.ObjectDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the extension methods to convert object types and traverse hierarchical structures through the pattern. +`ObjectDecoratorExtensions` provides extension methods on `Decorator.Enclose` for type conversion, hierarchical tree traversal, and property resolution via reflection. This example converts string representations of `"42"`, `"2024-01-15T10:30:00Z"`, `"not-a-number"`, and `"Ascending"` into their target types using `ChangeType` and `ChangeTypeOrDefault` with fallback support. It also builds a three-level `TreeNode` hierarchy and visits all nodes with `TraverseWhileNotEmpty`, and reads a property value through `DefaultPropertyValueResolver`. Console output confirms each type conversion succeeded and lists all visited node names in depth-first traversal order. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Reflection.ActivatorFactory.md b/.docfx/api/types/Cuemon.Reflection.ActivatorFactory.md index 7b582a12..925bc515 100644 --- a/.docfx/api/types/Cuemon.Reflection.ActivatorFactory.md +++ b/.docfx/api/types/Cuemon.Reflection.ActivatorFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to create instances of types at runtime using `ActivatorFactory`. It creates a `StringBuilder` with no arguments and a `DateTime` with constructor arguments, then prints each result. + ```csharp using System; using System.Text; diff --git a/.docfx/api/types/Cuemon.Reflection.AssemblyContext.md b/.docfx/api/types/Cuemon.Reflection.AssemblyContext.md index 3fed62d1..8b605569 100644 --- a/.docfx/api/types/Cuemon.Reflection.AssemblyContext.md +++ b/.docfx/api/types/Cuemon.Reflection.AssemblyContext.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to filter and enumerate loaded assemblies using `AssemblyContext`. It retrieves all assemblies whose name starts with "Cuemon" and prints each assembly name. + ```csharp using System; using System.Linq; diff --git a/.docfx/api/types/Cuemon.Reflection.AssemblyDecoratorExtensions.md b/.docfx/api/types/Cuemon.Reflection.AssemblyDecoratorExtensions.md index f0f654ec..ddd3d1dd 100644 --- a/.docfx/api/types/Cuemon.Reflection.AssemblyDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Reflection.AssemblyDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the to inspect assemblies and load embedded resources via the decorator pattern. +`AssemblyDecoratorExtensions` provides extension methods on `Decorator.Enclose` for inspecting assembly metadata, loading embedded resources, and filtering types. This example wraps the entry assembly and calls `IsDebugBuild`, `GetAssemblyVersion`, `GetFileVersion`, and `GetProductVersion` to retrieve version information. It also demonstrates `GetTypes` with optional namespace and interface filters, and `GetManifestResources` with various match modes including `ContainsName`, `Extension`, and `Name`. Console output displays each version string, boolean flags, and resource character counts. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Reflection.MemberInfoDecoratorExtensions.md b/.docfx/api/types/Cuemon.Reflection.MemberInfoDecoratorExtensions.md index 1b1af982..4d6d35d3 100644 --- a/.docfx/api/types/Cuemon.Reflection.MemberInfoDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Reflection.MemberInfoDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to check whether a MemberInfo has one or more custom attributes using MemberInfoDecoratorExtensions. +`MemberInfoDecoratorExtensions` provides extension methods on `Decorator.Enclose` for checking whether a `MemberInfo` has one or more custom attributes via `HasAttribute`. This example gets `MemberInfo` for a method without attributes and another decorated with `[Obsolete]`, then calls `HasAttribute` with single (`ObsoleteAttribute`) and multiple attribute types on each. Console output shows `False` for the method without `ObsoleteAttribute`, `False` for `Obsolete` or `EditorBrowsable`, and `True` for the deprecated method, confirming correct attribute detection through the decorator pattern. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Reflection.MethodBaseOptions.md b/.docfx/api/types/Cuemon.Reflection.MethodBaseOptions.md index 21964272..69609179 100644 --- a/.docfx/api/types/Cuemon.Reflection.MethodBaseOptions.md +++ b/.docfx/api/types/Cuemon.Reflection.MethodBaseOptions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example shows how to store method lookup rules in `MethodBaseOptions` and apply them during reflection. +`MethodBaseOptions` stores method lookup rules including binding flags, string comparison mode, and expected parameter types for use during reflection-based method resolution. This example configures options with `BindingFlags.Instance | BindingFlags.Public`, `StringComparison.OrdinalIgnoreCase`, and `typeof(decimal)` parameter types, then passes them to a custom `ResolveMethod` helper that searches the `PricingEngine` class for a method matching the name and parameter signature. Console output shows the resolved method name (`ApplyDiscount`) or `"not found"`, the binding flags, and the expected parameter type names (`Decimal, Decimal`). ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Reflection.MethodDescriptor.md b/.docfx/api/types/Cuemon.Reflection.MethodDescriptor.md index 609c1355..3e47d010 100644 --- a/.docfx/api/types/Cuemon.Reflection.MethodDescriptor.md +++ b/.docfx/api/types/Cuemon.Reflection.MethodDescriptor.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create a MethodDescriptor from a MethodInfo, inspect its parameters, append runtime arguments, and merge parameter signatures with values. +`MethodDescriptor` provides a structured representation of a method's metadata including its caller type, method name, parameters, and optional runtime arguments. This example creates a `MethodDescriptor` from `string.IndexOf`'s `MethodInfo`, inspects its `Caller` (`System.String`), `MethodName` (`IndexOf`), and `Parameters` (value and comparisonType), then appends runtime arguments via `AppendRuntimeArguments("Hello", StringComparison.OrdinalIgnoreCase)`. It also demonstrates the static `Create` factory and `MergeParameters` to combine parameter signatures with runtime values. Console output displays the caller full name, method name, signature, parameter list, runtime argument key-value pairs, and merged parameter values. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Reflection.MethodInfoDecoratorExtensions.md b/.docfx/api/types/Cuemon.Reflection.MethodInfoDecoratorExtensions.md index 828b1f83..106a33c2 100644 --- a/.docfx/api/types/Cuemon.Reflection.MethodInfoDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Reflection.MethodInfoDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example shows how to detect whether a reflected method overrides a base implementation. +`MethodInfoDecoratorExtensions` provides extension methods on `Decorator.Enclose` for detecting whether a reflected method overrides a base class implementation via `IsOverridden`. This example retrieves `MethodInfo` for `PricingCalculator.Calculate` (base method), `RegionalPricingCalculator.Calculate` (overridden), and `RegionalPricingCalculator.FormatRegion` (local method), then calls `IsOverridden()` on each. Console output shows `False` for the base method, `True` for the overridden method, and `False` for the local method that does not override anything. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Reflection.PropertyInfoDecoratorExtensions.md b/.docfx/api/types/Cuemon.Reflection.PropertyInfoDecoratorExtensions.md index f910ec56..166907c7 100644 --- a/.docfx/api/types/Cuemon.Reflection.PropertyInfoDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Reflection.PropertyInfoDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example shows how to inspect reflected properties for auto-property and override behavior. +`PropertyInfoDecoratorExtensions` provides extension methods on `Decorator.Enclose` for detecting auto-implemented properties and override behavior via `IsAutoProperty` and `IsOverridden`. This example retrieves `PropertyInfo` for `Product.Code` (auto-property), `Product.Label` (expression-bodied), and `FeaturedProduct.Summary` (overridden in a derived class), then calls `IsAutoProperty` on the first two and `IsOverridden` on the third. Console output shows `True` for the auto-property, `False` for the expression-bodied property, and `True` for the overridden property, confirming correct identification of property characteristics. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Resilience.TransientFaultEvidence.md b/.docfx/api/types/Cuemon.Resilience.TransientFaultEvidence.md index 523f440e..8e899fdb 100644 --- a/.docfx/api/types/Cuemon.Resilience.TransientFaultEvidence.md +++ b/.docfx/api/types/Cuemon.Resilience.TransientFaultEvidence.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create TransientFaultEvidence instances to capture retry attempt details, recovery wait times, and latency information for transient fault handling. +`TransientFaultEvidence` captures retry attempt details, recovery wait times, latency, and method signature information for transient fault handling scenarios. This example creates evidence with `attempts = 3`, `RecoveryWaitTime = 2s`, `TotalRecoveryWaitTime = 5s`, `Latency = 1500ms`, and a `MethodSignature` for `PaymentService.ProcessPayment`. It also demonstrates equality comparison between two identical evidence instances, and a minimal-info creation with `attempts = 1` and `Latency = 200ms` for simple scenarios. Console output displays the evidence's `ToString` representation, individual property values, equality results, and hash code consistency. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Resilience.TransientOperation.md b/.docfx/api/types/Cuemon.Resilience.TransientOperation.md index 4f9c9fcd..ac99e0da 100644 --- a/.docfx/api/types/Cuemon.Resilience.TransientOperation.md +++ b/.docfx/api/types/Cuemon.Resilience.TransientOperation.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to execute an HTTP request with retry logic using `TransientOperation`. It configures three retry attempts with exponential backoff and prints the response length on success. + ```csharp using System; using System.Net.Http; diff --git a/.docfx/api/types/Cuemon.Runtime.Caching.CachingManager.md b/.docfx/api/types/Cuemon.Runtime.Caching.CachingManager.md index 665901d2..9fa19306 100644 --- a/.docfx/api/types/Cuemon.Runtime.Caching.CachingManager.md +++ b/.docfx/api/types/Cuemon.Runtime.Caching.CachingManager.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to get or add a cached value using `CachingManager.Cache`. It checks for an existing key, adds a value with a 5-minute expiration if not found, and verifies the cached instance is reused on subsequent accesses. + ```csharp using System; using Cuemon.Runtime.Caching; diff --git a/.docfx/api/types/Cuemon.Runtime.Caching.SlimMemoryCache.md b/.docfx/api/types/Cuemon.Runtime.Caching.SlimMemoryCache.md index a87b612d..9f826c35 100644 --- a/.docfx/api/types/Cuemon.Runtime.Caching.SlimMemoryCache.md +++ b/.docfx/api/types/Cuemon.Runtime.Caching.SlimMemoryCache.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use `SlimMemoryCache` to store and retrieve cached values with various expiration strategies. +`SlimMemoryCache` provides in-memory caching with absolute and sliding expiration, namespace grouping, and automatic cleanup. This example creates a cache with cleanup enabled (`FirstSweep = 30s`, `SucceedingSweep = 10s`), adds a config entry with absolute expiration, a session entry with sliding expiration under the `"sessions"` namespace, and updates the config entry via the indexer. It demonstrates safe retrieval with `TryGet`, key-based removal with `Remove`, namespace-based counting with `Count("data")`, and bulk namespace removal with `RemoveAll("data")`. Console output confirms the cached values, update status, removal success, and namespace counts before and after removal. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Runtime.DependencyEventArgs.md b/.docfx/api/types/Cuemon.Runtime.DependencyEventArgs.md index 39eb1583..edf894a4 100644 --- a/.docfx/api/types/Cuemon.Runtime.DependencyEventArgs.md +++ b/.docfx/api/types/Cuemon.Runtime.DependencyEventArgs.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create and use DependencyEventArgs to report the UTC timestamp of a dependency change event. +`DependencyEventArgs` provides event data for dependency change notifications, carrying the UTC timestamp of the last modification. This example creates event args with `DateTime.UtcNow`, a specific past timestamp (`2026-06-01T12:00:00Z`), and the `Empty` sentinel representing no change. It also demonstrates raising a `DependencyChanged` event from a custom `DependencyMonitor` class and handling it to print the UTC timestamp. Console output displays the last modified timestamp in ISO 8601 format, confirms the `Empty` sentinel returns `MinValue`, and shows event-driven output. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Runtime.FileDependency.md b/.docfx/api/types/Cuemon.Runtime.FileDependency.md index 3bdb3717..65c73425 100644 --- a/.docfx/api/types/Cuemon.Runtime.FileDependency.md +++ b/.docfx/api/types/Cuemon.Runtime.FileDependency.md @@ -4,7 +4,7 @@ example: - *content --- -The following example shows how to defer file-watcher creation until a dependency starts monitoring. +`FileDependency` defers `FileWatcher` creation until monitoring begins by accepting a `Lazy` factory. This example creates a temporary `settings.json` file, wraps a `FileWatcher` in a `Lazy<>` with a 500ms polling period, and passes it to `FileDependency` with `breakTieOnChanged: true`. Key steps include checking `lazyWatcher.IsValueCreated` before and after `StartAsync` to confirm deferred creation, subscribing to `DependencyChanged`, and inspecting `HasChanged` after signaling. Console output shows the watcher creation status, `BreakTieOnChanged` value, and the changed state. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Runtime.Serialization.Formatters.Formatter.md b/.docfx/api/types/Cuemon.Runtime.Serialization.Formatters.Formatter.md index 8d38380d..496c6e33 100644 --- a/.docfx/api/types/Cuemon.Runtime.Serialization.Formatters.Formatter.md +++ b/.docfx/api/types/Cuemon.Runtime.Serialization.Formatters.Formatter.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to resolve .NET types from qualified type-name strings using the `Formatter` class. It demonstrates both a direct resolution and a safe TryGetType call that avoids exceptions. + ```csharp using System; using Cuemon.Runtime.Serialization.Formatters; diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.AesCryptor.md b/.docfx/api/types/Cuemon.Security.Cryptography.AesCryptor.md index 2ab388de..f5de17cb 100644 --- a/.docfx/api/types/Cuemon.Security.Cryptography.AesCryptor.md +++ b/.docfx/api/types/Cuemon.Security.Cryptography.AesCryptor.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to encrypt and decrypt data using AES encryption with AesCryptor, including key generation, custom cipher modes, and padding options. +`AesCryptor` provides AES encryption and decryption with configurable key size, cipher mode, and padding. This example generates a 256-bit key and 128-bit IV using `AesCryptor.GenerateKey()` and `GenerateInitializationVector()`, encrypts `"This is a sensitive message that needs encryption."`, decrypts the ciphertext, and verifies the round-trip matches the original. It also demonstrates explicit CBC mode with PKCS7 padding via an options delegate, custom key sizes (`AesSize.Aes128` and `AesSize.Aes192`), and the default constructor that generates random credentials automatically. Console output confirms key and IV lengths, base64 ciphertext, round-trip success, and explicit options round-trip verification. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.HmacMessageDigest5.md b/.docfx/api/types/Cuemon.Security.Cryptography.HmacMessageDigest5.md index 47af1c38..7b03a3be 100644 --- a/.docfx/api/types/Cuemon.Security.Cryptography.HmacMessageDigest5.md +++ b/.docfx/api/types/Cuemon.Security.Cryptography.HmacMessageDigest5.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to compute and verify HMAC-MD5 message authentication codes using HmacMessageDigest5, including tamper detection. +`HmacMessageDigest5` computes and verifies HMAC-MD5 message authentication codes with support for custom byte order and direct string input. This example creates a 64-byte secret key, computes the HMAC of `"Important: Transfer $100 to account 12345"`, then verifies it by recomputing with the same secret. A tampered message with a different account number produces a different HMAC, confirming tamper detection. It also demonstrates options-based construction with `Endianness.LittleEndian` and direct `ComputeHash(string)` overload. Console output shows the hex and base64 HMAC values, verification status (`True`), tamper detection (`False`), and options-based result. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.KeyedCryptoAlgorithm.md b/.docfx/api/types/Cuemon.Security.Cryptography.KeyedCryptoAlgorithm.md index c3989bc7..f4a5c422 100644 --- a/.docfx/api/types/Cuemon.Security.Cryptography.KeyedCryptoAlgorithm.md +++ b/.docfx/api/types/Cuemon.Security.Cryptography.KeyedCryptoAlgorithm.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the KeyedCryptoAlgorithm enumeration to select an HMAC algorithm (SHA-256, SHA-384, SHA-512, SHA-1, or MD5) for keyed hashing. +`KeyedCryptoAlgorithm` is an enumeration that selects an HMAC algorithm (SHA-256, SHA-384, SHA-512, SHA-1, or MD5) for keyed hashing operations. This example computes HMAC hashes for each algorithm using a shared key and sample data (`"The quick brown fox jumps over the lazy dog"`) with `HMACSHA256`, `HMACSHA384`, `HMACSHA512`, and `HMACSHA1`. It also uses a `KeyedCryptoAlgorithm` value in a switch expression to dynamically select the algorithm name, and demonstrates enum value comparison to confirm `HmacSha256 == 0`. Console output displays each hex hash and the selected algorithm name. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.KeyedHashFactory.md b/.docfx/api/types/Cuemon.Security.Cryptography.KeyedHashFactory.md index 1797aa0d..8847b59c 100644 --- a/.docfx/api/types/Cuemon.Security.Cryptography.KeyedHashFactory.md +++ b/.docfx/api/types/Cuemon.Security.Cryptography.KeyedHashFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to compute an HMAC-SHA256 hash for message authentication using `KeyedHashFactory`. It creates a keyed hash algorithm with a secret key, hashes an input string, and prints the hexadecimal digest. + ```csharp using System; using System.Text; diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedCryptoAlgorithm.md b/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedCryptoAlgorithm.md index fd6e0a61..0c48dce7 100644 --- a/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedCryptoAlgorithm.md +++ b/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedCryptoAlgorithm.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the UnkeyedCryptoAlgorithm enumeration to select a hash algorithm (SHA-256, SHA-384, SHA-512, SHA-1, or MD5) for unkeyed hashing. +`UnkeyedCryptoAlgorithm` is an enumeration that selects a hash algorithm (SHA-256, SHA-384, SHA-512, SHA-1, MD5, or SHA-512/256) for unkeyed hashing. This example computes hashes for each algorithm using `"The quick brown fox jumps over the lazy dog"` with `SHA256`, `SHA384`, `SHA512`, and `SHA1`. It also uses an `UnkeyedCryptoAlgorithm` value (`Sha512`) to output the selected algorithm name, and demonstrates enum value comparison to confirm `Sha256 == 0`. Console output displays each hex hash and the selected algorithm name. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedHashFactory.md b/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedHashFactory.md index 2dceb796..bd8c68a9 100644 --- a/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedHashFactory.md +++ b/.docfx/api/types/Cuemon.Security.Cryptography.UnkeyedHashFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to compute SHA-256 and SHA-512 hashes for data integrity using `UnkeyedHashFactory`. It hashes a sample input and prints the hexadecimal digest for each algorithm. + ```csharp using System; using System.Text; diff --git a/.docfx/api/types/Cuemon.Security.HashFactory.md b/.docfx/api/types/Cuemon.Security.HashFactory.md index 2589f92a..b18d21d7 100644 --- a/.docfx/api/types/Cuemon.Security.HashFactory.md +++ b/.docfx/api/types/Cuemon.Security.HashFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example shows how to compute non-cryptographic hashes using `HashFactory`. It demonstrates FNV-1a 32-bit, CRC-32, and FNV-1a 256-bit hashing of a sample input, printing each hexadecimal digest. + ```csharp using System; using System.Text; diff --git a/.docfx/api/types/Cuemon.StringDecoratorExtensions.md b/.docfx/api/types/Cuemon.StringDecoratorExtensions.md index 1ee9dde1..54049c54 100644 --- a/.docfx/api/types/Cuemon.StringDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.StringDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the to manipulate strings via the decorator pattern. +`StringDecoratorExtensions` provides extension methods on `Decorator.Enclose` for string manipulation including casing conversion, encoding, URI conversion, set operations, and content inspection. This example wraps `" Hello World! "` and applies `ToCasing` with `LowerCase`, `UpperCase`, and `TitleCase` modes, converts the string to a byte array and stream with configurable encoding, and extracts the differing portion between `"Hello World!"` and `"Hello Universe!"` using `Difference`. Key steps also include `StartsWith` checks with multiple candidate strings and `ContainsAny` for character matching. Console output confirms each transformed value, such as `" hello world! "` for lower-casing and `"Universe!"` for the set difference. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Text.ByteOrderMark.md b/.docfx/api/types/Cuemon.Text.ByteOrderMark.md index dc298d81..e9ee6086 100644 --- a/.docfx/api/types/Cuemon.Text.ByteOrderMark.md +++ b/.docfx/api/types/Cuemon.Text.ByteOrderMark.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates how to detect and remove byte order marks (BOM) from a UTF-8 byte array and detect encoding from a stream. The output shows the detected encoding name, the byte count after BOM removal, and the encoding detected from the stream. + ```csharp using System; using System.IO; diff --git a/.docfx/api/types/Cuemon.Text.ParserFactory.md b/.docfx/api/types/Cuemon.Text.ParserFactory.md index 7669541b..7cafb4ae 100644 --- a/.docfx/api/types/Cuemon.Text.ParserFactory.md +++ b/.docfx/api/types/Cuemon.Text.ParserFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates parsing a GUID string, a Base64-encoded value, and a URI string using the factory methods provided by `ParserFactory`. Each parser is created via a dedicated factory method and then invoked to produce a strongly typed result. + ```csharp using System; using Cuemon.Text; diff --git a/.docfx/api/types/Cuemon.Threading.AdvancedParallelFactory.md b/.docfx/api/types/Cuemon.Threading.AdvancedParallelFactory.md index 0ed4b3f7..8113088f 100644 --- a/.docfx/api/types/Cuemon.Threading.AdvancedParallelFactory.md +++ b/.docfx/api/types/Cuemon.Threading.AdvancedParallelFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates using `AdvancedParallelFactory` to compute an iterator value and evaluate a loop condition. The output shows the result of `5 + 3` and whether that result satisfies the greater-than-or-equal check of 8. + ```csharp using System; using Cuemon.Threading; diff --git a/.docfx/api/types/Cuemon.Threading.AsyncActionFactory-1.md b/.docfx/api/types/Cuemon.Threading.AsyncActionFactory-1.md index 9aca2772..cd424168 100644 --- a/.docfx/api/types/Cuemon.Threading.AsyncActionFactory-1.md +++ b/.docfx/api/types/Cuemon.Threading.AsyncActionFactory-1.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create and execute an for deferred asynchronous work with typed arguments. +`AsyncActionFactory` encapsulates a deferred asynchronous action with typed arguments, with support for cloning for safe concurrent execution. This example creates a factory using `AsyncActionFactory.Create` with a lambda that takes a channel name (`"orders"`) and retry count (`3`), delays 10ms, and prints them, then calls `ExecuteMethodAsync` to run it. Key steps include cloning the factory via `(AsyncActionFactory>)factory.Clone()` and executing the clone separately. Console output displays `"orders:3"` for both the original and cloned execution, confirming that cloned factories produce identical results. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Threading.AsyncActionFactory.md b/.docfx/api/types/Cuemon.Threading.AsyncActionFactory.md index 641bb3ff..3970dc93 100644 --- a/.docfx/api/types/Cuemon.Threading.AsyncActionFactory.md +++ b/.docfx/api/types/Cuemon.Threading.AsyncActionFactory.md @@ -4,6 +4,8 @@ example: - *content --- +`AsyncActionFactory` provides factory methods for creating deferred asynchronous actions with zero or more typed arguments, executed via `ExecuteMethodAsync`. This example creates an action that prints `"Async operation executed"` and another with a string argument that logs `"Hello from async action"` after a 10ms delay, then invokes each with `CancellationToken.None`. Key setup includes using `AsyncActionFactory.Create` with a lambda and passing arguments separately so the factory handles lifetime and error propagation. Console output confirms both actions execute successfully, with the parameterized action receiving and printing the supplied message. + ```csharp using System; using System.Threading; diff --git a/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory.md b/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory.md index 1200540c..b17b7983 100644 --- a/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory.md +++ b/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory.md @@ -4,6 +4,8 @@ example: - *content --- +`AsyncFuncFactory` provides factory methods for creating deferred asynchronous functions with zero or more typed arguments and a return value, executed via `ExecuteMethodAsync`. This example creates a function that returns `42` and another that sums two integers (`3` and `4`) after a 10ms delay, then invokes each with `CancellationToken.None`. Key setup includes using `AsyncFuncFactory.Create` with a lambda and passing arguments separately so the factory manages lifetime and error propagation. Console output displays `"Result: 42"` and `"Sum: 7"`, confirming both the parameterless and parameterized async function patterns. + ```csharp using System; using System.Threading; diff --git a/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory`2.md b/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory`2.md index 32ed914e..7520a27b 100644 --- a/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory`2.md +++ b/.docfx/api/types/Cuemon.Threading.AsyncFuncFactory`2.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create and execute a function asynchronously using AsyncFuncFactory, with support for cloning for safe concurrent use. +`AsyncFuncFactory` encapsulates a deferred asynchronous function with typed arguments and return value, with cloning support for safe concurrent use. This example creates a factory using `AsyncFuncFactory.Create` with a lambda that takes `"Hello"` and `"World"` and returns their combined length, then calls `ExecuteMethodAsync` to compute the result. Key steps include checking `HasDelegate` and `DelegateInfo` properties, and cloning the factory via `(AsyncFuncFactory, int>)factory.Clone()` to execute independently. Console output confirms `HasDelegate` is `True`, the combined length is `10`, and the cloned result is also `10`. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Threading.AsyncPatterns.md b/.docfx/api/types/Cuemon.Threading.AsyncPatterns.md index 6c1a5cc3..d2c7960c 100644 --- a/.docfx/api/types/Cuemon.Threading.AsyncPatterns.md +++ b/.docfx/api/types/Cuemon.Threading.AsyncPatterns.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use `AsyncPatterns` for safe disposal of `IDisposable` resources (CA2000) in asynchronous workflows. +`AsyncPatterns` provides safe asynchronous patterns for resource management, including `SafeInvokeAsync` that ensures proper disposal of `IDisposable` resources (CA2000 compliant). This example calls `SafeInvokeAsync` with a factory delegate creating a `MemoryStream`, an invocation delegate that writes `"Cuemon"` bytes to it and returns the stream, and a `CancellationToken`. The resulting stream is read back via `StreamReader` to confirm the content, and the `AsyncPatterns.Use` sentinel is compared with itself to verify static reference identity. Console output displays `"Cuemon"` and `True` for the reference comparison. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Threading.Awaiter.md b/.docfx/api/types/Cuemon.Threading.Awaiter.md index 1f942a57..dae69c48 100644 --- a/.docfx/api/types/Cuemon.Threading.Awaiter.md +++ b/.docfx/api/types/Cuemon.Threading.Awaiter.md @@ -4,6 +4,8 @@ example: - *content --- +The following example retries an asynchronous operation until it succeeds or a timeout is reached. The delegate returns `UnsuccessfulValue` twice before returning `SuccessfulValue`, and the output confirms the operation succeeded after three attempts. + ```csharp using System; using System.Threading.Tasks; diff --git a/.docfx/api/types/Cuemon.Threading.ParallelFactory.md b/.docfx/api/types/Cuemon.Threading.ParallelFactory.md index 3b817497..ba0cea2d 100644 --- a/.docfx/api/types/Cuemon.Threading.ParallelFactory.md +++ b/.docfx/api/types/Cuemon.Threading.ParallelFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates basic parallel loops using `ParallelFactory.For` and `ParallelFactory.ForEach`. Each iteration prints its index or item to the console, illustrating how the factory distributes work across threads. + ```csharp using System; using Cuemon.Threading; diff --git a/.docfx/api/types/Cuemon.Threading.TimerFactory.md b/.docfx/api/types/Cuemon.Threading.TimerFactory.md index 4382ead7..e15b3872 100644 --- a/.docfx/api/types/Cuemon.Threading.TimerFactory.md +++ b/.docfx/api/types/Cuemon.Threading.TimerFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example creates a non-capturing timer that fires every two seconds after an initial one-second delay. The callback prints "Timer ticked" each time it executes; the timer is disposed after five seconds. + ```csharp using System; using System.Threading; diff --git a/.docfx/api/types/Cuemon.TypeDecoratorExtensions.md b/.docfx/api/types/Cuemon.TypeDecoratorExtensions.md index 4ce9783e..12a2dc9d 100644 --- a/.docfx/api/types/Cuemon.TypeDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.TypeDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the to generate a reflection report before loading a plugin type. +`TypeDecoratorExtensions` provides extension methods on `Decorator.Enclose` for deep reflection inspection of .NET types, including member enumeration, interface detection, attribute checking, and circular-reference detection. This example wraps `AuditedOrder` (annotated with `[DataContract]`) and calls `GetAllProperties`, `GetAllFields`, `GetAllEvents`, and `GetAllMethods` to enumerate members across the full hierarchy including its base `TrackedEntity`. It also uses predicate methods like `HasTypes` (for `FileStream` → `Stream`), `HasInterfaces`, `HasAttribute`, `HasEnumerableImplementation`, `IsNullable`, and `HasAnonymousCharacteristics` to classify type capabilities. Console output includes sorted member names, boolean capability flags, default values such as `00000000-0000-0000-0000-000000000000` for `Guid`, friendly type names like `IList`, and circular-reference detection results for a `LinkedNode` with a self-referencing loop. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Xml.HierarchyDecoratorExtensions.md b/.docfx/api/types/Cuemon.Xml.HierarchyDecoratorExtensions.md index 51214694..23cb210f 100644 --- a/.docfx/api/types/Cuemon.Xml.HierarchyDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Xml.HierarchyDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to inspect XML-related metadata on a hierarchy node with . +`HierarchyDecoratorExtensions` provides extension methods on `Decorator.Enclose` for inspecting XML serialization metadata on `IHierarchy` nodes. This example creates a `Hierarchy` tree with a `Person` node (annotated with `[XmlRoot("person")]`) and an `Address` child node, then uses decorator methods to call `GetXmlQualifiedEntity`, `TryGetXmlRootAttribute`, `TryGetXmlElementAttribute`, `TryGetXmlTextAttribute`, `TryGetXmlAttributeAttribute`, `IsNodeEnumerable`, `HasXmlIgnoreAttribute`, and `OrderByXmlAttributes`. Console output displays the qualified entity local name, boolean results for attribute detection, and the count of ordered nodes. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Xml.Linq.StringDecoratorExtensions.md b/.docfx/api/types/Cuemon.Xml.Linq.StringDecoratorExtensions.md index 608e805c..cce74dd8 100644 --- a/.docfx/api/types/Cuemon.Xml.Linq.StringDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Xml.Linq.StringDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to validate and parse XML strings into XElement objects using StringDecoratorExtensions, with support for load options and whitespace preservation. +`StringDecoratorExtensions` in the `Xml.Linq` namespace provides extension methods on `Decorator.Enclose` for validating and parsing XML strings into `XElement` objects. This example checks valid XML (`"value"`) with `IsXmlString` returning `True`, parses it via `TryParseXElement` and navigates to read the root name, item attribute, and value. Invalid XML (`"not xml at all"`) returns `False` for `IsXmlString` and `TryParseXElement` returns `false` with `null`. It also demonstrates `TryParseXElement` with `LoadOptions.PreserveWhitespace` to retain whitespace in the parsed output. Console output confirms each validation and parsing result. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.Converters.ExceptionConverter.md b/.docfx/api/types/Cuemon.Xml.Serialization.Converters.ExceptionConverter.md index 67389155..ad438225 100644 --- a/.docfx/api/types/Cuemon.Xml.Serialization.Converters.ExceptionConverter.md +++ b/.docfx/api/types/Cuemon.Xml.Serialization.Converters.ExceptionConverter.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to serialize an to XML and deserialize it back using the . +`ExceptionConverter` in the `Xml.Serialization` namespace serializes `Exception` instances to XML and deserializes them back, with optional stack trace and `Data` dictionary inclusion. This example creates an outer `InvalidOperationException` with an inner `ArgumentNullException` and a `"Server"` data entry, configures an `XmlFormatter` with the converter including stack trace and data, and serializes to XML output showing ``, ``, ``, ``, and nested `` elements. It also demonstrates deserializing from an XML string back to an exception instance with `converter.ReadXml`, and serialization without stack trace or data for simpler output. Console output displays the XML content and deserialized type name. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.Converters.FailureConverter.md b/.docfx/api/types/Cuemon.Xml.Serialization.Converters.FailureConverter.md index 68b4a6bc..089c683d 100644 --- a/.docfx/api/types/Cuemon.Xml.Serialization.Converters.FailureConverter.md +++ b/.docfx/api/types/Cuemon.Xml.Serialization.Converters.FailureConverter.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to serialize a object to XML using the . +`FailureConverter` serializes `Failure` objects to XML via `XmlFormatter`, providing structured error output including exception type, source, and message. This example creates a `Failure` from an `InvalidOperationException("The requested resource was not found.")` with `Source = "MyApi"` and `FaultSensitivityDetails.None`, configures an `XmlFormatter` with the converter, and serializes to XML. The resulting XML output includes `` with `MyApi` and `The requested resource was not found.`, showing the default serialization format for failure objects. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverter.md b/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverter.md index 9ec00211..1717acec 100644 --- a/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverter.md +++ b/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverter.md @@ -4,6 +4,8 @@ example: - *content --- +The following example creates a `DynamicXmlConverter` with custom read and write delegates. Writing the value 42 produces an XML fragment containing a `` element; the converter can also read it back from XML. + ```csharp using System; using System.IO; diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverterCore.md b/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverterCore.md index ccc80dc5..bfc99d7d 100644 --- a/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverterCore.md +++ b/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlConverterCore.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create a custom XML converter using DynamicXmlConverterCore, with read and write delegates for serializing and deserializing objects to and from XML. +`DynamicXmlConverterCore` enables creating custom XML converters using read and write delegates, supporting both read/write and write-only scenarios. This example creates a `Person` class and builds a `DynamicXmlConverter` with a writer delegate that serializes `FirstName`, `LastName`, and `Age` as child elements and a reader delegate that deserializes them back. A `Person` instance is serialized to XML and deserialized to confirm round-trip fidelity, and a write-only converter is also demonstrated for scenarios where only serialization is needed. Console output displays the serialized XML, deserialized property values, and the converter's `CanRead`/`CanWrite` capabilities. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlSerializable.md b/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlSerializable.md index c33d0f43..931bbbef 100644 --- a/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlSerializable.md +++ b/.docfx/api/types/Cuemon.Xml.Serialization.DynamicXmlSerializable.md @@ -4,6 +4,8 @@ example: - *content --- +The following example wraps an anonymous object with `DynamicXmlSerializable` and provides a custom writer that emits `Name` and `Score` child elements. The resulting XML is written to a `StringWriter` and printed to the console. + ```csharp using System; using System.IO; diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.XmlConvert.md b/.docfx/api/types/Cuemon.Xml.Serialization.XmlConvert.md index 05552204..fd2ea7f9 100644 --- a/.docfx/api/types/Cuemon.Xml.Serialization.XmlConvert.md +++ b/.docfx/api/types/Cuemon.Xml.Serialization.XmlConvert.md @@ -4,6 +4,8 @@ example: - *content --- +The following example configures default `XmlSerializerOptions` on `XmlConvert` with UTF-8 encoding and tab indentation, then reads back the defaults and prints the encoding name. This demonstrates how to override global XML serialization settings. + ```csharp using System; using System.Text; diff --git a/.docfx/api/types/Cuemon.Xml.Serialization.XmlQualifiedEntity.md b/.docfx/api/types/Cuemon.Xml.Serialization.XmlQualifiedEntity.md index b1b2b2f3..b781c0f0 100644 --- a/.docfx/api/types/Cuemon.Xml.Serialization.XmlQualifiedEntity.md +++ b/.docfx/api/types/Cuemon.Xml.Serialization.XmlQualifiedEntity.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to create XmlQualifiedEntity instances from local names, namespaces, prefixes, and XML serialization attributes to control element naming. +`XmlQualifiedEntity` represents an XML element or attribute name with optional namespace and prefix, and can be created from XML serialization attributes. This example creates entities from a local name only (`"Order"`), with a namespace (`"http://example.com/orders"`), and with a prefix/namespace combination (`"o"`, `"Order"`, `"http://example.com/orders"`). It then creates entities from `XmlRootAttribute("PurchaseOrder")`, `XmlElementAttribute("LineItem")`, and `XmlAttributeAttribute("Quantity")`, and demonstrates using `XmlQualifiedEntity` with `XmlSerializerOptions` to set a custom root name. Console output displays each entity's `LocalName`, `Namespace`, `Prefix`, and decoration flags. ```csharp using System; diff --git a/.docfx/api/types/Cuemon.Xml.XPath.XPathDocumentFactory.md b/.docfx/api/types/Cuemon.Xml.XPath.XPathDocumentFactory.md index 003db799..7cef3002 100644 --- a/.docfx/api/types/Cuemon.Xml.XPath.XPathDocumentFactory.md +++ b/.docfx/api/types/Cuemon.Xml.XPath.XPathDocumentFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example creates an `XPathDocument` from an XML string using `XPathDocumentFactory`, then queries it with an XPath expression to retrieve the text content of an `` element. The resulting value "Hello" is written to the console. + ```csharp using System; using System.Xml.XPath; diff --git a/.docfx/api/types/Cuemon.Xml.XmlDocumentFactory.md b/.docfx/api/types/Cuemon.Xml.XmlDocumentFactory.md index 365c17ae..96b3b514 100644 --- a/.docfx/api/types/Cuemon.Xml.XmlDocumentFactory.md +++ b/.docfx/api/types/Cuemon.Xml.XmlDocumentFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example parses an XML string into an `XmlDocument` using `XmlDocumentFactory`, then navigates the document to read the root element name and a book's title attribute. The output displays "books" and "1984". + ```csharp using System; using System.Xml; diff --git a/.docfx/api/types/Cuemon.Xml.XmlStreamFactory.md b/.docfx/api/types/Cuemon.Xml.XmlStreamFactory.md index b7df7f4f..f003880c 100644 --- a/.docfx/api/types/Cuemon.Xml.XmlStreamFactory.md +++ b/.docfx/api/types/Cuemon.Xml.XmlStreamFactory.md @@ -4,6 +4,8 @@ example: - *content --- +The following example builds an XML document inline using `XmlStreamFactory.CreateStream` with an `XmlWriter` delegate. The resulting stream is read back as a string, producing a well-formed XML document with a `` root element. + ```csharp using System; using System.IO; diff --git a/.docfx/api/types/Cuemon.Xml.XmlWriterDecoratorExtensions.md b/.docfx/api/types/Cuemon.Xml.XmlWriterDecoratorExtensions.md index 5e08da4f..d0dfe198 100644 --- a/.docfx/api/types/Cuemon.Xml.XmlWriterDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Xml.XmlWriterDecoratorExtensions.md @@ -4,7 +4,7 @@ example: - *content --- -The following example demonstrates how to use the to serialize objects directly to an via the decorator pattern. +`XmlWriterDecoratorExtensions` provides extension methods on `Decorator.Enclose` for serializing objects directly to `XmlWriter` with root element handling, conditional encapsulation, and custom root naming. This example creates an `XmlWriter` targeting a `StringWriter` with indented settings, then uses `WriteXmlRootElement` with a custom delegate that writes a root element, serializes an anonymous `Person` object, and conditionally wraps notes in an encapsulating `` element via `WriteEncapsulatingElementIfNotNull`. A second example shows `WriteObject` to serialize a `Version` with a custom `RootName = new XmlQualifiedEntity("Version")`. Console output displays both XML results with the correct element structure. ```csharp using System; diff --git a/.docfx/api/types/System.Runtime.CompilerServices.CallerArgumentExpressionAttribute.md b/.docfx/api/types/System.Runtime.CompilerServices.CallerArgumentExpressionAttribute.md index 51d1af9d..6307dde9 100644 --- a/.docfx/api/types/System.Runtime.CompilerServices.CallerArgumentExpressionAttribute.md +++ b/.docfx/api/types/System.Runtime.CompilerServices.CallerArgumentExpressionAttribute.md @@ -4,6 +4,8 @@ example: - *content --- +The following example demonstrates `CallerArgumentExpressionAttribute` in a validation helper. `Validate` captures the source expression of its `condition` argument, so when `value > 0` is passed the console prints "Assertion passed: value > 0". + ```csharp using System; using System.Runtime.CompilerServices; diff --git a/.docfx/docfx.json b/.docfx/docfx.json index fd6d9199..606b2ee9 100644 --- a/.docfx/docfx.json +++ b/.docfx/docfx.json @@ -107,12 +107,15 @@ { "files": [ "api/**/*.yml", - "api/**/*.md", + "api/extensions/index.md", + "api/**/index.md", "packages/**/*.md", "toc.yml", "*.md" ], "exclude": [ + "api/namespaces/**", + "api/types/**", "bin/**", "obj/**" ] @@ -152,7 +155,8 @@ "overwrite": [ { "files": [ - "api/namespaces/**.md" + "api/namespaces/**/*.md", + "api/types/**/*.md" ], "exclude": [ "obj/**", From a0e95a52c30a7c4796872efcdd5c03ab5e429902 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Sat, 20 Jun 2026 11:06:52 +0200 Subject: [PATCH 6/8] =?UTF-8?q?=F0=9F=92=AC=20document=20docfx=20maintenan?= =?UTF-8?q?ce=20standards=20for=20public=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comprehensive DocFX documentation maintenance standards to AGENTS.md. Establishes requirements for public type documentation (examples, overwrite files, availability metadata), namespace-level extension member tables, and verification workflows. Clarifies the distinction between type page examples and namespace overview documentation, ensuring consistent, high-quality API reference generation. --- AGENTS.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 6ecfaa11..6ddf3b6a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -225,3 +225,51 @@ Agents must never automatically commit code changes or push to remote repositori 4. Build the affected source project to check for style violations. 5. Run targeted tests when changing logic. 6. Keep changes minimal and consistent with existing local style. + + +## DocFX Documentation Maintenance + +When changing public .NET APIs, keep the DocFX documentation current in the same change set. + +Documentation updates must cover public API only. Do not document private or internal types or members. Do not create namespace overview pages for namespaces that contain no public API. + +Public non-abstraction types — including enums, structs, records, plain classes, and static extension containers — are valid documentation targets. Generic public types and generic extension methods are valid documentation targets too. Do not exclude a type solely because it is generic or because reflection reports it as abstract and sealed (that is the IL pattern for a static class). + +For public non-abstraction types, include at least one realistic, copy/paste-ready usage example on the generated type page/overwrite section for that type UID. For example, a public `Class1` requires an example on the `Class1` API page, not only on the namespace page. Prefer deriving examples from existing unit, functional, or integration tests, but convert test code into real-life consumer-oriented usage. + +Missing type examples must be added through per-type DocFX overwrite files under `.docfx/api/types/{TypeUid}.md` in Codebelt repositories. Namespace overview text and `Extension Members` tables are not substitutes for type-page examples. + +Public extension methods must have examples too. Listing an extension method in an `Extension Members` table is required, but it is not enough. + +All added or changed code samples must be deterministic and verified to compile. Do not add pseudo-code, ellipses, hidden test helpers, or examples that rely on unverified behavior. + +Every namespace containing public API must have a DocFX namespace overview page named after the namespace, such as `X.Y.Z.md`, under `.docfx/api/namespaces/`, using DocFX overwrite front matter with the namespace `uid`. + +Namespaces exposing public extension methods must document those extension members at namespace level. The namespace page must include an `Extension Members` table listing the extended type, the extension marker, and the public extension methods. Extension members are rendered under the heading `Extension Members`. + +Both namespace overwrite files and type overwrite files are required deliverables in the same run. Generating only namespace pages or only type pages is incomplete. + +`docfx.json` must keep namespace and type overwrite files in separate subdirectories. `build.overwrite` must include both `api/namespaces/**/*.md` (for namespace pages) and `api/types/**/*.md` (for type pages). `build.content` must exclude both `api/namespaces/**` and `api/types/**` to prevent overwrite Markdown from being treated as conceptual content. Do not use `api/**/*.md` under `build.overwrite` or `build.content`. + +Availability must be documented by referencing the appropriate include file when one exists, or by adding explicit availability text when no suitable include exists. Availability must reflect the actual target frameworks, conditional compilation, and project configuration. + +Preserve manual documentation edits. Prefer additive changes, but correct stale or contradictory information so documentation remains accurate. + +Preserve working Markdown links, `Related:` references, and historical URL citations during prose rewrites. Remove or replace a URL only after directly verifying that the current destination returns HTTP 404. Timeouts, 403s, rate limits, DNS failures, and other lookup problems are not removal evidence. + +Interim scratch artifacts do not belong in the repository working tree. Store assessment queues, project manifests, review reports, captured validator output, progress notes, and one-off helper scripts in temp or session storage instead. New working-tree files are only legitimate when they are the managed `AGENTS.md` block, the active `docfx.json`, or DocFX-authored namespace/type Markdown that maps to a real public namespace or type. Everything else is blocking cleanup work, not a documentation deliverable. The validator auto-detects generic-arity type families (such as `MutableTuple`1`..`MutableTuple`N`) and skips redundant sibling examples from the public API surface alone, so no manifest or skip file is ever written into the repository. + +Before completing documentation work, run the relevant verification commands, normally: + +```bash +dotnet build +dotnet test +dotnet run --file skills/dotnet-docfx-digest/scripts/docfx.cs -- --repo-root . --verify-docfx-build +``` + +Codebelt repositories are normally strong-name signed with a `.snk` file in the repository root on the main author's codespace. Preserve and copy that root `.snk` file when building a temporary copy. If the repository or temp copy has no root `.snk`, run build and test verification with `-p:SkipSignAssembly=true`, for example `dotnet build -p:SkipSignAssembly=true` and `dotnet test -p:SkipSignAssembly=true`. + +The DocFX build verification must run outside the working tree when possible. The `--verify-docfx-build` option copies the repository to a temp workspace, runs DocFX against the resolved `docfx.json` there, and removes the temp workspace afterward so generated API YAML, manifest files, and site output do not flood git status. + +If a command cannot be run, report the exact limitation or failure instead of claiming the documentation was verified. + From a2dd5b8698243d8c04ce8fef9e8c77af627ac590 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Sat, 20 Jun 2026 14:30:07 +0200 Subject: [PATCH 7/8] =?UTF-8?q?=F0=9F=93=9D=20add=20example=20usage=20for?= =?UTF-8?q?=20StackDecoratorExtensions.TryPop=20method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ctions.Generic.StackDecoratorExtensions.md | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/.docfx/api/types/Cuemon.Collections.Generic.StackDecoratorExtensions.md b/.docfx/api/types/Cuemon.Collections.Generic.StackDecoratorExtensions.md index 88d5cdef..212182ec 100644 --- a/.docfx/api/types/Cuemon.Collections.Generic.StackDecoratorExtensions.md +++ b/.docfx/api/types/Cuemon.Collections.Generic.StackDecoratorExtensions.md @@ -4,4 +4,46 @@ example: - *content --- - +The following example demonstrates how to use StackDecoratorExtensions.TryPop to safely pop items from a Stack without throwing exceptions when the stack is empty, by wrapping the Stack in an IDecorator and calling the TryPop extension method. + +```csharp +using System; +using System.Collections.Generic; +using Cuemon; +using Cuemon.Collections.Generic; + +namespace MyApp.Examples; + +public class StackDecoratorExtensionsExample +{ + public static void Demonstrate() + { + var stack = new Stack(); + stack.Push("first"); + stack.Push("second"); + stack.Push("third"); + + var decorator = Decorator.Enclose(stack); + + if (StackDecoratorExtensions.TryPop(decorator, out string result1)) + { + Console.WriteLine("Popped: " + result1); + } + + if (StackDecoratorExtensions.TryPop(decorator, out string result2)) + { + Console.WriteLine("Popped: " + result2); + } + + if (StackDecoratorExtensions.TryPop(decorator, out string result3)) + { + Console.WriteLine("Popped: " + result3); + } + + if (!StackDecoratorExtensions.TryPop(decorator, out string _)) + { + Console.WriteLine("Stack is now empty"); + } + } +} +``` From c5ec2d14372ffa5810b0f57e85452cca0906d429 Mon Sep 17 00:00:00 2001 From: "aicia[bot]" Date: Sat, 20 Jun 2026 17:10:23 +0200 Subject: [PATCH 8/8] =?UTF-8?q?=F0=9F=92=AC=20finalize=2010.5.4=20release?= =?UTF-8?q?=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add release entry for 10.5.4 (2026-06-20) documenting dependency upgrades, test infrastructure improvements, and comprehensive API documentation enhancements. Update compare-link footer with v10.5.4 tag reference. --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01433d9a..b8d0d988 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), For more details, please refer to `PackageReleaseNotes.txt` on a per assembly basis in the `.nuget` folder. +## [10.5.4] - 2026-06-20 + +This is a patch release focused on dependency maintenance and comprehensive API documentation improvements. The release significantly expands published type-level and namespace-level guidance with concrete consumer-oriented examples, establishes DocFX documentation standards, and refactors test infrastructure for improved efficiency. + +### Changed + +- Upgrade dependencies to latest patch versions: Docker base image nginx (1.31.0 → 1.31.1), Codebelt.Extensions (11.0.9 → 11.1.0, 1.2.6 → 1.3.0), Microsoft.NET.Test.Sdk (18.5.1 → 18.6.0), and .NET 9/10 runtime packages, +- Refactor cache expiration tests in `SlimMemoryCacheTest` for improved readability and efficiency. + +### Added + +- Comprehensive API documentation across 100+ namespace and 570+ type documentation files with consumer-oriented descriptions and guidance, +- Type-level API documentation with concrete examples for 220+ public classes, structs, interfaces, and extension methods across the entire library, +- Namespace-level documentation featuring extension member tables that enumerate all extension methods grouped by extended type, +- DocFX documentation maintenance standards in `AGENTS.md` establishing requirements for public type documentation, examples, availability metadata, and verification workflows. + ## [10.5.3] - 2026-06-03 This is a patch release focused on fixing request service provider resolution for wrapped providers and significantly expanding test coverage across 15 assemblies to achieve >=95% coverage. The release consolidates ad-hoc coverage tests into integrated, maintainable test suites. @@ -1782,6 +1798,7 @@ This release was primarily focused on adapting a more modern way of performing C - XmlWriterUtility class from Cuemon.Xml namespace - XmlWriterUtilityExtensions class from the Cuemon.Xml namespace +[10.5.4]: https://github.com/codebeltnet/cuemon/compare/v10.5.3...v10.5.4 [10.5.3]: https://github.com/codebeltnet/cuemon/compare/v10.5.2...v10.5.3 [10.5.2]: https://github.com/codebeltnet/cuemon/compare/v10.5.1...v10.5.2 [10.5.1]: https://github.com/codebeltnet/cuemon/compare/v10.5.0...v10.5.1