diff --git a/.gitignore b/.gitignore
index 025815d8b..7a45a17b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -213,10 +213,16 @@ ModelManifest.xml
# Strong-Name Key
*.snk
-/src/Cuemon.Core/Cuemon.Core.csproj.DotSettings
# SonarLint
.sonarlint/
# Resharper
*.DotSettings
+
+# DocFx
+/docfx/wwwroot
+/docfx/api/**/*.yml
+/docfx/**/*.manifest
+/docfx/.vscode/docfx-assistant
+/.vscode/docfx-assistant
\ No newline at end of file
diff --git a/BuildDocfxImage.ps1 b/BuildDocfxImage.ps1
new file mode 100644
index 000000000..69e75910f
--- /dev/null
+++ b/BuildDocfxImage.ps1
@@ -0,0 +1,6 @@
+$version = (nbgv get-version -f json | ConvertFrom-Json).NuGetPackageVersion
+docfx metadata docfx/docfx.json
+docker build -t cuemon-docfx:$version -f Dockerfile.docfx .
+get-childItem -recurse -path docfx/api -include *.yml, .manifest | remove-item
+docker tag cuemon-docfx:$version tcr.cuemon.dk/cuemon-docfx:$version
+docker push tcr.cuemon.dk/cuemon-docfx:$version
\ No newline at end of file
diff --git a/Cuemon.sln b/Cuemon.sln
index 1108aa31f..ed4a866e5 100644
--- a/Cuemon.sln
+++ b/Cuemon.sln
@@ -13,9 +13,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.AspNetCore", "src\Cu
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Newtonsoft.Json", "src\Cuemon.Extensions.Newtonsoft.Json\Cuemon.Extensions.Newtonsoft.Json.csproj", "{080BDF91-E7C7-4CB4-A39D-E1A5374C5602}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml", "src\Cuemon.AspNetCore.Mvc.Formatters.Xml\Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.csproj", "{A70ADF91-E7C7-4CB4-A39D-E1A5374C5602}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml", "src\Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml\Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.csproj", "{A70ADF91-E7C7-4CB4-A39D-E1A5374C5602}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json", "src\Cuemon.AspNetCore.Mvc.Formatters.Json\Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json.csproj", "{A60ADF91-E7C7-4CB4-A39D-E1A5374C5602}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json", "src\Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json\Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.csproj", "{A60ADF91-E7C7-4CB4-A39D-E1A5374C5602}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.IO", "src\Cuemon.Extensions.IO\Cuemon.Extensions.IO.csproj", "{060BDF91-E7C7-4CB4-A39D-E1A5374C5602}"
EndProject
@@ -43,7 +43,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.AspNetCor
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.AspNetCore.Authentication", "src\Cuemon.AspNetCore.Authentication\Cuemon.AspNetCore.Authentication.csproj", "{A10ADF91-E7C7-4CB4-A39D-E1A5374C5602}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.AspNetCore.Razor", "src\Cuemon.AspNetCore.Razor\Cuemon.AspNetCore.Razor.csproj", "{A30ADF91-E7C7-4CB4-A39D-E1A5374C5602}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.AspNetCore.Razor.TagHelpers", "src\Cuemon.AspNetCore.Razor.TagHelpers\Cuemon.AspNetCore.Razor.TagHelpers.csproj", "{A30ADF91-E7C7-4CB4-A39D-E1A5374C5602}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Core.Tests", "test\Cuemon.Core.Tests\Cuemon.Core.Tests.csproj", "{CDE37A87-B35E-4F9B-9C5A-32E9B22A1B69}"
EndProject
@@ -55,7 +55,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Xunit", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Net.Tests", "test\Cuemon.Extensions.Net.Tests\Cuemon.Extensions.Net.Tests.csproj", "{E1C8F634-F655-487D-80B4-82F5F149FBA9}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Data.Integrity.Tests", "test\Cuemon.Extensions.Integrity.Tests\Cuemon.Extensions.Data.Integrity.Tests.csproj", "{4B1D7CA2-67E0-4D54-BBCA-6607A7770E44}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Data.Integrity.Tests", "test\Cuemon.Extensions.Data.Integrity.Tests\Cuemon.Extensions.Data.Integrity.Tests.csproj", "{4B1D7CA2-67E0-4D54-BBCA-6607A7770E44}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Core.Tests", "test\Cuemon.Extensions.Core.Tests\Cuemon.Extensions.Core.Tests.csproj", "{6ACD0AEE-4B47-4B29-9EA8-4FF9C20FF2F6}"
EndProject
@@ -105,6 +105,38 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Diagnostics", "src\C
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Diagnostics.Tests", "test\Cuemon.Diagnostics.Tests\Cuemon.Diagnostics.Tests.csproj", "{06559CB0-899C-4B48-AFB8-633CBF97A766}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Security.Cryptography", "src\Cuemon.Security.Cryptography\Cuemon.Security.Cryptography.csproj", "{1B0BDF91-E7C7-4CB4-A39D-E1A5374C5602}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Security.Cryptography.Tests", "test\Cuemon.Security.Cryptography.Tests\Cuemon.Security.Cryptography.Tests.csproj", "{5D67081C-4458-41AA-A1F5-FAC974D29FDF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Xunit.Hosting", "src\Cuemon.Extensions.Xunit.Hosting\Cuemon.Extensions.Xunit.Hosting.csproj", "{1E0BDF91-E7C7-4CB4-A39D-E1A5374C5602}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Hosting", "src\Cuemon.Extensions.Hosting\Cuemon.Extensions.Hosting.csproj", "{1D0BDF91-E7C7-4CB4-A39D-E1A5374C5602}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Xunit.Tests", "test\Cuemon.Extensions.Xunit.Tests\Cuemon.Extensions.Xunit.Tests.csproj", "{2108E7E7-F002-481C-B17F-918E76D98378}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Xunit.Hosting.Tests", "test\Cuemon.Extensions.Xunit.Hosting.Tests\Cuemon.Extensions.Xunit.Hosting.Tests.csproj", "{86B43822-0733-416E-8DA2-666C5657974F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Runtime.Caching.Tests", "test\Cuemon.Runtime.Caching.Tests\Cuemon.Runtime.Caching.Tests.csproj", "{581174AB-62AA-4A04-85DE-4F9E307C9712}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Runtime.Caching", "src\Cuemon.Extensions.Runtime.Caching\Cuemon.Extensions.Runtime.Caching.csproj", "{1F0BDF91-E7C7-4CB4-A39D-E1A5374C5602}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Runtime.Caching.Tests", "test\Cuemon.Extensions.Runtime.Caching.Tests\Cuemon.Extensions.Runtime.Caching.Tests.csproj", "{0F614FD1-BC7C-4F7F-9847-D3675614576C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Newtonsoft.Json.Tests", "test\Cuemon.Extensions.Newtonsoft.Json.Tests\Cuemon.Extensions.Newtonsoft.Json.Tests.csproj", "{8A3E26BD-A3C4-4684-909B-1ABDFDB4108D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Data.SqlClient.Tests", "test\Cuemon.Data.SqlClient.Tests\Cuemon.Data.SqlClient.Tests.csproj", "{A9610C9E-1944-4771-A5E1-CE47ADA243D5}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Xunit.Hosting.AspNetCore", "src\Cuemon.Extensions.Xunit.Hosting.AspNetCore\Cuemon.Extensions.Xunit.Hosting.AspNetCore.csproj", "{200BDF91-E7C7-4CB4-A39D-E1A5374C5602}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Xunit.Hosting.AspNetCore.Tests", "test\Cuemon.Extensions.Xunit.Hosting.AspNetCore.Tests\Cuemon.Extensions.Xunit.Hosting.AspNetCore.Tests.csproj", "{72422689-CDC3-4AD6-89D7-25F85545B0FE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc", "src\Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc\Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc.csproj", "{210BDF91-E7C7-4CB4-A39D-E1A5374C5602}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cuemon.AspNetCore.Authentication.Tests", "test\Cuemon.AspNetCore.Authentication.Tests\Cuemon.AspNetCore.Authentication.Tests.csproj", "{D29D6F7E-8A76-48AD-A042-EFC83CD474A5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cuemon.Extensions.AspNetCore.Authentication", "src\Cuemon.Extensions.AspNetCore.Authentication\Cuemon.Extensions.AspNetCore.Authentication.csproj", "{C5DB7806-EC4F-4D74-A9FE-A5B9A0625A41}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -307,6 +339,70 @@ Global
{06559CB0-899C-4B48-AFB8-633CBF97A766}.Debug|Any CPU.Build.0 = Debug|Any CPU
{06559CB0-899C-4B48-AFB8-633CBF97A766}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06559CB0-899C-4B48-AFB8-633CBF97A766}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1B0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1B0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1B0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1B0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5D67081C-4458-41AA-A1F5-FAC974D29FDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5D67081C-4458-41AA-A1F5-FAC974D29FDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5D67081C-4458-41AA-A1F5-FAC974D29FDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5D67081C-4458-41AA-A1F5-FAC974D29FDF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1E0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1E0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1E0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1E0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1D0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1D0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1D0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1D0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2108E7E7-F002-481C-B17F-918E76D98378}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2108E7E7-F002-481C-B17F-918E76D98378}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2108E7E7-F002-481C-B17F-918E76D98378}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2108E7E7-F002-481C-B17F-918E76D98378}.Release|Any CPU.Build.0 = Release|Any CPU
+ {86B43822-0733-416E-8DA2-666C5657974F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {86B43822-0733-416E-8DA2-666C5657974F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {86B43822-0733-416E-8DA2-666C5657974F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {86B43822-0733-416E-8DA2-666C5657974F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {581174AB-62AA-4A04-85DE-4F9E307C9712}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {581174AB-62AA-4A04-85DE-4F9E307C9712}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {581174AB-62AA-4A04-85DE-4F9E307C9712}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {581174AB-62AA-4A04-85DE-4F9E307C9712}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1F0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1F0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1F0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1F0BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0F614FD1-BC7C-4F7F-9847-D3675614576C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0F614FD1-BC7C-4F7F-9847-D3675614576C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0F614FD1-BC7C-4F7F-9847-D3675614576C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0F614FD1-BC7C-4F7F-9847-D3675614576C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8A3E26BD-A3C4-4684-909B-1ABDFDB4108D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8A3E26BD-A3C4-4684-909B-1ABDFDB4108D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8A3E26BD-A3C4-4684-909B-1ABDFDB4108D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8A3E26BD-A3C4-4684-909B-1ABDFDB4108D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A9610C9E-1944-4771-A5E1-CE47ADA243D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A9610C9E-1944-4771-A5E1-CE47ADA243D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A9610C9E-1944-4771-A5E1-CE47ADA243D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A9610C9E-1944-4771-A5E1-CE47ADA243D5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {200BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {200BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {200BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {200BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Release|Any CPU.Build.0 = Release|Any CPU
+ {72422689-CDC3-4AD6-89D7-25F85545B0FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {72422689-CDC3-4AD6-89D7-25F85545B0FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {72422689-CDC3-4AD6-89D7-25F85545B0FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {72422689-CDC3-4AD6-89D7-25F85545B0FE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {210BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {210BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {210BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {210BDF91-E7C7-4CB4-A39D-E1A5374C5602}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D29D6F7E-8A76-48AD-A042-EFC83CD474A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D29D6F7E-8A76-48AD-A042-EFC83CD474A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D29D6F7E-8A76-48AD-A042-EFC83CD474A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D29D6F7E-8A76-48AD-A042-EFC83CD474A5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C5DB7806-EC4F-4D74-A9FE-A5B9A0625A41}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C5DB7806-EC4F-4D74-A9FE-A5B9A0625A41}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C5DB7806-EC4F-4D74-A9FE-A5B9A0625A41}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C5DB7806-EC4F-4D74-A9FE-A5B9A0625A41}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -361,6 +457,22 @@ Global
{190BDF91-E7C7-4CB4-A39D-E1A5374C5602} = {B59C8DF7-7DEC-46AF-A165-CC9E3AD01EA8}
{1A0BDF91-E7C7-4CB4-A39D-E1A5374C5602} = {B59C8DF7-7DEC-46AF-A165-CC9E3AD01EA8}
{06559CB0-899C-4B48-AFB8-633CBF97A766} = {31707D2B-843E-4D4F-B9C7-3E74EF8DA338}
+ {1B0BDF91-E7C7-4CB4-A39D-E1A5374C5602} = {B59C8DF7-7DEC-46AF-A165-CC9E3AD01EA8}
+ {5D67081C-4458-41AA-A1F5-FAC974D29FDF} = {31707D2B-843E-4D4F-B9C7-3E74EF8DA338}
+ {1E0BDF91-E7C7-4CB4-A39D-E1A5374C5602} = {B59C8DF7-7DEC-46AF-A165-CC9E3AD01EA8}
+ {1D0BDF91-E7C7-4CB4-A39D-E1A5374C5602} = {B59C8DF7-7DEC-46AF-A165-CC9E3AD01EA8}
+ {2108E7E7-F002-481C-B17F-918E76D98378} = {31707D2B-843E-4D4F-B9C7-3E74EF8DA338}
+ {86B43822-0733-416E-8DA2-666C5657974F} = {31707D2B-843E-4D4F-B9C7-3E74EF8DA338}
+ {581174AB-62AA-4A04-85DE-4F9E307C9712} = {31707D2B-843E-4D4F-B9C7-3E74EF8DA338}
+ {1F0BDF91-E7C7-4CB4-A39D-E1A5374C5602} = {B59C8DF7-7DEC-46AF-A165-CC9E3AD01EA8}
+ {0F614FD1-BC7C-4F7F-9847-D3675614576C} = {31707D2B-843E-4D4F-B9C7-3E74EF8DA338}
+ {8A3E26BD-A3C4-4684-909B-1ABDFDB4108D} = {31707D2B-843E-4D4F-B9C7-3E74EF8DA338}
+ {A9610C9E-1944-4771-A5E1-CE47ADA243D5} = {31707D2B-843E-4D4F-B9C7-3E74EF8DA338}
+ {200BDF91-E7C7-4CB4-A39D-E1A5374C5602} = {B59C8DF7-7DEC-46AF-A165-CC9E3AD01EA8}
+ {72422689-CDC3-4AD6-89D7-25F85545B0FE} = {31707D2B-843E-4D4F-B9C7-3E74EF8DA338}
+ {210BDF91-E7C7-4CB4-A39D-E1A5374C5602} = {B59C8DF7-7DEC-46AF-A165-CC9E3AD01EA8}
+ {D29D6F7E-8A76-48AD-A042-EFC83CD474A5} = {31707D2B-843E-4D4F-B9C7-3E74EF8DA338}
+ {C5DB7806-EC4F-4D74-A9FE-A5B9A0625A41} = {B59C8DF7-7DEC-46AF-A165-CC9E3AD01EA8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2A848386-B682-4F6D-8254-B5F6247C3054}
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 000000000..ad1c4734f
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,74 @@
+
+
+ $(MSBuildProjectName.EndsWith('Tests'))
+
+
+
+ true
+ true
+
+
+
+ ..\..\.sonarlint\cuemoncsharp.ruleset
+
+
+
+ Copyright © Geekle 2009-2021. All rights reserved.
+ gimlichael
+ Geekle
+ Cuemon for .NET
+ https://nblcdn.net/cuemon.net/128x128.png
+ https://www.cuemon.net/
+ MIT
+ https://github.com/gimlichael/Cuemon
+ git
+ en-US
+ true
+ true
+ true
+ snupkg
+ true
+ true
+ $(MSBuildThisFileDirectory)cuemon.snk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ net5.0
+ false
+ false
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 000000000..ff27971c6
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,23 @@
+
+
+
+ <_LocalTopLevelSourceRoot Include="@(SourceRoot)" Condition="'%(SourceRoot.NestedRoot)' == ''"/>
+
+
+
+
+ $(MSBuildProjectDirectory)/Properties/PackageReleaseNotes.txt
+
+
+
+
+
+
+
+ @(PackageReleaseNotesLines, '%0A')
+
+
+
\ No newline at end of file
diff --git a/Dockerfile.docfx b/Dockerfile.docfx
new file mode 100644
index 000000000..f99f06682
--- /dev/null
+++ b/Dockerfile.docfx
@@ -0,0 +1,47 @@
+# escape=`
+
+FROM nginx:1.19.7 AS base
+RUN rm -rf /usr/share/nginx/html/*
+
+FROM mono:6.10.0.104 AS build
+ARG DOCFX_VERSION=v2.56.6
+
+ENV PATH ${PATH}:/opt/docfx
+ENV DOCFX_SOURCE_BRANCH_NAME="development"
+
+# MONO IMAGE
+RUN curl -sSL --output packages-microsoft-prod.deb https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb
+RUN dpkg -i packages-microsoft-prod.deb
+RUN apt-get update `
+&& apt-get install -y powershell zip apt-transport-https dirmngr gnupg ca-certificates git `
+&& mkdir -p /opt/docfx/ `
+&& curl -sSL --output docfx.zip "https://github.com/dotnet/docfx/releases/download/${DOCFX_VERSION}/docfx.zip" `
+&& unzip docfx.zip -d /opt/docfx/ `
+&& rm docfx.zip `
+&& echo '#!/bin/bash' >> /opt/docfx/docfx `
+&& echo 'exec mono /opt/docfx/docfx.exe $@' >> /opt/docfx/docfx `
+&& chmod +x /opt/docfx/docfx `
+&& apt-get -y purge unzip
+
+SHELL ["/opt/microsoft/powershell/7/pwsh", "-Command"]
+
+WORKDIR /build
+
+ADD ["docfx", "docfx"]
+#ADD ["src", "src"] INCLUDE THIS WHEN DOCFX IS MATURED - SEE NOTE BELOW
+
+RUN cd docfx; `
+# docfx metadata; ` INCLUDE THIS WHEN DOCFX IS MATURED - SEE NOTE BELOW
+docfx build
+
+# After carefull considerations, I have concluded that DoxFx is not a matured product to be run entirely as part of a Docker image.
+# Reason is that for DocFx to resolve cref correctly (and assembly names) it requires the msbuild project file (csproj) and not only the source files (cs).
+# As stated by docfx team themself: Visual Studio 2019 is needed for docfx metadata msbuild projects.
+# Given that VS2019 is to hard a dependency, I have moved the docfx metadata taskto my local development environment.
+# It would have been great to have all documentation done in a container - but for now this is not an option without significant drawbacks.
+
+FROM base AS final
+WORKDIR /usr/share/nginx/html
+COPY --from=build /build/docfx/wwwroot /usr/share/nginx/html
+
+ENTRYPOINT ["nginx", "-g", "daemon off;"]
\ No newline at end of file
diff --git a/README.md b/README.md
index f4c1b6b5e..9d5cd658d 100644
--- a/README.md
+++ b/README.md
@@ -1,31 +1,74 @@
-
+
-Cuemon
---------------------
-Cuemon is a free and flexible assembly package for the Microsoft .NET ecosystem. It was built to extend and boost your codebelt - providing vast ways of possibilities for all breeds of coders, programmers, developers and the likes thereof. Ideal for .NET, .NET Standard, .NET Core, Universal Windows Platform and .NET Framework 4.6.1 and newer.
+# Cuemon for .NET
-
+An open-source project (MIT license) that targets and complements the Microsoft .NET platform. It provides vast ways of possibilities for all breeds of coders, programmers, developers and the likes thereof. Ideal for .NET, .NET Standard, .NET Core, Universal Windows Platform and .NET Framework 4.6.1 and newer.
-This development branch contains the latest version which has been completely refactored and updated to suport .NET Core 3.1.
-An Azure DevOps pipeline is currently in progress.
+It is, by heart, free, flexible and built to extend and boost your agile codebelt.
-Once automated and tested thoroughly, it will be pushed to a new branch, release, and hereafter again tested and lastly to master and Nuget packages.
+## State of the Union
-[](https://gimlichael.visualstudio.com/CuemonCore/_build/latest?definitionId=1&branchName=development)
+Cuemon for .NET (formerly Cuemon .NET Standard) has been completely refactored and updated to support .NET 5 while for the most part being compatible with .NET Standard 2.0, .NET Core 2.0 and .NET Core 3.0.
-[](https://sonarcloud.io/dashboard?id=CuemonCore)
-[](https://sonarcloud.io/dashboard?id=CuemonCore)
-[](https://sonarcloud.io/dashboard?id=CuemonCore)
-[](https://sonarcloud.io/dashboard?id=CuemonCore)
-[](https://sonarcloud.io/dashboard?id=CuemonCore)
-[](https://sonarcloud.io/dashboard?id=CuemonCore)
-[](https://sonarcloud.io/dashboard?id=CuemonCore)
-[](https://sonarcloud.io/dashboard?id=CuemonCore)
-[](https://sonarcloud.io/dashboard?id=CuemonCore)
+Another big change for this upcoming release is the versioning; the developers has spoken and cast their love on semantic versioning.
+The release for now is planned to be 6.0.0.
-[](https://sonarcloud.io/dashboard?id=CuemonCore)
+Check out the WIP documentation (generated by DocFx): https://docs.cuemon.net/
-Stay tuned!
+All CI and CD integrations are done on [Microsoft Azure DevOps](https://azure.microsoft.com/en-us/services/devops/) and is currently in the process of being tweaked.
+
+All code quality analysis are done by [SonarCloud](https://sonarcloud.io/) and [CodeCov.io](https://codecov.io/).
+
+Currently work is done on ironing out the kinks in relations to NuGet package description, release notes conventions, concepts and last minute refactorings to provide the best experience possible with RC-1!
+
+ [](https://dev.azure.com/gimlichael/Cuemon/_build/latest?definitionId=9&branchName=development) [](https://codecov.io/gh/gimlichael/Cuemon) [](https://sonarcloud.io/dashboard?id=Cuemon)
+
+
+## Development Branch
+
+The `development` branch contains the latest (and greatest) version of the code.
+
+To consume a CI build, create a `NuGet.Config` in your root solution directory and add following content:
+
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+Do note, that builds from development are preview builds and not to be considered stable.
+
+Once tested thoroughly and feature milestone has been reached, the code will be pushed and merged to a new branch; `release`.
+
+## Release Branch
+
+The `release` branch contains the next version of Cuemon for .NET. Here it will be tested again while the next semantic version is being determined.
+
+All CI builds are pushed to NuGet.org as either `alpha`, `beta` or `rc` releases. For more information, check out [Package versioning - Pre-release Versions](https://docs.microsoft.com/en-us/nuget/concepts/package-versioning#pre-release-versions) at Microsoft.
+
+Lastly, when things are looking all fine and dandy, the code will be pushed and merged to the `master` branch.
+
+## Master Branch
+
+The `master` branch always contains the current `production` ready version of Cuemon for .NET.
+
+Builds performed from this repository are pushed to NuGet.org as the actual version they represent. Eg. the forthcoming version of Cuemon for .NET will be 6.0.0.
+
+### Code Quality Monitoring
+
+[](https://sonarcloud.io/dashboard?id=Cuemon) [](https://sonarcloud.io/dashboard?id=Cuemon) [](https://sonarcloud.io/dashboard?id=Cuemon) [](https://sonarcloud.io/dashboard?id=Cuemon)
+
+[](https://sonarcloud.io/dashboard?id=Cuemon) [](https://sonarcloud.io/dashboard?id=Cuemon) [](https://sonarcloud.io/dashboard?id=Cuemon) [](https://sonarcloud.io/dashboard?id=Cuemon) [](https://sonarcloud.io/dashboard?id=Cuemon) [](https://sonarcloud.io/dashboard?id=Cuemon)
+
+
+
+### Links to NuGet packages (will be updated once Cuemon for .NET has shipped in 6.0.0)
Useful links for this project (will soon be changed for the forthcoming release):
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
new file mode 100644
index 000000000..b75c1894d
--- /dev/null
+++ b/azure-pipelines.yml
@@ -0,0 +1,231 @@
+trigger:
+- development
+
+variables:
+ - group: Integration Test
+ - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE
+ value: true
+ - name: DOTNET_CLI_TELEMETRY_OPTOUT
+ value: 1
+ - name: BuildSource
+ value: 'src'
+ - name: BuildPlatform
+ value: 'Any CPU'
+ - name: BuildConfiguration
+ value: 'Release'
+
+jobs:
+- job: CI
+ timeoutInMinutes: 120
+
+ strategy:
+ matrix:
+ Linux_Build_and_Test:
+ imageName: 'ubuntu-20.04'
+ Windows_Build_Test_and_Package:
+ imageName: 'windows-2019'
+
+ pool:
+ vmImage: $(imageName)
+
+ steps:
+
+ - task: UseDotNet@2
+ condition: eq(variables['Agent.OS'], 'Linux')
+ displayName: 'Use .Net Core SDK 2.2.207 (SonarCloud)'
+ inputs:
+ version: 2.2.207
+
+ - task: UseDotNet@2
+ displayName: 'Use .Net Core SDK 5.0.103'
+ inputs:
+ version: 5.0.103
+
+ - task: DotNetCoreCLI@2
+ displayName: 'Install NBGV tool'
+ inputs:
+ command: custom
+ custom: tool
+ arguments: 'install --global nbgv'
+
+ - task: DotNetCoreCLI@2
+ condition: eq(variables['Agent.OS'], 'Linux')
+ displayName: 'Install ReportGenerator tool'
+ inputs:
+ command: custom
+ custom: tool
+ arguments: install --global dotnet-reportgenerator-globaltool
+
+ - script: 'nbgv cloud'
+ displayName: 'Set Version using NBGV'
+
+ - task: DownloadSecureFile@1
+ displayName: 'Download cuemon.snk'
+ inputs:
+ secureFile: 'cuemon.snk'
+
+ - task: CopyFiles@2
+ displayName: 'Copy cuemon.snk to $(System.DefaultWorkingDirectory)'
+ inputs:
+ SourceFolder: '$(Agent.TempDirectory)'
+ Contents: cuemon.snk
+ TargetFolder: '$(System.DefaultWorkingDirectory)'
+
+ - task: DotNetCoreCLI@2
+ displayName: Restore
+ inputs:
+ command: restore
+ projects: |
+ **/*.csproj
+
+ - task: DockerCompose@0
+ condition: eq(variables['Agent.OS'], 'Linux')
+ displayName: 'Spin up SQL Server for unit/integration test'
+ inputs:
+ containerregistrytype: 'Container Registry'
+ dockerComposeFile: '**/docker-compose.yml'
+ dockerComposeFileArgs: |
+ SA_PASSWORD=$(awsql-password)
+ dockerComposeCommand: "up -d"
+ action: 'Run a Docker Compose command'
+
+ - task: SonarCloudPrepare@1
+ condition: eq(variables['Agent.OS'], 'Linux')
+ displayName: 'Prepare Analysis on SonarCloud'
+ inputs:
+ SonarCloud: 'Cuemon-SonarCloud'
+ organization: 'geekle'
+ scannerMode: 'MSBuild'
+ projectKey: 'Cuemon'
+ projectName: 'Cuemon'
+ projectVersion: '$(GitAssemblyInformationalVersion)'
+ extraProperties: |
+ sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/**/*opencover.xml
+ sonar.cs.vstest.reportsPaths=$(Agent.TempDirectory)/*.trx
+
+ - task: DotNetCoreCLI@2
+ displayName: 'Build net5.0 compatible Assemblies'
+ inputs:
+ command: 'build'
+ projects: |
+ src/**/*.csproj
+ arguments: '--configuration $(BuildConfiguration) --no-restore --framework net5.0'
+ workingDirectory: '$(BuildSource)'
+
+ - task: DotNetCoreCLI@2
+ displayName: 'Build netcoreapp3.1 compatible Assemblies'
+ inputs:
+ command: 'build'
+ projects: |
+ src/**/Cuemon.Extensions.Xunit.Hosting.AspNetCore.csproj
+ src/**/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc.csproj
+ arguments: '--configuration $(BuildConfiguration) --no-restore --framework netcoreapp3.1'
+ workingDirectory: '$(BuildSource)'
+
+ - task: DotNetCoreCLI@2
+ displayName: 'Build netcoreapp3.0 compatible Assemblies'
+ inputs:
+ command: 'build'
+ projects: |
+ src/**/Cuemon.AspNetCore*.csproj
+ src/**/Cuemon.Extensions.AspNetCore*.csproj
+ src/**/Cuemon.Extensions.Hosting.csproj
+ src/**/Cuemon.Extensions.Xunit.Hosting.csproj
+ arguments: '--configuration $(BuildConfiguration) --no-restore --framework netcoreapp3.0'
+ workingDirectory: '$(BuildSource)'
+
+ - task: DotNetCoreCLI@2
+ displayName: 'Build netstandard2.1 compatible Assemblies'
+ inputs:
+ command: 'build'
+ projects: |
+ src/**/Cuemon.Extensions.IO.csproj
+ src/**/Cuemon.IO.csproj
+ arguments: '--configuration $(BuildConfiguration) --no-restore --framework netstandard2.1'
+ workingDirectory: '$(BuildSource)'
+
+ - task: DotNetCoreCLI@2
+ displayName: 'Build netstandard2.0 compatible Assemblies'
+ inputs:
+ command: 'build'
+ projects: |
+ src/**/*.csproj
+ !src/**/Cuemon.Extensions.Xunit.Hosting.AspNetCore.csproj
+ !src/**/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc.csproj
+ arguments: '--configuration $(BuildConfiguration) --no-restore --framework netstandard2.0'
+ workingDirectory: '$(BuildSource)'
+
+ - task: DotNetCoreCLI@2
+ displayName: 'Test Solution - Linux'
+ condition: eq(variables['Agent.OS'], 'Linux')
+ inputs:
+ command: 'test'
+ projects: test/**/*.csproj
+ arguments: '--configuration $(BuildConfiguration) --collect:"XPlat Code Coverage" /p:CollectCoverage=true /p:CoverletOutputFormat=opencover'
+ publishTestResults: true
+ env:
+ ConnectionStrings__AdventureWorks: $(ConnectionStrings--AdventureWorks)
+
+ - task: DotNetCoreCLI@2
+ displayName: 'Test Solution - Windows'
+ condition: eq(variables['Agent.OS'], 'Windows_NT')
+ inputs:
+ command: 'test'
+ projects: test/**/*.csproj
+ arguments: '--configuration $(BuildConfiguration) --collect:"XPlat Code Coverage" /p:CollectCoverage=true /p:CoverletOutputFormat=opencover --filter FullyQualifiedName!~SqlClient'
+ publishTestResults: true
+
+ - script: reportgenerator "-reports:**/*.opencover.xml" "-targetdir:$(Build.SourcesDirectory)/Coverage" "-reporttypes:Cobertura;HTMLInline;HTMLChart"
+ condition: eq(variables['Agent.OS'], 'Linux')
+ displayName: 'Create Code Coverage Reports'
+
+ - task: PublishCodeCoverageResults@1
+ condition: eq(variables['Agent.OS'], 'Linux')
+ displayName: 'Publish Code Coverage'
+ inputs:
+ codeCoverageTool: Cobertura
+ summaryFileLocation: '$(Build.SourcesDirectory)/Coverage/Cobertura.xml'
+ reportDirectory: '$(Build.SourcesDirectory)/Coverage'
+
+ - bash: bash <(curl -s https://codecov.io/bash)
+ condition: eq(variables['Agent.OS'], 'Linux')
+ displayName: 'Upload to codecov.io'
+
+ - task: SonarCloudAnalyze@1
+ condition: eq(variables['Agent.OS'], 'Linux')
+ displayName: 'Run Sonar Cloud Code Analysis'
+
+ - task: SonarCloudPublish@1
+ condition: eq(variables['Agent.OS'], 'Linux')
+ displayName: 'Publish Quality Gate Result to Sonar Cloud'
+ inputs:
+ pollingTimeoutSec: '300'
+
+ - task: DockerCompose@0
+ condition: eq(variables['Agent.OS'], 'Linux')
+ displayName: 'Take down SQL Server'
+ inputs:
+ containerregistrytype: 'Container Registry'
+ dockerComposeFile: '**/docker-compose.yml'
+ dockerComposeCommand: "down"
+ action: 'Run a Docker Compose command'
+
+ - task: DotNetCoreCLI@2
+ condition: eq(variables['Agent.OS'], 'Windows_NT')
+ displayName: dotnet pack
+ inputs:
+ command: pack
+ packagesToPack: src/**/*.csproj
+ nobuild: true
+
+ - task: WhiteSource Bolt@20
+ condition: eq(variables['Agent.OS'], 'Windows_NT')
+ displayName: 'WhiteSource Bolt'
+
+ - task: PublishBuildArtifacts@1
+ condition: eq(variables['Agent.OS'], 'Windows_NT')
+ displayName: 'Store NuGet Packages'
+ inputs:
+ PathtoPublish: $(Build.ArtifactStagingDirectory)
+ ArtifactName: Packages
+ publishLocation: Container
\ No newline at end of file
diff --git a/docfx/api/aspnet/ext/index.md b/docfx/api/aspnet/ext/index.md
new file mode 100644
index 000000000..5939a2736
--- /dev/null
+++ b/docfx/api/aspnet/ext/index.md
@@ -0,0 +1,45 @@
+---
+uid: extensions-aspnet-md
+title: Extensions for ASP.NET Core API Reference
+---
+## Cuemon Extensions for ASP.NET Core API Reference
+
+The **Cuemon** assembly family provides both enhancements and extension methods to these namespaces of [Microsoft .NET Standard](https://docs.microsoft.com/en-us/dotnet/api/?view=netstandard-2.0):
+
++ System
++ System.Collections
++ System.Collections.Concurrent
++ System.Collections.Generic
++ System.Collections.ObjectModel
++ System.Collections.Specialized
++ System.ComponentModel
++ System.Configuration
++ System.Data
++ System.Data.Common
++ System.Diagnostics
++ System.Globalization
++ System.Linq
++ System.IO
++ System.Net.Httpp
++ System.Net.Http.Headers
++ System.Net.Mail
++ System.Reflection
++ System.Runtime.CompilerServices
++ System.Security.Cryptography
++ System.Text
++ System.Threading
++ System.Threading.Tasks
++ System.Xml
++ System.Xml.Serialization
++ System.Xml.XPath
+
+### Cuemon.Data
+[NS-2.0-API](/api/cuemon/data/index.html)
+
+### Cuemon.Diagnostics
+[NS-2.0-API](/api/cuemon/diagnostics/index.html)
+
+### Cuemon.Xml
+[NS-2.0-API](/api/core/netstandard2.0/Cuemon.Xml.html)
+
+[](https://gimlichael.visualstudio.com/CuemonCore/_build/latest?definitionId=1)
\ No newline at end of file
diff --git a/docfx/api/aspnet/index.md b/docfx/api/aspnet/index.md
new file mode 100644
index 000000000..ef0528f00
--- /dev/null
+++ b/docfx/api/aspnet/index.md
@@ -0,0 +1,45 @@
+---
+uid: aspnet-md
+title: ASP.NET Core API Reference
+---
+## Cuemon ASP.NET Core API Reference
+
+The **Cuemon** assembly family provides both enhancements and extension methods to these namespaces of [Microsoft .NET Standard](https://docs.microsoft.com/en-us/dotnet/api/?view=netstandard-2.0):
+
++ System
++ System.Collections
++ System.Collections.Concurrent
++ System.Collections.Generic
++ System.Collections.ObjectModel
++ System.Collections.Specialized
++ System.ComponentModel
++ System.Configuration
++ System.Data
++ System.Data.Common
++ System.Diagnostics
++ System.Globalization
++ System.Linq
++ System.IO
++ System.Net.Httpp
++ System.Net.Http.Headers
++ System.Net.Mail
++ System.Reflection
++ System.Runtime.CompilerServices
++ System.Security.Cryptography
++ System.Text
++ System.Threading
++ System.Threading.Tasks
++ System.Xml
++ System.Xml.Serialization
++ System.Xml.XPath
+
+### Cuemon.Data
+[NS-2.0-API](/api/cuemon/data/index.html)
+
+### Cuemon.Diagnostics
+[NS-2.0-API](/api/cuemon/diagnostics/index.html)
+
+### Cuemon.Xml
+[NS-2.0-API](/api/core/netstandard2.0/Cuemon.Xml.html)
+
+[](https://gimlichael.visualstudio.com/CuemonCore/_build/latest?definitionId=1)
\ No newline at end of file
diff --git a/docfx/api/dotnet/ext/index.md b/docfx/api/dotnet/ext/index.md
new file mode 100644
index 000000000..382653803
--- /dev/null
+++ b/docfx/api/dotnet/ext/index.md
@@ -0,0 +1,45 @@
+---
+uid: extensions-dotnet-md
+title: Extensions for Core API Reference
+---
+## Cuemon Extensions for Core API Reference
+
+The **Cuemon** assembly family provides both enhancements and extension methods to these namespaces of [Microsoft .NET Standard](https://docs.microsoft.com/en-us/dotnet/api/?view=netstandard-2.0):
+
++ System
++ System.Collections
++ System.Collections.Concurrent
++ System.Collections.Generic
++ System.Collections.ObjectModel
++ System.Collections.Specialized
++ System.ComponentModel
++ System.Configuration
++ System.Data
++ System.Data.Common
++ System.Diagnostics
++ System.Globalization
++ System.Linq
++ System.IO
++ System.Net.Httpp
++ System.Net.Http.Headers
++ System.Net.Mail
++ System.Reflection
++ System.Runtime.CompilerServices
++ System.Security.Cryptography
++ System.Text
++ System.Threading
++ System.Threading.Tasks
++ System.Xml
++ System.Xml.Serialization
++ System.Xml.XPath
+
+### Cuemon.Data
+[NS-2.0-API](/api/cuemon/data/index.html)
+
+### Cuemon.Diagnostics
+[NS-2.0-API](/api/cuemon/diagnostics/index.html)
+
+### Cuemon.Xml
+[NS-2.0-API](/api/core/netstandard2.0/Cuemon.Xml.html)
+
+[](https://gimlichael.visualstudio.com/CuemonCore/_build/latest?definitionId=1)
\ No newline at end of file
diff --git a/docfx/api/dotnet/index.md b/docfx/api/dotnet/index.md
new file mode 100644
index 000000000..a6766c963
--- /dev/null
+++ b/docfx/api/dotnet/index.md
@@ -0,0 +1,45 @@
+---
+uid: dotnet-md
+title: Core API Reference
+---
+## Cuemon Core API Reference
+
+The **Cuemon** assembly family provides both enhancements and extension methods to these namespaces of [Microsoft .NET Standard](https://docs.microsoft.com/en-us/dotnet/api/?view=netstandard-2.0):
+
++ System
++ System.Collections
++ System.Collections.Concurrent
++ System.Collections.Generic
++ System.Collections.ObjectModel
++ System.Collections.Specialized
++ System.ComponentModel
++ System.Configuration
++ System.Data
++ System.Data.Common
++ System.Diagnostics
++ System.Globalization
++ System.Linq
++ System.IO
++ System.Net.Httpp
++ System.Net.Http.Headers
++ System.Net.Mail
++ System.Reflection
++ System.Runtime.CompilerServices
++ System.Security.Cryptography
++ System.Text
++ System.Threading
++ System.Threading.Tasks
++ System.Xml
++ System.Xml.Serialization
++ System.Xml.XPath
+
+### Cuemon.Data
+[NS-2.0-API](/api/cuemon/data/index.html)
+
+### Cuemon.Diagnostics
+[NS-2.0-API](/api/cuemon/diagnostics/index.html)
+
+### Cuemon.Xml
+[NS-2.0-API](/api/core/netstandard2.0/Cuemon.Xml.html)
+
+[](https://gimlichael.visualstudio.com/CuemonCore/_build/latest?definitionId=1)
\ No newline at end of file
diff --git a/docfx/api/index.md b/docfx/api/index.md
new file mode 100644
index 000000000..7ff9326b1
--- /dev/null
+++ b/docfx/api/index.md
@@ -0,0 +1,45 @@
+---
+uid: concept-md
+title: Cuemon Concept Reference
+---
+## Cuemon Concept Reference
+
+The **Cuemon** assembly family provides both enhancements and extension methods to these namespaces of [Microsoft .NET Standard](https://docs.microsoft.com/en-us/dotnet/api/?view=netstandard-2.0):
+
++ System
++ System.Collections
++ System.Collections.Concurrent
++ System.Collections.Generic
++ System.Collections.ObjectModel
++ System.Collections.Specialized
++ System.ComponentModel
++ System.Configuration
++ System.Data
++ System.Data.Common
++ System.Diagnostics
++ System.Globalization
++ System.Linq
++ System.IO
++ System.Net.Httpp
++ System.Net.Http.Headers
++ System.Net.Mail
++ System.Reflection
++ System.Runtime.CompilerServices
++ System.Security.Cryptography
++ System.Text
++ System.Threading
++ System.Threading.Tasks
++ System.Xml
++ System.Xml.Serialization
++ System.Xml.XPath
+
+### Cuemon.Data
+[NS-2.0-API](/api/cuemon/data/index.html)
+
+### Cuemon.Diagnostics
+[NS-2.0-API](/api/cuemon/diagnostics/index.html)
+
+### Cuemon.Xml
+[NS-2.0-API](/api/core/netstandard2.0/Cuemon.Xml.html)
+
+[](https://gimlichael.visualstudio.com/CuemonCore/_build/latest?definitionId=1)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Basic.md b/docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Basic.md
new file mode 100644
index 000000000..b94d60232
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Basic.md
@@ -0,0 +1,16 @@
+---
+uid: Cuemon.AspNetCore.Authentication.Basic
+summary: *content
+---
+The Cuemon.AspNetCore.Authentication.Basic namespace contains types that enable support for Basic Authentication Scheme.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore.Authentication/Basic)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore.Authentication/Basic)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore.Authentication/Basic)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore.Authentication (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore.Authentication)\
+[Cuemon.AspNetCore.Authentication (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.Authentication)
\ 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
new file mode 100644
index 000000000..46a052c31
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Digest.md
@@ -0,0 +1,16 @@
+---
+uid: Cuemon.AspNetCore.Authentication.Digest
+summary: *content
+---
+The Cuemon.AspNetCore.Authentication.Digest namespace contains types that enable support for Digest Access Authentication Scheme.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore.Authentication/Digest)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore.Authentication/Digest)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore.Authentication/Digest)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore.Authentication (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore.Authentication)\
+[Cuemon.AspNetCore.Authentication (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.Authentication)
\ 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
new file mode 100644
index 000000000..40c57b8c3
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Authentication.Hmac.md
@@ -0,0 +1,16 @@
+---
+uid: Cuemon.AspNetCore.Authentication.Hmac
+summary: *content
+---
+The Cuemon.AspNetCore.Authentication.Hmac namespace contains types that enable support for HMAC Access Authentication Scheme. 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).
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore.Authentication/Hmac)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore.Authentication/Hmac)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore.Authentication/Hmac)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore.Authentication (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore.Authentication)\
+[Cuemon.AspNetCore.Authentication (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.Authentication)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Authentication.md b/docfx/api/namespaces/Cuemon.AspNetCore.Authentication.md
new file mode 100644
index 000000000..8c85671b9
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Authentication.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Authentication namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication?view=aspnetcore-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore.Authentication)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore.Authentication)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore.Authentication)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore.Authentication (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore.Authentication)\
+[Cuemon.AspNetCore.Authentication (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.Authentication)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Builder.md b/docfx/api/namespaces/Cuemon.AspNetCore.Builder.md
new file mode 100644
index 000000000..091b508ee
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Builder.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Related: [Cuemon.Extensions.AspNetCore.Builder namespace](https://docs.cuemon.net/api/aspnet/ext/Cuemon.Extensions.AspNetCore.Builder.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Configuration.md b/docfx/api/namespaces/Cuemon.AspNetCore.Configuration.md
new file mode 100644
index 000000000..b6b0f457a
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Configuration.md
@@ -0,0 +1,18 @@
+---
+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).
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Related: [Cuemon.Extensions.AspNetCore.Mvc.Configuration namespace](https://docs.cuemon.net/api/aspnet/ext/Cuemon.Extensions.AspNetCore.Mvc.Configuration.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Diagnostics.md b/docfx/api/namespaces/Cuemon.AspNetCore.Diagnostics.md
new file mode 100644
index 000000000..f475cbae3
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Diagnostics.md
@@ -0,0 +1,22 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Diagnostics namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.diagnostics?view=aspnetcore-2.0) 🔗
+
+Related: [Cuemon.AspNetCore.Mvc.Filters.Diagnostics namespace](https://docs.cuemon.net/api/aspnet/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.html) 📘
+
+Related: [Cuemon.Extensions.AspNetCore.Diagnostics namespace](https://docs.cuemon.net/api/aspnet/ext/Cuemon.Extensions.AspNetCore.Diagnostics.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Hosting.md b/docfx/api/namespaces/Cuemon.AspNetCore.Hosting.md
new file mode 100644
index 000000000..758f0417d
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Hosting.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Hosting namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.hosting?view=aspnetcore-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Http.Headers.md b/docfx/api/namespaces/Cuemon.AspNetCore.Http.Headers.md
new file mode 100644
index 000000000..0ba680c00
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Http.Headers.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Http.Headers namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.headers?view=aspnetcore-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore)
\ 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
new file mode 100644
index 000000000..80253f3c3
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Http.Throttling.md
@@ -0,0 +1,18 @@
+---
+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.).
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Related: [Cuemon.Extensions.AspNetCore.Http.Throttling namespace](https://docs.cuemon.net/api/aspnet/ext/Cuemon.Extensions.AspNetCore.Http.Throttling.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Http.md b/docfx/api/namespaces/Cuemon.AspNetCore.Http.md
new file mode 100644
index 000000000..cafd6a7b8
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Http.md
@@ -0,0 +1,20 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Http namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http?view=aspnetcore-2.0) 🔗
+
+Related: [Cuemon.Extensions.AspNetCore.Http namespace](https://docs.cuemon.net/api/aspnet/ext/Cuemon.Extensions.AspNetCore.Http.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Cacheable.md b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Cacheable.md
new file mode 100644
index 000000000..1a2d8047e
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Cacheable.md
@@ -0,0 +1,20 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Mvc.Filters namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.filters?view=aspnetcore-2.0) 🔗
+
+Related: [Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable namespace](https://docs.cuemon.net/api/aspnet/ext/Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore.Mvc)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.Mvc)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.md b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.md
new file mode 100644
index 000000000..f2540d5a1
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.md
@@ -0,0 +1,20 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Mvc.Filters namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.filters?view=aspnetcore-2.0) 🔗
+
+Related: [Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics namespace](https://docs.cuemon.net/api/aspnet/ext/Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore.Mvc)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.Mvc)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Headers.md b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Headers.md
new file mode 100644
index 000000000..2d78e4fef
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Headers.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Mvc.Filters namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.filters?view=aspnetcore-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore.Mvc)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.Mvc)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.ModelBinding.md b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.ModelBinding.md
new file mode 100644
index 000000000..afa9abefd
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.ModelBinding.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Mvc.ModelBinding namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.modelbinding?view=aspnetcore-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore.Mvc)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.Mvc)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Throttling.md b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Throttling.md
new file mode 100644
index 000000000..4555e14cf
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.Throttling.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Mvc.Filters namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.filters?view=aspnetcore-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore.Mvc)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.Mvc)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.md b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.md
new file mode 100644
index 000000000..d7da0dd25
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.Filters.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Mvc.Filters namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.filters?view=aspnetcore-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore.Mvc)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.Mvc)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.md b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.md
new file mode 100644
index 000000000..90957ba0c
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Mvc.md
@@ -0,0 +1,20 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Mvc namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc?view=aspnetcore-2.0) 🔗
+
+Related: [Cuemon.Extensions.AspNetCore.Mvc namespace](https://docs.cuemon.net/api/aspnet/ext/Cuemon.Extensions.AspNetCore.Mvc.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore.Mvc)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.Mvc)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.Razor.TagHelpers.md b/docfx/api/namespaces/Cuemon.AspNetCore.Razor.TagHelpers.md
new file mode 100644
index 000000000..9da759522
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.Razor.TagHelpers.md
@@ -0,0 +1,18 @@
+---
+uid: Cuemon.AspNetCore.Razor.TagHelpers
+summary: *content
+---
+The Cuemon.AspNetCore.Razor.TagHelpers namespace contains types tailored tag helper implementations. The namespace is an addition to the Microsoft.AspNetCore.Razor.TagHelpers namespace.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Razor.TagHelpers namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.razor.taghelpers?view=aspnetcore-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore.Razor.TagHelpers)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore.Razor.TagHelpers)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore.Razor.TagHelpers)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore.Razor.TagHelpers (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore.Razor.TagHelpers)\
+[Cuemon.AspNetCore.Razor.TagHelpers (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore.Razor.TagHelpers)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.AspNetCore.md b/docfx/api/namespaces/Cuemon.AspNetCore.md
new file mode 100644
index 000000000..ce34245bd
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.AspNetCore.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore?view=aspnetcore-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.AspNetCore)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.AspNetCore)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.AspNetCore)
+
+NuGet packages 📦\
+[Cuemon.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.AspNetCore)\
+[Cuemon.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.AspNetCore)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Collections.Generic.md b/docfx/api/namespaces/Cuemon.Collections.Generic.md
new file mode 100644
index 000000000..53a1b8fd2
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Collections.Generic.md
@@ -0,0 +1,20 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Collections.Generic namespace](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic?view=netstandard-2.0) 🔗
+
+Related: [Cuemon.Extensions.Collections.Generic namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Collections.Generic.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Core/Collections/Generic)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Core/Collections/Generic)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Core/Collections/Generic)
+
+NuGet packages 📦\
+[Cuemon.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Core)\
+[Cuemon.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Core/)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Collections.md b/docfx/api/namespaces/Cuemon.Collections.md
new file mode 100644
index 000000000..80446ab84
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Collections.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Collections namespace](https://docs.microsoft.com/en-us/dotnet/api/system.collections?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Core/Collections)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Core/Collections)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Core/Collections)
+
+NuGet packages 📦\
+[Cuemon.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Core)\
+[Cuemon.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Core/)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Configuration.md b/docfx/api/namespaces/Cuemon.Configuration.md
new file mode 100644
index 000000000..4e90c033c
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Configuration.md
@@ -0,0 +1,16 @@
+---
+uid: Cuemon.Configuration
+summary: *content
+---
+The Cuemon.Configuration namespace contains types focusing on writing configurable classes to help suport adhering to Separation of Concerns (SoC).
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Core/Configuration)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Core/Configuration)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Core/Configuration)
+
+NuGet packages 📦\
+[Cuemon.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Core)\
+[Cuemon.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Core/)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Data.Integrity.md b/docfx/api/namespaces/Cuemon.Data.Integrity.md
new file mode 100644
index 000000000..467c6acb3
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Data.Integrity.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Related: [Cuemon.Extensions.Data.Integrity namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Data.Integrity.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Data.Integrity)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Data.Integrity)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Data.Integrity)
+
+NuGet packages 📦\
+[Cuemon.Data.Integrity (CI)](https://nuget.cuemon.net/packages/Cuemon.Data.Integrity)\
+[Cuemon.Data.Integrity (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Data.Integrity)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Data.SqlClient.md b/docfx/api/namespaces/Cuemon.Data.SqlClient.md
new file mode 100644
index 000000000..cb9219e5e
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Data.SqlClient.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Data.SqlClient namespace](https://docs.microsoft.com/en-us/dotnet/api/system.Data.SqlClient?view=netframework-4.8) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Data.SqlClient)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Data.SqlClient)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Data.SqlClient)
+
+NuGet packages 📦\
+[Cuemon.Data.SqlClient (CI)](https://nuget.cuemon.net/packages/Cuemon.Data.SqlClient)\
+[Cuemon.Data.SqlClient (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Data.SqlClient)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Data.Xml.md b/docfx/api/namespaces/Cuemon.Data.Xml.md
new file mode 100644
index 000000000..ed7166a59
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Data.Xml.md
@@ -0,0 +1,16 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Data/Xml)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Data/Xml)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Data/Xml)
+
+NuGet packages 📦\
+[Cuemon.Data.SqlClient (CI)](https://nuget.cuemon.net/packages/Cuemon.Data)\
+[Cuemon.Data.SqlClient (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Data)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Data.md b/docfx/api/namespaces/Cuemon.Data.md
new file mode 100644
index 000000000..14fb5a086
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Data.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Data namespace](https://docs.microsoft.com/en-us/dotnet/api/system.Data?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Data)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Data)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Data)
+
+NuGet packages 📦\
+[Cuemon.Data (CI)](https://nuget.cuemon.net/packages/Cuemon.Data)\
+[Cuemon.Data (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Data)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Diagnostics.md b/docfx/api/namespaces/Cuemon.Diagnostics.md
new file mode 100644
index 000000000..bcc81fe8a
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Diagnostics.md
@@ -0,0 +1,20 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Diagnostics namespace](https://docs.microsoft.com/en-us/dotnet/api/system.Diagnostics?view=netstandard-2.0) 🔗
+
+Related: [Cuemon.Extensions.Diagnostics namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Diagnostics.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Diagnostics)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Diagnostics)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Diagnostics)
+
+NuGet packages 📦\
+[Cuemon.Diagnostics (CI)](https://nuget.cuemon.net/packages/Cuemon.Diagnostics)\
+[Cuemon.Diagnostics (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Diagnostics)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Builder.md b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Builder.md
new file mode 100644
index 000000000..a07aca809
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Builder.md
@@ -0,0 +1,24 @@
+---
+uid: Cuemon.Extensions.AspNetCore.Builder
+summary: *content
+---
+The Cuemon.Extensions.AspNetCore.Builder namespace contains extension methods that complements the Cuemon.AspNetCore.Builder namespace.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.AspNetCore.Builder namespace](https://docs.cuemon.net/api/aspnet/Cuemon.AspNetCore.Builder.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore/Builder)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore/Builder)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore/Builder)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore)\
+[Cuemon.Extensions.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IApplicationBuilder|⬇️|`UseHostingEnvironment`, `UseCorrelationIdentifier`, `UseRequestIdentifier`, `UseUserAgentSentinel`, `UseThrottlingSentinel`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Data.Integrity.md b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Data.Integrity.md
new file mode 100644
index 000000000..d00b22675
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Data.Integrity.md
@@ -0,0 +1,25 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.Data.Integrity namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Data.Integrity.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore/Data/Integrity)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore/Data/Integrity)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore/Data/Integrity)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore)\
+[Cuemon.Extensions.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|CacheValidator|⬇️|`ToEntityTag`|
+|ChecksumBuilder|⬇️|`ToEntityTagHeaderValue`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.Throttling.md b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.Throttling.md
new file mode 100644
index 000000000..79dce2238
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.Throttling.md
@@ -0,0 +1,24 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.AspNetCore.Http.Throttling namespace](https://docs.cuemon.net/api/aspnet/Cuemon.AspNetCore.Http.Throttling.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore/Http/Throttling)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore/Http/Throttling)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore/Http/Throttling)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore)\
+[Cuemon.Extensions.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IServiceCollection|⬇️|`AddThrottlingCache{T}`, `AddMemoryThrottlingCache`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.md b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.md
new file mode 100644
index 000000000..3aaa10035
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Http.md
@@ -0,0 +1,27 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.AspNetCore.Http namespace](https://docs.cuemon.net/api/aspnet/Cuemon.AspNetCore.Http.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore/Http)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore/Http)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore/Http)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore)\
+[Cuemon.Extensions.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IHeaderDictionary|⬇️|`AddOrUpdateHeaders`, `AddOrUpdateHeader`|
+|HttpRequest|⬇️|`IsGetOrHeadMethod`, `IsClientSideResourceCached`|
+|HttpResponse|⬇️|`AddOrUpdateEntityTagHeader`, `AddOrUpdateLastModifiedHeader`, `WriteBodyAsync`, `OnStartingInvokeTransformer`|
+|Int32|⬇️|`IsInformationStatusCode`, `IsSuccessStatusCode`, `IsRedirectionStatusCode`, `IsNotModifiedStatusCode`, `IsClientErrorStatusCode`, `IsServerErrorStatusCode`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Configuration.md b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Configuration.md
new file mode 100644
index 000000000..bb5ae5edf
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Configuration.md
@@ -0,0 +1,24 @@
+---
+uid: Cuemon.Extensions.AspNetCore.Mvc.Configuration
+summary: *content
+---
+The Cuemon.Extensions.AspNetCore.Mvc.Configuration namespace contains both types and extension methods that complements the Cuemon.AspNetCore.Configuration namespace while being an addition to the Microsoft.AspNetCore.Mvc namespace. Provides a set of different cache busting strategies for ASP.NET Core MVC that can be easily customized.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.AspNetCore.Configuration namespace](https://docs.cuemon.net/api/aspnet/Cuemon.AspNetCore.Configuration.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore.Mvc (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore.Mvc)\
+[Cuemon.Extensions.AspNetCore.Mvc (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore.Mvc)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IServiceCollection|⬇️|`AddCacheBusting{T}`, `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
new file mode 100644
index 000000000..920b9a385
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable.md
@@ -0,0 +1,24 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.AspNetCore.Mvc.Filters.Cacheable namespace](https://docs.cuemon.net/api/aspnet/Cuemon.AspNetCore.Mvc.Filters.Cacheable.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore.Mvc (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore.Mvc)\
+[Cuemon.Extensions.AspNetCore.Mvc (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore.Mvc)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|ICacheableAsyncResultFilter|⬇️|`AddFilter{T, TOptions}`, `InsertFilter{T, TOptions}`, `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
new file mode 100644
index 000000000..053b1b75b
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics.md
@@ -0,0 +1,24 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.AspNetCore.Mvc.Filters.Diagnostics namespace](https://docs.cuemon.net/api/aspnet/Cuemon.AspNetCore.Mvc.Filters.Diagnostics.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore.Mvc (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore.Mvc)\
+[Cuemon.Extensions.AspNetCore.Mvc (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore.Mvc)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|FaultResolver|⬇️|`Add{T}`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.Converters.md b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.Converters.md
new file mode 100644
index 000000000..aae9bf089
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.Converters.md
@@ -0,0 +1,24 @@
+---
+uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.Converters
+summary: *content
+---
+The Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.Converters namespace contains extension methods that complements the Cuemon.Extensions.Newtonsoft.Json.Converters namespace.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.Extensions.Newtonsoft.Json.Converters namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Newtonsoft.Json.Converters.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)\
+[Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|JsonConverter|⬇️|`AddHttpExceptionDescriptorConverter`, `AddStringValuesConverter`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.md b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.md
new file mode 100644
index 000000000..d6eb73be4
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.md
@@ -0,0 +1,25 @@
+---
+uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json
+summary: *content
+---
+The Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json namespace contains both types and extension methods that complements the Cuemon.Extensions.Newtonsoft.Json namespace while being an addition to the Microsoft.AspNetCore.Mvc namespace. Provides JSON formatters for ASP.NET Core that is powered by Newtonsoft.Json.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.Extensions.Newtonsoft.Json namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Newtonsoft.Json.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json)\
+[Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IMvcBuilder|⬇️|`AddJsonSerializationFormatters`, `AddJsonFormatterOptions`|
+|IMvcCoreBuilder|⬇️|`AddJsonSerializationFormatters`, `AddJsonFormatterOptions`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Converters.md b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Converters.md
new file mode 100644
index 000000000..e1b7993fe
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Converters.md
@@ -0,0 +1,24 @@
+---
+uid: Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Converters
+summary: *content
+---
+The Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Converters namespace contains extension methods that complements the Cuemon.Extensions.Xml.Serialization.Converters namespace.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.Extensions.Xml.Serialization.Converters namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Xml.Serialization.Converters.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)\
+[Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|XmlConverter|⬇️|`AddHttpExceptionDescriptorConverter`, `AddStringValuesConverter`, `AddHeaderDictionaryConverter`, `AddQueryCollectionConverter`, `AddFormCollectionConverter`, `AddCookieCollectionConverter`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.md b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.md
new file mode 100644
index 000000000..5690aef9b
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.md
@@ -0,0 +1,25 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.Extensions.Xml namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Xml.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)\
+[Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IMvcBuilder|⬇️|`AddXmlSerializationFormatters`, `AddXmlFormatterOptions`|
+|IMvcCoreBuilder|⬇️|`AddXmlSerializationFormatters`, `AddXmlFormatterOptions`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Rendering.md b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Rendering.md
new file mode 100644
index 000000000..dfe3b5b93
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.Rendering.md
@@ -0,0 +1,24 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Mvc.Rendering namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.rendering?view=aspnetcore-3.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore.Mvc (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore.Mvc)\
+[Cuemon.Extensions.AspNetCore.Mvc (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore.Mvc)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IHtmlHelper|⬇️|`UseWhen`, `UseWhen{T}`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.md b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.md
new file mode 100644
index 000000000..88db4bc3f
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.Mvc.md
@@ -0,0 +1,26 @@
+---
+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 the Microsoft.AspNetCore.Mvc namespace. Provides a set of different cache busting strategies for ASP.NET Core MVC that can be easily customized.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.AspNetCore.Mvc namespace](https://docs.cuemon.net/api/aspnet/Cuemon.AspNetCore.Mvc.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore.Mvc (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore.Mvc)\
+[Cuemon.Extensions.AspNetCore.Mvc (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore.Mvc)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IApplicationBuilder|⬇️|`UseWhen`|
+|Object|⬇️|`MakeCacheable`, `MakeCacheable{T}`|
+|ViewDataDictionary|⬇️|`AddBreadcrumbs{T}`, `GetBreadcrumbs`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.md b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.md
new file mode 100644
index 000000000..f2f4054e0
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.AspNetCore.md
@@ -0,0 +1,18 @@
+---
+uid: Cuemon.Extensions.AspNetCore
+summary: *content
+---
+The Cuemon.Extensions.AspNetCore namespace contains both types and extension methods that complements the Cuemon.AspNetCore namespace while being an addition to the Microsoft.AspNetCore namespace. Provides an in-memory implementation of a throttling cache for ASP.NET Core.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Cuemon.AspNetCore namespace](https://docs.cuemon.net/api/aspnet/Cuemon.AspNetCore.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.AspNetCore)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.AspNetCore)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.AspNetCore)
+
+NuGet packages 📦\
+[Cuemon.Extensions.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.AspNetCore)\
+[Cuemon.Extensions.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.AspNetCore)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Collections.Generic.md b/docfx/api/namespaces/Cuemon.Extensions.Collections.Generic.md
new file mode 100644
index 000000000..6df1d3cc2
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Collections.Generic.md
@@ -0,0 +1,27 @@
+---
+uid: Cuemon.Extensions.Collections.Generic
+summary: *content
+---
+The Cuemon.Extensions.Collections.Specialized namespace contains extension methods that complements the Cuemon.Collections.Generic namespace while being an addition to the System.Collections.Specialized namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Collections.Specialized namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Collections.Generic.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Collections.Generic)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Collections.Generic)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Collections.Generic)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Collections.Generic (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Collections.Generic)\
+[Cuemon.Extensions.Collections.Generic (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Collections.Generic)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|ICollection{T}|⬇️|`ToPartitioner{T}`, `AddRange{T}`|
+|IDictionary{TKey, TValue}|⬇️|`GetValueOrDefault{TKey, TValue}`, `TryGetValueOrFallback{TKey, TValue}`, `ToEnumerable{TKey, TValue}`, `TryAdd{TKey, TValue}`, `TryAddOrUpdate{TKey, TValue}`|
+|IEnumerable{T}|⬇️|`Chunk{T}`, `Shuffle{T}`, `OrderBy{T}`, `OrderByDescending{T}`, `RandomOrDefault{T}`, `Yield{T}`, `ToDictionary{TKey, TValue}`, `ToPartitioner{T}`, `ToPagedCollection{T}`|
+|IList{T}|⬇️|`Remove{T}`, `HasIndex{T}`, `Next{T}`, `Previous{T}`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Collections.Specialized.md b/docfx/api/namespaces/Cuemon.Extensions.Collections.Specialized.md
new file mode 100644
index 000000000..ada5764da
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Collections.Specialized.md
@@ -0,0 +1,25 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Collections.Specialized namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Collections.Specialized.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Collections.Specialized)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Collections.Specialized)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Collections.Specialized)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Collections.Specialized (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Collections.Specialized)\
+[Cuemon.Extensions.Collections.Specialized (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Collections.Specialized)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IDictionary{string, string[]}|⬇️|`ToNameValueCollection`|
+|NameValueCollection|⬇️|`ContainsKey`, `ToDictionary`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Data.Integrity.md b/docfx/api/namespaces/Cuemon.Extensions.Data.Integrity.md
new file mode 100644
index 000000000..b922d8574
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Data.Integrity.md
@@ -0,0 +1,27 @@
+---
+uid: Cuemon.Extensions.Data.Integrity
+summary: *content
+---
+The Cuemon.Extensions.Data.Integrity namespace contains extension methods that complements the Cuemon.Data.Integrity namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Data.Integrity namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Data.Integrity.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Data.Integrity)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Data.Integrity)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Data.Integrity)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Data.Integrity (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Data.Integrity)\
+[Cuemon.Extensions.Data.Integrity (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Data.Integrity)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|Assembly|⬇️|`GetCacheValidator`|
+|ChecksumBuilder|⬇️|`CombineWith{T}`|
+|DateTime|⬇️|`GetCacheValidator`|
+|FileInfo|⬇️|`GetCacheValidator`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Data.md b/docfx/api/namespaces/Cuemon.Extensions.Data.md
new file mode 100644
index 000000000..dd4aacd56
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Data.md
@@ -0,0 +1,25 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Data namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Data.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Data)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Data)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Data)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Data (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Data)\
+[Cuemon.Extensions.Data (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Data)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IDataReader|⬇️|`ToColumns`, `ToRows`|
+|QueryFormat|⬇️|`Embed`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.DependencyInjection.md b/docfx/api/namespaces/Cuemon.Extensions.DependencyInjection.md
new file mode 100644
index 000000000..51d88c2e7
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.DependencyInjection.md
@@ -0,0 +1,24 @@
+---
+uid: Cuemon.Extensions.DependencyInjection
+summary: *content
+---
+The Cuemon.Extensions.DependencyInjection namespace contains extension methods that complements the Microsoft.Extensions.DependencyInjection namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Microsoft.Extensions.DependencyInjection namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection?view=dotnet-plat-ext-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.DependencyInjection)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.DependencyInjection)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.DependencyInjection)
+
+NuGet packages 📦\
+[Cuemon.Extensions.DependencyInjection (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.DependencyInjection)\
+[Cuemon.Extensions.DependencyInjection (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.DependencyInjection)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IServiceCollection|⬇️|`Add`, `Add{TOptions}`, `Add{TService, TImplementation}`, `Add{TService, TImplementation, TOptions}`, `TryAdd`, `TryAdd{TOptions}`, `TryAdd{TService, TImplementation}`, `TryAdd{TService, TImplementation, TOptions}`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Diagnostics.md b/docfx/api/namespaces/Cuemon.Extensions.Diagnostics.md
new file mode 100644
index 000000000..e178394b8
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Diagnostics.md
@@ -0,0 +1,25 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Diagnostics namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Diagnostics.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Diagnostics)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Diagnostics)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Diagnostics)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Diagnostics (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Diagnostics)\
+[Cuemon.Extensions.Diagnostics (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Diagnostics)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|ExceptionDescriptor|⬇️|`ToInsightsString`|
+|FileVersionInfo|⬇️|`ToProductVersion`, `ToFileVersion`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Hosting.md b/docfx/api/namespaces/Cuemon.Extensions.Hosting.md
new file mode 100644
index 000000000..9d4e4003b
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Hosting.md
@@ -0,0 +1,25 @@
+---
+uid: Cuemon.Extensions.Hosting
+summary: *content
+---
+The Cuemon.Extensions.Hosting namespace contains extension methods and features related to the Microsoft.Extensions.Hosting namespace.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [Microsoft.Extensions.Hosting namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting?view=dotnet-plat-ext-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Hosting)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Hosting)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Hosting)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Hosting (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Hosting)\
+[Cuemon.Extensions.Hosting (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Hosting)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IHostEnvironment|⬇️|`IsLocalDevelopment`, `IsNonProduction`|
+|IHostingEnvironment|⬇️|`IsLocalDevelopment`, `IsNonProduction`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.IO.md b/docfx/api/namespaces/Cuemon.Extensions.IO.md
new file mode 100644
index 000000000..28efe6242
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.IO.md
@@ -0,0 +1,27 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Standard 2.1, .NET 5.0
+
+Complements: [Cuemon.IO namespace](https://docs.cuemon.net/api/dotnet/Cuemon.IO.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.IO)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.IO)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.IO)
+
+NuGet packages 📦\
+[Cuemon.Extensions.IO (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.IO)\
+[Cuemon.Extensions.IO (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.IO)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|byte[]|⬇️|`ToStream`, `ToStreamAsync`|
+|Stream|⬇️|`Concat`, `ToCharArray`, `ToByteArray`, `ToByteArrayAsync`, `WriteAsync`, `TryDetectUnicodeEncoding`, `ToEncodedString`, `ToEncodedStringAsync`, `CompressBrotli`, `CompressBrotliAsync`, `CompressDeflate`, `CompressDeflateAsync`, `CompressGZip`, `CompressGZipAsync`, `DecompressBrotli`, `DecompressBrotliAsync`, `DecompressDeflate`, `DecompressDeflateAsync`, `DecompressGZip`, `DecompressGZipAsync`|
+|String|⬇️|`ToStream`, `ToStreamAsync`, `ToTextReader`|
+|TextReader|⬇️|`CopyToAsync`, `ReadAllLines`, `ReadAllLinesAsync`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Net.Http.md b/docfx/api/namespaces/Cuemon.Extensions.Net.Http.md
new file mode 100644
index 000000000..71c1e61c1
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Net.Http.md
@@ -0,0 +1,23 @@
+---
+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).
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Net/Http)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Net/Http)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Net/Http)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Net (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Net)\
+[Cuemon.Extensions.Net (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Net)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|HttpMethod|⬇️|`ToHttpMethod`|
+|Uri|⬇️|`HttpDeleteAsync`, `HttpGetAsync`, `HttpHeadAsync`, `HttpOptionsAsync`, `HttpPostAsync`, `HttpPutAsync`, `HttpPatchAsync`, `HttpTraceAsync`, `HttpAsync`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Net.Security.md b/docfx/api/namespaces/Cuemon.Extensions.Net.Security.md
new file mode 100644
index 000000000..cbe162418
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Net.Security.md
@@ -0,0 +1,23 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Net/Security)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Net/Security)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Net/Security)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Net (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Net)\
+[Cuemon.Extensions.Net (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Net)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|String|⬇️|`ToSignedUri`, `ValidateSignedUri`|
+|Uri|⬇️|`ToSignedUri`, `ValidateSignedUri`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Net.md b/docfx/api/namespaces/Cuemon.Extensions.Net.md
new file mode 100644
index 000000000..e97df1d87
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Net.md
@@ -0,0 +1,28 @@
+---
+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).
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Net namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Net.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Net)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Net)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Net)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Net (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Net)\
+[Cuemon.Extensions.Net (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Net)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|byte[]|⬇️|`UrlEncode`|
+|IDictionary{string, string[]}|⬇️|`ToQueryString`|
+|HttpStatusCode|⬇️|`IsInformationStatusCode`, `IsSuccessStatusCode`, `IsRedirectionStatusCode`, `IsClientErrorStatusCode`, `IsServerErrorStatusCode`|
+|NameValueCollection|⬇️|`ToQueryString`|
+|String|⬇️|`UrlDecode`, `UrlEncode`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Newtonsoft.Json.Converters.md b/docfx/api/namespaces/Cuemon.Extensions.Newtonsoft.Json.Converters.md
new file mode 100644
index 000000000..a7bbb93c7
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Newtonsoft.Json.Converters.md
@@ -0,0 +1,24 @@
+---
+uid: Cuemon.Extensions.Newtonsoft.Json.Converters
+summary: *content
+---
+The Cuemon.Extensions.Newtonsoft.Json.Converters namespace contains both types and extension methods that complements the Newtonsoft.Json.Converters namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Newtonsoft.Json.Converters namespace](https://www.newtonsoft.com/json/help/html/N_Newtonsoft_Json_Converters.htm) 🔗
+
+Github branches: 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Newtonsoft.Json/Converters)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Newtonsoft.Json/Converters)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Newtonsoft.Json/Converters)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Newtonsoft.Json (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Newtonsoft.Json)\
+[Cuemon.Extensions.Newtonsoft.Json (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Newtonsoft.Json)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|JsonConverter|⬇️|`AddStringEnumConverter`, `AddStringFlagsEnumConverter`, `AddExceptionDescriptorConverter`, `AddTimeSpanConverter`, `AddExceptionConverter`, `AddDataPairConverter`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Newtonsoft.Json.Diagnostics.md b/docfx/api/namespaces/Cuemon.Extensions.Newtonsoft.Json.Diagnostics.md
new file mode 100644
index 000000000..4e6a5b48f
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Newtonsoft.Json.Diagnostics.md
@@ -0,0 +1,24 @@
+---
+uid: Cuemon.Extensions.Newtonsoft.Json.Diagnostics
+summary: *content
+---
+The Cuemon.Extensions.Newtonsoft.Json.Diagnostics namespace contains extension methods that complements the Cuemon.Diagnostics namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Diagnostics namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Diagnostics.html) 🔗
+
+Github branches: 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Newtonsoft.Json/Diagnostics)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Newtonsoft.Json/Diagnostics)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Newtonsoft.Json/Diagnostics)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Newtonsoft.Json (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Newtonsoft.Json)\
+[Cuemon.Extensions.Newtonsoft.Json (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Newtonsoft.Json)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|ExceptionDescriptor|⬇️|`ToInsightsJsonString`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Newtonsoft.Json.Formatters.md b/docfx/api/namespaces/Cuemon.Extensions.Newtonsoft.Json.Formatters.md
new file mode 100644
index 000000000..bff68a885
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Newtonsoft.Json.Formatters.md
@@ -0,0 +1,18 @@
+---
+uid: Cuemon.Extensions.Newtonsoft.Json.Formatters
+summary: *content
+---
+The Cuemon.Extensions.Newtonsoft.Json.Formatters namespace contains types that are used to serialize and deserialize objects into and from JSON format using a generic signature.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Newtonsoft.Json.Serialization namespace](https://www.newtonsoft.com/json/help/html/N_Newtonsoft_Json_Serialization.htm) 🔗
+
+Github branches: 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Newtonsoft.Json/Formatters)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Newtonsoft.Json/Formatters)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Newtonsoft.Json/Formatters)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Newtonsoft.Json (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Newtonsoft.Json)\
+[Cuemon.Extensions.Newtonsoft.Json (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Newtonsoft.Json)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Newtonsoft.Json.md b/docfx/api/namespaces/Cuemon.Extensions.Newtonsoft.Json.md
new file mode 100644
index 000000000..7ef6e033e
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Newtonsoft.Json.md
@@ -0,0 +1,28 @@
+---
+uid: Cuemon.Extensions.Newtonsoft.Json
+summary: *content
+---
+The Cuemon.Extensions.Newtonsoft.Json namespace contains both types and extension methods that complements the Newtonsoft.Json namespace by adding new ways of working with JSON; both in terms of serialization and parsing.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Newtonsoft.Json namespace](https://www.newtonsoft.com/json/help/html/N_Newtonsoft_Json.htm) 🔗
+
+Github branches: 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Newtonsoft.Json)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Newtonsoft.Json)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Newtonsoft.Json)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Newtonsoft.Json (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Newtonsoft.Json)\
+[Cuemon.Extensions.Newtonsoft.Json (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Newtonsoft.Json)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|JDataResult|⬇️|`Flatten`, `ExtractArrayValues`, `ExtractObjectValues`|
+|JsonReader|⬇️|`ToHierarchy`|
+|JsonSerializerSettings|⬇️|`ApplyToDefaultSettings`, `UseCamelCase`|
+|JsonWriter|⬇️|`WriteObject`, `WritePropertyName`|
+|Validator|⬇️|`InvalidJsonDocument`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Reflection.md b/docfx/api/namespaces/Cuemon.Extensions.Reflection.md
new file mode 100644
index 000000000..afb29fef8
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Reflection.md
@@ -0,0 +1,27 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Reflection namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Reflection.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Reflection)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Reflection)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Reflection)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Reflection (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Reflection)\
+[Cuemon.Extensions.Reflection (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Reflection)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|Assembly|⬇️|`GetAssemblyVersion`, `GetFileVersion`, `GetProductVersion`, `IsDebugBuild`|
+|MemberInfo|⬇️|`HasAttributes`|
+|PropertyInfo|⬇️|`IsAutoProperty`|
+|Type|⬇️|`GetEmbeddedResources`, `ToMethodBase`, `GetRuntimePropertiesExceptOf{T}`, `ToFullNameIncludingAssemblyName`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Runtime.Caching.md b/docfx/api/namespaces/Cuemon.Extensions.Runtime.Caching.md
new file mode 100644
index 000000000..e584fd101
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Runtime.Caching.md
@@ -0,0 +1,24 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Runtime.Caching namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Runtime.Caching.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Runtime.Caching)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Runtime.Caching)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Runtime.Caching)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Runtime.Caching (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Runtime.Caching)\
+[Cuemon.Extensions.Runtime.Caching (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Runtime.Caching)
+
+### Extension Methods
+
+|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}`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Text.md b/docfx/api/namespaces/Cuemon.Extensions.Text.md
new file mode 100644
index 000000000..cd196cb58
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Text.md
@@ -0,0 +1,25 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Text namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Text.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Text)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Text)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Text)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Text (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Text)\
+[Cuemon.Extensions.Text (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Text)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IEncodingOptions|⬇️|`DetectUnicodeEncoding`|
+|String|⬇️|`ToEncodedString`, `ToAsciiEncodedString`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Threading.Tasks.md b/docfx/api/namespaces/Cuemon.Extensions.Threading.Tasks.md
new file mode 100644
index 000000000..bd44b9081
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Threading.Tasks.md
@@ -0,0 +1,24 @@
+---
+uid: Cuemon.Extensions.Threading.Tasks
+summary: *content
+---
+The Cuemon.Extensions.Threading.Tasks namespace contains extension methods that complements the System.Threading.Tasks namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Threading.Tasks namespace](https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Threading/Tasks)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Threading/Tasks)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Threading/Tasks)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Threading (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Threading)\
+[Cuemon.Extensions.Threading (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Threading)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|Task|⬇️|`ContinueWithCapturedContext`, `ContinueWithCapturedContext{TResult}`, `ContinueWithSuppressedContext`, `ContinueWithSuppressedContext{TResult}`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Threading.md b/docfx/api/namespaces/Cuemon.Extensions.Threading.md
new file mode 100644
index 000000000..e6121d392
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Threading.md
@@ -0,0 +1,18 @@
+---
+uid: Cuemon.Extensions.Threading
+summary: *content
+---
+The Cuemon.Extensions.Threading namespace contains extension methods that complements the System.Threading namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Threading namespace](https://docs.microsoft.com/en-us/dotnet/api/system.threading?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Threading)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Threading)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Threading)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Threading (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Threading)\
+[Cuemon.Extensions.Threading (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Threading)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Xml.Linq.md b/docfx/api/namespaces/Cuemon.Extensions.Xml.Linq.md
new file mode 100644
index 000000000..a8e853fa1
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Xml.Linq.md
@@ -0,0 +1,22 @@
+---
+uid: Cuemon.Extensions.Xml.Linq
+summary: *content
+---
+The Cuemon.Extensions.Xml.Linq namespace contains extension methods that complements the System namespace while being an addition to the System.Xml.Linq namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Xml/Linq)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Xml/Linq)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Xml/Linq)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Xml)\
+[Cuemon.Extensions.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Xml)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|String|⬇️|`IsXmlString`, `TryParseXElement`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.Converters.md b/docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.Converters.md
new file mode 100644
index 000000000..f83b23b24
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.Converters.md
@@ -0,0 +1,24 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Xml.Serialization.Converters namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Xml.Serialization.Converters.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Xml/Serialization/Converters)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Xml/Serialization/Converters)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Xml/Serialization/Converters)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Xml)\
+[Cuemon.Extensions.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Xml)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|IList{XmlConverter}|⬇️|`FirstOrDefaultReaderConverter`, `FirstOrDefaultWriterConverter`, `AddXmlConverter`, `InsertXmlConverter`, `AddEnumerableConverter`, `AddExceptionDescriptorConverter`, `AddUriConverter`, `AddDateTimeConverter`, `AddTimeSpanConverter`, `AddStringConverter`, `AddExceptionConverter`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.Diagnostics.md b/docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.Diagnostics.md
new file mode 100644
index 000000000..054dd7ebb
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.Diagnostics.md
@@ -0,0 +1,24 @@
+---
+uid: Cuemon.Extensions.Xml.Serialization.Diagnostics
+summary: *content
+---
+The Cuemon.Extensions.Xml.Serialization.Diagnostics namespace contains extension methods that complements the Cuemon.Diagnostics namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Diagnostics namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Diagnostics.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Xml/Serialization/Diagnostics)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Xml/Serialization/Diagnostics)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Xml/Serialization/Diagnostics)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Xml)\
+[Cuemon.Extensions.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Xml)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|ExceptionDescriptor|⬇️|`ToInsightsXmlString`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.md b/docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.md
new file mode 100644
index 000000000..ec71dd2b7
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Xml.Serialization.md
@@ -0,0 +1,24 @@
+---
+uid: Cuemon.Extensions.Xml.Serialization
+summary: *content
+---
+The Cuemon.Extensions.Xml.Serialization namespace contains extension methods that complements the Cuemon.Xml.Serialization namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Xml.Serialization namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Xml.Serialization.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Xml/Serialization)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Xml/Serialization)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Xml/Serialization)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Xml)\
+[Cuemon.Extensions.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Xml)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|XmlSerializerOptions|⬇️|`ApplyToDefaultSettings`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Xml.md b/docfx/api/namespaces/Cuemon.Extensions.Xml.md
new file mode 100644
index 000000000..2456c2712
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Xml.md
@@ -0,0 +1,31 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon.Xml namespace](https://docs.cuemon.net/api/dotnet/Cuemon.Xml.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Xml)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Xml)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Xml)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Xml)\
+[Cuemon.Extensions.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Xml)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|byte[]|⬇️|`ToXmlReader`|
+|DateTime|⬇️|`ToString`|
+|IHierarchy{T}|⬇️|`HasXmlIgnoreAttribute`, `IsNodeEnumerable`, `GetXmlRootOrElement`, `OrderByXmlAttributes`|
+|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}`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc.md b/docfx/api/namespaces/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc.md
new file mode 100644
index 000000000..289a76fa4
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc.md
@@ -0,0 +1,18 @@
+---
+uid: Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc
+summary: *content
+---
+The Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc namespace contains types that provides a uniform way of doing unit testing that depends on ASP.NET Core MVC and used in conjunction with Microsoft Dependency Injection. The namespace relates to the Microsoft.AspNetCore.Mvc.Testing namespace.
+
+Availability: NET Core 3.1, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.Mvc.Testing namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.testing?view=aspnetcore-3.0) 🔗
+
+Github branches: 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc)\
+[Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Xunit.Hosting.AspNetCore.md b/docfx/api/namespaces/Cuemon.Extensions.Xunit.Hosting.AspNetCore.md
new file mode 100644
index 000000000..7c65d9835
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Xunit.Hosting.AspNetCore.md
@@ -0,0 +1,18 @@
+---
+uid: Cuemon.Extensions.Xunit.Hosting.AspNetCore
+summary: *content
+---
+The Cuemon.Extensions.Xunit.Hosting.AspNetCore namespace contains types that provides a uniform way of doing unit testing that depends on ASP.NET Core and used in conjunction with Microsoft Dependency Injection. The namespace relates to the Microsoft.AspNetCore.TestHost namespace.
+
+Availability: NET Core 3.1, .NET 5.0
+
+Complements: [Microsoft.AspNetCore.TestHost namespace](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.testhost?view=aspnetcore-3.0) 🔗
+
+Github branches: 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Xunit.Hosting.AspNetCore)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Xunit.Hosting.AspNetCore)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Xunit.Hosting.AspNetCore)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Xunit.Hosting.AspNetCore (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Xunit.Hosting.AspNetCore)\
+[Cuemon.Extensions.Xunit.Hosting.AspNetCore (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Xunit.Hosting.AspNetCore)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Xunit.Hosting.md b/docfx/api/namespaces/Cuemon.Extensions.Xunit.Hosting.md
new file mode 100644
index 000000000..75a957658
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Xunit.Hosting.md
@@ -0,0 +1,18 @@
+---
+uid: Cuemon.Extensions.Xunit.Hosting
+summary: *content
+---
+The Cuemon.Extensions.Xunit.Hosting namespace contains types that provides a uniform way of doing unit testing that is used in conjunction with Microsoft Dependency Injection. The namespace relates to the Xunit.Abstractions namespace.
+
+Availability: NET Standard 2.0, NET Core 3.0, .NET 5.0
+
+Complements: [xUnit: Shared Context between Tests](https://xunit.net/docs/shared-context) 🔗
+
+Github branches: 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Xunit.Hosting)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Xunit.Hosting)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Xunit.Hosting)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Xunit.Hosting (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Xunit.Hosting)\
+[Cuemon.Extensions.Xunit.Hosting (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Xunit.Hosting)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.Xunit.md b/docfx/api/namespaces/Cuemon.Extensions.Xunit.md
new file mode 100644
index 000000000..6641e0d4c
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.Xunit.md
@@ -0,0 +1,18 @@
+---
+uid: Cuemon.Extensions.Xunit
+summary: *content
+---
+The Cuemon.Extensions.Xunit namespace contains types that provides a uniform way of doing unit testing. The namespace relates to the Xunit.Abstractions namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [xUnit: Capturing Output](https://xunit.net/docs/capturing-output) 🔗
+
+Github branches: 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Xunit)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Xunit)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Xunit)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Xunit (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Xunit)\
+[Cuemon.Extensions.Xunit (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Xunit)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Extensions.md b/docfx/api/namespaces/Cuemon.Extensions.md
new file mode 100644
index 000000000..07de24eb8
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Extensions.md
@@ -0,0 +1,37 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [Cuemon namespace](https://docs.cuemon.net/api/dotnet/Cuemon.html) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Core)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Core)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Core)
+
+NuGet packages 📦\
+[Cuemon.Extensions.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Extensions.Core)\
+[Cuemon.Extensions.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Extensions.Core)
+
+### Extension Methods
+
+|Type|Ext|Methods|
+|--:|:-:|---|
+|Action|⬇️|`Configure{TOptions}`, `CreateInstance{T}`|
+|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`|
+|Int*|⬇️|`Min`, `Max`, `IsPrime`, `IsCountableSequence`, `IsEven`, `IsOdd`|
+|Mapping|⬇️|`Add`|
+|Object|⬇️|`UseWrapper{T}`, `As{T}`, `GetHashCode32{T}`, `GetHashCode64{T}`, `ToDelimitedString{T}`, `Adjust{T}`, `IsNullable{T}`|
+|String|⬇️|`Difference`, `ToCharArray`, `ToByteArray`, `FromUrlEncodedBase64`, `ToGuid`, `FromBinaryDigits`, `FromBase64`, `Join`, `ToCasing`, `ToUri`, `IsNullOrEmpty`, `IsNullOrWhiteSpace`, `IsEmailAddress`, `IsGuid`, `IsHex`, `IsNumeric`, `IsBase64`, `IsCountableSequence`, `SplitDelimited`, `Count`, `RemoveAll`, `ReplaceAll`, `JsEscape`, `JsUnescape`, `ContainsAny`, `ContainsAll`, `EqualsAny`, `StartsWith`, `TrimAll`, `IsSequenceOf{T}`, `FromHexadecimal`, `ToHexadecimal`, `ToEnum{TEnum}`, `ToTimeSpan`, `SubstringBefore`, `Chunk`, `SuffixWith`, `SuffixWithForwardingSlash`, `PrefixWith`|
+|TimeSpan|⬇️|`GetTotalNanoseconds`, `GetTotalMicroseconds`, `Floor`, `Ceiling`, `Round`|
+|Type|⬇️|`ToFriendlyName`, `ToTypeCode`, `HasEqualityComparerImplementation`, `HasComparableImplementation`, `HasComparerImplementation`, `HasEnumerableImplementation`, `HasDictionaryImplementation`, `HasKeyValuePairImplementation`, `IsNullable`, `HasAnonymousCharacteristics`, `IsComplex`, `IsSimple`, `GetDefaultValue`, `HasTypes`, `HasInterfaces`, `HasAttributes`|
+|Validator|⬇️|`HasDifference`, `NoDifference`|
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Globalization.md b/docfx/api/namespaces/Cuemon.Globalization.md
new file mode 100644
index 000000000..549d677a5
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Globalization.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Globalization namespace](https://docs.microsoft.com/en-us/dotnet/api/system.globalization?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Core/Globalization)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Core/Globalization)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Core/Globalization)
+
+NuGet packages 📦\
+[Cuemon.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Core)\
+[Cuemon.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Core)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.IO.md b/docfx/api/namespaces/Cuemon.IO.md
new file mode 100644
index 000000000..2fabbdc65
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.IO.md
@@ -0,0 +1,9 @@
+---
+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.
+
+Availability: NET Standard 2.0, NET Standard 2.1, .NET 5.0
+
+Complements: [System.IO namespace](https://docs.microsoft.com/en-us/dotnet/api/system.io?view=netstandard-2.1)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Messaging.md b/docfx/api/namespaces/Cuemon.Messaging.md
new file mode 100644
index 000000000..d14400c3f
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Messaging.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Messaging namespace](https://docs.microsoft.com/en-us/dotnet/api/system.messaging?view=netframework-4.6.1) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Core/Messaging)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Core/Messaging)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Core/Messaging)
+
+NuGet packages 📦\
+[Cuemon.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Core)\
+[Cuemon.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Core)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Net.Http.md b/docfx/api/namespaces/Cuemon.Net.Http.md
new file mode 100644
index 000000000..f9a596aef
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Net.Http.md
@@ -0,0 +1,9 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Net.Http namespace](https://docs.microsoft.com/en-us/dotnet/api/system.net.http?view=netstandard-2.0)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Net.Mail.md b/docfx/api/namespaces/Cuemon.Net.Mail.md
new file mode 100644
index 000000000..d0d8c583b
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Net.Mail.md
@@ -0,0 +1,9 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Net.Mail namespace](https://docs.microsoft.com/en-us/dotnet/api/system.net.mail?view=netstandard-2.0)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Net.md b/docfx/api/namespaces/Cuemon.Net.md
new file mode 100644
index 000000000..357b7f670
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Net.md
@@ -0,0 +1,9 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Net namespace](https://docs.microsoft.com/en-us/dotnet/api/system.net?view=netstandard-2.0)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Reflection.md b/docfx/api/namespaces/Cuemon.Reflection.md
new file mode 100644
index 000000000..8cedf1af7
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Reflection.md
@@ -0,0 +1,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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Reflection namespace](https://docs.microsoft.com/en-us/dotnet/api/system.reflection?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Core/Reflection)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Core/Reflection)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Core/Reflection)
+
+NuGet packages 📦\
+[Cuemon.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Core)\
+[Cuemon.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Core)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Resilience.md b/docfx/api/namespaces/Cuemon.Resilience.md
new file mode 100644
index 000000000..400d08ab1
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Resilience.md
@@ -0,0 +1,16 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Github branches: 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Resilience)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Resilience)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Resilience)
+
+NuGet packages 📦\
+[Cuemon.Resilience (CI)](https://nuget.cuemon.net/packages/Cuemon.Resilience)\
+[Cuemon.Resilience (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Resilience)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Runtime.Caching.md b/docfx/api/namespaces/Cuemon.Runtime.Caching.md
new file mode 100644
index 000000000..b56f3d367
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Runtime.Caching.md
@@ -0,0 +1,20 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Runtime.Caching namespace](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.caching?view=netframework-4.6.1) 🔗
+
+Related: [Cuemon.Extensions.Runtime.Caching namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Runtime.Caching.html) 📘
+
+Github branches: 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Runtime.Caching)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Runtime.Caching)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Runtime.Caching)
+
+NuGet packages 📦\
+[Cuemon.Runtime.Caching (CI)](https://nuget.cuemon.net/packages/Cuemon.Runtime.Caching)\
+[Cuemon.Runtime.Caching (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Runtime.Caching)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Runtime.Serialization.Formatters.md b/docfx/api/namespaces/Cuemon.Runtime.Serialization.Formatters.md
new file mode 100644
index 000000000..12e011e2d
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Runtime.Serialization.Formatters.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Runtime.Serialization.Formatters namespace](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Core/Runtime/Serialization/Formatters)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Core/Runtime/Serialization/Formatters)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Core/Runtime/Serialization/Formatters)
+
+NuGet packages 📦\
+[Cuemon.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Core)\
+[Cuemon.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Core)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Runtime.Serialization.md b/docfx/api/namespaces/Cuemon.Runtime.Serialization.md
new file mode 100644
index 000000000..7471f8a38
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Runtime.Serialization.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Runtime.Serialization namespace](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Core/Runtime/Serialization)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Core/Runtime/Serialization)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Core/Runtime/Serialization)
+
+NuGet packages 📦\
+[Cuemon.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Core)\
+[Cuemon.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Core)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Runtime.md b/docfx/api/namespaces/Cuemon.Runtime.md
new file mode 100644
index 000000000..82a037734
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Runtime.md
@@ -0,0 +1,18 @@
+---
+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. The namespace is an addition to the System.Runtime namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Runtime namespace](https://docs.microsoft.com/en-us/dotnet/api/system.runtime?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Core/Runtime)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Core/Runtime)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Core/Runtime)
+
+NuGet packages 📦\
+[Cuemon.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Core)\
+[Cuemon.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Core)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Security.Cryptography.md b/docfx/api/namespaces/Cuemon.Security.Cryptography.md
new file mode 100644
index 000000000..0cbdf5ed1
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Security.Cryptography.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Security.Cryptography namespace](https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Security.Cryptography)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Security.Cryptography)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Security.Cryptography)
+
+NuGet packages 📦\
+[Cuemon.Security.Cryptography (CI)](https://nuget.cuemon.net/packages/Cuemon.Security.Cryptography)\
+[Cuemon.Security.Cryptography (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Security.Cryptography)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Security.md b/docfx/api/namespaces/Cuemon.Security.md
new file mode 100644
index 000000000..8ee178beb
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Security.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Security namespace](https://docs.microsoft.com/en-us/dotnet/api/system.security?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Core/Security)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Core/Security)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Core/Security)
+
+NuGet packages 📦\
+[Cuemon.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Core)\
+[Cuemon.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Core)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Text.md b/docfx/api/namespaces/Cuemon.Text.md
new file mode 100644
index 000000000..89cc3dc70
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Text.md
@@ -0,0 +1,18 @@
+---
+uid: Cuemon.Text
+summary: *content
+---
+The Cuemon.Text namespace contains types tailored to ease the pain of working with encodings, BOM, parsing, preamble sequences and stems. Also includes way to conform to a uniform way of turning strings into objects of a particular type. The namespace is an addition to the System.Text namespace.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Text namespace](https://docs.microsoft.com/en-us/dotnet/api/system.text?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Core/Text)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Core/Text)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Core/Text)
+
+NuGet packages 📦\
+[Cuemon.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Core)\
+[Cuemon.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Core)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Threading.md b/docfx/api/namespaces/Cuemon.Threading.md
new file mode 100644
index 000000000..b30396695
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Threading.md
@@ -0,0 +1,20 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Threading namespace](https://docs.microsoft.com/en-us/dotnet/api/system.threading?view=netstandard-2.0) 🔗
+
+Related: [Cuemon.Extensions.Threading.Tasks namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Threading.Tasks.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Threading)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Threading)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Threading)
+
+NuGet packages 📦\
+[Cuemon.Threading (CI)](https://nuget.cuemon.net/packages/Cuemon.Threading)\
+[Cuemon.Threading (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Threading)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Xml.Linq.md b/docfx/api/namespaces/Cuemon.Xml.Linq.md
new file mode 100644
index 000000000..a478802c8
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Xml.Linq.md
@@ -0,0 +1,20 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Xml.Linq namespace](https://docs.microsoft.com/en-us/dotnet/api/system.xml.linq?view=netstandard-2.0) 🔗
+
+Related: [Cuemon.Extensions.Xml.Linq namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Xml.Linq.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Xml/Extensions/Linq)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Xml/Extensions/Linq)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Xml/Extensions/Linq)
+
+NuGet packages 📦\
+[Cuemon.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Xml)\
+[Cuemon.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Xml)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Xml.Serialization.Converters.md b/docfx/api/namespaces/Cuemon.Xml.Serialization.Converters.md
new file mode 100644
index 000000000..fef54ded0
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Xml.Serialization.Converters.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Related: [Cuemon.Extensions.Xml.Serialization.Converters namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Xml.Serialization.Converters.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Extensions.Xml/Serialization/Converters)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Extensions.Xml/Serialization/Converters)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Extensions.Xml/Serialization/Converters)
+
+NuGet packages 📦\
+[Cuemon.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Xml)\
+[Cuemon.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Xml)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Xml.Serialization.Formatters.md b/docfx/api/namespaces/Cuemon.Xml.Serialization.Formatters.md
new file mode 100644
index 000000000..4713fe8ba
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Xml.Serialization.Formatters.md
@@ -0,0 +1,16 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Xml/Serialization/Formatters)\
+[release](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Xml/Serialization/Formatters)\
+[master](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Xml/Serialization/Formatters)
+
+NuGet packages 📦\
+[Cuemon.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Xml)\
+[Cuemon.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Xml)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Xml.Serialization.md b/docfx/api/namespaces/Cuemon.Xml.Serialization.md
new file mode 100644
index 000000000..0a8ed138a
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Xml.Serialization.md
@@ -0,0 +1,20 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Xml.Serialization namespace](https://docs.microsoft.com/en-us/dotnet/api/system.xml.serialization?view=netstandard-2.0) 🔗
+
+Related: [Cuemon.Extensions.Xml.Serialization namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Xml.Serialization.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Xml/Serialization)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Xml/Serialization)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Xml/Serialization)
+
+NuGet packages 📦\
+[Cuemon.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Xml)\
+[Cuemon.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Xml)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Xml.XPath.md b/docfx/api/namespaces/Cuemon.Xml.XPath.md
new file mode 100644
index 000000000..1f13bf0b5
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Xml.XPath.md
@@ -0,0 +1,18 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Xml.XPath namespace](https://docs.microsoft.com/en-us/dotnet/api/system.xml.xpath?view=netstandard-2.0) 🔗
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Xml/XPath)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Xml/XPath)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Xml/XPath)
+
+NuGet packages 📦\
+[Cuemon.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Xml)\
+[Cuemon.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Xml)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.Xml.md b/docfx/api/namespaces/Cuemon.Xml.md
new file mode 100644
index 000000000..0d9fbd408
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.Xml.md
@@ -0,0 +1,20 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System.Xml namespace](https://docs.microsoft.com/en-us/dotnet/api/system.xml?view=netstandard-2.0) 🔗
+
+Related: [Cuemon.Extensions.Xml namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.Xml.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Xml)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Xml)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Xml)
+
+NuGet packages 📦\
+[Cuemon.Xml (CI)](https://nuget.cuemon.net/packages/Cuemon.Xml)\
+[Cuemon.Xml (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Xml)
\ No newline at end of file
diff --git a/docfx/api/namespaces/Cuemon.md b/docfx/api/namespaces/Cuemon.md
new file mode 100644
index 000000000..a1a68a211
--- /dev/null
+++ b/docfx/api/namespaces/Cuemon.md
@@ -0,0 +1,20 @@
+---
+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.
+
+Availability: NET Standard 2.0, .NET 5.0
+
+Complements: [System namespace](https://docs.microsoft.com/en-us/dotnet/api/system?view=netstandard-2.0) 🔗
+
+Related: [Cuemon.Extensions namespace](https://docs.cuemon.net/api/dotnet/ext/Cuemon.Extensions.html) 📘
+
+Github branches 🌱\
+[development](https://github.com/gimlichael/Cuemon/tree/development/src/Cuemon.Core)\
+[release](https://github.com/gimlichael/Cuemon/tree/release/src/Cuemon.Core)\
+[master](https://github.com/gimlichael/Cuemon/tree/master/src/Cuemon.Core)
+
+NuGet packages 📦\
+[Cuemon.Core (CI)](https://nuget.cuemon.net/packages/Cuemon.Core)\
+[Cuemon.Core (Stable and Preview)](https://www.nuget.org/packages/Cuemon.Core)
\ No newline at end of file
diff --git a/docfx/docfx.json b/docfx/docfx.json
new file mode 100644
index 000000000..d1006e714
--- /dev/null
+++ b/docfx/docfx.json
@@ -0,0 +1,162 @@
+{
+ "metadata": [
+ {
+ "src": [
+ {
+ "files": [
+ "Cuemon.Core/**.csproj",
+ "Cuemon.Data/**.csproj",
+ "Cuemon.Data.Integrity/**.csproj",
+ "Cuemon.Data.SqlClient/**.csproj",
+ "Cuemon.Diagnostics/**.csproj",
+ "Cuemon.IO/**.csproj",
+ "Cuemon.Net/**.csproj",
+ "Cuemon.Resilience/**.csproj",
+ "Cuemon.Runtime.Caching/**.csproj",
+ "Cuemon.Security.Cryptography/**.csproj",
+ "Cuemon.Threading/**.csproj",
+ "Cuemon.Xml/**.csproj"
+ ],
+ "src": "../src"
+ }
+ ],
+ "dest": "api/dotnet",
+ "filter": "filterConfig.yml",
+ "properties": {
+ "TargetFramework": "netstandard2.1"
+ }
+ },
+ {
+ "src": [
+ {
+ "files": [
+ "Cuemon.Extensions.Collections.Generic/**.csproj",
+ "Cuemon.Extensions.Collections.Specialized/**.csproj",
+ "Cuemon.Extensions.Core/**.csproj",
+ "Cuemon.Extensions.Data/**.csproj",
+ "Cuemon.Extensions.Data.Integrity/**.csproj",
+ "Cuemon.Extensions.DependencyInjection/**.csproj",
+ "Cuemon.Extensions.Diagnostics/**.csproj",
+ "Cuemon.Extensions.IO/**.csproj",
+ "Cuemon.Extensions.Net/**.csproj",
+ "Cuemon.Extensions.Newtonsoft.Json/**.csproj",
+ "Cuemon.Extensions.Reflection/**.csproj",
+ "Cuemon.Extensions.Runtime.Caching/**.csproj",
+ "Cuemon.Extensions.Text/**.csproj",
+ "Cuemon.Extensions.Threading/**.csproj",
+ "Cuemon.Extensions.Xml/**.csproj",
+ "Cuemon.Extensions.Xunit/**.csproj",
+ "Cuemon.Extensions.Xunit.Hosting/**.csproj",
+ "Cuemon.Extensions.Xunit.Hosting.AspNetCore/**.csproj",
+ "Cuemon.Extensions.Xunit.Hosting.AspNetCore.Mvc/**.csproj"
+ ],
+ "src": "../src"
+ }
+ ],
+ "dest": "api/dotnet/ext",
+ "filter": "filterConfig.yml",
+ "properties": {
+ "TargetFramework": "netstandard2.1"
+ }
+ },
+ {
+ "src": [
+ {
+ "files": [
+ "Cuemon.AspNetCore/**.csproj",
+ "Cuemon.AspNetCore.Authentication/**.csproj",
+ "Cuemon.AspNetCore.Mvc/**.csproj",
+ "Cuemon.AspNetCore.Razor/**.csproj"
+ ],
+ "src": "../src"
+ }
+ ],
+ "dest": "api/aspnet",
+ "filter": "filterConfig.yml",
+ "properties": {
+ "TargetFramework": "netcoreapp3.0"
+ }
+ },
+ {
+ "src": [
+ {
+ "files": [
+ "Cuemon.Extensions.AspNetCore/**.csproj",
+ "Cuemon.Extensions.AspNetCore.Authentication/**.csproj",
+ "Cuemon.Extensions.AspNetCore.Mvc/**.csproj",
+ "Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/**.csproj",
+ "Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/**.csproj"
+ ],
+ "src": "../src"
+ }
+ ],
+ "dest": "api/aspnet/ext",
+ "filter": "filterConfig.yml",
+ "properties": {
+ "TargetFramework": "netcoreapp3.0"
+ }
+ }
+ ],
+ "build": {
+ "content": [
+ {
+ "files": [
+ "api/**/*.yml",
+ "api/**/*.md",
+ "toc.yml",
+ "*.md"
+ ],
+ "exclude": [
+ "bin/**",
+ "obj/**"
+ ]
+ }
+ ],
+ "resource": [
+ {
+ "files": [
+ "images/**"
+ ]
+ }
+ ],
+ "globalMetadata": {
+ "_appTitle": "Cuemon for .NET",
+ "_appFooter": "Copyright 2008-2021 Geekle. All rights reserved. Code with passion; love your code; deliver with pride. 👨💻️🔥❤️🚀🤘
Generated by DocFX",
+ "_appLogoPath": "images/50x50.png",
+ "_appFaviconPath": "images/favicon.ico",
+ "_enableSearch": false,
+ "_disableContribution": false,
+ "_gitContribute": {
+ "repo": "https://github.com/gimlichael/Cuemon",
+ "branch": "development"
+ },
+ "_gitUrlPattern": "github"
+ },
+ "dest": "wwwroot",
+ "globalMetadataFiles": [],
+ "fileMetadataFiles": [],
+ "template": [
+ "default",
+ "templates/cuemon"
+ ],
+ "overwrite": [
+ {
+ "files": [
+ "api/namespaces/**.md"
+ ],
+ "exclude": [
+ "obj/**",
+ "wwwroot/**"
+ ]
+ }
+ ],
+ "postProcessors": [],
+ "markdownEngineName": "markdig",
+ "noLangKeyword": false,
+ "keepFileLink": false,
+ "cleanupCacheHistory": false,
+ "disableGitFeatures": false,
+ "xrefService": [
+ "https://xref.docs.microsoft.com/query?uid={uid}" ]
+ }
+}
\ No newline at end of file
diff --git a/docfx/filterConfig.yml b/docfx/filterConfig.yml
new file mode 100644
index 000000000..837050d4a
--- /dev/null
+++ b/docfx/filterConfig.yml
@@ -0,0 +1,4 @@
+apiRules:
+- exclude:
+ uidRegex: ^System\.Object
+ type: Type
\ No newline at end of file
diff --git a/docfx/images/32x32.png b/docfx/images/32x32.png
new file mode 100644
index 000000000..b6ea41cf6
Binary files /dev/null and b/docfx/images/32x32.png differ
diff --git a/docfx/images/50x50.png b/docfx/images/50x50.png
new file mode 100644
index 000000000..093c47b1a
Binary files /dev/null and b/docfx/images/50x50.png differ
diff --git a/docfx/images/favicon.ico b/docfx/images/favicon.ico
new file mode 100644
index 000000000..6edab735b
Binary files /dev/null and b/docfx/images/favicon.ico differ
diff --git a/docfx/templates/cuemon/layout/_master.tmpl b/docfx/templates/cuemon/layout/_master.tmpl
new file mode 100644
index 000000000..0c151594e
--- /dev/null
+++ b/docfx/templates/cuemon/layout/_master.tmpl
@@ -0,0 +1,65 @@
+{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
+{{!include(/^styles/.*/)}}
+{{!include(/^fonts/.*/)}}
+{{!include(favicon.ico)}}
+{{!include(logo.svg)}}
+{{!include(search-stopwords.json)}}
+
+
+
+ {{>partials/head}}
+
+
+
+ {{^_disableNavbar}}
+ {{>partials/navbar}}
+ {{/_disableNavbar}}
+ {{^_disableBreadcrumb}}
+ {{>partials/breadcrumb}}
+ {{/_disableBreadcrumb}}
+
+ {{#_enableSearch}}
+
+ {{>partials/searchResults}}
+
+ {{/_enableSearch}}
+
+ {{^_disableToc}}
+ {{>partials/toc}}
+
+ {{/_disableToc}}
+ {{#_disableToc}}
+
+ {{/_disableToc}}
+ {{#_disableAffix}}
+
+ {{/_disableAffix}}
+ {{^_disableAffix}}
+
+ {{^_disableAffix}}
+ {{>partials/affix}}
+ {{/_disableAffix}}
+
+
+ {{^_disableFooter}}
+ {{>partials/footer}}
+ {{/_disableFooter}}
+
+ {{>partials/scripts}}
+
+
\ No newline at end of file
diff --git a/docfx/templates/cuemon/partials/head.tmpl.partial b/docfx/templates/cuemon/partials/head.tmpl.partial
new file mode 100644
index 000000000..f66a69b23
--- /dev/null
+++ b/docfx/templates/cuemon/partials/head.tmpl.partial
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
{{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}
+
+
+
+ {{#_description}}
{{/_description}}
+
+
+
+
+
+
+
+ {{#_noindex}}
{{/_noindex}}
+ {{#_enableSearch}}
{{/_enableSearch}}
+ {{#_enableNewTab}}
{{/_enableNewTab}}
+
\ No newline at end of file
diff --git a/docfx/templates/cuemon/partials/logo.tmpl.partial b/docfx/templates/cuemon/partials/logo.tmpl.partial
new file mode 100644
index 000000000..0e4e54801
--- /dev/null
+++ b/docfx/templates/cuemon/partials/logo.tmpl.partial
@@ -0,0 +1,5 @@
+{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}}
+
+
+
+
\ No newline at end of file
diff --git a/docfx/templates/cuemon/styles/main.css b/docfx/templates/cuemon/styles/main.css
new file mode 100644
index 000000000..a42dcd26b
--- /dev/null
+++ b/docfx/templates/cuemon/styles/main.css
@@ -0,0 +1,60 @@
+nav .container {
+ margin: 5px auto;
+}
+
+nav .container .navbar-header {
+ padding-right: 25px;
+}
+
+.hero {
+ height: 400px;
+ font-weight: 300;
+ text-align: center;
+ background-image: url("https://nblcdn.net/cuemon/i/splash.jpg");
+ background-position: center;
+ background-size: cover;
+}
+
+.caption.header.cuemon {
+ color: #000;
+ position: absolute;
+ padding: 0 10px 7px;
+ background: rgba(0,0,0,0.5);
+}
+
+.wrap {
+ position: relative;
+ min-height: 400px;
+}
+
+.bottom {
+ position: absolute;
+ bottom: 5px;
+ width: 100%;
+}
+
+.btn {
+ margin: 5px 0;
+}
+
+ .btn a {
+ color: white;
+ }
+
+#wrapper .container.nuget {
+ padding-top: 25px;
+}
+
+.btn-omen {
+ background-color: #A177B0;
+ color: #fff;
+}
+
+.btn-omen-package {
+ background-color: #7C528B;
+ color: #fff;
+}
+
+.container.nuget .row button {
+ margin-top: 30px;
+}
diff --git a/docfx/toc.yml b/docfx/toc.yml
new file mode 100644
index 000000000..89bd30aab
--- /dev/null
+++ b/docfx/toc.yml
@@ -0,0 +1,15 @@
+- name: Cuemon Conventions
+ href: api
+ topicHref: api/index.md
+- name: Core API
+ href: api/dotnet
+ topicHref: api/dotnet/index.md
+- name: Extensions for Core APIs
+ href: api/dotnet/ext
+ topicHref: api/dotnet/ext/index.md
+- name: ASP.NET Core API
+ href: api/aspnet
+ topicHref: api/aspnet/index.md
+- name: Extensions for ASP.NET Core APIs
+ href: api/aspnet/ext
+ topicHref: api/aspnet/ext/index.md
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 000000000..848892a50
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,14 @@
+version: "3.8"
+
+services:
+ database:
+ image: gimlichael/aw-mssql-server:2019-GA-ubuntu-16.04
+ container_name: "awsql"
+ hostname: "awsql"
+ ports:
+ - "1433:1433"
+ environment:
+ SA_PASSWORD:
+ ACCEPT_EULA: "Y"
+ SECONDS_TO_AWAIT_SQLSERVER: "45"
+ MSSQL_PID: "Express"
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/AuthenticationOptions.cs b/src/Cuemon.AspNetCore.Authentication/AuthenticationOptions.cs
index a2f484b8a..b7bb2fb83 100644
--- a/src/Cuemon.AspNetCore.Authentication/AuthenticationOptions.cs
+++ b/src/Cuemon.AspNetCore.Authentication/AuthenticationOptions.cs
@@ -1,6 +1,6 @@
using System;
-using System.Text;
-using Cuemon.Text;
+using System.Net;
+using System.Net.Http;
namespace Cuemon.AspNetCore.Authentication
{
@@ -12,16 +12,32 @@ public abstract class AuthenticationOptions
///
/// Initializes a new instance of the class.
///
+ ///
+ /// The following table shows the initial property values for an instance of .
+ ///
+ ///
+ /// Property
+ /// Initial Value
+ ///
+ /// -
+ ///
+ /// () => new HttpResponseMessage(HttpStatusCode.Unauthorized) { Content = new StringContent(UnauthorizedMessage) };
+ ///
+ /// -
+ ///
+ /// true
+ ///
+ /// -
+ ///
+ /// The request has not been applied because it lacks valid authentication credentials for the target resource.
+ ///
+ ///
+ ///
protected AuthenticationOptions()
{
- HttpNotAuthorizedBody = () =>
- {
- return Convertible.GetBytes("401 Unauthorized", o =>
- {
- o.Encoding = Encoding.UTF8;
- o.Preamble = PreambleSequence.Remove;
- });
- };
+ ResponseHandler = () => new HttpResponseMessage(HttpStatusCode.Unauthorized) { Content = new StringContent(UnauthorizedMessage) };
+ RequireSecureConnection = true;
+ UnauthorizedMessage = "The request has not been applied because it lacks valid authentication credentials for the target resource.";
}
///
@@ -31,9 +47,15 @@ protected AuthenticationOptions()
public bool RequireSecureConnection { get; set; }
///
- /// Gets or sets the function delegate for retrieving content for the body of an unauthorized request.
+ /// Gets or sets the function delegate that configures the unauthorized response in the form of a .
///
- /// A for retrieving content for the body of an unauthorized request.
- public Func HttpNotAuthorizedBody { get; set; }
+ /// The function delegate that configures the unauthorized response in the form of a .
+ public Func ResponseHandler { get; set; }
+
+ ///
+ /// Gets or sets the message of an unauthorized request.
+ ///
+ /// The message of an unauthorized request.
+ public string UnauthorizedMessage { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/AuthenticationUtility.cs b/src/Cuemon.AspNetCore.Authentication/Authenticator.cs
similarity index 69%
rename from src/Cuemon.AspNetCore.Authentication/AuthenticationUtility.cs
rename to src/Cuemon.AspNetCore.Authentication/Authenticator.cs
index 1447cf51e..ba5925867 100644
--- a/src/Cuemon.AspNetCore.Authentication/AuthenticationUtility.cs
+++ b/src/Cuemon.AspNetCore.Authentication/Authenticator.cs
@@ -1,42 +1,16 @@
using System;
using System.Security;
using System.Security.Claims;
-using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;
namespace Cuemon.AspNetCore.Authentication
{
///
- /// Provides a set of generic ways to work with HTTP based authentication.
+ /// Provides a set of static methods for working with HTTP based authentication.
///
- public static class AuthenticationUtility
+ public static class Authenticator
{
- ///
- /// The value of the header credential separator of a HTTP Basic access authentication.
- ///
- public const char BasicAuthenticationCredentialSeparator = ':';
-
- ///
- /// The value of the header credential separator of a HTTP Digest access authentication.
- ///
- public const char DigestAuthenticationCredentialSeparator = ',';
-
- ///
- /// The value of the header credential separator of a HTTP JSON Web Token authentication.
- ///
- public const char JwtAuthenticationCredentialSeparator = '.';
-
- ///
- /// The value of the status description associated with .
- ///
- public const string HttpNotAuthorizedStatus = "401 Unauthorized";
-
- ///
- /// Equivalent to HTTP status 401. Unauthorized indicates that the requested resource requires authentication.
- ///
- public const int HttpNotAuthorizedStatusCode = 401;
-
///
/// Provides a generic way to make authentication requests using the specified .
///
@@ -92,19 +66,5 @@ private static bool TryGetPrincipal(HttpContext context, Func httpNotAuthorizedBody)
- {
- var bodyContent = httpNotAuthorizedBody?.Invoke();
- if (bodyContent != null)
- {
- await context.Response.Body.WriteAsync(bodyContent, 0, bodyContent.Length).ConfigureAwait(false);
- }
- }
}
}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/AuthorizationHeader.cs b/src/Cuemon.AspNetCore.Authentication/AuthorizationHeader.cs
new file mode 100644
index 000000000..d49fd894a
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/AuthorizationHeader.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Cuemon.Collections.Generic;
+
+namespace Cuemon.AspNetCore.Authentication
+{
+ ///
+ /// Represents the base class from which all implementations of authorization header should derive.
+ ///
+ public abstract class AuthorizationHeader
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name of the authentication scheme.
+ protected AuthorizationHeader(string authenticationScheme)
+ {
+ Validator.ThrowIfNullOrWhitespace(authenticationScheme, nameof(authenticationScheme));
+ AuthenticationScheme = authenticationScheme;
+ }
+
+ ///
+ /// Gets the name of the authentication scheme.
+ ///
+ /// The name of the authentication scheme.
+ public string AuthenticationScheme { get; }
+
+ ///
+ /// Parses the specified .
+ ///
+ /// The authorization header to parse.
+ /// The which need to be configured.
+ /// An equivalent of .
+ public virtual AuthorizationHeader Parse(string authorizationHeader, Action setup)
+ {
+ Validator.ThrowIfNullOrWhitespace(authorizationHeader, nameof(authorizationHeader));
+ Validator.ThrowIfFalse(() => authorizationHeader.StartsWith(AuthenticationScheme), nameof(authorizationHeader), $"Header did not start with {AuthenticationScheme}.");
+
+ var options = Patterns.Configure(setup);
+ var headerWithoutScheme = authorizationHeader.Remove(0, AuthenticationScheme.Length + 1);
+ var credentials = DelimitedString.Split(headerWithoutScheme, o => o.Delimiter = options.CredentialsDelimiter).ToList();
+
+ var dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ foreach (var credential in credentials)
+ {
+ var kvp = DelimitedString.Split(credential, o => o.Delimiter = options.CredentialsKeyValueDelimiter);
+ var key = kvp[0].Trim();
+ var value = kvp[1].Trim('"');
+ Decorator.Enclose(dictionary).TryAdd(key, value);
+ }
+
+ return ParseCore(dictionary);
+ }
+
+ ///
+ /// The core parser that resolves an from a set of .
+ ///
+ /// The credentials used in authentication.
+ /// An equivalent of .
+ protected abstract AuthorizationHeader ParseCore(IReadOnlyDictionary credentials);
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// A that represents this instance.
+ public abstract override string ToString();
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/AuthorizationHeaderBuilder.cs b/src/Cuemon.AspNetCore.Authentication/AuthorizationHeaderBuilder.cs
new file mode 100644
index 000000000..7d249ff14
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/AuthorizationHeaderBuilder.cs
@@ -0,0 +1,127 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using Cuemon.Collections.Generic;
+
+namespace Cuemon.AspNetCore.Authentication
+{
+ ///
+ /// Represents the base class from which all implementations of authorization header builders should derive.
+ /// Implements the
+ ///
+ /// The type of the authorization header result.
+ /// The type of the authorization header builder.
+ public abstract class AuthorizationHeaderBuilder : AuthorizationHeaderBuilder
+ where TAuthorizationHeader : AuthorizationHeader
+ where TAuthorizationHeaderBuilder : AuthorizationHeaderBuilder
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name of the authentication scheme.
+ protected AuthorizationHeaderBuilder(string authenticationScheme) : base(authenticationScheme)
+ {
+ }
+
+ ///
+ /// Attempts to add or update an existing field with the provided with the specified .
+ ///
+ /// The name of the field to add or update.
+ /// The value of the field to add or update.
+ /// that can be used to further build the header.
+ public TAuthorizationHeaderBuilder AddOrUpdate(string name, string value)
+ {
+ Validator.ThrowIfNullOrWhitespace(name, nameof(name));
+ Decorator.Enclose(Data).AddOrUpdate(name, value);
+ return this as TAuthorizationHeaderBuilder;
+ }
+
+ ///
+ /// Builds an instance of that implements .
+ ///
+ /// .
+ public abstract TAuthorizationHeader Build();
+ }
+
+ ///
+ /// The base class of an .
+ ///
+ public abstract class AuthorizationHeaderBuilder
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name of the authentication scheme.
+ protected AuthorizationHeaderBuilder(string authenticationScheme)
+ {
+ Validator.ThrowIfNullOrWhitespace(authenticationScheme, nameof(authenticationScheme));
+ AuthenticationScheme = authenticationScheme;
+ }
+
+ ///
+ /// Gets the fields added to this instance.
+ ///
+ /// The fields added to this instance.
+ protected IDictionary Data { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ ///
+ /// Gets the relations added to this instance.
+ ///
+ /// The relations added to this instance.
+ protected IDictionary Relation { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ ///
+ /// Gets the name of the authentication scheme.
+ ///
+ /// The name of the authentication scheme.
+ public string AuthenticationScheme { get; }
+
+ ///
+ /// Maps the logical relation between a and the associated.
+ ///
+ /// The name of a member.
+ /// The field names to associate with .
+ protected void MapRelation(string memberName, params string[] fieldNames)
+ {
+ Validator.ThrowIfNullOrWhitespace(memberName, nameof(memberName));
+ Validator.ThrowIfSequenceNullOrEmpty(fieldNames, nameof(fieldNames));
+ foreach (var key in fieldNames) { Decorator.Enclose(Relation).AddOrUpdate(key, memberName); }
+ }
+
+ ///
+ /// Validates that any has been added to .
+ ///
+ /// The required field names to validate.
+ ///
+ /// The required field is missing.
+ ///
+ protected void ValidateData(params string[] requiredFieldNames)
+ {
+ foreach (var rfn in requiredFieldNames)
+ {
+ var invalidState = !Data.ContainsKey(rfn) || Data[rfn] == null;
+ if (Relation.TryGetValue(rfn, out var member) && invalidState) { throw new ArgumentException($"Required field is missing. Did you forget to invoke {member}?", rfn); }
+ if (invalidState) { throw new ArgumentException("Required field is missing.", rfn); }
+ }
+ }
+
+ ///
+ /// Converts this instance to an .
+ ///
+ /// An equivalent of this instance.
+ public ImmutableDictionary ToImmutableDictionary()
+ {
+ return Data.ToImmutableDictionary();
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// A that represents this instance.
+ public override string ToString()
+ {
+ return DelimitedString.Create(Data.Keys.Select(key => $"{key}={Data[key]}"));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/AuthorizationHeaderOptions.cs b/src/Cuemon.AspNetCore.Authentication/AuthorizationHeaderOptions.cs
new file mode 100644
index 000000000..7b8216109
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/AuthorizationHeaderOptions.cs
@@ -0,0 +1,46 @@
+namespace Cuemon.AspNetCore.Authentication
+{
+ ///
+ /// Configuration options for .
+ ///
+ public class AuthorizationHeaderOptions
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The following table shows the initial property values for an instance of .
+ ///
+ ///
+ /// Property
+ /// Initial Value
+ ///
+ /// -
+ ///
+ /// ,
+ ///
+ /// -
+ ///
+ /// =
+ ///
+ ///
+ ///
+ public AuthorizationHeaderOptions()
+ {
+ CredentialsDelimiter = ",";
+ CredentialsKeyValueDelimiter = "=";
+ }
+
+ ///
+ /// Gets or sets the credentials delimiter.
+ ///
+ /// The credentials delimiter.
+ public string CredentialsDelimiter { get; set; }
+
+ ///
+ /// Gets or sets the credentials key value delimiter.
+ ///
+ /// The credentials key value delimiter.
+ public string CredentialsKeyValueDelimiter { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthenticationMiddleware.cs b/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthenticationMiddleware.cs
new file mode 100644
index 000000000..4293d54f9
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthenticationMiddleware.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using Cuemon.IO;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+using Microsoft.Net.Http.Headers;
+
+namespace Cuemon.AspNetCore.Authentication.Basic
+{
+ ///
+ /// Provides a HTTP Basic Authentication middleware implementation for ASP.NET Core.
+ ///
+ public class BasicAuthenticationMiddleware : ConfigurableMiddleware
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The delegate of the request pipeline to invoke.
+ /// The which need to be configured.
+ public BasicAuthenticationMiddleware(RequestDelegate next, IOptions setup) : base(next, setup)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The delegate of the request pipeline to invoke.
+ /// The middleware which need to be configured.
+ public BasicAuthenticationMiddleware(RequestDelegate next, Action setup) : base(next, setup)
+ {
+ }
+
+ ///
+ /// Executes the .
+ ///
+ /// The context of the current request.
+ /// A task that represents the execution of this middleware.
+ public override async Task InvokeAsync(HttpContext context)
+ {
+ if (!Authenticator.TryAuthenticate(context, Options.RequireSecureConnection, AuthorizationHeaderParser, TryAuthenticate))
+ {
+ await Decorator.Enclose(context).InvokeAuthenticationAsync(Options, async (message, response) =>
+ {
+ context.Response.OnStarting(() =>
+ {
+ context.Response.Headers.Add(HeaderNames.WWWAuthenticate, FormattableString.Invariant($"{BasicAuthorizationHeader.Scheme} realm=\"{Options.Realm}\""));
+ return Task.CompletedTask;
+ });
+ response.StatusCode = (int)message.StatusCode;
+ await Decorator.Enclose(response.Body).WriteAsync(await message.Content.ReadAsByteArrayAsync().ConfigureAwait(false)).ConfigureAwait(false);
+ }).ConfigureAwait(false);
+ }
+ await Next(context).ConfigureAwait(false);
+ }
+
+ private bool TryAuthenticate(HttpContext context, BasicAuthorizationHeader header, out ClaimsPrincipal result)
+ {
+ if (Options.Authenticator == null) { throw new InvalidOperationException(FormattableString.Invariant($"The {nameof(Options.Authenticator)} cannot be null.")); }
+ result = Options.Authenticator(header.UserName, header.Password);
+ return Condition.IsNotNull(result);
+ }
+
+ private BasicAuthorizationHeader AuthorizationHeaderParser(HttpContext context, string authorizationHeader)
+ {
+ return BasicAuthorizationHeader.Create(authorizationHeader);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/BasicAuthenticationOptions.cs b/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthenticationOptions.cs
similarity index 56%
rename from src/Cuemon.AspNetCore.Authentication/BasicAuthenticationOptions.cs
rename to src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthenticationOptions.cs
index 26599646f..16cbc1eef 100644
--- a/src/Cuemon.AspNetCore.Authentication/BasicAuthenticationOptions.cs
+++ b/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthenticationOptions.cs
@@ -1,4 +1,4 @@
-namespace Cuemon.AspNetCore.Authentication
+namespace Cuemon.AspNetCore.Authentication.Basic
{
///
/// Configuration options for . This class cannot be inherited.
@@ -9,8 +9,26 @@ public sealed class BasicAuthenticationOptions : AuthenticationOptions
///
/// Initializes a new instance of the class.
///
+ ///
+ /// The following table shows the initial property values for an instance of .
+ ///
+ ///
+ /// Property
+ /// Initial Value
+ ///
+ /// -
+ ///
+ /// null
+ ///
+ /// -
+ ///
+ /// AuthenticationServer
+ ///
+ ///
+ ///
public BasicAuthenticationOptions()
{
+ Realm = "AuthenticationServer";
}
///
diff --git a/src/Cuemon.AspNetCore.Authentication/BasicAuthenticator.cs b/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthenticator.cs
similarity index 93%
rename from src/Cuemon.AspNetCore.Authentication/BasicAuthenticator.cs
rename to src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthenticator.cs
index 2d92cd552..630644c46 100644
--- a/src/Cuemon.AspNetCore.Authentication/BasicAuthenticator.cs
+++ b/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthenticator.cs
@@ -1,6 +1,6 @@
using System.Security.Claims;
-namespace Cuemon.AspNetCore.Authentication
+namespace Cuemon.AspNetCore.Authentication.Basic
{
///
/// Represents the method that defines an Authenticator typically assigned on .
diff --git a/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthorizationHeader.cs b/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthorizationHeader.cs
new file mode 100644
index 000000000..63b6ee829
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthorizationHeader.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Cuemon.Text;
+
+namespace Cuemon.AspNetCore.Authentication.Basic
+{
+ ///
+ /// Provides a representation of a HTTP Basic Authentication header.
+ /// Implements the
+ ///
+ ///
+ public class BasicAuthorizationHeader : AuthorizationHeader
+ {
+ ///
+ /// Creates an instance of from the specified parameters.
+ ///
+ /// The raw HTTP authorization header.
+ /// An instance of .
+ ///
+ /// cannot be null.
+ ///
+ ///
+ /// cannot be empty or consist only of white-space characters.
+ ///
+ public static BasicAuthorizationHeader Create(string authorizationHeader)
+ {
+ Validator.ThrowIfNullOrWhitespace(authorizationHeader, nameof(authorizationHeader));
+ return new BasicAuthorizationHeader().Parse(authorizationHeader, null) as BasicAuthorizationHeader;
+ }
+
+ ///
+ /// The default authentication scheme of the .
+ ///
+ public const string Scheme = "Basic";
+
+ BasicAuthorizationHeader() : base(Scheme)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The username of the credentials.
+ /// The password of the credentials.
+ ///
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
+ ///
+ /// cannot be empty or consist only of white-space characters -or-
+ /// cannot be empty or consist only of white-space characters -or-
+ /// does not allow the presence of the colon character.
+ ///
+ public BasicAuthorizationHeader(string username, string password) : base(Scheme)
+ {
+ Validator.ThrowIfNullOrWhitespace(username, nameof(username));
+ Validator.ThrowIfNullOrWhitespace(password, nameof(password));
+ Validator.ThrowIfTrue(() => username.Contains(":"), nameof(username), $"Colon is not allowed as part of the {nameof(username)}.");
+ UserName = username;
+ Password = password;
+ }
+
+
+ ///
+ /// Gets the username of the credentials.
+ ///
+ /// The username of the credentials.
+ public string UserName { get; }
+
+ ///
+ /// Gets the password of the credentials.
+ ///
+ /// The password of the credentials.
+ public string Password { get; }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// A that represents this instance.
+ public override string ToString()
+ {
+ var credentials = Convert.ToBase64String(Decorator.Enclose($"{UserName}:{Password}").ToByteArray());
+ return $"{AuthenticationScheme} {credentials}";
+ }
+
+ ///
+ /// Parses the specified .
+ ///
+ /// The authorization header to parse.
+ /// The which need to be configured.
+ /// An equivalent of .
+ public override AuthorizationHeader Parse(string authorizationHeader, Action setup)
+ {
+ Validator.ThrowIfNullOrWhitespace(authorizationHeader, nameof(authorizationHeader));
+ Validator.ThrowIfFalse(() => authorizationHeader.StartsWith(AuthenticationScheme), nameof(authorizationHeader), $"Header did not start with {AuthenticationScheme}.");
+
+ var headerWithoutScheme = authorizationHeader.Remove(0, AuthenticationScheme.Length + 1);
+ var credentials = new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ { BasicFields.Credentials, headerWithoutScheme.Trim() }
+ };
+ return ParseCore(credentials);
+ }
+
+ ///
+ /// The core parser that resolves an from a set of .
+ ///
+ /// The credentials used in authentication.
+ /// An equivalent of .
+ protected override AuthorizationHeader ParseCore(IReadOnlyDictionary credentials)
+ {
+ if (credentials.TryGetValue(BasicFields.Credentials, out var base64EncodedCredentials) && Condition.IsBase64(base64EncodedCredentials))
+ {
+ var plainCredentials = Convertible.ToString(Convert.FromBase64String(base64EncodedCredentials), options =>
+ {
+ options.Encoding = Encoding.ASCII;
+ options.Preamble = PreambleSequence.Remove;
+ }).Split(new [] { ':' }, 2);
+
+ if (plainCredentials.Length == 2 &&
+ !string.IsNullOrWhiteSpace(plainCredentials[0]) &&
+ !string.IsNullOrWhiteSpace(plainCredentials[1]))
+ {
+ return new BasicAuthorizationHeader(plainCredentials[0], plainCredentials[1]);
+ }
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthorizationHeaderBuilder.cs b/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthorizationHeaderBuilder.cs
new file mode 100644
index 000000000..8737a4a45
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Basic/BasicAuthorizationHeaderBuilder.cs
@@ -0,0 +1,48 @@
+namespace Cuemon.AspNetCore.Authentication.Basic
+{
+ ///
+ /// Provides a way to fluently represent a HTTP Basic Authentication header.
+ ///
+ public class BasicAuthorizationHeaderBuilder : AuthorizationHeaderBuilder
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public BasicAuthorizationHeaderBuilder() : base(BasicAuthorizationHeader.Scheme)
+ {
+ MapRelation(nameof(AddUserName), BasicFields.UserName);
+ MapRelation(nameof(AddPassword), BasicFields.Password);
+ }
+
+
+ ///
+ /// Adds the credential scope that defines the remote resource.
+ ///
+ /// The credential scope that defines the remote resource.
+ /// An that can be used to further build the HTTP HMAC Authentication header.
+ public BasicAuthorizationHeaderBuilder AddUserName(string username)
+ {
+ return AddOrUpdate(BasicFields.UserName, username);
+ }
+
+ ///
+ /// Adds the client identifier that is the public key of the signing process.
+ ///
+ /// The client identifier that is the public key of the signing process.
+ /// An that can be used to further build the HTTP HMAC Authentication header.
+ public BasicAuthorizationHeaderBuilder AddPassword(string password)
+ {
+ return AddOrUpdate(BasicFields.Password, password);
+ }
+
+ ///
+ /// Builds an instance of that implements .
+ ///
+ /// An instance of .
+ public override BasicAuthorizationHeader Build()
+ {
+ ValidateData(BasicFields.UserName, BasicFields.Password);
+ return new BasicAuthorizationHeader(Data[BasicFields.UserName], Data[BasicFields.Password]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Basic/BasicFields.cs b/src/Cuemon.AspNetCore.Authentication/Basic/BasicFields.cs
new file mode 100644
index 000000000..7824921ac
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Basic/BasicFields.cs
@@ -0,0 +1,28 @@
+namespace Cuemon.AspNetCore.Authentication.Basic
+{
+ ///
+ /// A collection of constants for .
+ ///
+ public static class BasicFields
+ {
+ ///
+ /// The realm field of a HTTP Basic access authentication.
+ ///
+ public const string Realm = "realm";
+
+ ///
+ /// The username of the .
+ ///
+ public const string UserName = "username";
+
+ ///
+ /// The password of the .
+ ///
+ public const string Password = "password";
+
+ ///
+ /// The credentials of the HTTP Basic access authentication.
+ ///
+ public const string Credentials = "credentials";
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/BasicAuthenticationMiddleware.cs b/src/Cuemon.AspNetCore.Authentication/BasicAuthenticationMiddleware.cs
deleted file mode 100644
index 21e7d4341..000000000
--- a/src/Cuemon.AspNetCore.Authentication/BasicAuthenticationMiddleware.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-using System;
-using System.Security.Claims;
-using System.Text;
-using System.Threading.Tasks;
-using Cuemon.AspNetCore.Builder;
-using Cuemon.Text;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Options;
-using Microsoft.Net.Http.Headers;
-
-namespace Cuemon.AspNetCore.Authentication
-{
- ///
- /// Provides a HTTP Basic Authentication middleware implementation for ASP.NET Core.
- ///
- public class BasicAuthenticationMiddleware : ConfigurableMiddleware
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The delegate of the request pipeline to invoke.
- /// The which need to be configured.
- public BasicAuthenticationMiddleware(RequestDelegate next, IOptions setup) : base(next, setup)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The delegate of the request pipeline to invoke.
- /// The middleware which need to be configured.
- public BasicAuthenticationMiddleware(RequestDelegate next, Action setup) : base(next, setup)
- {
- }
-
- ///
- /// Executes the .
- ///
- /// The context of the current request.
- /// A task that represents the execution of this middleware.
- public override async Task InvokeAsync(HttpContext context)
- {
- if (!AuthenticationUtility.TryAuthenticate(context, Options.RequireSecureConnection, AuthorizationHeaderParser, TryAuthenticate))
- {
- context.Response.StatusCode = AuthenticationUtility.HttpNotAuthorizedStatusCode;
- context.Response.Headers.Add(HeaderNames.WWWAuthenticate, FormattableString.Invariant($"{AuthenticationScheme} realm=\"{Options.Realm}\""));
- await context.WriteHttpNotAuthorizedBody(Options.HttpNotAuthorizedBody).ConfigureAwait(false);
- return;
- }
- await Next.Invoke(context).ConfigureAwait(false);
- }
-
- ///
- /// Gets the name of the authentication scheme.
- ///
- /// The name of the authentication scheme.
- public string AuthenticationScheme => "Basic";
-
- private bool TryAuthenticate(HttpContext context, Template credentials, out ClaimsPrincipal result)
- {
- if (Options.Authenticator == null) { throw new InvalidOperationException(FormattableString.Invariant($"The {nameof(Options.Authenticator)} cannot be null.")); }
- result = Options.Authenticator(credentials.Arg1, credentials.Arg2);
- return Condition.IsNotNull(result);
- }
-
- private Template AuthorizationHeaderParser(HttpContext context, string authorizationHeader)
- {
- if (AuthenticationUtility.IsAuthenticationSchemeValid(authorizationHeader, AuthenticationScheme))
- {
- var base64Credentials = authorizationHeader.Remove(0, AuthenticationScheme.Length + 1);
- if (Condition.IsBase64(base64Credentials))
- {
- var credentials = Convertible.ToString(Convert.FromBase64String(base64Credentials), options =>
- {
- options.Encoding = Encoding.ASCII;
- options.Preamble = PreambleSequence.Remove;
- }).Split(AuthenticationUtility.BasicAuthenticationCredentialSeparator);
- if (credentials.Length == 2 &&
- !string.IsNullOrEmpty(credentials[0]) &&
- !string.IsNullOrEmpty(credentials[1]))
- { return Template.CreateTwo(credentials[0], credentials[1]); }
- }
- }
- return null;
- }
- }
-
- ///
- /// This is a factory implementation of the class.
- ///
- public static class BasicAuthenticationBuilderExtension
- {
- ///
- /// Adds a HTTP Basic Authentication scheme to the request execution pipeline.
- ///
- /// The type that provides the mechanisms to configure an application’s request pipeline.
- /// The HTTP middleware which need to be configured.
- /// A reference to this instance after the operation has completed.
- public static IApplicationBuilder UseBasicAuthentication(this IApplicationBuilder builder, Action setup = null)
- {
- return ApplicationBuilderFactory.UseMiddlewareConfigurable(builder, setup);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Cuemon.AspNetCore.Authentication.csproj b/src/Cuemon.AspNetCore.Authentication/Cuemon.AspNetCore.Authentication.csproj
index 45690205d..c7c46be4e 100644
--- a/src/Cuemon.AspNetCore.Authentication/Cuemon.AspNetCore.Authentication.csproj
+++ b/src/Cuemon.AspNetCore.Authentication/Cuemon.AspNetCore.Authentication.csproj
@@ -1,36 +1,21 @@
-
+
- netcoreapp3.0;netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netcoreapp3.0;netstandard2.0
a10adf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon .NET Standard
Cuemon.AspNetCore.Authentication
Cuemon.AspNetCore.Authentication
- The Cuemon.AspNetCore.Authentication assembly provides supplemental ways of authentication forms to Microsoft ASP.NET Core.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ 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. The namespace is an addition to the Microsoft.AspNetCore.Authentication namespace.
+ basic-authentication basic-authentication-middleware digest-access-authentication digest-authentication-middleware hmac-authentication hmac-authentication-middleware authenticator authorization-header authorization-header-builder nonce-tracker
+
+
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthenticationMiddleware.cs b/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthenticationMiddleware.cs
new file mode 100644
index 000000000..dcab39d81
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthenticationMiddleware.cs
@@ -0,0 +1,132 @@
+using System;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using Cuemon.IO;
+using Cuemon.Security.Cryptography;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+using Microsoft.Net.Http.Headers;
+
+namespace Cuemon.AspNetCore.Authentication.Digest
+{
+ ///
+ /// Provides a HTTP Digest Access Authentication middleware implementation for ASP.NET Core.
+ ///
+ public class DigestAuthenticationMiddleware : ConfigurableMiddleware
+ {
+ private INonceTracker _nonceTracker;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The delegate of the request pipeline to invoke.
+ /// The which need to be configured.
+ public DigestAuthenticationMiddleware(RequestDelegate next, IOptions setup) : base(next, setup)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The delegate of the request pipeline to invoke.
+ /// The middleware which need to be configured.
+ public DigestAuthenticationMiddleware(RequestDelegate next, Action setup) : base(next, setup)
+ {
+ }
+
+ ///
+ /// Executes the .
+ ///
+ /// The context of the current request.
+ /// The dependency injected implementation of an .
+ /// A task that represents the execution of this middleware.
+ public override async Task InvokeAsync(HttpContext context, INonceTracker nonceTracker)
+ {
+ _nonceTracker = nonceTracker;
+ if (!Authenticator.TryAuthenticate(context, Options.RequireSecureConnection, AuthorizationHeaderParser, TryAuthenticate))
+ {
+ await Decorator.Enclose(context).InvokeAuthenticationAsync(Options, async (message, response) =>
+ {
+ context.Response.OnStarting(() =>
+ {
+ string etag = context.Response.Headers[HeaderNames.ETag];
+ if (string.IsNullOrEmpty(etag)) { etag = "no-entity-tag"; }
+ var opaqueGenerator = Options.OpaqueGenerator;
+ var nonceSecret = Options.NonceSecret;
+ var nonceGenerator = Options.NonceGenerator;
+ var staleNonce = context.Items[DigestFields.Stale] as string ?? "false";
+ context.Response.Headers.Add(HeaderNames.WWWAuthenticate, FormattableString.Invariant($"{DigestAuthorizationHeader.Scheme} realm=\"{Options.Realm}\", qop=\"auth, auth-int\", nonce=\"{nonceGenerator(DateTime.UtcNow, etag, nonceSecret())}\", opaque=\"{opaqueGenerator()}\", stale=\"{staleNonce}\", algorithm=\"{ParseAlgorithm(Options.Algorithm)}\""));
+ return Task.CompletedTask;
+ });
+ response.StatusCode = (int)message.StatusCode;
+ await Decorator.Enclose(response.Body).WriteAsync(await message.Content.ReadAsByteArrayAsync().ConfigureAwait(false)).ConfigureAwait(false);
+ }).ConfigureAwait(false);
+ }
+ await Next.Invoke(context).ConfigureAwait(false);
+ }
+
+ private bool TryAuthenticate(HttpContext context, DigestAuthorizationHeader header, out ClaimsPrincipal result)
+ {
+ if (Options.Authenticator == null) { throw new InvalidOperationException(FormattableString.Invariant($"The {nameof(Options.Authenticator)} delegate cannot be null.")); }
+
+ if (header == null)
+ {
+ result = null;
+ return false;
+ }
+
+ result = null;
+ var nonceExpiredParser = Options.NonceExpiredParser;
+ var staleNonce = nonceExpiredParser(header.Nonce, TimeSpan.FromSeconds(30));
+ if (staleNonce)
+ {
+ context.Items.Add(DigestFields.Stale, "true");
+ return false;
+ }
+
+ if (_nonceTracker != null)
+ {
+ var nc = Convert.ToInt32(header.NC, 16);
+ if (_nonceTracker.TryGetEntry(header.Nonce, out var previousNonce))
+ {
+ if (previousNonce.Count == nc)
+ {
+ context.Items.Add(DigestFields.Stale, "true");
+ return false;
+ }
+ }
+ else
+ {
+ _nonceTracker.TryAddEntry(header.Nonce, nc);
+ }
+ }
+
+ result = Options.Authenticator(header.UserName, out var password);
+
+ var db = new DigestAuthorizationHeaderBuilder().AddFromDigestAuthorizationHeader(header);
+ var ha1 = db.ComputeHash1(password);
+ var ha2 = db.ComputeHash2(context.Request.Method, Decorator.Enclose(context.Request.Body).ToEncodedString(o => o.LeaveOpen = true));
+ var serverResponse = db.ComputeResponse(ha1, ha2);
+
+ return serverResponse != null && serverResponse.Equals(header.Response, StringComparison.Ordinal) && Condition.IsNotNull(result);
+ }
+
+ private DigestAuthorizationHeader AuthorizationHeaderParser(HttpContext context, string authorizationHeader)
+ {
+ return DigestAuthorizationHeader.Create(authorizationHeader);
+ }
+
+ private static string ParseAlgorithm(UnkeyedCryptoAlgorithm algorithm)
+ {
+ switch (algorithm)
+ {
+ case UnkeyedCryptoAlgorithm.Sha256:
+ return "SHA-256";
+ case UnkeyedCryptoAlgorithm.Sha512:
+ return "SHA-512-256";
+ default:
+ return "MD5";
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthenticationOptions.cs b/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthenticationOptions.cs
new file mode 100644
index 000000000..9879a5146
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthenticationOptions.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Globalization;
+using System.Text;
+using Cuemon.Security.Cryptography;
+using Cuemon.Text;
+
+namespace Cuemon.AspNetCore.Authentication.Digest
+{
+ ///
+ /// Configuration options for . This class cannot be inherited.
+ ///
+ ///
+ public sealed class DigestAuthenticationOptions : AuthenticationOptions
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The following table shows the initial property values for an instance of .
+ ///
+ ///
+ /// Property
+ /// Initial Value
+ ///
+ /// -
+ ///
+ ///
+ ///
+ /// -
+ ///
+ /// null
+ ///
+ /// -
+ ///
+ /// A default implementation of a nonce generator.
+ ///
+ /// -
+ ///
+ /// A default implementation of an opaque generator.
+ ///
+ /// -
+ ///
+ /// A default implementation of a nonce expiry parser.
+ ///
+ /// -
+ ///
+ /// A default secret to get you started without overwhelming configuration. Do change when moving outside a development environment.
+ ///
+ /// -
+ ///
+ /// AuthenticationServer
+ ///
+ ///
+ ///
+ public DigestAuthenticationOptions()
+ {
+ Algorithm = UnkeyedCryptoAlgorithm.Sha256;
+ OpaqueGenerator = () => Generate.RandomString(32, Alphanumeric.Hexadecimal).ToLowerInvariant();
+ NonceExpiredParser = (nonce, timeToLive) =>
+ {
+ Validator.ThrowIfNullOrEmpty(nonce, nameof(nonce));
+ if (ParserFactory.FromBase64().TryParse(nonce, out var rawNonce))
+ {
+ var nonceProtocol = Convertible.ToString(rawNonce, options =>
+ {
+ options.Encoding = Encoding.UTF8;
+ options.Preamble = PreambleSequence.Remove;
+ });
+ var nonceTimestamp = DateTime.ParseExact(nonceProtocol.Substring(0, nonceProtocol.LastIndexOf(':')), "u", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
+ var difference = (DateTime.UtcNow - nonceTimestamp);
+ return (difference > timeToLive);
+ }
+ return false;
+ };
+ NonceGenerator = (timestamp, entityTag, privateKey) =>
+ {
+ Validator.ThrowIfNullOrWhitespace(entityTag, nameof(entityTag));
+ Validator.ThrowIfNull(privateKey, nameof(privateKey));
+ var nonceHash = UnkeyedHashFactory.CreateCryptoSha256().ComputeHash(timestamp.Ticks, entityTag, Convert.ToBase64String(privateKey)).ToHexadecimalString();
+ var nonceProtocol = string.Format(CultureInfo.InvariantCulture, "{0}:{1}", timestamp.ToString("u", CultureInfo.InvariantCulture), nonceHash);
+ return Convert.ToBase64String(Convertible.GetBytes(nonceProtocol, options =>
+ {
+ options.Encoding = Encoding.UTF8;
+ options.Preamble = PreambleSequence.Remove;
+ }));
+ };
+ NonceSecret = () => Convert.FromBase64String("ZHBGWDRrVGVxbFlhVEpWQ3hoYUc5VUlZM05penNOaUk=");
+ Realm = "AuthenticationServer";
+ }
+
+ ///
+ /// Gets or sets the function delegate that will perform the authentication from the specified username.
+ ///
+ /// The function delegate that will perform the authentication.
+ public DigestAuthenticator Authenticator { get; set; }
+
+ ///
+ /// Gets or sets the algorithm of the HTTP Digest Access Authentication. Default is .
+ ///
+ /// The algorithm of the HTTP Digest Access Authentication.
+ /// Allowed values are: , and .
+ public UnkeyedCryptoAlgorithm Algorithm { get; set; }
+
+ ///
+ /// Gets the realm that defines the protection space.
+ ///
+ /// The realm that defines the protection space.
+ public string Realm { get; set; }
+
+ ///
+ /// Gets or sets the function delegate for generating opaque string values.
+ ///
+ /// The function delegate for generating opaque string values.
+ public Func OpaqueGenerator { get; set; }
+
+ ///
+ /// Gets or sets the function delegate for retrieving the cryptographic secret used in nonce string values.
+ ///
+ /// The function delegate for retrieving the cryptographic secret used in nonce string values.
+ public Func NonceSecret { get; set; }
+
+ ///
+ /// Gets or sets the function delegate for generating nonce string values.
+ ///
+ /// The function delegate for generating nonce string values.
+ public Func NonceGenerator { get; set; }
+
+ ///
+ /// Gets or sets the function delegate for parsing nonce string values for expiration.
+ ///
+ /// The function delegate for parsing nonce string values for expiration.
+ public Func NonceExpiredParser { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/DigestAccessAuthenticator.cs b/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthenticator.cs
similarity index 68%
rename from src/Cuemon.AspNetCore.Authentication/DigestAccessAuthenticator.cs
rename to src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthenticator.cs
index f87945b2d..5ade72881 100644
--- a/src/Cuemon.AspNetCore.Authentication/DigestAccessAuthenticator.cs
+++ b/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthenticator.cs
@@ -1,12 +1,12 @@
using System.Security.Claims;
-namespace Cuemon.AspNetCore.Authentication
+namespace Cuemon.AspNetCore.Authentication.Digest
{
///
- /// Represents the method that defines an Authenticator typically assigned on .
+ /// Represents the method that defines an Authenticator typically assigned on .
///
/// The username to match and lookup the paired .
/// The password paired with .
/// A that is associated with the result of .
- public delegate ClaimsPrincipal DigestAccessAuthenticator(string username, out string password);
+ public delegate ClaimsPrincipal DigestAuthenticator(string username, out string password);
}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthorizationHeader.cs b/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthorizationHeader.cs
new file mode 100644
index 000000000..5be734edd
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthorizationHeader.cs
@@ -0,0 +1,182 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Cuemon.AspNetCore.Authentication.Digest
+{
+ ///
+ /// Provides a representation of a HTTP Digest Access Authentication header.
+ /// Implements the
+ ///
+ ///
+ public class DigestAuthorizationHeader : AuthorizationHeader
+ {
+ ///
+ /// Creates an instance of from the specified parameters.
+ ///
+ /// The raw HTTP authorization header.
+ /// An instance of .
+ ///
+ /// cannot be null.
+ ///
+ ///
+ /// cannot be empty or consist only of white-space characters.
+ ///
+ public static DigestAuthorizationHeader Create(string authorizationHeader)
+ {
+ Validator.ThrowIfNullOrWhitespace(authorizationHeader, nameof(authorizationHeader));
+ return new DigestAuthorizationHeader().Parse(authorizationHeader, o => o.CredentialsDelimiter = " ") as DigestAuthorizationHeader;
+ }
+
+ ///
+ /// The authentication scheme of the .
+ ///
+ public const string Scheme = "Digest";
+
+ DigestAuthorizationHeader() : base(Scheme)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The realm/credential scope that defines the remote resource.
+ /// The unique server generated string.
+ /// The string of data specified by the server.
+ /// The case-insensitive flag indicating if the previous request from the client was rejected because the value was stale.
+ /// The algorithm used to produce the digest and an unkeyed digest.
+ /// The username of the specified .
+ /// The effective request URI.
+ /// The hexadecimal count of the number of requests the client has sent with the value.
+ /// The unique client generated string.
+ /// The "quality of protection" the client has applied to the message.
+ /// The computed response which proves that the user knows a password.
+ public DigestAuthorizationHeader(string realm, string nonce, string opaque, string stale, string algorithm, string userName, string uri, string nc, string cNonce, string qop, string response) : base(Scheme)
+ {
+ Realm = realm;
+ Nonce = nonce;
+ Opaque = opaque;
+ Stale = stale;
+ Algorithm = algorithm;
+ UserName = userName;
+ Uri = uri;
+ NC = nc;
+ CNonce = cNonce;
+ Qop = qop;
+ Response = response;
+ }
+
+ ///
+ /// Gets the realm/credential scope that defines the remote resource.
+ ///
+ /// The realm/credential scope that defines the remote resource.
+ public string Realm { get; }
+
+ ///
+ /// Gets the unique server generated string.
+ ///
+ /// The unique server generated string.
+ public string Nonce { get; }
+
+ ///
+ /// Gets the string of data specified by the server.
+ ///
+ /// The string of data specified by the server.
+ public string Opaque { get; }
+
+ ///
+ /// Gets the algorithm used to produce the digest and an unkeyed digest.
+ ///
+ /// The algorithm used to produce the digest and an unkeyed digest.
+ public string Algorithm { get; }
+
+ ///
+ /// Gets the username of the specified .
+ ///
+ /// The username of the specified .
+ public string UserName { get; }
+
+ ///
+ /// Gets the effective request URI.
+ ///
+ /// The effective request URI.
+ public string Uri { get; }
+
+ ///
+ /// Gets the computed response which proves that the user knows a password.
+ ///
+ /// The computed response which proves that the user knows a password.
+ public string Response { get; }
+
+ ///
+ /// Gets the "quality of protection" the client has applied to the message.
+ ///
+ /// The "quality of protection" the client has applied to the message.
+ public string Qop { get; }
+
+ ///
+ /// Gets the unique client generated string.
+ ///
+ /// The unique client generated string.
+ public string CNonce { get; }
+
+ ///
+ /// Gets the hexadecimal count of the number of requests the client has sent with the value.
+ ///
+ /// The hexadecimal count of the number of requests the client has sent with the value.
+ public string NC { get; }
+
+ ///
+ /// Gets the case-insensitive flag indicating if the previous request from the client was rejected because the value was stale.
+ ///
+ /// The case-insensitive flag indicating if the previous request from the client was rejected because the value was stale.
+ public string Stale { get; }
+
+ ///
+ /// The core parser that resolves an from a set of .
+ ///
+ /// The credentials used in authentication.
+ /// An equivalent of .
+ protected override AuthorizationHeader ParseCore(IReadOnlyDictionary credentials)
+ {
+ var valid = credentials.TryGetValue(DigestFields.Realm, out var realm);
+ valid |= credentials.TryGetValue(DigestFields.Nonce, out var nonce);
+ valid |= credentials.TryGetValue(DigestFields.Opaque, out var opaque);
+ valid |= credentials.TryGetValue(DigestFields.Algorithm, out var algorithm);
+ valid |= credentials.TryGetValue(DigestFields.UserName, out var userName);
+ valid |= credentials.TryGetValue(DigestFields.DigestUri, out var uri);
+ valid |= credentials.TryGetValue(DigestFields.Response, out var response);
+ valid |= credentials.TryGetValue(DigestFields.QualityOfProtection, out var qop);
+ valid |= credentials.TryGetValue(DigestFields.ClientNonce, out var cnonce);
+ valid |= credentials.TryGetValue(DigestFields.NonceCount, out var nc);
+ valid |= credentials.TryGetValue(DigestFields.Stale, out var stale);
+ return valid ? new DigestAuthorizationHeader(realm, nonce, opaque, stale, algorithm, userName, uri, nc, cnonce, qop, response) : null;
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// A that represents this instance.
+ public override string ToString()
+ {
+ var sb = new StringBuilder(AuthenticationScheme);
+ AppendField(sb, DigestFields.UserName, UserName);
+ AppendField(sb, DigestFields.Realm, Realm);
+ AppendField(sb, DigestFields.Nonce, Nonce);
+ AppendField(sb, DigestFields.DigestUri, Uri);
+ AppendField(sb, DigestFields.QualityOfProtection, Qop);
+ AppendField(sb, DigestFields.NonceCount, NC);
+ AppendField(sb, DigestFields.ClientNonce, CNonce);
+ AppendField(sb, DigestFields.Response, Response);
+ AppendField(sb, DigestFields.Opaque, Opaque);
+ AppendField(sb, DigestFields.Stale, Stale);
+ AppendField(sb, DigestFields.Algorithm, Algorithm);
+ return sb.ToString();
+ }
+
+ private void AppendField(StringBuilder sb, string fn, string fv)
+ {
+ if (!string.IsNullOrWhiteSpace(fv)) { sb.Append($" {fn}=\"{fv}\""); }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthorizationHeaderBuilder.cs b/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthorizationHeaderBuilder.cs
new file mode 100644
index 000000000..856110eb0
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Digest/DigestAuthorizationHeaderBuilder.cs
@@ -0,0 +1,257 @@
+using System;
+using System.Globalization;
+using System.Text;
+using Cuemon.Security.Cryptography;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Net.Http.Headers;
+
+namespace Cuemon.AspNetCore.Authentication.Digest
+{
+ ///
+ /// Provides a way to fluently represent a HTTP Digest Access Authentication header.
+ ///
+ public class DigestAuthorizationHeaderBuilder : AuthorizationHeaderBuilder
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The algorithm to use when computing HA1, HA2 and/or RESPONSE value(s).
+ /// Allowed values for are: , and .
+ public DigestAuthorizationHeaderBuilder(UnkeyedCryptoAlgorithm algorithm = UnkeyedCryptoAlgorithm.Sha256) : base(DigestAuthorizationHeader.Scheme)
+ {
+ Validator.ThrowIfEqual(algorithm, UnkeyedCryptoAlgorithm.Sha1, nameof(algorithm));
+ Validator.ThrowIfEqual(algorithm, UnkeyedCryptoAlgorithm.Sha384, nameof(algorithm));
+ Algorithm = algorithm;
+ MapRelation(nameof(AddResponse), DigestFields.Response);
+ MapRelation(nameof(AddRealm), DigestFields.Realm);
+ MapRelation(nameof(AddUserName), DigestFields.UserName);
+ MapRelation(nameof(AddUri), DigestFields.DigestUri);
+ MapRelation(nameof(AddNc), DigestFields.NonceCount);
+ MapRelation(nameof(AddCnonce), DigestFields.ClientNonce);
+ MapRelation(nameof(AddQopAuthentication), DigestFields.QualityOfProtection);
+ MapRelation(nameof(AddQopAuthenticationIntegrity), DigestFields.QualityOfProtection);
+ MapRelation(nameof(ComputeHash1), DigestFields.UserName, DigestFields.Realm);
+ MapRelation(nameof(ComputeHash2), DigestFields.QualityOfProtection, DigestFields.DigestUri);
+ MapRelation(nameof(ComputeResponse), DigestFields.Nonce, DigestFields.NonceCount, DigestFields.ClientNonce, DigestFields.QualityOfProtection);
+ }
+
+ ///
+ /// Gets the algorithm of the HTTP Digest Access Authentication.
+ ///
+ /// The algorithm of the HTTP Digest Access Authentication.
+ public UnkeyedCryptoAlgorithm Algorithm { get; private set; }
+
+ ///
+ /// Associates the field with the specified .
+ ///
+ /// The realm that defines the remote resource.
+ /// An that can be used to further build the HTTP Digest Access Authentication header.
+ public DigestAuthorizationHeaderBuilder AddRealm(string realm)
+ {
+ return AddOrUpdate(DigestFields.Realm, realm);
+ }
+
+ ///
+ /// Associates the field with the specified .
+ ///
+ /// The username to use in the authentication process.
+ /// An that can be used to further build the HTTP Digest Access Authentication header.
+ public DigestAuthorizationHeaderBuilder AddUserName(string username)
+ {
+ Validator.ThrowIfNullOrWhitespace(username, nameof(username));
+ return AddOrUpdate(DigestFields.UserName, username);
+ }
+
+ ///
+ /// Associates the field with the specified .
+ ///
+ /// The effective request URI to use in the authentication process.
+ /// An that can be used to further build the HTTP Digest Access Authentication header.
+ public DigestAuthorizationHeaderBuilder AddUri(string digestUri)
+ {
+ Validator.ThrowIfNullOrWhitespace(digestUri, nameof(digestUri));
+ return AddOrUpdate(DigestFields.DigestUri, digestUri);
+ }
+
+ ///
+ /// Associates the field with the specified .
+ ///
+ /// The count of the number of requests to use in the authentication process.
+ /// An that can be used to further build the HTTP Digest Access Authentication header.
+ public DigestAuthorizationHeaderBuilder AddNc(int nonceCount)
+ {
+ Validator.ThrowIfLowerThan(nonceCount, 0, nameof(nonceCount));
+ return AddOrUpdate(DigestFields.NonceCount, nonceCount.ToString("x8"));
+ }
+
+ ///
+ /// Associates the field with the specified .
+ ///
+ /// The cryptographic client nonce to use in the authentication process.
+ /// An that can be used to further build the HTTP Digest Access Authentication header.
+ public DigestAuthorizationHeaderBuilder AddCnonce(string clientNonce = null)
+ {
+ if (clientNonce == null) { clientNonce = Generate.RandomString(32); }
+ return AddOrUpdate(DigestFields.ClientNonce, clientNonce);
+ }
+
+ ///
+ /// Associates the field with "auth".
+ ///
+ /// An that can be used to further build the HTTP Digest Access Authentication header.
+ public DigestAuthorizationHeaderBuilder AddQopAuthentication()
+ {
+ return AddOrUpdate(DigestFields.QualityOfProtection, "auth");
+ }
+
+ ///
+ /// Associates the field with "auth-int".
+ ///
+ /// An that can be used to further build the HTTP Digest Access Authentication header.
+ public DigestAuthorizationHeaderBuilder AddQopAuthenticationIntegrity()
+ {
+ return AddOrUpdate(DigestFields.QualityOfProtection, "auth-int");
+ }
+
+ ///
+ /// Associates any Digest fields found in the HTTP WWW-Authenticate header from the specified .
+ ///
+ /// An implementation of .
+ /// An that can be used to further build the HTTP Digest Access Authentication header.
+ public DigestAuthorizationHeaderBuilder AddFromWwwAuthenticateHeader(IHeaderDictionary headers)
+ {
+ Validator.ThrowIfNull(headers, nameof(headers));
+ string header = headers[HeaderNames.WWWAuthenticate];
+ Validator.ThrowIfFalse(() => header.StartsWith(AuthenticationScheme), nameof(header), $"Header did not start with {AuthenticationScheme}.");
+ var headerWithoutScheme = header.Remove(0, AuthenticationScheme.Length + 1);
+
+ var fields = DelimitedString.Split(headerWithoutScheme);
+ foreach (var field in fields)
+ {
+ var kvp = DelimitedString.Split(field, o => o.Delimiter = "=");
+ var key = kvp[0].Trim();
+ var value = kvp[1].Trim('"');
+ if (key == DigestFields.QualityOfProtection) { continue; }
+ AddOrUpdate(key, value);
+ }
+ return this;
+ }
+
+ ///
+ /// Associates any Digest fields found in the HTTP Authorization header from the specified .
+ ///
+ /// An instance of .
+ /// An that can be used to further build the HTTP Digest Access Authentication header.
+ public DigestAuthorizationHeaderBuilder AddFromDigestAuthorizationHeader(DigestAuthorizationHeader header)
+ {
+ Validator.ThrowIfNull(header, nameof(header));
+ Algorithm = ParseAlgorithm(header.Algorithm);
+ AddUserName(header.UserName);
+ AddRealm(header.Realm);
+ AddUri(header.Uri);
+ AddNc(Convert.ToInt32(header.NC, 16));
+ AddCnonce(header.CNonce);
+ AddOrUpdate(DigestFields.Nonce, header.Nonce);
+ Condition.FlipFlop(header.Qop.Equals("auth-int", StringComparison.OrdinalIgnoreCase), () => AddQopAuthenticationIntegrity(), () => AddQopAuthentication());
+ return this;
+ }
+
+ private static UnkeyedCryptoAlgorithm ParseAlgorithm(string algorithm)
+ {
+ return algorithm.StartsWith("SHA-512", StringComparison.OrdinalIgnoreCase) ? UnkeyedCryptoAlgorithm.Sha512
+ : algorithm.StartsWith("SHA-256", StringComparison.OrdinalIgnoreCase) ? UnkeyedCryptoAlgorithm.Sha256
+ : UnkeyedCryptoAlgorithm.Md5;
+ }
+
+ ///
+ /// Associates the field with the computed values of , and .
+ ///
+ /// The password to include in the HA1 computed value.
+ /// The HTTP method to include in the HA2 computed value.
+ /// The entity body to apply in the signature when qop is set to auth-int.
+ /// An that can be used to further build the HTTP Digest Access Authentication header.
+ public DigestAuthorizationHeaderBuilder AddResponse(string password, string method, string entityBody = null)
+ {
+ Validator.ThrowIfNullOrWhitespace(password, nameof(password));
+ Validator.ThrowIfNullOrWhitespace(method, nameof(method));
+ ValidateData(DigestFields.UserName, DigestFields.Realm, DigestFields.QualityOfProtection, DigestFields.DigestUri, DigestFields.Nonce, DigestFields.NonceCount, DigestFields.ClientNonce);
+ return AddOrUpdate(DigestFields.Response, ComputeResponse(ComputeHash1(password), ComputeHash2(method, entityBody)));
+ }
+
+ ///
+ /// Computes a by parameter defined hash value of the required values for the HTTP Digest access authentication HA1.
+ ///
+ /// The password to include in the HA1 computed value.
+ /// A in the format of H(::). H is determined by .
+ public virtual string ComputeHash1(string password)
+ {
+ Validator.ThrowIfNullOrWhitespace(password, nameof(password));
+ ValidateData(DigestFields.UserName, DigestFields.Realm);
+ return UnkeyedHashFactory.CreateCrypto(Algorithm).ComputeHash(string.Format(CultureInfo.InvariantCulture, "{0}:{1}:{2}", Data[DigestFields.UserName], Data[DigestFields.Realm], password), o =>
+ {
+ o.Encoding = Encoding.UTF8;
+ }).ToHexadecimalString();
+ }
+
+ ///
+ /// Computes a by parameter defined hash value of the required values for the HTTP Digest access authentication HA2.
+ ///
+ /// The HTTP method to include in the HA2 computed value.
+ /// The entity body to apply in the signature when qop is set to auth-int.
+ /// A in the format of H(:) OR H(::H()). H is determined by .
+ public virtual string ComputeHash2(string method, string entityBody = null)
+ {
+ Validator.ThrowIfNullOrWhitespace(method, nameof(method));
+ method = method.ToUpperInvariant();
+ ValidateData(DigestFields.QualityOfProtection, DigestFields.DigestUri);
+ var qop = Data[DigestFields.QualityOfProtection];
+ var hasIntegrityProtection = qop.Equals("auth-int", StringComparison.OrdinalIgnoreCase);
+ if (hasIntegrityProtection && entityBody == null) { throw new ArgumentNullException(nameof(entityBody), "The entity body cannot be null when qop is set to auth-int."); }
+
+ var hashFields = !hasIntegrityProtection
+ ? FormattableString.Invariant($"{method}:{Data[DigestFields.DigestUri]}")
+ : FormattableString.Invariant($"{method}:{Data[DigestFields.DigestUri]}:{UnkeyedHashFactory.CreateCrypto(Algorithm).ComputeHash(entityBody, o => o.Encoding = Encoding.UTF8).ToHexadecimalString()}");
+ return UnkeyedHashFactory.CreateCrypto(Algorithm).ComputeHash(hashFields, o =>
+ {
+ o.Encoding = Encoding.UTF8;
+ }).ToHexadecimalString();
+ }
+
+ ///
+ /// Computes a by parameter defined hash value of the required values for the HTTP Digest access authentication RESPONSE.
+ ///
+ /// The HA1 to include in the RESPONSE computed value.
+ /// The HA2 to include in the RESPONSE computed value.
+ /// A in the format of H(:::::). H is determined by .
+ public virtual string ComputeResponse(string hash1, string hash2)
+ {
+ Validator.ThrowIfNullOrWhitespace(hash1, nameof(hash1));
+ Validator.ThrowIfNullOrWhitespace(hash2, nameof(hash2));
+ ValidateData(DigestFields.Nonce, DigestFields.NonceCount, DigestFields.ClientNonce, DigestFields.QualityOfProtection);
+ return UnkeyedHashFactory.CreateCrypto(Algorithm).ComputeHash(FormattableString.Invariant($"{hash1}:{Data[DigestFields.Nonce]}:{Data[DigestFields.NonceCount]}:{Data[DigestFields.ClientNonce]}:{Data[DigestFields.QualityOfProtection]}:{hash2}"), o =>
+ {
+ o.Encoding = Encoding.UTF8;
+ }).ToHexadecimalString();
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// A that represents this instance.
+ public override DigestAuthorizationHeader Build()
+ {
+ ValidateData(DigestFields.Realm, DigestFields.Nonce, DigestFields.UserName, DigestFields.QualityOfProtection, DigestFields.DigestUri, DigestFields.NonceCount, DigestFields.ClientNonce, DigestFields.QualityOfProtection, DigestFields.Response);
+ return new DigestAuthorizationHeader(Data[DigestFields.Realm],
+ Data[DigestFields.Nonce],
+ Data[DigestFields.Opaque],
+ Data[DigestFields.Stale],
+ Data[DigestFields.Algorithm],
+ Data[DigestFields.UserName],
+ Data[DigestFields.DigestUri],
+ Data[DigestFields.NonceCount],
+ Data[DigestFields.ClientNonce],
+ Data[DigestFields.QualityOfProtection],
+ Data[DigestFields.Response]);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Digest/DigestFields.cs b/src/Cuemon.AspNetCore.Authentication/Digest/DigestFields.cs
new file mode 100644
index 000000000..b80d423e1
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Digest/DigestFields.cs
@@ -0,0 +1,63 @@
+namespace Cuemon.AspNetCore.Authentication.Digest
+{
+ ///
+ /// A collection of constants for .
+ ///
+ public static class DigestFields
+ {
+ ///
+ /// The username field of a HTTP Digest access authentication.
+ ///
+ public const string UserName = "username";
+
+ ///
+ /// The realm field of a HTTP Digest access authentication.
+ ///
+ public const string Realm = "realm";
+
+ ///
+ /// The response field of a HTTP Digest access authentication.
+ ///
+ public const string Response = "response";
+
+ ///
+ /// The qop (quality of protection) field of a HTTP Digest access authentication.
+ ///
+ public const string QualityOfProtection = "qop";
+
+ ///
+ /// The client nonce (cnonce) field of a HTTP Digest access authentication.
+ ///
+ public const string ClientNonce = "cnonce";
+
+ ///
+ /// The nc (nonce count) field of a HTTP Digest access authentication.
+ ///
+ public const string NonceCount = "nc";
+
+ ///
+ /// The nonce field of a HTTP Digest access authentication.
+ ///
+ public const string Nonce = "nonce";
+
+ ///
+ /// The uri (digest URI) field of a HTTP Digest access authentication.
+ ///
+ public const string DigestUri = "uri";
+
+ ///
+ /// The opaque field of a HTTP Digest access authentication.
+ ///
+ public const string Opaque = "opaque";
+
+ ///
+ /// The algorithm field of a HTTP Digest access authentication.
+ ///
+ public const string Algorithm = "algorithm";
+
+ ///
+ /// The stale field of a HTTP Digest access authentication.
+ ///
+ public const string Stale = "stale";
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/DigestAccessAuthenticationMiddleware.cs b/src/Cuemon.AspNetCore.Authentication/DigestAccessAuthenticationMiddleware.cs
deleted file mode 100644
index a9b201ba6..000000000
--- a/src/Cuemon.AspNetCore.Authentication/DigestAccessAuthenticationMiddleware.cs
+++ /dev/null
@@ -1,183 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Linq;
-using System.Security.Claims;
-using System.Threading;
-using System.Threading.Tasks;
-using Cuemon.AspNetCore.Builder;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Options;
-using Microsoft.Net.Http.Headers;
-
-namespace Cuemon.AspNetCore.Authentication
-{
- ///
- /// Provides a HTTP Digest Access Authentication middleware implementation for ASP.NET Core.
- ///
- public class DigestAccessAuthenticationMiddleware : ConfigurableMiddleware
- {
- private static readonly ConcurrentDictionary> NonceCounter = new ConcurrentDictionary>();
- private static Timer _nonceCounterSweeper;
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The delegate of the request pipeline to invoke.
- /// The which need to be configured.
- public DigestAccessAuthenticationMiddleware(RequestDelegate next, IOptions setup) : base(next, setup)
- {
- InitializeNonceCounterSweeper();
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The delegate of the request pipeline to invoke.
- /// The middleware which need to be configured.
- public DigestAccessAuthenticationMiddleware(RequestDelegate next, Action setup) : base(next, setup)
- {
- InitializeNonceCounterSweeper();
- }
-
- private static void InitializeNonceCounterSweeper()
- {
- _nonceCounterSweeper = new Timer(s =>
- {
- var utcStaleTimestamp = DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(5));
- var staledEntries = NonceCounter.Where(pair => pair.Value.Arg1 <= utcStaleTimestamp).ToList();
- foreach (var staledEntry in staledEntries)
- {
- NonceCounter.TryRemove(staledEntry.Key, out _);
- }
- }, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(2));
- }
-
- ///
- /// Executes the .
- ///
- /// The context of the current request.
- /// A task that represents the execution of this middleware.
- public override async Task InvokeAsync(HttpContext context)
- {
- if (!AuthenticationUtility.TryAuthenticate(context, Options.RequireSecureConnection, AuthorizationHeaderParser, TryAuthenticate))
- {
- context.Response.StatusCode = AuthenticationUtility.HttpNotAuthorizedStatusCode;
- string etag = context.Response.Headers[HeaderNames.ETag];
- if (string.IsNullOrEmpty(etag)) { etag = "no-entity-tag"; }
- var opaqueGenerator = Options.OpaqueGenerator;
- var nonceSecret = Options.NonceSecret;
- var nonceGenerator = Options.NonceGenerator;
- var staleNonce = context.Items["staleNonce"] as string ?? "FALSE";
- context.Response.Headers.Add(HeaderNames.WWWAuthenticate, FormattableString.Invariant($"{AuthenticationScheme} realm=\"{Options.Realm}\", qop=\"{DigestAuthenticationUtility.CredentialQualityOfProtectionOptions}\", nonce=\"{nonceGenerator(DateTime.UtcNow, etag, nonceSecret())}\", opaque=\"{opaqueGenerator()}\", stale=\"{staleNonce}\", algorithm=\"{DigestAuthenticationUtility.ParseAlgorithm(Options.Algorithm)}\""));
- await context.WriteHttpNotAuthorizedBody(Options.HttpNotAuthorizedBody).ConfigureAwait(false);
- return;
- }
- await Next.Invoke(context).ConfigureAwait(false);
- }
-
- ///
- /// Gets the name of the authentication scheme.
- ///
- /// The name of the authentication scheme.
- public string AuthenticationScheme => "Digest";
-
- private bool TryAuthenticate(HttpContext context, Dictionary credentials, out ClaimsPrincipal result)
- {
- if (Options.Authenticator == null) { throw new InvalidOperationException(FormattableString.Invariant($"The {nameof(Options.Authenticator)} delegate cannot be null.")); }
- credentials.TryGetValue(DigestAuthenticationUtility.CredentialUserName, out var userName);
- credentials.TryGetValue(DigestAuthenticationUtility.CredentialResponse, out var clientResponse);
- credentials.TryGetValue(DigestAuthenticationUtility.CredentialNonceCount, out var nonceCount);
- if (credentials.TryGetValue(DigestAuthenticationUtility.CredentialNonce, out var nonce))
- {
- result = null;
- var nonceExpiredParser = Options.NonceExpiredParser;
- var staleNonce = nonceExpiredParser(nonce, TimeSpan.FromSeconds(30));
- context.Items["staleNonce"] = staleNonce.ToString().ToUpperInvariant();
- if (staleNonce) { return false; }
-
- if (NonceCounter.TryGetValue(nonce, out var previousNonce))
- {
- if (previousNonce.Arg2.Equals(nonceCount, StringComparison.Ordinal)) { return false; }
- }
- else
- {
- NonceCounter.TryAdd(nonce, Template.CreateTwo(DateTime.UtcNow, nonceCount));
- }
- }
- result = Options.Authenticator(userName, out var password);
-
- var serverResponse = Options?.DigestAccessSigner(new DigestAccessAuthenticationParameters(credentials.ToImmutableDictionary(), context.Request.Method, password, Options.Algorithm));
- return serverResponse != null && StringFactory.CreateHexadecimal(serverResponse).Equals(clientResponse, StringComparison.Ordinal) && Condition.IsNotNull(result);
- }
-
- private Dictionary AuthorizationHeaderParser(HttpContext context, string authorizationHeader)
- {
- if (AuthenticationUtility.IsAuthenticationSchemeValid(authorizationHeader, AuthenticationScheme))
- {
- var digestCredentials = authorizationHeader.Remove(0, AuthenticationScheme.Length + 1);
- var credentials = digestCredentials.Split(AuthenticationUtility.DigestAuthenticationCredentialSeparator);
- if (IsDigestCredentialsValid(credentials))
- {
- var result = new Dictionary(StringComparer.OrdinalIgnoreCase);
- for (var i = 0; i < credentials.Length; i++)
- {
- var credentialPair = DelimitedString.Split(credentials[i], o => o.Qualifier = "=");
- result.Add(credentialPair[0].Trim(), QuotedStringParser(credentialPair[1]));
- }
- return IsDigestCredentialsValid(result) ? result : null;
- }
- }
- return new Dictionary();
- }
-
- private static bool IsDigestCredentialsValid(Dictionary credentials)
- {
- var valid = credentials.ContainsKey("username");
- valid |= credentials.ContainsKey("realm");
- valid |= credentials.ContainsKey("nonce");
- valid |= credentials.ContainsKey("uri");
- valid |= credentials.ContainsKey("response");
- return valid;
- }
-
- private string QuotedStringParser(string value)
- {
- if (value.StartsWith("\"", StringComparison.OrdinalIgnoreCase) &&
- value.EndsWith("\"", StringComparison.OrdinalIgnoreCase))
- {
- value = value.Trim('"');
- }
- return value.Trim();
- }
-
- private static bool IsDigestCredentialsValid(string[] credentials)
- {
- var valid = (credentials.Length >= 5 && credentials.Length <= 10);
- for (var i = 0; i < credentials.Length; i++)
- {
- valid |= !string.IsNullOrEmpty(credentials[i]);
- }
- return valid;
- }
- }
-
- ///
- /// This is a factory implementation of the class.
- ///
- public static class DigestAccessAuthenticationBuilderExtension
- {
- ///
- /// Adds a HTTP Digest Authentication scheme to the request execution pipeline.
- ///
- /// The type that provides the mechanisms to configure an application’s request pipeline.
- /// The HTTP middleware which need to be configured.
- /// A reference to this instance after the operation has completed.
- public static IApplicationBuilder UseDigestAccessAuthentication(this IApplicationBuilder builder, Action setup = null)
- {
- return ApplicationBuilderFactory.UseMiddlewareConfigurable(builder, setup);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/DigestAccessAuthenticationOptions.cs b/src/Cuemon.AspNetCore.Authentication/DigestAccessAuthenticationOptions.cs
deleted file mode 100644
index c7cb36ee2..000000000
--- a/src/Cuemon.AspNetCore.Authentication/DigestAccessAuthenticationOptions.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using System;
-using Cuemon.Security.Cryptography;
-
-namespace Cuemon.AspNetCore.Authentication
-{
- ///
- /// Configuration options for . This class cannot be inherited.
- ///
- ///
- public sealed class DigestAccessAuthenticationOptions : AuthenticationOptions
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public DigestAccessAuthenticationOptions()
- {
- Algorithm = CryptoAlgorithm.Md5;
- OpaqueGenerator = DigestAuthenticationUtility.DefaultOpaqueGenerator;
- NonceExpiredParser = DigestAuthenticationUtility.DefaultNonceExpiredParser;
- NonceGenerator = DigestAuthenticationUtility.DefaultNonceGenerator;
- NonceSecret = () => DigestAuthenticationUtility.DefaultPrivateKey;
- DigestAccessSigner = parameters =>
- {
- var ha1 = DigestAuthenticationUtility.ComputeHash1(parameters.Credentials, parameters.Password, parameters.Algorithm);
- var ha2 = DigestAuthenticationUtility.ComputeHash2(parameters.Credentials, parameters.HttpMethod, parameters.Algorithm);
- return DigestAuthenticationUtility.ComputeResponse(parameters.Credentials, ha1, ha2, parameters.Algorithm);
- };
- }
-
- ///
- /// Gets or sets the function delegate that will perform the authentication from the specified username.
- ///
- /// The function delegate that will perform the authentication.
- public DigestAccessAuthenticator Authenticator { get; set; }
-
- ///
- /// Gets or sets the function delegate that will sign a message retrieved from a HTTP request.
- ///
- /// The function delegate that will sign a message.
- public Func DigestAccessSigner { get; set; }
-
- ///
- /// Gets or sets the algorithm of the HTTP Digest Access Authentication. Default is .
- ///
- /// The algorithm of the HTTP Digest Access Authentication.
- public CryptoAlgorithm Algorithm { get; set; }
-
- ///
- /// Gets the realm that defines the protection space.
- ///
- /// The realm that defines the protection space.
- public string Realm { get; set; }
-
- ///
- /// Gets or sets the function delegate for generating opaque string values.
- ///
- /// The function delegate for generating opaque string values.
- public Func OpaqueGenerator { get; set; }
-
- ///
- /// Gets or sets the function delegate for retrieving the cryptographic secret used in nonce string values.
- ///
- /// The function delegate for retrieving the cryptographic secret used in nonce string values.
- public Func NonceSecret { get; set; }
-
- ///
- /// Gets or sets the function delegate for generating nonce string values.
- ///
- /// The function delegate for generating nonce string values.
- public Func NonceGenerator { get; set; }
-
- ///
- /// Gets or sets the function delegate for parsing nonce string values for expiration.
- ///
- /// The function delegate for parsing nonce string values for expiration.
- public Func NonceExpiredParser { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/DigestAccessAuthenticationParameters.cs b/src/Cuemon.AspNetCore.Authentication/DigestAccessAuthenticationParameters.cs
deleted file mode 100644
index 534429b33..000000000
--- a/src/Cuemon.AspNetCore.Authentication/DigestAccessAuthenticationParameters.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System.Collections.Immutable;
-using Cuemon.Security.Cryptography;
-
-namespace Cuemon.AspNetCore.Authentication
-{
- ///
- /// Represents a set of parameters that is needed for creating an application of cryptographic hashing with usage of nonce values to prevent replay attacks.
- ///
- public class DigestAccessAuthenticationParameters
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The credentials used in the computation of HA1-, HA2-, and response hash values.
- /// The HTTP method to include in the HA2 computed value.
- /// The password to include in the HA1 computed value.
- /// The algorithm to use when computing the HA1-, HA2-, and response hash values.
- internal DigestAccessAuthenticationParameters(ImmutableDictionary credentials, string httpMethod, string password, CryptoAlgorithm algorithm)
- {
- Credentials = credentials;
- HttpMethod = httpMethod;
- Password = password;
- Algorithm = algorithm;
- }
-
- ///
- /// Gets the credentials used in the computation of HA1-, HA2-, and response hash values.
- ///
- /// The credentials used in the computation of HA1-, HA2-, and response hash values.
- public ImmutableDictionary Credentials { get; }
-
- ///
- /// Gets the HTTP method to include in the HA2 computed value.
- ///
- /// The HTTP method to include in the HA2 computed value.
- public string HttpMethod { get; }
-
- ///
- /// Gets the password to include in the HA1 computed value.
- ///
- /// The password to include in the HA1 computed value.
- public string Password { get; }
-
- ///
- /// Gets the algorithm to use when computing the HA1-, HA2-, and response hash values.
- ///
- /// The algorithm to use when computing the HA1-, HA2-, and response hash values.
- public CryptoAlgorithm Algorithm { get; }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/DigestAuthenticationUtility.cs b/src/Cuemon.AspNetCore.Authentication/DigestAuthenticationUtility.cs
deleted file mode 100644
index a80ddfc46..000000000
--- a/src/Cuemon.AspNetCore.Authentication/DigestAuthenticationUtility.cs
+++ /dev/null
@@ -1,205 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Text;
-using Cuemon.Security.Cryptography;
-using Cuemon.Text;
-
-namespace Cuemon.AspNetCore.Authentication
-{
- ///
- /// Provides an isolated set of members to work with HTTP Digest access authentication.
- ///
- public static class DigestAuthenticationUtility
- {
- internal static readonly byte[] DefaultPrivateKey = Convert.FromBase64String("ZHBGWDRrVGVxbFlhVEpWQ3hoYUc5VUlZM05penNOaUk=");
-
- ///
- /// The value of the header credential user name of a HTTP Digest access authentication.
- ///
- public const string CredentialUserName = "username";
-
- ///
- /// The value of the header credential realm of a HTTP Digest access authentication.
- ///
- public const string CredentialRealm = "realm";
-
- ///
- /// The value of the header credential response of a HTTP Digest access authentication.
- ///
- public const string CredentialResponse = "response";
-
- ///
- /// The value of the header credential quality of protection of a HTTP Digest access authentication.
- ///
- public const string CredentialQualityOfProtection = "qop";
-
- ///
- /// The value of the header credential quality of protection options of a HTTP Digest access authentication.
- ///
- public const string CredentialQualityOfProtectionOptions = "auth,auth-int";
-
- ///
- /// The value of the header credential client nonce of a HTTP Digest access authentication.
- ///
- public const string CredentialClientNonce = "cnonce";
-
- ///
- /// The value of the header credential nonce count of a HTTP Digest access authentication.
- ///
- public const string CredentialNonceCount = "nc";
-
- ///
- /// The value of the header credential nonce of a HTTP Digest access authentication.
- ///
- public const string CredentialNonce = "nonce";
-
- ///
- /// The value of the header credential digest URI of a HTTP Digest access authentication.
- ///
- public const string CredentialDigestUri = "uri";
-
- ///
- /// The value of the header credential opaque of a HTTP Digest access authentication.
- ///
- public const string CredentialOpaque = "opaque";
-
- ///
- /// The value of the header credential algorithm of a HTTP Digest access authentication.
- ///
- public const string CredentialAlgorithm = "algorithm";
-
- ///
- /// Computes a by parameter defined hash value of the required values for the HTTP Digest access authentication HA1.
- ///
- /// The credentials of the HA1 computed value (, ).
- /// The password to include in the HA1 computed value.
- /// The algorithm to use when computing the HA1 value.
- /// A in the format of H('[CredentialUserName]:[CredentialRealm]:').
- public static string ComputeHash1(IDictionary credentials, string password, CryptoAlgorithm algorithm)
- {
- ValidateCredentials(credentials, CredentialUserName, CredentialRealm);
- return HashFactory.CreateCrypto(algorithm).ComputeHash(string.Format(CultureInfo.InvariantCulture, "{0}:{1}:{2}", credentials[CredentialUserName], credentials[CredentialRealm], password), o =>
- {
- o.Encoding = Encoding.UTF8;
- }).ToHexadecimalString();
- }
-
- ///
- /// Computes a by parameter defined hash value of the required values for the HTTP Digest access authentication HA2.
- ///
- /// The credentials of the HA2 computed value ().
- /// The HTTP method to include in the HA2 computed value.
- /// The algorithm to use when computing the HA2 value.
- /// A in the format of H(':[CredentialDigestUri]').
- public static string ComputeHash2(IDictionary credentials, string httpMethod, CryptoAlgorithm algorithm)
- {
- ValidateCredentials(credentials, CredentialDigestUri);
- return HashFactory.CreateCrypto(algorithm).ComputeHash(string.Format(CultureInfo.InvariantCulture, "{0}:{1}", httpMethod, credentials[CredentialDigestUri]), o =>
- {
- o.Encoding = Encoding.UTF8;
- }).ToHexadecimalString();
- }
-
- ///
- /// Computes a by parameter defined hash value of the required values for the HTTP Digest access authentication RESPONSE.
- ///
- /// The credentials of the RESPONSE computed value (, , , ).
- /// The HA1 to include in the RESPONSE computed value.
- /// The HA2 to include in the RESPONSE computed value.
- /// The algorithm to use when computing the RESPONSE value.
- /// A in the format of H(':[CredentialNonce]:[CredentialNonceCount]:[CredentialClientNonce]:[CredentialQualityOfProtection]:').
- public static byte[] ComputeResponse(IDictionary credentials, string hash1, string hash2, CryptoAlgorithm algorithm)
- {
- ValidateCredentials(credentials, CredentialNonce, CredentialNonceCount, CredentialClientNonce, CredentialQualityOfProtection);
- return HashFactory.CreateCrypto(algorithm).ComputeHash(FormattableString.Invariant($"{hash1}:{credentials[CredentialNonce]}:{credentials[CredentialNonceCount]}:{credentials[CredentialClientNonce]}:{credentials[CredentialQualityOfProtection]}:{hash2}"), o =>
- {
- o.Encoding = Encoding.UTF8;
- }).GetBytes();
- }
-
- ///
- /// A default implementation of a nonce parser.
- ///
- /// The nonce protocol.
- /// The time-to-live (ttl) of the .
- /// true if the specified has expired compared to ; otherwise, false.
- public static bool DefaultNonceExpiredParser(string nonce, TimeSpan timeToLive)
- {
- Validator.ThrowIfNullOrEmpty(nonce, nameof(nonce));
- if (ParserFactory.FromBase64().TryParse(nonce, out var rawNonce))
- {
- var nonceProtocol = Convertible.ToString(rawNonce, options =>
- {
- options.Encoding = Encoding.UTF8;
- options.Preamble = PreambleSequence.Remove;
- });
- var nonceTimestamp = DateTime.ParseExact(nonceProtocol.Substring(0, nonceProtocol.LastIndexOf(':')), "u", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);
- var difference = (DateTime.UtcNow - nonceTimestamp);
- return (difference > timeToLive);
- }
- return false;
- }
-
- ///
- /// A default implementation of a nonce generator.
- ///
- /// The value to include in the generated nonce.
- /// An opaque identifier to include in the generated nonce.
- /// A cryptographic private key to include as a cipher in the generated nonce.
- /// A nonce protocol in the format of ':H()'.
- public static string DefaultNonceGenerator(DateTime timestamp, string entityTag, byte[] privateKey)
- {
- Validator.ThrowIfNullOrEmpty(entityTag, nameof(entityTag));
- Validator.ThrowIfNull(privateKey, nameof(privateKey));
- var nonceHash = ComputeNonceHash(timestamp, entityTag, privateKey);
- var nonceProtocol = string.Format(CultureInfo.InvariantCulture, "{0}:{1}", timestamp.ToString("u", CultureInfo.InvariantCulture), nonceHash);
- return Convert.ToBase64String(Convertible.GetBytes(nonceProtocol, options =>
- {
- options.Encoding = Encoding.UTF8;
- options.Preamble = PreambleSequence.Remove;
- }));
- }
-
- ///
- /// A default implementation of opaque generator.
- ///
- /// An opaque value consisting of hexadecimal characters with a length of 32 bytes.
- public static string DefaultOpaqueGenerator()
- {
- return Generate.RandomString(32, Alphanumeric.Hexadecimal).ToLowerInvariant();
- }
-
- ///
- /// Converts the specified to its HTTP Digest access authentication header credential algorithm equivalent.
- ///
- /// The algorithm to convert.
- /// A string containing either MD5, SHA-256 or SHA-512-256.
- public static string ParseAlgorithm(CryptoAlgorithm algorithm)
- {
- switch (algorithm)
- {
- case CryptoAlgorithm.Sha256:
- return "SHA-256";
- case CryptoAlgorithm.Sha512:
- return "SHA-512-256";
- default:
- return "MD5";
- }
- }
-
- private static void ValidateCredentials(IDictionary credentials, params string[] requiredCredentials)
- {
- Validator.ThrowIfNull(credentials, nameof(credentials));
- foreach (var requiredCredential in requiredCredentials)
- {
- if (!credentials.ContainsKey(requiredCredential)) { throw new ArgumentException("One or more required credentials are missing.", nameof(credentials)); }
- }
- }
-
- private static string ComputeNonceHash(DateTime timeStamp, string entityTag, byte[] privateKey)
- {
- return HashFactory.CreateCryptoSha256().ComputeHash(timeStamp, entityTag, Convert.ToBase64String(privateKey)).ToHexadecimalString();
- }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Extensions/HttpContextDecoratorExtensions.cs b/src/Cuemon.AspNetCore.Authentication/Extensions/HttpContextDecoratorExtensions.cs
new file mode 100644
index 000000000..d9d5275c3
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Extensions/HttpContextDecoratorExtensions.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+
+namespace Cuemon.AspNetCore.Authentication
+{
+ internal static class HttpContextDecoratorExtensions
+ {
+ internal static async Task InvokeAuthenticationAsync(this IDecorator decorator, TOptions options, Action transformer) where TOptions : AuthenticationOptions
+ {
+ var message = options.ResponseHandler?.Invoke();
+ if (message != null)
+ {
+ transformer?.Invoke(message, decorator.Inner.Response);
+ throw new UnauthorizedException((int)message.StatusCode, await message.Content.ReadAsStringAsync().ConfigureAwait(false));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/GlobalSuppressions.cs b/src/Cuemon.AspNetCore.Authentication/GlobalSuppressions.cs
new file mode 100644
index 000000000..f678d64ee
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/GlobalSuppressions.cs
@@ -0,0 +1,8 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design to support the Digest protocol.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Authentication.Digest.DigestAuthorizationHeader.#ctor(System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String,System.String)")]
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthenticationMiddleware.cs b/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthenticationMiddleware.cs
new file mode 100644
index 000000000..8f687d15d
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthenticationMiddleware.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Linq;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using Cuemon.IO;
+using Cuemon.Security.Cryptography;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+using Microsoft.Net.Http.Headers;
+
+namespace Cuemon.AspNetCore.Authentication.Hmac
+{
+ ///
+ /// Provides a HTTP HMAC Authentication middleware implementation for ASP.NET Core.
+ ///
+ public class HmacAuthenticationMiddleware : ConfigurableMiddleware
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The delegate of the request pipeline to invoke.
+ /// The which need to be configured.
+ public HmacAuthenticationMiddleware(RequestDelegate next, IOptions setup) : base(next, setup)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The delegate of the request pipeline to invoke.
+ /// The middleware which need to be configured.
+ public HmacAuthenticationMiddleware(RequestDelegate next, Action setup) : base(next, setup)
+ {
+ }
+
+ ///
+ /// Executes the .
+ ///
+ /// The context of the current request.
+ /// A task that represents the execution of this middleware.
+ public override async Task InvokeAsync(HttpContext context)
+ {
+ if (!Authenticator.TryAuthenticate(context, Options.RequireSecureConnection, AuthorizationHeaderParser, TryAuthenticate))
+ {
+ await Decorator.Enclose(context).InvokeAuthenticationAsync(Options, async (message, response) =>
+ {
+ context.Response.OnStarting(() =>
+ {
+ context.Response.Headers.Add(HeaderNames.WWWAuthenticate, Options.AuthenticationScheme);
+ return Task.CompletedTask;
+ });
+ response.StatusCode = (int)message.StatusCode;
+ await Decorator.Enclose(response.Body).WriteAsync(await message.Content.ReadAsByteArrayAsync().ConfigureAwait(false)).ConfigureAwait(false);
+ }).ConfigureAwait(false);
+ }
+ await Next.Invoke(context).ConfigureAwait(false);
+ }
+
+ private bool TryAuthenticate(HttpContext context, HmacAuthorizationHeader header, out ClaimsPrincipal result)
+ {
+ if (Options.Authenticator == null) { throw new InvalidOperationException(FormattableString.Invariant($"The {nameof(Options.Authenticator)} cannot be null.")); }
+
+ if (header == null)
+ {
+ result = null;
+ return false;
+ }
+
+ var requestBodyMd5 = context.Request.Headers[HeaderNames.ContentMD5].FirstOrDefault()?.ToLowerInvariant();
+ if (!string.IsNullOrWhiteSpace(requestBodyMd5) && !UnkeyedHashFactory.CreateCrypto(UnkeyedCryptoAlgorithm.Md5).ComputeHash(context.Request.Body).ToHexadecimalString().Equals(requestBodyMd5, StringComparison.Ordinal))
+ {
+ result = null;
+ return false;
+ }
+
+ var clientId = header.ClientId;
+ result = Options.Authenticator(clientId, out var clientSecret);
+ if (clientSecret == null)
+ {
+ result = null;
+ return false;
+ }
+ var signature = header.Signature;
+
+ var hb = new HmacAuthorizationHeaderBuilder(Options.AuthenticationScheme)
+ .AddCredentialScope(header.CredentialScope)
+ .AddClientId(clientId)
+ .AddClientSecret(clientSecret)
+ .AddSignedHeaders(header.SignedHeaders)
+ .AddFromRequest(context.Request);
+
+ var computedSignature = hb.ComputeSignature();
+ return computedSignature != null && signature.Equals(computedSignature, StringComparison.Ordinal) && Condition.IsNotNull(result);
+ }
+
+ private HmacAuthorizationHeader AuthorizationHeaderParser(HttpContext context, string authorizationHeader)
+ {
+ return HmacAuthorizationHeader.Create(Options.AuthenticationScheme, authorizationHeader);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthenticationOptions.cs b/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthenticationOptions.cs
new file mode 100644
index 000000000..2bb6ad860
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthenticationOptions.cs
@@ -0,0 +1,38 @@
+using Cuemon.Security.Cryptography;
+
+namespace Cuemon.AspNetCore.Authentication.Hmac
+{
+ ///
+ /// Configuration options for . This class cannot be inherited.
+ ///
+ ///
+ public sealed class HmacAuthenticationOptions : AuthenticationOptions
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public HmacAuthenticationOptions()
+ {
+ AuthenticationScheme = HmacAuthorizationHeader.Scheme;
+ Algorithm = KeyedCryptoAlgorithm.HmacSha1;
+ }
+
+ ///
+ /// Gets the name of the authentication scheme. Default is .
+ ///
+ /// The name of the authentication scheme.
+ public string AuthenticationScheme { get; set; }
+
+ ///
+ /// Gets or sets the algorithm of the HMAC Authentication. Default is .
+ ///
+ /// The algorithm of the HMAC Authentication.
+ public KeyedCryptoAlgorithm Algorithm { get; set; }
+
+ ///
+ /// Gets or sets the function delegate that will perform the authentication from the specified publicKey.
+ ///
+ /// The function delegate that will perform the authentication.
+ public HmacAuthenticator Authenticator { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthenticator.cs b/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthenticator.cs
new file mode 100644
index 000000000..24d49516a
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthenticator.cs
@@ -0,0 +1,12 @@
+using System.Security.Claims;
+
+namespace Cuemon.AspNetCore.Authentication.Hmac
+{
+ ///
+ /// Represents the method that defines an Authenticator typically assigned on .
+ ///
+ /// The public key to match and lookup the paired shared .
+ /// The shared secret-private key paired with .
+ /// A that is associated with the result of .
+ public delegate ClaimsPrincipal HmacAuthenticator(string clientId, out string clientSecret);
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthorizationHeader.cs b/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthorizationHeader.cs
new file mode 100644
index 000000000..92ef66728
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthorizationHeader.cs
@@ -0,0 +1,136 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Cuemon.AspNetCore.Authentication.Hmac
+{
+ ///
+ /// Provides a representation of a HTTP HMAC Authentication header.
+ /// Implements the
+ ///
+ ///
+ public class HmacAuthorizationHeader : AuthorizationHeader
+ {
+ ///
+ /// Creates an instance of from the specified parameters.
+ ///
+ /// The name of the authentication scheme.
+ /// The raw HTTP authorization header.
+ /// The which may be configured.
+ /// An instance of .
+ ///
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
+ ///
+ /// cannot be empty or consist only of white-space characters -or-
+ /// cannot be empty or consist only of white-space characters.
+ ///
+ public static HmacAuthorizationHeader Create(string authenticationScheme, string authorizationHeader, Action setup = null)
+ {
+ Validator.ThrowIfNullOrWhitespace(authenticationScheme, nameof(authenticationScheme));
+ Validator.ThrowIfNullOrWhitespace(authorizationHeader, nameof(authorizationHeader));
+ return new HmacAuthorizationHeader(authenticationScheme).Parse(authorizationHeader, setup) as HmacAuthorizationHeader;
+ }
+
+ ///
+ /// The default authentication scheme of the .
+ ///
+ public const string Scheme = "HMAC";
+
+ HmacAuthorizationHeader(string authenticationScheme) : base(authenticationScheme)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The client identifier that is the public key of the signing process.
+ /// The credential scope that defines the remote resource.
+ /// The headers that will be part of the signing process.
+ /// The signature that represents the integrity of this header.
+ /// The authentication scheme of this header. Default is (HMAC).
+ public HmacAuthorizationHeader(string clientId, string credentialScope, string signedHeaders, string signature, string authenticationScheme = Scheme) : base(authenticationScheme)
+ {
+ ClientId = clientId;
+ CredentialScope = credentialScope;
+ SignedHeaders = signedHeaders.Split(';');
+ Signature = signature;
+ }
+
+ ///
+ /// Gets the client identifier that is the public key of the signing process.
+ ///
+ /// The client identifier that is the public key of the signing process.
+ public string ClientId { get; }
+
+ ///
+ /// Gets the credential scope that defines the remote resource.
+ ///
+ /// The credential scope that defines the remote resource.
+ public string CredentialScope { get; }
+
+ ///
+ /// Gets the headers that will be part of the signing process.
+ ///
+ /// The headers that will be part of the signing process.
+ public string[] SignedHeaders { get; }
+
+ ///
+ /// Gets the signature that represents the integrity of this header.
+ ///
+ /// The signature that represents the integrity of this header.
+ public string Signature { get; }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// A that represents this instance.
+ public override string ToString()
+ {
+ return $"{AuthenticationScheme} Credential={ClientId}/{CredentialScope}, SignedHeaders={string.Join(";", SignedHeaders)}, Signature={Signature}";
+ }
+
+ ///
+ /// The core parser that resolves an from a set of .
+ ///
+ /// The credentials used in authentication.
+ /// An equivalent of .
+ protected override AuthorizationHeader ParseCore(IReadOnlyDictionary credentials)
+ {
+ string clientId = null, credentialScope = null, signedHeaders = null, signature = null;
+ foreach (var kvp in credentials)
+ {
+ var key = kvp.Key;
+ var value = kvp.Value;
+
+ if (key == "Credential")
+ {
+ var cs = value.Split(new [] { '/' }, 2);
+ clientId = cs[0];
+ credentialScope = cs[1];
+ }
+
+ if (key == "SignedHeaders")
+ {
+ signedHeaders = value;
+ }
+
+ if (key == "Signature")
+ {
+ signature = value;
+ }
+ }
+
+ if (!string.IsNullOrWhiteSpace(clientId) &&
+ credentialScope != null &&
+ signedHeaders != null && signedHeaders.Any() &&
+ !string.IsNullOrWhiteSpace(signature))
+ {
+ return new HmacAuthorizationHeader(clientId, credentialScope, signedHeaders, signature);
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthorizationHeaderBuilder.cs b/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthorizationHeaderBuilder.cs
new file mode 100644
index 000000000..2c37d60f1
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Hmac/HmacAuthorizationHeaderBuilder.cs
@@ -0,0 +1,180 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using Cuemon.AspNetCore.Authentication.Digest;
+using Cuemon.Collections.Generic;
+using Cuemon.Net;
+using Cuemon.Security.Cryptography;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Net.Http.Headers;
+
+namespace Cuemon.AspNetCore.Authentication.Hmac
+{
+ ///
+ /// Provides a way to fluently represent a HTTP HMAC Authentication header.
+ /// Inspired by AWS Signature Version 4 (https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html, https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html).
+ ///
+ public class HmacAuthorizationHeaderBuilder : AuthorizationHeaderBuilder
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name of the authentication scheme. Default is HMAC.
+ /// The algorithm to use when computing the final signature of the HMAC Authentication header.
+ /// The algorithm to use when computing in-between signatures as part of the final signing of the HMAC Authentication header.
+ public HmacAuthorizationHeaderBuilder(string authenticationScheme = HmacAuthorizationHeader.Scheme, KeyedCryptoAlgorithm hmacAlgorithm = KeyedCryptoAlgorithm.HmacSha256, UnkeyedCryptoAlgorithm algorithm = UnkeyedCryptoAlgorithm.Sha256) : base(authenticationScheme)
+ {
+ HmacAlgorithm = hmacAlgorithm;
+ Algorithm = algorithm;
+ MapRelation(nameof(AddCredentialScope), HmacFields.CredentialScope);
+ MapRelation(nameof(AddClientId), HmacFields.ClientId);
+ MapRelation(nameof(AddClientSecret), HmacFields.ClientSecret);
+ MapRelation(nameof(AddFromRequest), HmacFields.UriPath, HmacFields.UriQuery, HmacFields.HttpHeaders, HmacFields.Payload, HmacFields.ServerDateTime);
+ }
+
+ ///
+ /// Gets the non-keyed algorithm of the HTTP HMAC Authentication.
+ ///
+ /// The non-keyed algorithm of the HTTP HMAC Authentication.
+ public UnkeyedCryptoAlgorithm Algorithm { get; }
+
+ ///
+ /// Gets the keyed algorithm of the HTTP HMAC Authentication.
+ ///
+ /// The keyed algorithm of the HTTP HMAC Authentication.
+ public KeyedCryptoAlgorithm HmacAlgorithm { get; }
+
+
+ ///
+ /// Adds the credential scope that defines the remote resource.
+ ///
+ /// The credential scope that defines the remote resource.
+ /// An that can be used to further build the HTTP HMAC Authentication header.
+ public HmacAuthorizationHeaderBuilder AddCredentialScope(string credentialScope)
+ {
+ return AddOrUpdate(HmacFields.CredentialScope, credentialScope);
+ }
+
+ ///
+ /// Adds the client identifier that is the public key of the signing process.
+ ///
+ /// The client identifier that is the public key of the signing process.
+ /// An that can be used to further build the HTTP HMAC Authentication header.
+ public HmacAuthorizationHeaderBuilder AddClientId(string clientId)
+ {
+ return AddOrUpdate(HmacFields.ClientId, clientId);
+ }
+
+ ///
+ /// Adds the client secret that is the private key of the signing process.
+ ///
+ /// The client secret that is the private key of the signing process.
+ /// An that can be used to further build the HTTP HMAC Authentication header.
+ public HmacAuthorizationHeaderBuilder AddClientSecret(string clientSecret)
+ {
+ return AddOrUpdate(HmacFields.ClientSecret, clientSecret);
+ }
+
+ ///
+ /// Adds the necessary fields that is part of an HTTP request.
+ ///
+ /// An instance of the object.
+ /// An that can be used to further build the HTTP HMAC Authentication header.
+ public HmacAuthorizationHeaderBuilder AddFromRequest(HttpRequest request)
+ {
+ Validator.ThrowIfNull(request, nameof(request));
+ return AddOrUpdate(HmacFields.HttpMethod, request.Method)
+ .AddOrUpdate(HmacFields.UriPath, request.Path.ToUriComponent())
+ .AddOrUpdate(HmacFields.UriQuery, string.Concat(request.Query.OrderBy(pair => pair.Key).Select(pair => $"{Decorator.Enclose(pair.Value.ToString()).UrlEncode()}")))
+ .AddOrUpdate(HmacFields.HttpHeaders, request.Headers.Count == 0 ? null : string.Concat(request.Headers.OrderBy(pair => pair.Key).Select(pair => $"{pair.Key.ToLowerInvariant()}:{DelimitedString.Create(pair.Value, o => o.StringConverter = s => $"{s.Trim()}{Alphanumeric.Linefeed}")}")))
+ .AddOrUpdate(HmacFields.Payload, UnkeyedHashFactory.CreateCrypto(Algorithm).ComputeHash(request.Body).ToHexadecimalString())
+ .AddOrUpdate(HmacFields.ServerDateTime, DateTime.Parse(request.Headers[HeaderNames.Date].ToString(), CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind).ToString("O"));
+ }
+
+ ///
+ /// Adds the headers that will be part of the signing process.
+ ///
+ /// The headers that will be part of the signing process. Default is host and date
+ /// An that can be used to further build the HTTP HMAC Authentication header.
+ public HmacAuthorizationHeaderBuilder AddSignedHeaders(params string[] signedHeaders)
+ {
+ if (signedHeaders == null) { return this; }
+ return AddOrUpdate(HmacFields.SignedHeaders, DelimitedString.Create(signedHeaders, o =>
+ {
+ o.Delimiter = ";";
+ o.StringConverter = s => s.ToLowerInvariant();
+ }));
+ }
+
+ ///
+ /// Converts the request to a standardized (canonical) format and computes a message digest using .
+ ///
+ /// A representation, in hexadecimal, of the computed canonical request.
+ public virtual string ComputeCanonicalRequest()
+ {
+ ValidateData(HmacFields.UriPath, HmacFields.UriQuery, HmacFields.HttpHeaders, HmacFields.Payload);
+ EnsureSignedHeaders(out var signedHeaders);
+ var signedHeadersLookup = signedHeaders.Split(';').ToList();
+ var headersToSign = DelimitedString.Create(Data[HmacFields.HttpHeaders].Split(Alphanumeric.Linefeed.ToCharArray()).Where(header =>
+ {
+ var kvp = header.Split(':');
+ return signedHeadersLookup.Contains(kvp[0]);
+ }), o => o.Delimiter = Alphanumeric.Linefeed) + Alphanumeric.Linefeed;
+
+ var stringToSign = new StringBuilder(Data[HmacFields.HttpMethod])
+ .Append(Alphanumeric.Linefeed)
+ .Append(Data[HmacFields.UriPath])
+ .Append(Alphanumeric.Linefeed)
+ .Append(Data[HmacFields.UriQuery])
+ .Append(Alphanumeric.Linefeed)
+ .Append(headersToSign)
+ .Append(Alphanumeric.Linefeed)
+ .Append(signedHeaders)
+ .Append(Alphanumeric.Linefeed)
+ .Append(Data[HmacFields.Payload]).ToString();
+
+ return UnkeyedHashFactory.CreateCrypto(Algorithm).ComputeHash(stringToSign).ToHexadecimalString();
+ }
+
+ ///
+ /// Computes the signature of this instance using a series of hash-based message authentication codes (HMACs) using .
+ ///
+ /// A representation, in hexadecimal, of the computed signature of this instance.
+ public virtual string ComputeSignature()
+ {
+ ValidateData(HmacFields.ServerDateTime, HmacFields.ClientSecret);
+ var secret = Decorator.Enclose(Data[HmacFields.ClientSecret]).ToByteArray();
+ var stringToSign = string.Concat(Algorithm,
+ Alphanumeric.Linefeed,
+ Data[HmacFields.ServerDateTime],
+ Alphanumeric.Linefeed,
+ Decorator.Enclose(Data).GetValueOrDefault(HmacFields.CredentialScope),
+ Alphanumeric.Linefeed,
+ ComputeCanonicalRequest());
+ var date = DateTime.Parse(Data[HmacFields.ServerDateTime], CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind).Date.ToString("yyyyMMdd");
+ var dateSecret = KeyedHashFactory.CreateHmacCrypto(secret, HmacAlgorithm).ComputeHash(date).GetBytes();
+ return KeyedHashFactory.CreateHmacCrypto(dateSecret, HmacAlgorithm).ComputeHash(stringToSign).ToHexadecimalString();
+ }
+
+ ///
+ /// Builds an instance of that implements .
+ ///
+ /// An instance of .
+ public override HmacAuthorizationHeader Build()
+ {
+ ValidateData(HmacFields.ClientId, HmacFields.ServerDateTime, HmacFields.ClientSecret, HmacFields.UriPath, HmacFields.UriQuery, HmacFields.HttpHeaders, HmacFields.Payload);
+ EnsureSignedHeaders(out var signedHeaders);
+ return new HmacAuthorizationHeader(Data[HmacFields.ClientId], Decorator.Enclose(Data).GetValueOrDefault(HmacFields.CredentialScope), signedHeaders, ComputeSignature(), AuthenticationScheme);
+ }
+
+ private void EnsureSignedHeaders(out string signedHeaders)
+ {
+ if (!Data.TryGetValue(HmacFields.SignedHeaders, out signedHeaders))
+ {
+ signedHeaders = "host;date";
+ AddSignedHeaders(signedHeaders);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Hmac/HmacFields.cs b/src/Cuemon.AspNetCore.Authentication/Hmac/HmacFields.cs
new file mode 100644
index 000000000..ec3bd782d
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Hmac/HmacFields.cs
@@ -0,0 +1,58 @@
+namespace Cuemon.AspNetCore.Authentication.Hmac
+{
+ ///
+ /// A collection of constants for .
+ ///
+ public static class HmacFields
+ {
+ ///
+ /// The HTTP request method.
+ ///
+ public const string HttpMethod = "httpRequestMethod";
+
+ ///
+ /// The canonical URI that is the URI-encoded version of the absolute path component of an URI.
+ ///
+ public const string UriPath = "canonicalUri";
+
+ ///
+ /// The canonical query string.
+ ///
+ public const string UriQuery = "canonicalQueryString";
+
+ ///
+ /// The canonical headers.
+ ///
+ public const string HttpHeaders = "canonicalHeaders";
+
+ ///
+ /// The headers that must be part of the signing process.
+ ///
+ public const string SignedHeaders = "signedHeaders";
+
+ ///
+ /// The request payload.
+ ///
+ public const string Payload = "requestPayload";
+
+ ///
+ /// The server date time expressed in ISO 8601 format.
+ ///
+ public const string ServerDateTime = "serverDateTime";
+
+ ///
+ /// The public key of the signing process.
+ ///
+ public const string ClientId = "clientId";
+
+ ///
+ /// The private key of the signing process.
+ ///
+ public const string ClientSecret = "clientSecret";
+
+ ///
+ /// The credential scope that defines the remote resource.
+ ///
+ public const string CredentialScope = "credentialScope";
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/HmacAuthenticationMiddleware.cs b/src/Cuemon.AspNetCore.Authentication/HmacAuthenticationMiddleware.cs
deleted file mode 100644
index 47ef8603d..000000000
--- a/src/Cuemon.AspNetCore.Authentication/HmacAuthenticationMiddleware.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-using System;
-using System.Linq;
-using System.Security.Claims;
-using System.Threading.Tasks;
-using Cuemon.AspNetCore.Builder;
-using Cuemon.Security.Cryptography;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.Options;
-using Microsoft.Net.Http.Headers;
-
-namespace Cuemon.AspNetCore.Authentication
-{
- ///
- /// Provides a HTTP HMAC Authentication middleware implementation for ASP.NET Core.
- ///
- public class HmacAuthenticationMiddleware : ConfigurableMiddleware
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The delegate of the request pipeline to invoke.
- /// The which need to be configured.
- public HmacAuthenticationMiddleware(RequestDelegate next, IOptions setup) : base(next, setup)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The delegate of the request pipeline to invoke.
- /// The middleware which need to be configured.
- public HmacAuthenticationMiddleware(RequestDelegate next, Action setup) : base(next, setup)
- {
- }
-
- ///
- /// Executes the .
- ///
- /// The context of the current request.
- /// A task that represents the execution of this middleware.
- public override async Task InvokeAsync(HttpContext context)
- {
- if (!AuthenticationUtility.TryAuthenticate(context, Options.RequireSecureConnection, AuthorizationHeaderParser, TryAuthenticate))
- {
- context.Response.StatusCode = AuthenticationUtility.HttpNotAuthorizedStatusCode;
- context.Response.Headers.Add(HeaderNames.WWWAuthenticate, Options.AuthenticationScheme);
- await context.WriteHttpNotAuthorizedBody(Options.HttpNotAuthorizedBody).ConfigureAwait(false);
- return;
- }
- await Next.Invoke(context).ConfigureAwait(false);
- }
-
- private bool TryAuthenticate(HttpContext context, Template credentials, out ClaimsPrincipal result)
- {
- if (Options.Authenticator == null) { throw new InvalidOperationException(FormattableString.Invariant($"The {nameof(Options.Authenticator)} cannot be null.")); }
- var requestBodyMd5 = context.Request.Headers[HeaderNames.ContentMD5].FirstOrDefault()?.ToLowerInvariant();
- if (!string.IsNullOrWhiteSpace(requestBodyMd5) && !HashFactory.CreateCrypto(CryptoAlgorithm.Md5).ComputeHash(context.Request.Body).ToHexadecimalString().Equals(requestBodyMd5, StringComparison.Ordinal))
- {
- result = null;
- return false;
- }
- var publicKey = credentials.Arg1;
- var signature = credentials.Arg2;
- var stringToSign = Options.MessageDescriptor(context);
- var privateKey = new byte[0];
- result = Options?.Authenticator(publicKey, out privateKey);
- if (privateKey == null)
- {
- result = null;
- return false;
- }
- var computedSignature = Options?.HmacSigner(new HmacAuthenticationParameters(Options.Algorithm, privateKey, stringToSign));
- return computedSignature != null && signature.Equals(Convert.ToBase64String(computedSignature), StringComparison.Ordinal) && Condition.IsNotNull(result);
- }
-
- private Template AuthorizationHeaderParser(HttpContext context, string authorizationHeader)
- {
- if (AuthenticationUtility.IsAuthenticationSchemeValid(authorizationHeader, Options.AuthenticationScheme) && authorizationHeader.Length > Options.AuthenticationScheme.Length)
- {
- var credentials = authorizationHeader.Remove(0, Options.AuthenticationScheme.Length + 1).Split(':');
- if (credentials.Length == 2)
- {
- var publicKey = credentials[0];
- var signature = credentials[1];
- if (!string.IsNullOrWhiteSpace(publicKey) && !string.IsNullOrWhiteSpace(signature)) { return Template.CreateTwo(publicKey, signature); }
- }
- }
- return null;
- }
- }
-
- ///
- /// This is a factory implementation of the class.
- ///
- public static class HmacAuthenticationBuilderExtension
- {
- ///
- /// Adds a HTTP HMAC Authentication scheme to the request execution pipeline.
- ///
- /// The type that provides the mechanisms to configure an application’s request pipeline.
- /// The HTTP middleware which need to be configured.
- /// A reference to this instance after the operation has completed.
- public static IApplicationBuilder UseHmacAuthentication(this IApplicationBuilder builder, Action setup = null)
- {
- return ApplicationBuilderFactory.UseMiddlewareConfigurable(builder, setup);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/HmacAuthenticationOptions.cs b/src/Cuemon.AspNetCore.Authentication/HmacAuthenticationOptions.cs
deleted file mode 100644
index 9399a8564..000000000
--- a/src/Cuemon.AspNetCore.Authentication/HmacAuthenticationOptions.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System;
-using System.Linq;
-using System.Text;
-using Cuemon.Security.Cryptography;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Http.Extensions;
-using Microsoft.Net.Http.Headers;
-
-namespace Cuemon.AspNetCore.Authentication
-{
- ///
- /// Configuration options for . This class cannot be inherited.
- ///
- ///
- public sealed class HmacAuthenticationOptions : AuthenticationOptions
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public HmacAuthenticationOptions()
- {
- AuthenticationScheme = "HMAC";
- Algorithm = KeyedCryptoAlgorithm.HmacSha1;
- MessageDescriptor = context => FormattableString.Invariant($"{context.Request.Method}:{context.Request.GetDisplayUrl()}:{context.Request.Headers[HeaderNames.ContentMD5].FirstOrDefault()}:{context.Request.Headers[HeaderNames.ContentType].FirstOrDefault()}:{context.Request.Headers[HeaderNames.Date].FirstOrDefault()}:{context.Request.Headers[HeaderNames.UserAgent].FirstOrDefault()}");
- HmacSigner = parameters => HashFactory.CreateHmacCrypto(parameters.PrivateKey, parameters.Algorithm).ComputeHash(parameters.Message, o =>
- {
- o.Encoding = Encoding.UTF8;
- }).GetBytes();
- }
-
- ///
- /// Gets the name of the authentication scheme. Default is "HMAC".
- ///
- /// The name of the authentication scheme.
- public string AuthenticationScheme { get; set; }
-
- ///
- /// Gets or sets the algorithm of the HMAC Authentication. Default is .
- ///
- /// The algorithm of the HMAC Authentication.
- public KeyedCryptoAlgorithm Algorithm { get; set; }
-
- ///
- /// Gets or sets the function delegate that provides information about the message to be signed.
- ///
- /// The function delegate that provides information about the message to be signed.
- public Func MessageDescriptor { get; set; }
-
- ///
- /// Gets or sets the function delegate that will perform the authentication from the specified publicKey.
- ///
- /// The function delegate that will perform the authentication.
- public HmacAuthenticator Authenticator { get; set; }
-
- ///
- /// Gets or sets the function delegate that will sign a message retrieved by .
- ///
- /// The function delegate that will sign a message.
- public Func HmacSigner { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/HmacAuthenticationParameters.cs b/src/Cuemon.AspNetCore.Authentication/HmacAuthenticationParameters.cs
deleted file mode 100644
index 3bfb37914..000000000
--- a/src/Cuemon.AspNetCore.Authentication/HmacAuthenticationParameters.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using Cuemon.Security.Cryptography;
-
-namespace Cuemon.AspNetCore.Authentication
-{
- ///
- /// Represents a set of parameters that is needed for creating a keyed-hash message authentication code (HMAC).
- ///
- public class HmacAuthenticationParameters
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The hash algorithm to use for the computation.
- /// The secret key for the hashed encryption. The key can be any length, but it is strongly recommended to use a size of either 64 bytes (for and ) or 128 bytes (for and ).
- /// The value to compute a hash code for.
- internal HmacAuthenticationParameters(KeyedCryptoAlgorithm algorithm, byte[] privateKey, string message)
- {
- Algorithm = algorithm;
- Message = message;
- PrivateKey = privateKey;
- }
-
- ///
- /// Gets the algorithm of the HMAC. Default is .
- ///
- /// The algorithm of the HMAC.
- public KeyedCryptoAlgorithm Algorithm { get; }
-
- ///
- /// Gets the secret key for the hashed encryption.
- ///
- /// The secret key for the hashed encryption.
- public byte[] PrivateKey { get; }
-
- ///
- /// Gets the message to compute a hash code for.
- ///
- /// The message to compute a hash code for.
- public string Message { get; }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/HmacAuthenticator.cs b/src/Cuemon.AspNetCore.Authentication/HmacAuthenticator.cs
deleted file mode 100644
index c85196dec..000000000
--- a/src/Cuemon.AspNetCore.Authentication/HmacAuthenticator.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System.Security.Claims;
-
-namespace Cuemon.AspNetCore.Authentication
-{
- ///
- /// Represents the method that defines an Authenticator typically assigned on .
- ///
- /// The public key to match and lookup the paired shared secret-.
- /// The shared secret-private key paired with .
- /// A that is associated with the result of .
- public delegate ClaimsPrincipal HmacAuthenticator(string publicKey, out byte[] privateKey);
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/INonceTracker.cs b/src/Cuemon.AspNetCore.Authentication/INonceTracker.cs
new file mode 100644
index 000000000..d015b936c
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/INonceTracker.cs
@@ -0,0 +1,34 @@
+using System;
+
+namespace Cuemon.AspNetCore.Authentication
+{
+ ///
+ /// Represents tracking of server-generated nonce values.
+ ///
+ ///
+ public interface INonceTracker
+ {
+ ///
+ /// Attempts to get the associated with the specified from the tracker.
+ ///
+ /// The unique identifier of the tracker.
+ /// When this method returns, contains the entry associated with the specified , or null if the operation failed.
+ /// true if the was found in the tracker; otherwise, false.
+ bool TryGetEntry(string nonce, out NonceTrackerEntry entry);
+
+ ///
+ /// Attempts to insert a into the tracker.
+ ///
+ /// The unique identifier of the tracker.
+ /// The number or bit string that should be used only once.
+ /// true if insertion succeeded; otherwise, false when there is already an entry in the tracker with the same key.
+ bool TryAddEntry(string nonce, int count);
+
+ ///
+ /// Attempts to remove an entry from the tracker.
+ ///
+ /// The unique identifier of the tracker.
+ /// true if the entry is removed from the tracker; otherwise, false.
+ bool TryRemoveEntry(string nonce);
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/MemoryNonceTracker.cs b/src/Cuemon.AspNetCore.Authentication/MemoryNonceTracker.cs
new file mode 100644
index 000000000..be7e4fd31
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/MemoryNonceTracker.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Collections.Concurrent;
+using System.Linq;
+using System.Threading;
+using Cuemon.Threading;
+
+namespace Cuemon.AspNetCore.Authentication
+{
+ ///
+ /// Provides a default in-memory implementation of the interface.
+ ///
+ ///
+ ///
+ public class MemoryNonceTracker : Disposable, INonceTracker
+ {
+ private readonly ConcurrentDictionary _entries = new ConcurrentDictionary();
+ private readonly Timer _expirationTimer;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public MemoryNonceTracker()
+ {
+ _expirationTimer = TimerFactory.CreateNonCapturingTimer(state => ((MemoryNonceTracker)state).OnAutomatedSweepCleanup(), this, TimeSpan.FromMinutes(15), TimeSpan.FromHours(1));
+ }
+
+ ///
+ /// Attempts to get the associated with the specified from the tracker.
+ ///
+ /// The unique identifier of the tracker.
+ /// When this method returns, contains the entry associated with the specified , or null if the operation failed.
+ /// true if the was found in the tracker; otherwise, false.
+ ///
+ /// cannot be null.
+ ///
+ ///
+ /// cannot be empty or consist only of white-space characters.
+ ///
+ public bool TryGetEntry(string nonce, out NonceTrackerEntry entry)
+ {
+ Validator.ThrowIfNullOrWhitespace(nonce, nameof(nonce));
+ return _entries.TryGetValue(nonce, out entry);
+ }
+
+ ///
+ /// Attempts to insert a into the tracker.
+ ///
+ /// The unique identifier of the tracker.
+ /// The number or bit string that should be used only once.
+ /// true if insertion succeeded; otherwise, false when there is already an entry in the tracker with the same key.
+ ///
+ /// cannot be null.
+ ///
+ ///
+ /// cannot be empty or consist only of white-space characters.
+ ///
+ public bool TryAddEntry(string nonce, int count)
+ {
+ Validator.ThrowIfNullOrWhitespace(nonce, nameof(nonce));
+ return _entries.TryAdd(nonce, new NonceTrackerEntry(count, DateTime.UtcNow));
+ }
+
+ ///
+ /// Attempts to remove an entry from the tracker.
+ ///
+ /// The unique identifier of the tracker.
+ /// true if the entry is removed from the tracker; otherwise, false.
+ ///
+ /// cannot be null.
+ ///
+ ///
+ /// cannot be empty or consist only of white-space characters.
+ ///
+ public bool TryRemoveEntry(string nonce)
+ {
+ Validator.ThrowIfNullOrWhitespace(nonce, nameof(nonce));
+ return _entries.TryRemove(nonce, out _);
+ }
+
+ private void OnAutomatedSweepCleanup()
+ {
+ var utcStaleTime = DateTime.UtcNow.Subtract(TimeSpan.FromMinutes(5));
+ var entries = _entries.Where(pair => pair.Value.Created <= utcStaleTime).ToList();
+ if (entries.Count > 0)
+ {
+ foreach (var entry in entries)
+ {
+ _entries.TryRemove(entry.Key, out _);
+ }
+ }
+ }
+
+ ///
+ /// Called when this object is being disposed by either or having disposing set to true and is false.
+ ///
+ protected override void OnDisposeManagedResources()
+ {
+ _expirationTimer?.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/NonceTrackerEntry.cs b/src/Cuemon.AspNetCore.Authentication/NonceTrackerEntry.cs
new file mode 100644
index 000000000..0b23745bb
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/NonceTrackerEntry.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Cuemon.AspNetCore.Authentication
+{
+ ///
+ /// Represents an individual nonce entry in the .
+ ///
+ public class NonceTrackerEntry
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The number that should be used only once.
+ /// The timestamp from when this entry was created.
+ public NonceTrackerEntry(int count, DateTime created)
+ {
+ Count = count;
+ Created = created;
+ }
+
+ ///
+ /// Gets the number that should be used only once.
+ ///
+ /// The number that should be used only once.
+ public int Count { get; }
+
+ ///
+ /// Gets the timestamp from when this entry was created.
+ ///
+ /// The timestamp from when this entry was created.
+ public DateTime Created { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Properties/AssemblyInfo.cs b/src/Cuemon.AspNetCore.Authentication/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..20b98e714
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Properties/AssemblyInfo.cs
@@ -0,0 +1,4 @@
+using System.Runtime.InteropServices;
+
+[assembly: ComVisible(false)]
+[assembly: Guid("cbba5566-2383-459e-86d5-8a1fc232e8ed")]
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Authentication/Properties/PackageReleaseNotes.txt b/src/Cuemon.AspNetCore.Authentication/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..61c98ba14
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Authentication/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,37 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET Core 3.0, NET 5.0
+
+# Upgrade Steps
+- Any former extension methods of the Cuemon.AspNetCore.Authentication namespace was merged into the Cuemon.Extensions.AspNetCore.Authentication namespace
+
+# Breaking Changes
+- RENAMED AuthenticationUtility class in the Cuemon.AspNetCore.Authentication namespace to Authenticator and removed all constants
+- REMOVED DigestAccessAuthenticationParameters class from the Cuemon.AspNetCore.Authentication namespace
+- REMOVED DigestAuthenticationUtility class from the Cuemon.AspNetCore.Authentication namespace
+- REMOVED HmacAuthenticationParameters class from the Cuemon.AspNetCore.Authentication namespace
+- MOVED BasicAuthenticationMiddleware class from the Cuemon.AspNetCore.Authentication namespace to Cuemon.AspNetCore.Authentication.Basic namespace (including refactoring)
+- MOVED BasicAuthenticationOptions class from the Cuemon.AspNetCore.Authentication namespace to Cuemon.AspNetCore.Authentication.Basic namespace
+- MOVED BasicAuthenticator delegate from the Cuemon.AspNetCore.Authentication namespace to Cuemon.AspNetCore.Authentication.Basic namespace
+- MOVED DigestAccessAuthenticationMiddleware class from the Cuemon.AspNetCore.Authentication namespace to Cuemon.AspNetCore.Authentication.Digest namespace (including refactoring)
+- MOVED DigestAccessAuthenticationOptions class from the Cuemon.AspNetCore.Authentication namespace to Cuemon.AspNetCore.Authentication.Digest namespace (including refactoring)
+- MOVED DigestAccessAuthenticator delegate from the Cuemon.AspNetCore.Authentication namespace to Cuemon.AspNetCore.Authentication.Digest namespace
+- RENAMED DigestAccessAuthenticationMiddleware class in the Cuemon.AspNetCore.Authentication.Digest namespace to DigestAuthenticationMiddleware
+- RENAMED DigestAccessAuthenticationOptions class in the Cuemon.AspNetCore.Authentication.Digest namespace to DigestAuthenticationOptions
+- RENAMED DigestAccessAuthenticator class in the Cuemon.AspNetCore.Authentication.Digest namespace to DigestAuthenticator
+- MOVED HmacAuthenticationMiddleware class from the Cuemon.AspNetCore.Authentication namespace to Cuemon.AspNetCore.Authentication.Hmac namespace (including refactoring)
+- MOVED HmacAuthenticationOptions class from the Cuemon.AspNetCore.Authentication namespace to Cuemon.AspNetCore.Authentication.Hmac namespace (including refactoring)
+- MOVED HmacAuthenticator delegate from the Cuemon.AspNetCore.Authentication namespace to Cuemon.AspNetCore.Authentication.Hmac namespace
+
+# New Features
+- ADDED BasicAuthorizationHeader class in the Cuemon.AspNetCore.Authentication.Basic namespace that provides a representation of a HTTP Basic Authentication header
+- ADDED BasicAuthorizationHeaderBuilder class in the Cuemon.AspNetCore.Authentication.Basic namespace that provides a way to fluently represent a HTTP Basic Authentication header
+- ADDED BasicFields class in the Cuemon.AspNetCore.Authentication.Basic namespace that holds a collection of constants for BasicAuthorizationHeaderBuilder
+- ADDED DigestAuthorizationHeader class in the Cuemon.AspNetCore.Authentication.Basic namespace that provides a representation of a HTTP Digest Access Authentication header
+- ADDED DigestAuthorizationHeaderBuilder class in the Cuemon.AspNetCore.Authentication.Basic namespace that provides a way to fluently represent a HTTP Digest Access Authentication header
+- ADDED DigestFields class in the Cuemon.AspNetCore.Authentication.Basic namespace that holds a collection of constants for DigestAuthorizationHeaderBuilder
+- ADDED AuthorizationHeader class in the Cuemon.AspNetCore.Authentication namespace that represents the base class from which all implementations of authorization header should derive
+- ADDED AuthorizationHeaderBuilder class in the Cuemon.AspNetCore.Authentication namespace that represents the base class from which all implementations of authorization header builders should derive
+- ADDED AuthorizationHeaderOptions class in the Cuemon.AspNetCore.Authentication namespace that specifies options related to AuthorizationHeader
+- ADDED INonceTracker interface in the Cuemon.AspNetCore.Authentication namespace that represents tracking of server-generated nonce values
+- ADDED MemoryNonceTracker class in the Cuemon.AspNetCore.Authentication namespace that provides a default in-memory implementation of the INonceTracker interface
+
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json.csproj b/src/Cuemon.AspNetCore.Mvc.Formatters.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json.csproj
deleted file mode 100644
index 590579815..000000000
--- a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json.csproj
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
- netcoreapp3.0;netstandard2.0
- true
- ..\cuemon.snk
- true
- a60adf91-e7c7-4cb4-a39d-e1a5374c5602
-
-
-
- Cuemon .NET Standard
- Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json
- Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json
- The Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json assembly is a serialization supplement to Microsoft ASP.NET Core.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/DefaultJsonSerializerSettings.cs b/src/Cuemon.AspNetCore.Mvc.Formatters.Json/DefaultJsonSerializerSettings.cs
deleted file mode 100644
index 205de9af8..000000000
--- a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/DefaultJsonSerializerSettings.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using System;
-using Cuemon.Diagnostics;
-using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json.Converters;
-using Cuemon.Extensions.Newtonsoft.Json.Converters;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Serialization;
-
-namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json
-{
- ///
- /// Specifies the default settings on a object as interpreted by this framework.
- ///
- public class DefaultJsonSerializerSettings : JsonSerializerSettings
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public DefaultJsonSerializerSettings()
- {
- IncludeExceptionDescriptorFailure = true;
- IncludeExceptionDescriptorEvidence = true;
- IncludeExceptionStackTrace = false;
- Formatting = Formatting.Indented;
- NullValueHandling = NullValueHandling.Ignore;
- MissingMemberHandling = MissingMemberHandling.Ignore;
- ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
- DateParseHandling = DateParseHandling.DateTimeOffset;
- DateFormatHandling = DateFormatHandling.IsoDateFormat;
- DateTimeZoneHandling = DateTimeZoneHandling.Utc;
- ContractResolver = new CamelCasePropertyNamesContractResolver();
- Converters.AddStringValuesConverter()
- .AddHttpExceptionDescriptorConverter(o =>
- {
- o.IncludeEvidence = IncludeExceptionDescriptorEvidence;
- o.IncludeFailure = IncludeExceptionDescriptorFailure;
- })
- .AddExceptionConverter(() => IncludeExceptionStackTrace)
- .AddDataPairConverter()
- .AddStringEnumConverter()
- .AddStringFlagsEnumConverter()
- .AddTimeSpanConverter();
- }
-
- ///
- /// Gets or sets a value indicating whether the stack of an is included in the converter that handles exceptions.
- ///
- /// true if the stack of an is included in the converter that handles exceptions; otherwise, false.
- public bool IncludeExceptionStackTrace { get; set; }
-
- ///
- /// Gets or sets a value indicating whether the failure of an is included in the converter that handles exception descriptors.
- ///
- /// true if the failure of an is included in the converter that handles exception descriptors; otherwise, false.
- public bool IncludeExceptionDescriptorFailure { get; set; }
-
- ///
- /// Gets or sets a value indicating whether the evidence of an is included in the converter that handles exception descriptors.
- ///
- /// true if the evidence of an is included in the converter that handles exception descriptors; otherwise, false.
- public bool IncludeExceptionDescriptorEvidence { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.csproj b/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.csproj
deleted file mode 100644
index b00d076d2..000000000
--- a/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.csproj
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
- netcoreapp3.0;netstandard2.0
- true
- ..\cuemon.snk
- true
- a70adf91-e7c7-4cb4-a39d-e1a5374c5602
-
-
-
- Cuemon .NET Standard
- Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml
- Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml
- The Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml assembly is a serialization supplement to Microsoft ASP.NET Core.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/XmlMvcCoreBuilderExtensions.cs b/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/XmlMvcCoreBuilderExtensions.cs
deleted file mode 100644
index 6e6ff3299..000000000
--- a/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/XmlMvcCoreBuilderExtensions.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-using System;
-using Cuemon.Collections.Generic;
-using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Converters;
-using Cuemon.Xml.Serialization.Formatters;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-using Microsoft.Extensions.Options;
-
-namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml
-{
- ///
- /// Extension methods for adding XML formatters to MVC.
- ///
- public static class XmlMvcCoreBuilderExtensions
- {
- ///
- /// Adds the XML Serializer formatters to MVC.
- ///
- /// The .
- /// The .
- public static IMvcCoreBuilder AddXmlSerializationFormatters(this IMvcCoreBuilder builder)
- {
- Validator.ThrowIfNull(builder, nameof(builder));
- builder.Services.TryAddEnumerable(ServiceDescriptor.Transient, XmlSerializationMvcOptionsSetup>());
- return builder;
- }
-
- ///
- /// Adds the XML Serializer formatters to MVC.
- ///
- /// The .
- /// The .
- public static IMvcBuilder AddXmlSerializationFormatters(this IMvcBuilder builder)
- {
- Validator.ThrowIfNull(builder, nameof(builder));
- builder.Services.TryAddEnumerable(ServiceDescriptor.Transient, XmlSerializationMvcOptionsSetup>());
- return builder;
- }
-
- ///
- /// Adds configuration of for the application.
- ///
- /// The .
- /// The which need to be configured.
- /// The .
- public static IMvcCoreBuilder AddXmlFormatterOptions(this IMvcCoreBuilder builder, Action setup)
- {
- Validator.ThrowIfNull(builder, nameof(builder));
- Validator.ThrowIfNull(setup, nameof(setup));
- builder.Services.Configure(DefaultXmlFormatterOptions(setup));
- return builder;
- }
-
- ///
- /// Adds configuration of for the application.
- ///
- /// The .
- /// The which need to be configured.
- /// The .
- public static IMvcBuilder AddXmlFormatterOptions(this IMvcBuilder builder, Action setup)
- {
- Validator.ThrowIfNull(builder, nameof(builder));
- Validator.ThrowIfNull(setup, nameof(setup));
- builder.Services.Configure(DefaultXmlFormatterOptions(setup));
- return builder;
- }
-
- private static Action DefaultXmlFormatterOptions(Action setup)
- {
- var options = Patterns.Configure(setup);
- return o =>
- {
- o.IncludeExceptionStackTrace = options.IncludeExceptionStackTrace;
- o.SynchronizeWithXmlConvert = options.SynchronizeWithXmlConvert;
- o.Settings.Writer = options.Settings.Writer;
- o.Settings.RootName = options.Settings.RootName;
- o.Settings.Reader = options.Settings.Reader;
- Decorator.Enclose(o.Settings.Converters).AddRange(options.Settings.Converters);
- o.Settings.Converters.AddStringValuesConverter();
- o.Settings.Converters.AddHeaderDictionaryConverter();
- o.Settings.Converters.AddQueryCollectionConverter();
- o.Settings.Converters.AddFormCollectionConverter();
- o.Settings.Converters.AddCookieCollectionConverter();
- o.Settings.Converters.AddHttpExceptionDescriptorConverter();
- };
- }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc/CacheableObjectFactory.cs b/src/Cuemon.AspNetCore.Mvc/CacheableObjectFactory.cs
index f7ac1db7e..e60a5f1e1 100644
--- a/src/Cuemon.AspNetCore.Mvc/CacheableObjectFactory.cs
+++ b/src/Cuemon.AspNetCore.Mvc/CacheableObjectFactory.cs
@@ -86,7 +86,7 @@ public static ICacheableObjectResult CreateCacheableObjectResult(T instance,
/// An implementation.
///
///
- ///
+ ///
///
///
///
@@ -110,7 +110,7 @@ public static ICacheableObjectResult CreateCacheableObjectResult(object instance
/// An implementation.
///
///
- ///
+ ///
///
///
///
diff --git a/src/Cuemon.AspNetCore.Mvc/ContentBasedObjectResult.cs b/src/Cuemon.AspNetCore.Mvc/ContentBasedObjectResult.cs
index 40168ad01..39ae30f86 100644
--- a/src/Cuemon.AspNetCore.Mvc/ContentBasedObjectResult.cs
+++ b/src/Cuemon.AspNetCore.Mvc/ContentBasedObjectResult.cs
@@ -1,5 +1,5 @@
using Cuemon.Data.Integrity;
-using Cuemon.Security.Cryptography;
+using Cuemon.Security;
namespace Cuemon.AspNetCore.Mvc
{
@@ -9,13 +9,13 @@ internal ContentBasedObjectResult(object instance, byte[] checksum, bool isWeak
{
Checksum = new HashResult(checksum);
Validation = checksum == null || checksum.Length == 0
- ? EntityDataIntegrityStrength.Unspecified
+ ? EntityDataIntegrityValidation.Unspecified
: isWeak
- ? EntityDataIntegrityStrength.Weak
- : EntityDataIntegrityStrength.Strong;
+ ? EntityDataIntegrityValidation.Weak
+ : EntityDataIntegrityValidation.Strong;
}
- public EntityDataIntegrityStrength Validation { get; }
+ public EntityDataIntegrityValidation Validation { get; }
public HashResult Checksum { get; }
}
diff --git a/src/Cuemon.AspNetCore.Mvc/ContentTimeBasedObjectResult.cs b/src/Cuemon.AspNetCore.Mvc/ContentTimeBasedObjectResult.cs
index 6a0d56def..878ebecaa 100644
--- a/src/Cuemon.AspNetCore.Mvc/ContentTimeBasedObjectResult.cs
+++ b/src/Cuemon.AspNetCore.Mvc/ContentTimeBasedObjectResult.cs
@@ -1,10 +1,10 @@
using System;
using Cuemon.Data.Integrity;
-using Cuemon.Security.Cryptography;
+using Cuemon.Security;
namespace Cuemon.AspNetCore.Mvc
{
- internal class ContentTimeBasedObjectResult : CacheableObjectResult, IEntityData
+ internal class ContentTimeBasedObjectResult : CacheableObjectResult, IEntityInfo
{
internal ContentTimeBasedObjectResult(object instance, IEntityDataTimestamp timestamp, IEntityDataIntegrity dataIntegrity) : base(instance)
{
@@ -18,7 +18,7 @@ internal ContentTimeBasedObjectResult(object instance, IEntityDataTimestamp time
public DateTime? Modified { get; set; }
- public EntityDataIntegrityStrength Validation { get; set; }
+ public EntityDataIntegrityValidation Validation { get; set; }
public HashResult Checksum { get; set; }
}
diff --git a/src/Cuemon.AspNetCore.Mvc/Cuemon.AspNetCore.Mvc.csproj b/src/Cuemon.AspNetCore.Mvc/Cuemon.AspNetCore.Mvc.csproj
index 270f62836..12c9fe0ca 100644
--- a/src/Cuemon.AspNetCore.Mvc/Cuemon.AspNetCore.Mvc.csproj
+++ b/src/Cuemon.AspNetCore.Mvc/Cuemon.AspNetCore.Mvc.csproj
@@ -1,32 +1,15 @@
- netcoreapp3.0;netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netcoreapp3.0;netstandard2.0
a20adf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon
Cuemon.AspNetCore.Mvc
Cuemon.AspNetCore.Mvc
- The Cuemon.AspNetCore.Mvc assembly is a fit companion to the Microsoft.AspNetCore.Mvc namespace that provides an abundant range of filters and action results to your codebelt.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ 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.
+ cacheable-object-factory cacheable-object-result content-based-object-result content-time-based-object-result see-other-result http-cacheable-filter http-entity-tag-header-filter http-last-modified-header-filter fault-descriptor-filter fault-resolver http-request-evidence server-timing-filter user-agent-sentinel-filter throttling-sentinel-filter
@@ -35,7 +18,7 @@
-
+
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc/ExceptionDescriptorResult.cs b/src/Cuemon.AspNetCore.Mvc/ExceptionDescriptorResult.cs
index f0e5e218c..f65a70015 100644
--- a/src/Cuemon.AspNetCore.Mvc/ExceptionDescriptorResult.cs
+++ b/src/Cuemon.AspNetCore.Mvc/ExceptionDescriptorResult.cs
@@ -1,5 +1,5 @@
using System;
-using Cuemon.AspNetCore.Http;
+using Cuemon.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;
namespace Cuemon.AspNetCore.Mvc
diff --git a/src/Cuemon.AspNetCore.Mvc/Extensions/Filters/Diagnostics/FaultResolverDecoratorExtensions.cs b/src/Cuemon.AspNetCore.Mvc/Extensions/Filters/Diagnostics/FaultResolverDecoratorExtensions.cs
index d683840f1..5ebd07f20 100644
--- a/src/Cuemon.AspNetCore.Mvc/Extensions/Filters/Diagnostics/FaultResolverDecoratorExtensions.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Extensions/Filters/Diagnostics/FaultResolverDecoratorExtensions.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
+using Cuemon.AspNetCore.Diagnostics;
using Cuemon.AspNetCore.Http;
-using Cuemon.AspNetCore.Mvc.Filters.Diagnostics;
-namespace Cuemon.AspNetCore.Mvc.Extensions.Filters.Diagnostics
+namespace Cuemon.AspNetCore.Mvc.Filters.Diagnostics
{
///
/// Extension methods for the class tailored to adhere the decorator pattern.
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpCacheableFilter.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpCacheableFilter.cs
index 1bb4878c9..f3ecbacdf 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpCacheableFilter.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpCacheableFilter.cs
@@ -30,7 +30,7 @@ public override async Task OnResultExecutionAsync(ResultExecutingContext context
{
foreach (var filter in Options.Filters)
{
- await filter.OnResultExecutionAsync(context, next);
+ await filter.OnResultExecutionAsync(context, next).ConfigureAwait(false);
}
if (context.Result is ObjectResult result && result.Value is ICacheableObjectResult cacheableObjectResult)
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpEntityTagHeaderFilter.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpEntityTagHeaderFilter.cs
index ff8578238..466492263 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpEntityTagHeaderFilter.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpEntityTagHeaderFilter.cs
@@ -3,7 +3,6 @@
using System.Threading.Tasks;
using Cuemon.AspNetCore.Http;
using Cuemon.Configuration;
-using Cuemon.Data;
using Cuemon.Data.Integrity;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -20,8 +19,8 @@ public class HttpEntityTagHeaderFilter : IConfigurable
/// Initializes a new instance of the class.
///
- /// The which need to be configured.
- public HttpEntityTagHeaderFilter(Action setup)
+ /// The which may be configured.
+ public HttpEntityTagHeaderFilter(Action setup = null)
{
Options = Patterns.Configure(setup);
}
@@ -61,12 +60,12 @@ public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultE
originalValue = result.Value;
result.Value = cacheableObjectResult.Value;
}
- await InvokeEntityTagResponseParser(context, next, statusCodeBeforeBodyRead);
+ await InvokeEntityTagResponseParser(context, next, statusCodeBeforeBodyRead).ConfigureAwait(false);
result.Value = originalValue;
}
else
{
- await InvokeEntityTagResponseParser(context, next, statusCodeBeforeBodyRead);
+ await InvokeEntityTagResponseParser(context, next, statusCodeBeforeBodyRead).ConfigureAwait(false);
}
}
}
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpEntityTagHeaderOptions.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpEntityTagHeaderOptions.cs
index 31799ce30..71bd0edf4 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpEntityTagHeaderOptions.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpEntityTagHeaderOptions.cs
@@ -1,8 +1,9 @@
using System;
using System.IO;
using Cuemon.AspNetCore.Http;
-using Cuemon.Data;
using Cuemon.Data.Integrity;
+using Cuemon.IO;
+using Cuemon.Security;
using Cuemon.Security.Cryptography;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -31,8 +32,8 @@ public class HttpEntityTagHeaderOptions
///
/// (integrity, context) =>
/// {
- /// var builder = new ChecksumBuilder(integrity.Checksum.Value);
- /// context.Response.SetEntityTagHeaderInformation(context.Request, builder, integrity.ChecksumStrength == ChecksumStrength.Weak);
+ /// var builder = new ChecksumBuilder(integrity.Checksum.GetBytes(), () => HashFactory.CreateFnv128());
+ /// Decorator.Enclose(context.Response).TryAddOrUpdateEntityTagHeader(context.Request, builder, integrity.Validation == EntityDataIntegrityValidation.Weak);
/// };
///
///
@@ -41,12 +42,10 @@ public class HttpEntityTagHeaderOptions
///
/// (body, request, response) =>
/// {
- /// var builder = new ChecksumBuilder(body.ComputeHash(o =>
- /// {
- /// o.AlgorithmType = HashAlgorithmType.MD5;
- /// o.LeaveStreamOpen = true;
- /// }).Value);
- /// response.SetEntityTagHeaderInformation(request, builder);
+ /// var ms = new MemoryStream();
+ /// Decorator.Enclose(body).CopyStream(ms);
+ /// var builder = new ChecksumBuilder(ms.ToArray(), () => UnkeyedHashFactory.CreateCryptoMd5());
+ /// Decorator.Enclose(response).TryAddOrUpdateEntityTagHeader(request, builder);
/// };
///
///
@@ -60,13 +59,15 @@ public HttpEntityTagHeaderOptions()
{
EntityTagProvider = (integrity, context) =>
{
- var builder = new ChecksumBuilder(integrity.Checksum.GetBytes());
- Decorator.Enclose(context.Response).TryAddOrUpdateEntityTagHeader(context.Request, builder, integrity.Validation == EntityDataIntegrityStrength.Weak);
+ var builder = new ChecksumBuilder(integrity.Checksum.GetBytes(), () => HashFactory.CreateFnv128());
+ Decorator.Enclose(context.Response).AddOrUpdateEntityTagHeader(context.Request, builder, integrity.Validation == EntityDataIntegrityValidation.Weak);
};
EntityTagResponseParser = (body, request, response) =>
{
- var builder = new ChecksumBuilder(HashFactory.CreateCrypto(CryptoAlgorithm.Md5).ComputeHash(body).GetBytes());
- Decorator.Enclose(response).TryAddOrUpdateEntityTagHeader(request, builder);
+ var ms = new MemoryStream();
+ Decorator.Enclose(body).CopyStream(ms);
+ var builder = new ChecksumBuilder(ms.ToArray(), () => UnkeyedHashFactory.CreateCryptoMd5());
+ Decorator.Enclose(response).AddOrUpdateEntityTagHeader(request, builder);
};
UseEntityTagResponseParser = false;
}
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpLastModifiedHeaderFilter.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpLastModifiedHeaderFilter.cs
index c932c0b3b..11b7dc967 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpLastModifiedHeaderFilter.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpLastModifiedHeaderFilter.cs
@@ -2,7 +2,6 @@
using System.Threading.Tasks;
using Cuemon.AspNetCore.Http;
using Cuemon.Configuration;
-using Cuemon.Data;
using Cuemon.Data.Integrity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
@@ -18,8 +17,8 @@ public class HttpLastModifiedHeaderFilter : IConfigurable
/// Initializes a new instance of the class.
///
- /// The which need to be configured.
- public HttpLastModifiedHeaderFilter(Action setup)
+ /// The which may be configured.
+ public HttpLastModifiedHeaderFilter(Action setup = null)
{
Options = Patterns.Configure(setup);
}
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpLastModifiedHeaderOptions.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpLastModifiedHeaderOptions.cs
index 617a860b5..eb30642b1 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpLastModifiedHeaderOptions.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/HttpLastModifiedHeaderOptions.cs
@@ -1,6 +1,5 @@
using System;
using Cuemon.AspNetCore.Http;
-using Cuemon.Data;
using Cuemon.Data.Integrity;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -29,7 +28,7 @@ public class HttpLastModifiedHeaderOptions
///
/// (timestamp, context) =>
/// {
- /// context.Response.SetLastModifiedHeaderInformation(context.Request, timestamp.Modified ?? timestamp.Created);
+ /// Decorator.Enclose(context.Response).TryAddOrUpdateLastModifiedHeader(context.Request, timestamp.Modified ?? timestamp.Created);
/// };
///
///
@@ -39,7 +38,7 @@ public HttpLastModifiedHeaderOptions()
{
LastModifiedProvider = (timestamp, context) =>
{
- Decorator.Enclose(context.Response).TryAddOrUpdateLastModifiedHeader(context.Request, timestamp.Modified ?? timestamp.Created);
+ Decorator.Enclose(context.Response).AddOrUpdateLastModifiedHeader(context.Request, timestamp.Modified ?? timestamp.Created);
};
}
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/ICacheableAsyncResultFilter.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/ICacheableAsyncResultFilter.cs
index 7421e615f..797d5b534 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/ICacheableAsyncResultFilter.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Cacheable/ICacheableAsyncResultFilter.cs
@@ -1,19 +1,11 @@
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.Mvc.Filters;
namespace Cuemon.AspNetCore.Mvc.Filters.Cacheable
{
///
- /// A filter that asynchronously surrounds execution of action results successfully returned from an action.
+ /// A filter tailored to the cacheable flows, that asynchronously surrounds execution of action results successfully returned from an action.
///
- public interface ICacheableAsyncResultFilter
+ public interface ICacheableAsyncResultFilter : IAsyncResultFilter
{
- ///
- /// Called asynchronously before the action result.
- ///
- /// The .
- /// The . Invoked to execute the next result filter or the result itself.
- /// A that on completion indicates the filter has executed.
- Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next);
}
}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/FaultDescriptorFilter.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/FaultDescriptorFilter.cs
index dbe45c613..a8c965cec 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/FaultDescriptorFilter.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/FaultDescriptorFilter.cs
@@ -12,7 +12,6 @@ namespace Cuemon.AspNetCore.Mvc.Filters.Diagnostics
{
///
/// A filter that, after an action has faulted, provides developer friendly information about an along with a correct .
- /// Implements the
///
///
///
@@ -21,6 +20,11 @@ namespace Cuemon.AspNetCore.Mvc.Filters.Diagnostics
///
public class FaultDescriptorFilter : Configurable, IExceptionFilter
{
+ ///
+ /// The key to set or get a copy of a captured request body.
+ ///
+ public const string HttpContextItemsKeyForCapturedRequestBody = "CuemonAspNetCoreMvcFiltersDiagnostics_HttpContextItemsKeyForCapturedRequestBody";
+
///
/// Initializes a new instance of the class.
///
@@ -32,7 +36,7 @@ public FaultDescriptorFilter(IOptions setup) : base(setu
///
/// Called after an action has thrown an .
///
- /// The .
+ /// The .
public virtual void OnException(ExceptionContext context)
{
if (context.ActionDescriptor is ControllerActionDescriptor actionDescriptor)
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/FaultDescriptorOptions.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/FaultDescriptorOptions.cs
index da3243bd4..4011a56d8 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/FaultDescriptorOptions.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/FaultDescriptorOptions.cs
@@ -3,10 +3,9 @@
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Reflection;
-using Cuemon.AspNetCore.Http;
+using Cuemon.AspNetCore.Diagnostics;
using Cuemon.AspNetCore.Http.Headers;
using Cuemon.AspNetCore.Http.Throttling;
-using Cuemon.AspNetCore.Mvc.Extensions.Filters.Diagnostics;
using Microsoft.AspNetCore.Http;
namespace Cuemon.AspNetCore.Mvc.Filters.Diagnostics
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/FaultResolver.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/FaultResolver.cs
index 3279e6b0c..2809302ca 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/FaultResolver.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/FaultResolver.cs
@@ -1,5 +1,5 @@
using System;
-using Cuemon.AspNetCore.Http;
+using Cuemon.AspNetCore.Diagnostics;
namespace Cuemon.AspNetCore.Mvc.Filters.Diagnostics
{
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/HttpRequestEvidence.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/HttpRequestEvidence.cs
index 01ebcac1e..3418b1b63 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/HttpRequestEvidence.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/HttpRequestEvidence.cs
@@ -11,22 +11,23 @@ namespace Cuemon.AspNetCore.Mvc.Filters.Diagnostics
///
public class HttpRequestEvidence
{
- // TODO: REMEMBER TO TEST THIS THOROUGHLY ON ASPNET CORE 3
- internal HttpRequestEvidence(HttpRequest request, Func bodyParser = null)
+ internal HttpRequestEvidence(HttpRequest request, Func bodyConverter = null)
{
var hasMultipartContentType = request.GetMultipartBoundary().Length > 0;
- if (bodyParser == null) { bodyParser = body => hasMultipartContentType ? null : Decorator.Enclose(body).ToEncodedString(); }
+ if (bodyConverter == null) { bodyConverter = body => hasMultipartContentType ? null : Decorator.Enclose(body).ToEncodedString(); }
Location = request.GetDisplayUrl();
Method = request.Method;
Headers = request.Headers;
Query = request.Query;
if (request.HasFormContentType && !hasMultipartContentType) { Form = request.Form; }
Cookies = request.Cookies;
- #if NETCOREAPP
- Body = bodyParser(request.BodyReader.AsStream(true));
- #else
- Body = bodyParser(request.Body);
- #endif
+ var requestBody = new MemoryStream();
+ if (request.HttpContext.Items.TryGetValue(FaultDescriptorFilter.HttpContextItemsKeyForCapturedRequestBody, out var capturedRequestBody) && capturedRequestBody is MemoryStream crb)
+ {
+ crb.Position = 0;
+ requestBody = crb;
+ }
+ Body = bodyConverter(requestBody);
}
///
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/TimeMeasureAttribute.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/ServerTimingAttribute.cs
similarity index 62%
rename from src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/TimeMeasureAttribute.cs
rename to src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/ServerTimingAttribute.cs
index 7dd9af602..463acad24 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/TimeMeasureAttribute.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/ServerTimingAttribute.cs
@@ -10,37 +10,38 @@ namespace Cuemon.AspNetCore.Mvc.Filters.Diagnostics
/// Represents an attribute that is used to mark an action method for time measure profiling.
///
///
- public class TimeMeasureAttribute : ActionFilterAttribute, IFilterFactory
+ public class ServerTimingAttribute : ActionFilterAttribute, IFilterFactory
{
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
- public TimeMeasureAttribute() : this(0, TimeUnit.Ticks)
+ public ServerTimingAttribute()
{
}
///
- /// Initializes a new instance of the class.
+ /// Gets or sets the server-specified metric name.
///
- /// The value that in combination with specifies the threshold of the action method.
- /// One of the enumeration values that specifies the time unit of .
- public TimeMeasureAttribute(double threshold, TimeUnit thresholdTimeUnit)
- {
- Threshold = threshold;
- ThresholdTimeUnit = thresholdTimeUnit;
- }
+ /// The server-specified metric name.
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the server-specified metric description.
+ ///
+ /// The server-specified metric description.
+ public string Description { get; set; }
///
/// Gets or sets the value that in combination with specifies the threshold of the action method.
///
/// The threshold value of the action method.
- public double Threshold { get; set; }
+ public double Threshold { get; set; } = 0;
///
/// Gets or sets one of the enumeration values that specifies the time unit of .
///
/// The that defines the actual .
- public TimeUnit ThresholdTimeUnit { get; set; }
+ public TimeUnit ThresholdTimeUnit { get; set; } = TimeUnit.Ticks;
///
/// Creates an instance of the executable filter.
@@ -54,10 +55,21 @@ public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
#elif NETCOREAPP
var he = serviceProvider.GetRequiredService();
#endif
- return new TimeMeasuringFilter(Options.Create(new TimeMeasuringOptions()
+ var filter = new ServerTimingFilter(Options.Create(new ServerTimingOptions()
{
TimeMeasureCompletedThreshold = Decorator.Enclose(Threshold).ToTimeSpan(ThresholdTimeUnit)
- }), he);
+ }), he)
+ {
+ Name = Name,
+ Description = Description
+ };
+ var stOptions = serviceProvider.GetService>();
+ if (stOptions?.Value?.SuppressHeaderPredicate != null)
+ {
+ filter.Options.SuppressHeaderPredicate = stOptions.Value.SuppressHeaderPredicate;
+ }
+
+ return filter;
}
///
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/TimeMeasuringFilter.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/ServerTimingFilter.cs
similarity index 75%
rename from src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/TimeMeasuringFilter.cs
rename to src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/ServerTimingFilter.cs
index c6386d512..70ace5571 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/TimeMeasuringFilter.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/ServerTimingFilter.cs
@@ -1,12 +1,13 @@
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.Linq;
-using Cuemon.AspNetCore.Http.Headers;
+using Cuemon.AspNetCore.Diagnostics;
using Cuemon.Diagnostics;
using Cuemon.Reflection;
+using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
@@ -17,26 +18,26 @@ namespace Cuemon.AspNetCore.Mvc.Filters.Diagnostics
///
///
///
- public class TimeMeasuringFilter : ConfigurableActionFilter
+ public class ServerTimingFilter : ConfigurableActionFilter
{
#if NETSTANDARD
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The which need to be configured.
/// The dependency injected .
- public TimeMeasuringFilter(IOptions setup, IHostingEnvironment he) : base(setup)
+ public ServerTimingFilter(IOptions setup, IHostingEnvironment he) : base(setup)
{
Profiler = new TimeMeasureProfiler();
Environment = he;
}
#elif NETCOREAPP
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The which need to be configured.
/// The dependency injected .
- public TimeMeasuringFilter(IOptions setup, IHostEnvironment he) : base(setup)
+ public ServerTimingFilter(IOptions setup, IHostEnvironment he) : base(setup)
{
Profiler = new TimeMeasureProfiler();
Environment = he;
@@ -51,6 +52,10 @@ public TimeMeasuringFilter(IOptions setup, IHostEnvironmen
private TimeMeasureProfiler Profiler { get; }
+ internal string Name { get; set; }
+
+ internal string Description { get; set; }
+
///
/// Called before the action executes, after model binding is complete.
///
@@ -76,13 +81,14 @@ public override void OnActionExecuting(ActionExecutingContext context)
public override void OnActionExecuted(ActionExecutedContext context)
{
Profiler.Timer.Stop();
+ var serverTiming = context.HttpContext.RequestServices.GetRequiredService();
+ serverTiming.AddServerTiming(Name ?? "mvc", Profiler.Elapsed, Description ?? $"[{Decorator.Enclose(Profiler.Member.MethodName).ToAsciiEncodedString()}@{Decorator.Enclose(Profiler.Member.Caller.Name).ToAsciiEncodedString()}]({context.HttpContext.Request.GetEncodedUrl().ToLowerInvariant()})");
if (Options.TimeMeasureCompletedThreshold == TimeSpan.Zero || Profiler.Elapsed > Options.TimeMeasureCompletedThreshold)
{
TimeMeasure.CompletedCallback?.Invoke(Profiler);
if (!Options.SuppressHeaderPredicate(Environment))
{
- if (Options.UseServerTimingHeader) { Decorator.Enclose(context.HttpContext.Response.Headers).TryAddOrUpdateHeader("Server-Timing", FormattableString.Invariant($"CPU;dur={Profiler.Elapsed.TotalMilliseconds.ToString("N1", CultureInfo.InvariantCulture)}")); }
- if (Options.UseCustomHeader) { Decorator.Enclose(context.HttpContext.Response.Headers).TryAddOrUpdateHeader(Options.HeaderName, Profiler.ToString()); }
+ context.HttpContext.Response.Headers.Add(ServerTiming.HeaderName, serverTiming.Metrics.Select(metric => metric.ToString()).ToArray());
}
}
}
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/ServerTimingOptions.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/ServerTimingOptions.cs
new file mode 100644
index 000000000..e6a2afc95
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/ServerTimingOptions.cs
@@ -0,0 +1,48 @@
+using System;
+using Cuemon.Diagnostics;
+using Microsoft.Extensions.Hosting;
+
+namespace Cuemon.AspNetCore.Mvc.Filters.Diagnostics
+{
+ ///
+ /// Configuration options for .
+ ///
+ ///
+ public class ServerTimingOptions : TimeMeasureOptions
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ ///
+ /// The following table shows the initial property values for an instance of .
+ ///
+ ///
+ /// Property
+ /// Initial Value
+ ///
+ /// -
+ ///
+ ///
+ ///
+ /// -
+ ///
+ /// he => he.IsProduction()
+ ///
+ ///
+ ///
+ public ServerTimingOptions()
+ {
+ SuppressHeaderPredicate = he => he.IsProduction();
+ }
+
+ ///
+ /// Gets or sets the predicate that can suppress the Server-Timing HTTP header(s).
+ ///
+ /// The function delegate that can determine if the Server-Timing HTTP header(s) should be suppressed.
+ #if NETSTANDARD
+ public Func SuppressHeaderPredicate { get; set; }
+ #elif NETCOREAPP
+ public Func SuppressHeaderPredicate { get; set; }
+ #endif
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/TimeMeasuringOptions.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/TimeMeasuringOptions.cs
deleted file mode 100644
index 20cbb0c5e..000000000
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Diagnostics/TimeMeasuringOptions.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using System;
-using Cuemon.Diagnostics;
-using Microsoft.Extensions.Hosting;
-
-namespace Cuemon.AspNetCore.Mvc.Filters.Diagnostics
-{
- ///
- /// Configuration options for .
- ///
- ///
- public class TimeMeasuringOptions : TimeMeasureOptions
- {
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The following table shows the initial property values for an instance of .
- ///
- ///
- /// Property
- /// Initial Value
- ///
- /// -
- ///
- ///
- ///
- /// -
- ///
- /// X-Action-Profiler
- ///
- /// -
- ///
- /// _ => false
- ///
- /// -
- ///
- /// true
- ///
- ///
- ///
- public TimeMeasuringOptions()
- {
- HeaderName = "X-Action-Profiler";
- SuppressHeaderPredicate = _ => false;
- UseServerTimingHeader = true;
- UseCustomHeader = true;
- }
-
- ///
- /// Gets or sets the name of the custom time-measured HTTP header.
- ///
- /// The name of the custom time-measured HTTP header.
- public string HeaderName { get; set; }
-
- ///
- /// Gets or sets the predicate that can suppress either of the time-measured HTTP headers.
- ///
- /// The function delegate that can determine if either of the time-measured HTTP headers should be suppressed.
- #if NETSTANDARD
- public Func SuppressHeaderPredicate { get; set; }
- #elif NETCOREAPP
- public Func SuppressHeaderPredicate { get; set; }
- #endif
-
- ///
- /// Gets or sets a value indicating whether to include a Server-Timing HTTP header specifying how long an action took to execute.
- ///
- /// true to include a Server-Timing HTTP header specifying how long an action took to execute; otherwise, false.
- public bool UseServerTimingHeader { get; set; }
-
- ///
- /// Gets or sets a value indicating whether to include the custom specifying how long an action took to execute.
- ///
- /// true to include the custom specifying how long an action took to execute; otherwise, false.
- public bool UseCustomHeader { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Headers/UserAgentSentinelFilter.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Headers/UserAgentSentinelFilter.cs
index 61744fa8b..601fd7a4f 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Headers/UserAgentSentinelFilter.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Headers/UserAgentSentinelFilter.cs
@@ -1,6 +1,6 @@
using System.Threading.Tasks;
+using Cuemon.AspNetCore.Http;
using Cuemon.AspNetCore.Http.Headers;
-using Cuemon.AspNetCore.Infrastructure;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
@@ -29,10 +29,10 @@ public UserAgentSentinelFilter(IOptions setup) : base(
/// A that on completion indicates the filter has executed.
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
- await AspNetCoreInfrastructure.InvokeUserAgentSentinelAsync(context.HttpContext, Options, (message, response) =>
+ await Decorator.Enclose(context.HttpContext).InvokeUserAgentSentinelAsync(Options, (message, response) =>
{
response.StatusCode = (int) message.StatusCode;
- Decorator.Enclose(response.Headers).TryAddOrUpdateHeaders(message.Headers);
+ Decorator.Enclose(response.Headers).AddOrUpdateHeaders(message.Headers);
}).ConfigureAwait(false);
await next().ConfigureAwait(false);
}
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Throttling/ThrottlingSentinelAttribute.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Throttling/ThrottlingSentinelAttribute.cs
index d3c03c833..6b7c9767b 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Throttling/ThrottlingSentinelAttribute.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Throttling/ThrottlingSentinelAttribute.cs
@@ -1,6 +1,7 @@
using System;
-using System.Text;
+using Cuemon.AspNetCore.Http.Headers;
using Cuemon.AspNetCore.Http.Throttling;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
@@ -11,7 +12,7 @@ namespace Cuemon.AspNetCore.Mvc.Filters.Throttling
/// Represents an attribute that is used to mark an action method to be protected by a throttling sentinel.
///
///
- public class ThrottlingSentinelAttribute : ActionFilterAttribute, IFilterFactory
+ public abstract class ThrottlingSentinelAttribute : ActionFilterAttribute, IFilterFactory
{
///
/// Initializes a new instance of the class.
@@ -19,18 +20,19 @@ public class ThrottlingSentinelAttribute : ActionFilterAttribute, IFilterFactory
/// The allowed rate from within a given .
/// The duration of the window.
/// One of the enumeration values that specifies the time unit of .
- public ThrottlingSentinelAttribute(int rateLimit, double window, TimeUnit windowUnit)
+ protected ThrottlingSentinelAttribute(int rateLimit, double window, TimeUnit windowUnit)
{
var options= new ThrottlingSentinelOptions();
RateLimit = rateLimit;
Window = window;
WindowUnit = windowUnit;
UseRetryAfterHeader = options.UseRetryAfterHeader;
- RetryAfterHeader = options.RetryAfterHeader;
+ RetryAfterScope = options.RetryAfterScope;
TooManyRequestsMessage = options.TooManyRequestsMessage;
RateLimitHeaderName = options.RateLimitHeaderName;
RateLimitRemainingHeaderName = options.RateLimitRemainingHeaderName;
RateLimitResetHeaderName = options.RateLimitResetHeaderName;
+ RateLimitResetScope = options.RateLimitResetScope;
}
private int RateLimit { get; }
@@ -55,7 +57,7 @@ public ThrottlingSentinelAttribute(int rateLimit, double window, TimeUnit window
/// Gets or sets the preferred Retry-After HTTP header value that conforms with RFC 2616.
///
/// The preferred Retry-After HTTP header value that conforms with RFC 2616.
- public ThrottlingRetryAfterHeader RetryAfterHeader { get; set; }
+ public RetryConditionScope RetryAfterScope { get; set; }
///
/// Gets or sets the name of the rate limit remaining HTTP header.
@@ -75,6 +77,12 @@ public ThrottlingSentinelAttribute(int rateLimit, double window, TimeUnit window
/// The name of the rate limit reset HTTP header.
public string RateLimitResetHeaderName { get; set; }
+ ///
+ /// Gets or sets the preferred rate limit reset HTTP header value that conforms with RFC 7231.
+ ///
+ /// The preferred rate limit reset HTTP header value that conforms with RFC 7231.
+ public RetryConditionScope RateLimitResetScope { get; set; }
+
///
/// Creates an instance of the executable filter.
///
@@ -86,16 +94,24 @@ public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
return new ThrottlingSentinelFilter(Options.Create(new ThrottlingSentinelOptions()
{
Quota = new ThrottleQuota(RateLimit, Window, WindowUnit),
- ContextResolver = context => new StringBuilder().Append(context.Request.Scheme).Append("://").Append(context.Request.Host).Append(context.Request.PathBase).Append(context.Request.Path).ToString().ToLowerInvariant(),
+ ContextResolver = UniqueContextResolver,
UseRetryAfterHeader = UseRetryAfterHeader,
- RetryAfterHeader = RetryAfterHeader,
+ RetryAfterScope = RetryAfterScope,
TooManyRequestsMessage = TooManyRequestsMessage,
RateLimitHeaderName = RateLimitHeaderName,
RateLimitRemainingHeaderName = RateLimitRemainingHeaderName,
- RateLimitResetHeaderName = RateLimitResetHeaderName
+ RateLimitResetHeaderName = RateLimitResetHeaderName,
+ RateLimitResetScope = RateLimitResetScope
}), tc);
}
+ ///
+ /// Resolves a unique context of the throttling middleware (eg. IP-address, Authorization header, etc.).
+ ///
+ /// The to extract a unique context from.
+ /// A string that uniquely identifies the requester in need of throttling.
+ public abstract string UniqueContextResolver(HttpContext context);
+
///
/// Gets a value that indicates if the result of can be reused across requests.
///
diff --git a/src/Cuemon.AspNetCore.Mvc/Filters/Throttling/ThrottlingSentinelFilter.cs b/src/Cuemon.AspNetCore.Mvc/Filters/Throttling/ThrottlingSentinelFilter.cs
index 64ca787be..561fd254d 100644
--- a/src/Cuemon.AspNetCore.Mvc/Filters/Throttling/ThrottlingSentinelFilter.cs
+++ b/src/Cuemon.AspNetCore.Mvc/Filters/Throttling/ThrottlingSentinelFilter.cs
@@ -1,7 +1,7 @@
using System.Threading.Tasks;
+using Cuemon.AspNetCore.Http;
using Cuemon.AspNetCore.Http.Headers;
using Cuemon.AspNetCore.Http.Throttling;
-using Cuemon.AspNetCore.Infrastructure;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Options;
@@ -34,10 +34,10 @@ public ThrottlingSentinelFilter(IOptions setup, IThro
/// A that on completion indicates the filter has executed.
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
- await AspNetCoreInfrastructure.InvokeThrottlerSentinelAsync(context.HttpContext, ThrottlingCache, Options, (message, response) =>
+ await Decorator.Enclose(context.HttpContext).InvokeThrottlerSentinelAsync(ThrottlingCache, Options, (message, response) =>
{
response.StatusCode = (int) message.StatusCode;
- Decorator.Enclose(response.Headers).TryAddOrUpdateHeaders(message.Headers);
+ Decorator.Enclose(response.Headers).AddOrUpdateHeaders(message.Headers);
}).ConfigureAwait(false);
await next().ConfigureAwait(false);
}
diff --git a/src/Cuemon.AspNetCore.Mvc/GlobalSuppressions.cs b/src/Cuemon.AspNetCore.Mvc/GlobalSuppressions.cs
new file mode 100644
index 000000000..9b5d87846
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Mvc/GlobalSuppressions.cs
@@ -0,0 +1,11 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Major Code Smell", "S3358:Ternary operators should not be nested", Justification = "Clear enough.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Mvc.ContentBasedObjectResult.#ctor(System.Object,System.Byte[],System.Boolean)")]
+[assembly: SuppressMessage("Major Code Smell", "S1066:Collapsible \"if\" statements should be merged", Justification = "By design; easier for debug purposes and with clear scope.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpLastModifiedHeaderFilter.OnResultExecutionAsync(Microsoft.AspNetCore.Mvc.Filters.ResultExecutingContext,Microsoft.AspNetCore.Mvc.Filters.ResultExecutionDelegate)~System.Threading.Tasks.Task")]
+[assembly: SuppressMessage("Major Code Smell", "S1066:Collapsible \"if\" statements should be merged", Justification = "By design; easier for debug purposes and with clear scope.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Mvc.Filters.Cacheable.HttpEntityTagHeaderFilter.OnResultExecutionAsync(Microsoft.AspNetCore.Mvc.Filters.ResultExecutingContext,Microsoft.AspNetCore.Mvc.Filters.ResultExecutionDelegate)~System.Threading.Tasks.Task")]
+[assembly: SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "If i invert the if-statement, the warning goes away - but the code becomes harder to read. So for now, i exclude it as 'by design'.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Mvc.Filters.Diagnostics.FaultDescriptorFilter.OnException(Microsoft.AspNetCore.Mvc.Filters.ExceptionContext)")]
diff --git a/src/Cuemon.AspNetCore.Mvc/ICacheableObjectResult.cs b/src/Cuemon.AspNetCore.Mvc/ICacheableObjectResult.cs
index 68b12a07b..ae9ed9c80 100644
--- a/src/Cuemon.AspNetCore.Mvc/ICacheableObjectResult.cs
+++ b/src/Cuemon.AspNetCore.Mvc/ICacheableObjectResult.cs
@@ -7,7 +7,7 @@ namespace Cuemon.AspNetCore.Mvc
///
/// .
/// .
- /// .
+ /// .
public interface ICacheableObjectResult
{
///
diff --git a/src/Cuemon.AspNetCore.Mvc/Properties/PackageReleaseNotes.txt b/src/Cuemon.AspNetCore.Mvc/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..b9612900c
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Mvc/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,24 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET Core 3.0, NET 5.0
+
+# Upgrade Steps
+- Any former extension methods of the Cuemon.AspNetCore.Mvc namespace was merged either into the Cuemon.Extensions.AspNetCore.Mvc namespace or Cuemon.Extensions.AspNetCore namespace
+
+# Breaking Changes
+- MOVED ICacheBusting interface (and related) from the Cuemon.AspNetCore.Mvc.Configuration namespace to Cuemon.AspNetCore.Configuration namespace
+- MOVED AssemblyCacheBusting class (and related) from the Cuemon.AspNetCore.Mvc.Configuration namespace to Cuemon.Extensions.AspNetCore.Configuration namespace
+- MOVED ICacheableObjectResult interface (and related) from the Cuemon.AspNetCore.Mvc.Filters.Cacheable namespace to Cuemon.AspNetCore.Mvc namespace
+- RENAMED HttpEntityTagHeader class in the Cuemon.AspNetCore.Mvc.Filters.Cacheable namespace to HttpEntityTagHeaderFilter
+- RENAMED HttpLastModifiedHeader class in the Cuemon.AspNetCore.Mvc.Filters.Cacheable namespace to HttpLastModifiedHeaderFilter
+- RENAMED TimeMeasureAttribute class in the Cuemon.AspNetCore.Mvc.Filters.Diagnostics namespace to ServerTimingAttribute (including refactoring)
+- RENAMED TimeMeasuringFilter class in the Cuemon.AspNetCore.Mvc.Filters.Diagnostics namespace to ServerTimingFilter (including refactoring)
+- RENAMED TimeMeasuringOptions class in the Cuemon.AspNetCore.Mvc.Filters.Diagnostics namespace to ServerTimingOptions (including refactoring)
+
+# New Features
+- ADDED TooManyRequestsObjectResult class in the Cuemon.AspNetCore.Mvc namespace that is an ObjectResult that when executed will produce a Too Many Requests (429) response
+- ADDED TooManyRequestsResult class in the Cuemon.AspNetCore.Mvc namespace that is an ActionResult that returns a TooManyRequests (429) response
+- ADDED CacheableObjectFactory class in the Cuemon.AspNetCore.Mvc namespace that provides access to factory methods for creating and configuring objects implementing the ICacheableObjectResult interface
+
+# Improvements
+- COMPATIBLE with the changes applied to NET Core 3 in regards to only allowing asynchronous I/O
+
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc/TimeBasedObjectResult.cs b/src/Cuemon.AspNetCore.Mvc/TimeBasedObjectResult.cs
index aa750b4eb..6e5631f93 100644
--- a/src/Cuemon.AspNetCore.Mvc/TimeBasedObjectResult.cs
+++ b/src/Cuemon.AspNetCore.Mvc/TimeBasedObjectResult.cs
@@ -1,5 +1,4 @@
using System;
-using Cuemon.Data;
using Cuemon.Data.Integrity;
namespace Cuemon.AspNetCore.Mvc
diff --git a/src/Cuemon.AspNetCore.Mvc/TooManyRequestsObjectResult.cs b/src/Cuemon.AspNetCore.Mvc/TooManyRequestsObjectResult.cs
new file mode 100644
index 000000000..a64e2371f
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Mvc/TooManyRequestsObjectResult.cs
@@ -0,0 +1,20 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Cuemon.AspNetCore.Mvc
+{
+ ///
+ /// An that when executed will produce a Too Many Requests (429) response.
+ ///
+ public class TooManyRequestsObjectResult : ObjectResult
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Contains the errors to be returned to the client.
+ public TooManyRequestsObjectResult(object error) : base(error)
+ {
+ StatusCode = StatusCodes.Status429TooManyRequests;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc/TooManyRequestsResult.cs b/src/Cuemon.AspNetCore.Mvc/TooManyRequestsResult.cs
new file mode 100644
index 000000000..c72f75dc5
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Mvc/TooManyRequestsResult.cs
@@ -0,0 +1,18 @@
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Cuemon.AspNetCore.Mvc
+{
+ ///
+ /// An that returns a TooManyRequests (429) response.
+ ///
+ public class TooManyRequestsResult : StatusCodeResult
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TooManyRequestsResult() : base(StatusCodes.Status429TooManyRequests)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Razor/TagHelpers/CdnTagHelper.cs b/src/Cuemon.AspNetCore.Razor.TagHelpers/CdnTagHelper.cs
similarity index 100%
rename from src/Cuemon.AspNetCore.Razor/TagHelpers/CdnTagHelper.cs
rename to src/Cuemon.AspNetCore.Razor.TagHelpers/CdnTagHelper.cs
diff --git a/src/Cuemon.AspNetCore.Razor/TagHelpers/CdnTagHelperOptions.cs b/src/Cuemon.AspNetCore.Razor.TagHelpers/CdnTagHelperOptions.cs
similarity index 100%
rename from src/Cuemon.AspNetCore.Razor/TagHelpers/CdnTagHelperOptions.cs
rename to src/Cuemon.AspNetCore.Razor.TagHelpers/CdnTagHelperOptions.cs
diff --git a/src/Cuemon.AspNetCore.Razor/TagHelpers/CdnUriScheme.cs b/src/Cuemon.AspNetCore.Razor.TagHelpers/CdnUriScheme.cs
similarity index 100%
rename from src/Cuemon.AspNetCore.Razor/TagHelpers/CdnUriScheme.cs
rename to src/Cuemon.AspNetCore.Razor.TagHelpers/CdnUriScheme.cs
diff --git a/src/Cuemon.AspNetCore.Razor.TagHelpers/Cuemon.AspNetCore.Razor.TagHelpers.csproj b/src/Cuemon.AspNetCore.Razor.TagHelpers/Cuemon.AspNetCore.Razor.TagHelpers.csproj
new file mode 100644
index 000000000..780dd263d
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Razor.TagHelpers/Cuemon.AspNetCore.Razor.TagHelpers.csproj
@@ -0,0 +1,19 @@
+
+
+
+ net5.0;netcoreapp3.0;netstandard2.0
+ a30adf91-e7c7-4cb4-a39d-e1a5374c5602
+
+
+
+ Cuemon.AspNetCore.Razor.TagHelpers
+ Cuemon.AspNetCore.Razor.TagHelpers
+ The Cuemon.AspNetCore.Razor.TagHelpers namespace contains types tailored tag helper implementations. The namespace is an addition to the Microsoft.AspNetCore.Razor.TagHelpers namespace.
+ cdn-tag-helper cdn-uri-scheme image-cdn-tag-helper link-cdn-tag-helper script-cdn-tag-helper
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Razor/TagHelpers/ImageCdnTagHelper.cs b/src/Cuemon.AspNetCore.Razor.TagHelpers/ImageCdnTagHelper.cs
similarity index 100%
rename from src/Cuemon.AspNetCore.Razor/TagHelpers/ImageCdnTagHelper.cs
rename to src/Cuemon.AspNetCore.Razor.TagHelpers/ImageCdnTagHelper.cs
diff --git a/src/Cuemon.AspNetCore.Razor/TagHelpers/LinkCdnTagHelper.cs b/src/Cuemon.AspNetCore.Razor.TagHelpers/LinkCdnTagHelper.cs
similarity index 100%
rename from src/Cuemon.AspNetCore.Razor/TagHelpers/LinkCdnTagHelper.cs
rename to src/Cuemon.AspNetCore.Razor.TagHelpers/LinkCdnTagHelper.cs
diff --git a/src/Cuemon.AspNetCore.Razor.TagHelpers/Properties/AssemblyInfo.cs b/src/Cuemon.AspNetCore.Razor.TagHelpers/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..8db3562bc
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Razor.TagHelpers/Properties/AssemblyInfo.cs
@@ -0,0 +1,4 @@
+using System.Runtime.InteropServices;
+
+[assembly: ComVisible(false)]
+[assembly: Guid("74d499ee-862e-412b-9a2d-fb2fe30d518e")]
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Razor.TagHelpers/Properties/PackageReleaseNotes.txt b/src/Cuemon.AspNetCore.Razor.TagHelpers/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..ffcac726d
--- /dev/null
+++ b/src/Cuemon.AspNetCore.Razor.TagHelpers/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,6 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET Core 3.0, NET 5.0
+
+# Upgrade Steps
+- Any former extension methods of the Cuemon.AspNetCore.Razor.TagHelpers namespace was merged into the Cuemon.Extensions.Core namespace
+
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Razor/TagHelpers/ScriptCdnTagHelper.cs b/src/Cuemon.AspNetCore.Razor.TagHelpers/ScriptCdnTagHelper.cs
similarity index 100%
rename from src/Cuemon.AspNetCore.Razor/TagHelpers/ScriptCdnTagHelper.cs
rename to src/Cuemon.AspNetCore.Razor.TagHelpers/ScriptCdnTagHelper.cs
diff --git a/src/Cuemon.AspNetCore.Razor/Cuemon.AspNetCore.Razor.csproj b/src/Cuemon.AspNetCore.Razor/Cuemon.AspNetCore.Razor.csproj
deleted file mode 100644
index 43b37b886..000000000
--- a/src/Cuemon.AspNetCore.Razor/Cuemon.AspNetCore.Razor.csproj
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
- netcoreapp3.0;netstandard2.0
- true
- ..\cuemon.snk
- true
- a30adf91-e7c7-4cb4-a39d-e1a5374c5602
-
-
-
- Cuemon .NET Standard
- Cuemon.AspNetCore.Razor
- Cuemon.AspNetCore.Razor
- The Cuemon.AspNetCore.Razor assembly is a supplement to Microsoft ASP.NET Core.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore/Builder/ApplicationBuilderFactory.cs b/src/Cuemon.AspNetCore/Builder/MiddlewareBuilderFactory.cs
similarity index 90%
rename from src/Cuemon.AspNetCore/Builder/ApplicationBuilderFactory.cs
rename to src/Cuemon.AspNetCore/Builder/MiddlewareBuilderFactory.cs
index a2520ff06..4d136e840 100644
--- a/src/Cuemon.AspNetCore/Builder/ApplicationBuilderFactory.cs
+++ b/src/Cuemon.AspNetCore/Builder/MiddlewareBuilderFactory.cs
@@ -7,7 +7,7 @@ namespace Cuemon.AspNetCore.Builder
///
/// Provides support for creating, using and configuring or implementations.
///
- public static class ApplicationBuilderFactory
+ public static class MiddlewareBuilderFactory
{
///
/// Adds a middleware type to the application request pipeline.
@@ -28,7 +28,7 @@ public static IApplicationBuilder UseMiddleware(IApplicationBuilder
/// The instance.
/// The which need to be configured.
/// The instance.
- public static IApplicationBuilder UseMiddlewareConfigurable(IApplicationBuilder builder, Action setup = null)
+ public static IApplicationBuilder UseConfigurableMiddleware(IApplicationBuilder builder, Action setup = null)
where TMiddleware : ConfigurableMiddlewareCore
where TOptions : class, new()
{
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/CacheBustingOptions.cs b/src/Cuemon.AspNetCore/Configuration/CacheBustingOptions.cs
similarity index 95%
rename from src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/CacheBustingOptions.cs
rename to src/Cuemon.AspNetCore/Configuration/CacheBustingOptions.cs
index 01be125aa..a16ac6fe6 100644
--- a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/CacheBustingOptions.cs
+++ b/src/Cuemon.AspNetCore/Configuration/CacheBustingOptions.cs
@@ -1,4 +1,4 @@
-namespace Cuemon.Extensions.AspNetCore.Mvc.Configuration
+namespace Cuemon.AspNetCore.Configuration
{
///
/// Specifies options that is related to operations.
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/DynamicCacheBusting.cs b/src/Cuemon.AspNetCore/Configuration/DynamicCacheBusting.cs
similarity index 97%
rename from src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/DynamicCacheBusting.cs
rename to src/Cuemon.AspNetCore/Configuration/DynamicCacheBusting.cs
index fed90ce4d..41cb66a82 100644
--- a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/DynamicCacheBusting.cs
+++ b/src/Cuemon.AspNetCore/Configuration/DynamicCacheBusting.cs
@@ -2,7 +2,7 @@
using Cuemon.Configuration;
using Microsoft.Extensions.Options;
-namespace Cuemon.Extensions.AspNetCore.Mvc.Configuration
+namespace Cuemon.AspNetCore.Configuration
{
///
/// Provides cache-busting capabilities on a duration based interval. This class cannot be inherited.
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/DynamicCacheBustingOptions.cs b/src/Cuemon.AspNetCore/Configuration/DynamicCacheBustingOptions.cs
similarity index 91%
rename from src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/DynamicCacheBustingOptions.cs
rename to src/Cuemon.AspNetCore/Configuration/DynamicCacheBustingOptions.cs
index b68d5ab2a..39a955cc0 100644
--- a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/DynamicCacheBustingOptions.cs
+++ b/src/Cuemon.AspNetCore/Configuration/DynamicCacheBustingOptions.cs
@@ -1,9 +1,9 @@
using System;
-namespace Cuemon.Extensions.AspNetCore.Mvc.Configuration
+namespace Cuemon.AspNetCore.Configuration
{
///
- /// Specifies options that is related to operations.
+ /// Specifies options that is related to operations.
///
///
public class DynamicCacheBustingOptions : CacheBustingOptions
@@ -28,13 +28,13 @@ public class DynamicCacheBustingOptions : CacheBustingOptions
///
/// -
///
- /// 20 minutes
+ /// 12 hours
///
///
///
public DynamicCacheBustingOptions()
{
- TimeToLive = TimeSpan.FromMinutes(20);
+ TimeToLive = TimeSpan.FromHours(12);
PreferredLength = 8;
PreferredCharacters = Alphanumeric.LettersAndNumbers;
}
diff --git a/src/Cuemon.AspNetCore/Cuemon.AspNetCore.csproj b/src/Cuemon.AspNetCore/Cuemon.AspNetCore.csproj
index 4c98a08dc..b6bd4d9e1 100644
--- a/src/Cuemon.AspNetCore/Cuemon.AspNetCore.csproj
+++ b/src/Cuemon.AspNetCore/Cuemon.AspNetCore.csproj
@@ -1,33 +1,20 @@
- netcoreapp3.0;netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netcoreapp3.0;netstandard2.0
a00adf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon .NET Standard
Cuemon.AspNetCore
Cuemon.AspNetCore
- The Cuemon.AspNetCore assembly is a supplement to Microsoft ASP.NET Core.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
+ 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.
+ configurable-middleware middleware http-exception-descriptor throttling-sentinel-middleware user-agent-sentinel-middleware request-identifier-middleware correlation-identifier-middleware hosting-environment-middleware server-timing cache-busting middleware-builder-factory
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
-
+
+
+
@@ -43,8 +30,9 @@
-
+
+
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore/Http/HttpExceptionDescriptor.cs b/src/Cuemon.AspNetCore/Diagnostics/HttpExceptionDescriptor.cs
similarity index 98%
rename from src/Cuemon.AspNetCore/Http/HttpExceptionDescriptor.cs
rename to src/Cuemon.AspNetCore/Diagnostics/HttpExceptionDescriptor.cs
index 6924e7291..e2433fe23 100644
--- a/src/Cuemon.AspNetCore/Http/HttpExceptionDescriptor.cs
+++ b/src/Cuemon.AspNetCore/Diagnostics/HttpExceptionDescriptor.cs
@@ -3,7 +3,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
-namespace Cuemon.AspNetCore.Http
+namespace Cuemon.AspNetCore.Diagnostics
{
///
/// Provides information about an , in a developer friendly way, optimized for open- and otherwise public application programming interfaces (API).
diff --git a/src/Cuemon.AspNetCore/Diagnostics/IServerTiming.cs b/src/Cuemon.AspNetCore/Diagnostics/IServerTiming.cs
new file mode 100644
index 000000000..a0be43623
--- /dev/null
+++ b/src/Cuemon.AspNetCore/Diagnostics/IServerTiming.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+
+namespace Cuemon.AspNetCore.Diagnostics
+{
+ ///
+ /// Represents the Server Timing as per W3C Working Draft 28 July 2020 (https://www.w3.org/TR/2020/WD-server-timing-20200728/).
+ ///
+ public interface IServerTiming
+ {
+ ///
+ /// Adds a to the .
+ ///
+ /// The server-specified metric name.
+ /// A reference to this instance after the operation has completed.
+ IServerTiming AddServerTiming(string name);
+
+ ///
+ /// Adds a to the .
+ ///
+ /// The server-specified metric name.
+ /// The server-specified metric duration.
+ /// A reference to this instance after the operation has completed.
+ IServerTiming AddServerTiming(string name, TimeSpan duration);
+
+ ///
+ /// Adds a to the .
+ ///
+ /// The server-specified metric name.
+ /// The server-specified metric duration.
+ /// The server-specified metric description.
+ /// A reference to this instance after the operation has completed.
+ IServerTiming AddServerTiming(string name, TimeSpan duration, string description);
+
+ ///
+ /// Gets the entries used to communicate one or more metrics and descriptions for the given request-response cycle.
+ ///
+ /// The entries used to communicate one or more metrics and descriptions for the given request-response cycle.
+ IEnumerable Metrics { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore/Diagnostics/ServerTiming.cs b/src/Cuemon.AspNetCore/Diagnostics/ServerTiming.cs
new file mode 100644
index 000000000..7fbe6fee7
--- /dev/null
+++ b/src/Cuemon.AspNetCore/Diagnostics/ServerTiming.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+
+namespace Cuemon.AspNetCore.Diagnostics
+{
+ ///
+ /// Provides a default implementation of the interface.
+ ///
+ ///
+ public class ServerTiming : IServerTiming
+ {
+ ///
+ /// The name of the Server-Timing header field.
+ ///
+ public const string HeaderName = "Server-Timing";
+
+ private readonly List _metrics = new List();
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ServerTiming()
+ {
+ }
+
+ ///
+ /// Adds a to the .
+ ///
+ /// The server-specified metric name.
+ /// A reference to this instance after the operation has completed.
+ public IServerTiming AddServerTiming(string name)
+ {
+ _metrics.Add(new ServerTimingMetric(name));
+ return this;
+ }
+
+ ///
+ /// Adds a to the .
+ ///
+ /// The server-specified metric name.
+ /// The server-specified metric duration.
+ /// A reference to this instance after the operation has completed.
+ public IServerTiming AddServerTiming(string name, TimeSpan duration)
+ {
+ _metrics.Add(new ServerTimingMetric(name, duration));
+ return this;
+ }
+
+ ///
+ /// Adds a to the .
+ ///
+ /// The server-specified metric name.
+ /// The server-specified metric duration.
+ /// The server-specified metric description.
+ /// A reference to this instance after the operation has completed.
+ public IServerTiming AddServerTiming(string name, TimeSpan duration, string description)
+ {
+ _metrics.Add(new ServerTimingMetric(name, duration, description));
+ return this;
+ }
+
+ ///
+ /// Gets the entries used to communicate one or more metrics and descriptions for the given request-response cycle.
+ ///
+ /// The entries used to communicate one or more metrics and descriptions for the given request-response cycle.
+ public IEnumerable Metrics => _metrics;
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore/Diagnostics/ServerTimingMetric.cs b/src/Cuemon.AspNetCore/Diagnostics/ServerTimingMetric.cs
new file mode 100644
index 000000000..3689185e4
--- /dev/null
+++ b/src/Cuemon.AspNetCore/Diagnostics/ServerTimingMetric.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Globalization;
+
+namespace Cuemon.AspNetCore.Diagnostics
+{
+ ///
+ /// Represents a HTTP Server-Timing header field entry to communicate one metric and description for the given request-response cycle.
+ ///
+ public class ServerTimingMetric
+ {
+ private readonly string _metric;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The server-specified metric name.
+ /// The server-specified metric duration.
+ /// The server-specified metric description.
+ public ServerTimingMetric(string name, TimeSpan? duration = null, string description = null)
+ {
+ Validator.ThrowIfNullOrWhitespace(name, nameof(name));
+ if (duration.HasValue && duration <= TimeSpan.Zero) { duration = TimeSpan.Zero; }
+
+ var metric = name;
+ if (duration.HasValue) { metric = string.Concat(metric, ";", FormattableString.Invariant($"dur={duration.Value.TotalMilliseconds.ToString("F1", CultureInfo.InvariantCulture)}")); }
+ if (description != null) { metric = string.Concat(metric, ";", $"desc=\"{description}\""); }
+
+ Name = name;
+ Duration = duration;
+ Description = description;
+
+ _metric = metric;
+ }
+
+ ///
+ /// Gets the server-specified metric name.
+ ///
+ /// The server-specified metric name.
+ public string Name { get; }
+
+ ///
+ /// Gets the server-specified metric duration.
+ ///
+ /// The server-specified metric duration.
+ public TimeSpan? Duration { get; }
+
+ ///
+ /// Gets the server-specified metric description.
+ ///
+ /// The server-specified metric description.
+ public string Description { get; }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// A that represents this instance.
+ public override string ToString()
+ {
+ return _metric;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore/Extensions/Http/Headers/HeaderDictionaryDecoratorExtensions.cs b/src/Cuemon.AspNetCore/Extensions/Http/Headers/HeaderDictionaryDecoratorExtensions.cs
index cd51ed490..882722cbf 100644
--- a/src/Cuemon.AspNetCore/Extensions/Http/Headers/HeaderDictionaryDecoratorExtensions.cs
+++ b/src/Cuemon.AspNetCore/Extensions/Http/Headers/HeaderDictionaryDecoratorExtensions.cs
@@ -24,14 +24,13 @@ public static class HeaderDictionaryDecoratorExtensions
///
/// cannot be null.
///
- public static bool TryAddOrUpdateHeader(this IDecorator decorator, string key, StringValues value, bool useAsciiEncodingConversion = true)
+ public static void AddOrUpdateHeader(this IDecorator decorator, string key, StringValues value, bool useAsciiEncodingConversion = true)
{
var headerValue = useAsciiEncodingConversion ? new StringValues(Decorator.Enclose(value).ToAsciiEncodedString()) : value;
if (headerValue != StringValues.Empty)
{
- return decorator.TryAddOrUpdate(key, Decorator.Enclose(headerValue.ToString().Where(c => !char.IsControl(c))).ToStringEquivalent());
+ decorator.AddOrUpdate(key, Decorator.Enclose(headerValue.ToString().Where(c => !char.IsControl(c))).ToStringEquivalent());
}
- return false;
}
///
@@ -39,12 +38,12 @@ public static bool TryAddOrUpdateHeader(this IDecorator decor
///
/// The to extend.
/// The to copy.
- public static void TryAddOrUpdateHeaders(this IDecorator decorator, HttpResponseHeaders responseHeaders)
+ public static void AddOrUpdateHeaders(this IDecorator decorator, HttpResponseHeaders responseHeaders)
{
if (decorator == null || responseHeaders == null) { return; }
foreach (var header in responseHeaders)
{
- decorator.TryAddOrUpdate(header.Key, header.Value != null ? DelimitedString.Create(header.Value) : "");
+ decorator.AddOrUpdate(header.Key, header.Value != null ? DelimitedString.Create(header.Value) : "");
}
}
}
diff --git a/src/Cuemon.AspNetCore/Extensions/Http/HttpContextDecoratorExtensions.cs b/src/Cuemon.AspNetCore/Extensions/Http/HttpContextDecoratorExtensions.cs
new file mode 100644
index 000000000..2330b8157
--- /dev/null
+++ b/src/Cuemon.AspNetCore/Extensions/Http/HttpContextDecoratorExtensions.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Threading;
+using System.Threading.Tasks;
+using Cuemon.AspNetCore.Http.Headers;
+using Cuemon.AspNetCore.Http.Throttling;
+using Cuemon.Collections.Generic;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Net.Http.Headers;
+
+namespace Cuemon.AspNetCore.Http
+{
+ ///
+ /// Extension methods for the class tailored to adhere the decorator pattern.
+ /// This API supports the product infrastructure and is not intended to be used directly from your code.
+ ///
+ ///
+ ///
+ public static class HttpContextDecoratorExtensions
+ {
+ private static readonly SemaphoreSlim ThrottleLocker = new SemaphoreSlim(1);
+
+ ///
+ /// Common throttler operation logic for ASP.NET Core and ASP.NET Core MVC. Not intended to be used directly from your code.
+ ///
+ /// The to extend.
+ /// The implementation.
+ /// The configured options.
+ /// The delegate that merges an instance of into the pipeline.
+ public static async Task InvokeThrottlerSentinelAsync(this IDecorator decorator, IThrottlingCache tc, ThrottlingSentinelOptions options, Action transformer)
+ {
+ var utcNow = DateTime.UtcNow;
+ var throttlingContext = options.ContextResolver?.Invoke(decorator.Inner);
+ if (!string.IsNullOrWhiteSpace(throttlingContext))
+ {
+ ThrottleRequest tr = null;
+ try
+ {
+ await ThrottleLocker.WaitAsync().ConfigureAwait(false);
+
+ if (!tc.TryGetValue(throttlingContext, out tr))
+ {
+ tr = new ThrottleRequest(options.Quota);
+ Decorator.Enclose(tc).TryAdd(throttlingContext, tr);
+ }
+ else
+ {
+ tr.Refresh();
+ tr.IncrementTotal();
+ }
+
+ var window = new TimeRange(utcNow, tr.Expires);
+ var delta = window.Duration;
+ var reset = utcNow.Add(delta);
+ Decorator.Enclose(decorator.Inner.Response.Headers).AddOrUpdate(options.RateLimitHeaderName, tr.Quota.RateLimit.ToString(CultureInfo.InvariantCulture));
+ Decorator.Enclose(decorator.Inner.Response.Headers).AddOrUpdate(options.RateLimitRemainingHeaderName, Math.Max(tr.Quota.RateLimit - tr.Total, 0).ToString(CultureInfo.InvariantCulture));
+ if (options.UseRetryAfterHeader) { options.RateLimitResetScope = options.RetryAfterScope; } // if a response contains both the Retry-After and the RateLimit-Reset header fields, the value of RateLimit-Reset MUST be consistent with the one of Retry-After https://tools.ietf.org/id/draft-polli-ratelimit-headers-00.html#providing-ratelimit-headers
+ switch (options.RateLimitResetScope)
+ {
+ case RetryConditionScope.DeltaSeconds:
+ Decorator.Enclose(decorator.Inner.Response.Headers).AddOrUpdate(options.RateLimitResetHeaderName, new RetryConditionHeaderValue(delta).ToString());
+ break;
+ case RetryConditionScope.HttpDate:
+ Decorator.Enclose(decorator.Inner.Response.Headers).AddOrUpdate(options.RateLimitResetHeaderName, new RetryConditionHeaderValue(reset).ToString());
+ break;
+ }
+ if (tr.Total > tr.Quota.RateLimit && tr.Expires > utcNow)
+ {
+ var message = options.ResponseBroker?.Invoke(delta, reset);
+ if (message != null)
+ {
+ transformer?.Invoke(message, decorator.Inner.Response);
+ throw new ThrottlingException((int)message.StatusCode, await message.Content.ReadAsStringAsync().ConfigureAwait(false), tr.Quota.RateLimit, delta, reset);
+ }
+ }
+ }
+ finally
+ {
+ tc[throttlingContext] = tr;
+ ThrottleLocker.Release();
+ }
+ }
+ }
+
+ ///
+ /// Common user agent logic for ASP.NET Core and ASP.NET Core MVC. Not intended to be used directly from your code.
+ ///
+ /// The to extend.
+ /// The configured options.
+ /// The delegate that merges an instance of into the pipeline.
+ public static async Task InvokeUserAgentSentinelAsync(this IDecorator decorator, UserAgentSentinelOptions options, Action transformer)
+ {
+ var userAgent = decorator.Inner.Request.Headers[HeaderNames.UserAgent].FirstOrDefault();
+ if (options.RequireUserAgentHeader)
+ {
+ var message = options.ResponseHandler?.Invoke(userAgent);
+ if (message != null)
+ {
+ transformer?.Invoke(message, decorator.Inner.Response);
+ throw new UserAgentException((int)message.StatusCode, await message.Content.ReadAsStringAsync().ConfigureAwait(false));
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore/Extensions/Http/HttpResponseDecoratorExtensions.cs b/src/Cuemon.AspNetCore/Extensions/Http/HttpResponseDecoratorExtensions.cs
index 23e270e54..a59ce7d23 100644
--- a/src/Cuemon.AspNetCore/Extensions/Http/HttpResponseDecoratorExtensions.cs
+++ b/src/Cuemon.AspNetCore/Extensions/Http/HttpResponseDecoratorExtensions.cs
@@ -28,14 +28,14 @@ public static class HttpResponseDecoratorExtensions
/// cannot be null -or-
/// cannot be null.
///
- public static void TryAddOrUpdateEntityTagHeader(this IDecorator decorator, HttpRequest request, ChecksumBuilder builder, bool isWeak = false)
+ public static void AddOrUpdateEntityTagHeader(this IDecorator decorator, HttpRequest request, ChecksumBuilder builder, bool isWeak = false)
{
Validator.ThrowIfNull(decorator, nameof(decorator));
Validator.ThrowIfNull(request, nameof(request));
Validator.ThrowIfNull(builder, nameof(builder));
builder = Decorator.Enclose(builder).CombineWith(request.Headers[HeaderNames.Accept]);
if (Decorator.Enclose(decorator.Inner.StatusCode).IsSuccessStatusCode() && Decorator.Enclose(request).IsClientSideResourceCached(builder)) { decorator.Inner.StatusCode = StatusCodes.Status304NotModified; }
- Decorator.Enclose(decorator.Inner.Headers).TryAddOrUpdate(HeaderNames.ETag, new StringValues(Decorator.Enclose(builder).ToEntityTagHeaderValue(isWeak).ToString()));
+ Decorator.Enclose(decorator.Inner.Headers).AddOrUpdate(HeaderNames.ETag, new StringValues(Decorator.Enclose(builder).ToEntityTagHeaderValue(isWeak).ToString()));
}
///
@@ -48,12 +48,12 @@ public static void TryAddOrUpdateEntityTagHeader(this IDecorator d
/// cannot be null -or-
/// cannot be null.
///
- public static void TryAddOrUpdateLastModifiedHeader(this IDecorator decorator, HttpRequest request, DateTime lastModified)
+ public static void AddOrUpdateLastModifiedHeader(this IDecorator decorator, HttpRequest request, DateTime lastModified)
{
Validator.ThrowIfNull(decorator, nameof(decorator));
Validator.ThrowIfNull(request, nameof(request));
if (Decorator.Enclose(decorator.Inner.StatusCode).IsSuccessStatusCode() && Decorator.Enclose(request).IsClientSideResourceCached(lastModified)) { decorator.Inner.StatusCode = StatusCodes.Status304NotModified; }
- Decorator.Enclose(decorator.Inner.Headers).TryAddOrUpdate(HeaderNames.LastModified, new StringValues(lastModified.ToUniversalTime().ToString("R", DateTimeFormatInfo.InvariantInfo)));
+ Decorator.Enclose(decorator.Inner.Headers).AddOrUpdate(HeaderNames.LastModified, new StringValues(lastModified.ToUniversalTime().ToString("R", DateTimeFormatInfo.InvariantInfo)));
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore/GlobalSuppressions.cs b/src/Cuemon.AspNetCore/GlobalSuppressions.cs
index 01f8ad206..23a31c393 100644
--- a/src/Cuemon.AspNetCore/GlobalSuppressions.cs
+++ b/src/Cuemon.AspNetCore/GlobalSuppressions.cs
@@ -3,7 +3,16 @@
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
-[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S3442:\"abstract\" classes should not have \"public\" constructors", Justification = "Infrastructure class.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Infrastructure.ConfigurableMiddlewareCore`1.#ctor(Microsoft.AspNetCore.Http.RequestDelegate,System.Action{`0})")]
-[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S3442:\"abstract\" classes should not have \"public\" constructors", Justification = "Infrastructure class.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Infrastructure.MiddlewareCore.#ctor(Microsoft.AspNetCore.Http.RequestDelegate)")]
-[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S3442:\"abstract\" classes should not have \"public\" constructors", Justification = "Infrastructure class.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Infrastructure.ConfigurableMiddlewareCore`1.#ctor(Microsoft.AspNetCore.Http.RequestDelegate,Microsoft.Extensions.Options.IOptions{`0})")]
-[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Critical Code Smell", "S927:parameter names should match base declaration and other partial definitions", Justification = "Generic parameter; implementation reflects usage.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Hosting.HostingEnvironmentMiddleware.InvokeAsync(Microsoft.AspNetCore.Http.HttpContext,Microsoft.Extensions.Hosting.IHostEnvironment)~System.Threading.Tasks.Task")]
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Major Code Smell", "S3442:\"abstract\" classes should not have \"public\" constructors", Justification = "Infrastructure class.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Infrastructure.ConfigurableMiddlewareCore`1.#ctor(Microsoft.AspNetCore.Http.RequestDelegate,System.Action{`0})")]
+[assembly: SuppressMessage("Major Code Smell", "S3442:\"abstract\" classes should not have \"public\" constructors", Justification = "Infrastructure class.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Infrastructure.MiddlewareCore.#ctor(Microsoft.AspNetCore.Http.RequestDelegate)")]
+[assembly: SuppressMessage("Major Code Smell", "S3442:\"abstract\" classes should not have \"public\" constructors", Justification = "Infrastructure class.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Infrastructure.ConfigurableMiddlewareCore`1.#ctor(Microsoft.AspNetCore.Http.RequestDelegate,Microsoft.Extensions.Options.IOptions{`0})")]
+[assembly: SuppressMessage("Critical Code Smell", "S927:parameter names should match base declaration and other partial definitions", Justification = "Generic parameter; implementation reflects usage.", Scope = "member", Target = "~M:Cuemon.AspNetCore.Hosting.HostingEnvironmentMiddleware.InvokeAsync(Microsoft.AspNetCore.Http.HttpContext,Microsoft.Extensions.Hosting.IHostEnvironment)~System.Threading.Tasks.Task")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up to a max. of 5 generic parameters.", Scope = "type", Target = "~T:Cuemon.AspNetCore.ConfigurableMiddleware`3")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up to a max. of 5 generic parameters.", Scope = "type", Target = "~T:Cuemon.AspNetCore.ConfigurableMiddleware`4")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up to a max. of 5 generic parameters.", Scope = "type", Target = "~T:Cuemon.AspNetCore.ConfigurableMiddleware`5")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up to a max. of 5 generic parameters.", Scope = "type", Target = "~T:Cuemon.AspNetCore.ConfigurableMiddleware`6")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up to a max. of 5 generic parameters.", Scope = "type", Target = "~T:Cuemon.AspNetCore.Middleware`3")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up to a max. of 5 generic parameters.", Scope = "type", Target = "~T:Cuemon.AspNetCore.Middleware`4")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up to a max. of 5 generic parameters.", Scope = "type", Target = "~T:Cuemon.AspNetCore.Middleware`5")]
diff --git a/src/Cuemon.AspNetCore/Http/Headers/CorrelationIdentifierMiddleware.cs b/src/Cuemon.AspNetCore/Http/Headers/CorrelationIdentifierMiddleware.cs
index 3262106c3..3d14e71ba 100644
--- a/src/Cuemon.AspNetCore/Http/Headers/CorrelationIdentifierMiddleware.cs
+++ b/src/Cuemon.AspNetCore/Http/Headers/CorrelationIdentifierMiddleware.cs
@@ -45,7 +45,7 @@ public override Task InvokeAsync(HttpContext context)
Decorator.Enclose(context.Items).TryAdd(HttpContextItemsKey, correlationId);
context.Response.OnStarting(() =>
{
- Decorator.Enclose(context.Response.Headers).TryAddOrUpdate(Options.HeaderName, correlationId);
+ Decorator.Enclose(context.Response.Headers).AddOrUpdate(Options.HeaderName, correlationId);
return Task.CompletedTask;
});
return Next(context);
diff --git a/src/Cuemon.AspNetCore/Http/Headers/RequestIdentifierMiddleware.cs b/src/Cuemon.AspNetCore/Http/Headers/RequestIdentifierMiddleware.cs
index 439d42517..ced05a16e 100644
--- a/src/Cuemon.AspNetCore/Http/Headers/RequestIdentifierMiddleware.cs
+++ b/src/Cuemon.AspNetCore/Http/Headers/RequestIdentifierMiddleware.cs
@@ -45,7 +45,7 @@ public override Task InvokeAsync(HttpContext context)
Decorator.Enclose(context.Items).TryAdd(HttpContextItemsKey, requestId);
context.Response.OnStarting(() =>
{
- Decorator.Enclose(context.Response.Headers).TryAddOrUpdate(Options.HeaderName, requestId);
+ Decorator.Enclose(context.Response.Headers).AddOrUpdate(Options.HeaderName, requestId);
return Task.CompletedTask;
});
return Next(context);
diff --git a/src/Cuemon.AspNetCore/Http/Throttling/ThrottlingRetryAfterHeader.cs b/src/Cuemon.AspNetCore/Http/Headers/RetryConditionScope.cs
similarity index 57%
rename from src/Cuemon.AspNetCore/Http/Throttling/ThrottlingRetryAfterHeader.cs
rename to src/Cuemon.AspNetCore/Http/Headers/RetryConditionScope.cs
index e2894c8dc..e8358e31f 100644
--- a/src/Cuemon.AspNetCore/Http/Throttling/ThrottlingRetryAfterHeader.cs
+++ b/src/Cuemon.AspNetCore/Http/Headers/RetryConditionScope.cs
@@ -1,9 +1,9 @@
-namespace Cuemon.AspNetCore.Http.Throttling
+namespace Cuemon.AspNetCore.Http.Headers
{
///
- /// Specifies a set of values defining what value to use with a HTTP Retry-After header.
+ /// Specifies a set of values defining what value to use with a given HTTP header in regards to a retry condition. Recommended value is always as it does not rely on clock synchronization and is resilient to clock skew between client and server.
///
- public enum ThrottlingRetryAfterHeader
+ public enum RetryConditionScope
{
///
/// A non-negative decimal integer indicating the seconds to delay after the response is received.
diff --git a/src/Cuemon.AspNetCore/Http/Headers/UserAgentSentinelMiddleware.cs b/src/Cuemon.AspNetCore/Http/Headers/UserAgentSentinelMiddleware.cs
index f2af71337..69314ad9b 100644
--- a/src/Cuemon.AspNetCore/Http/Headers/UserAgentSentinelMiddleware.cs
+++ b/src/Cuemon.AspNetCore/Http/Headers/UserAgentSentinelMiddleware.cs
@@ -1,6 +1,5 @@
using System;
using System.Threading.Tasks;
-using Cuemon.AspNetCore.Infrastructure;
using Cuemon.IO;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
@@ -37,21 +36,17 @@ public UserAgentSentinelMiddleware(RequestDelegate next, ActionA task that represents the execution of this middleware.
public override async Task InvokeAsync(HttpContext context)
{
- var exception = false;
- try
+ await Decorator.Enclose(context).InvokeUserAgentSentinelAsync(Options, async (message, response) =>
{
- await AspNetCoreInfrastructure.InvokeUserAgentSentinelAsync(context, Options, async (message, response) =>
+ context.Response.OnStarting(() =>
{
- response.StatusCode = (int) message.StatusCode;
- Decorator.Enclose(response.Headers).TryAddOrUpdateHeaders(message.Headers);
- await Decorator.Enclose(response.Body).WriteAsync(await message.Content.ReadAsByteArrayAsync().ConfigureAwait(false)).ConfigureAwait(false);
- }).ConfigureAwait(false);
- }
- catch (UserAgentException)
- {
- exception = true;
- }
- if (!exception) { await Next(context).ConfigureAwait(false); }
+ Decorator.Enclose(response.Headers).AddOrUpdateHeaders(message.Headers);
+ return Task.CompletedTask;
+ });
+ response.StatusCode = (int)message.StatusCode;
+ await Decorator.Enclose(response.Body).WriteAsync(await message.Content.ReadAsByteArrayAsync().ConfigureAwait(false)).ConfigureAwait(false);
+ }).ConfigureAwait(false);
+ await Next(context).ConfigureAwait(false);
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore/Http/Headers/UserAgentSentinelOptions.cs b/src/Cuemon.AspNetCore/Http/Headers/UserAgentSentinelOptions.cs
index 8d7a6ede9..c8775b9f2 100644
--- a/src/Cuemon.AspNetCore/Http/Headers/UserAgentSentinelOptions.cs
+++ b/src/Cuemon.AspNetCore/Http/Headers/UserAgentSentinelOptions.cs
@@ -14,7 +14,7 @@ public class UserAgentSentinelOptions
///
/// Initializes a new instance of the class.
///
- ///
+ ///
/// The following table shows the initial property values for an instance of .
///
///
@@ -42,7 +42,7 @@ public class UserAgentSentinelOptions
/// false
///
/// -
- ///
+ ///
/// A initialized to either a HTTP status code 400 or 403 and a body of either or .
///
/// -
@@ -53,11 +53,10 @@ public class UserAgentSentinelOptions
///
public UserAgentSentinelOptions()
{
- UseGenericResponse = false;
BadRequestMessage = "The requirements of the HTTP User-Agent header was not met.";
ForbiddenMessage = "The HTTP User-Agent specified was rejected.";
AllowedUserAgents = new List();
- ResponseBroker = userAgent =>
+ ResponseHandler = userAgent =>
{
var userAgentIsNullOrWhiteSpace = string.IsNullOrWhiteSpace(userAgent);
var forbidden = !userAgentIsNullOrWhiteSpace &&
@@ -65,14 +64,14 @@ public UserAgentSentinelOptions()
AllowedUserAgents.Count > 0 &&
!AllowedUserAgents.Any(allowedUserAgent => userAgent.Equals(allowedUserAgent, StringComparison.OrdinalIgnoreCase));
- if (userAgentIsNullOrWhiteSpace || (forbidden && UseGenericResponse))
+ if (userAgentIsNullOrWhiteSpace || forbidden && UseGenericResponse)
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = new StringContent(BadRequestMessage)
};
}
-
+
if (forbidden)
{
return new HttpResponseMessage(HttpStatusCode.Forbidden)
@@ -89,12 +88,12 @@ public UserAgentSentinelOptions()
/// Gets or sets the function delegate that configures the response in the form of a .
///
/// The function delegate that configures the response in the form of a .
- public Func ResponseBroker { get; set; }
+ public Func ResponseHandler { get; set; }
///
- /// Gets or sets a value indicating whether the produced should be as neutral as possible.
+ /// Gets or sets a value indicating whether the produced should be as neutral as possible.
///
- /// true if the produced should be as neutral as possible; otherwise, false.
+ /// true if the produced should be as neutral as possible; otherwise, false.
public bool UseGenericResponse { get; set; }
///
diff --git a/src/Cuemon.AspNetCore/Http/Throttling/IThrottlingCache.cs b/src/Cuemon.AspNetCore/Http/Throttling/IThrottlingCache.cs
index 923bca83b..e7403279f 100644
--- a/src/Cuemon.AspNetCore/Http/Throttling/IThrottlingCache.cs
+++ b/src/Cuemon.AspNetCore/Http/Throttling/IThrottlingCache.cs
@@ -4,7 +4,6 @@ namespace Cuemon.AspNetCore.Http.Throttling
{
///
/// Specifies the contract for the storage of a throttling cache.
- /// Implements the .
///
///
public interface IThrottlingCache : IDictionary
diff --git a/src/Cuemon.Extensions.AspNetCore/Http/Throttling/MemoryThrottlingCache.cs b/src/Cuemon.AspNetCore/Http/Throttling/MemoryThrottlingCache.cs
similarity index 66%
rename from src/Cuemon.Extensions.AspNetCore/Http/Throttling/MemoryThrottlingCache.cs
rename to src/Cuemon.AspNetCore/Http/Throttling/MemoryThrottlingCache.cs
index 2d2bd6036..3701f381b 100644
--- a/src/Cuemon.Extensions.AspNetCore/Http/Throttling/MemoryThrottlingCache.cs
+++ b/src/Cuemon.AspNetCore/Http/Throttling/MemoryThrottlingCache.cs
@@ -1,12 +1,9 @@
using System.Collections.Concurrent;
-using Cuemon.AspNetCore.Http.Throttling;
-namespace Cuemon.Extensions.AspNetCore.Http.Throttling
+namespace Cuemon.AspNetCore.Http.Throttling
{
///
/// Provides a simple in-memory representation of the . This class cannot be inherited.
- /// Implements the .
- /// Implements the .
///
///
///
diff --git a/src/Cuemon.AspNetCore/Http/Throttling/ThrottlingSentinelMiddleware.cs b/src/Cuemon.AspNetCore/Http/Throttling/ThrottlingSentinelMiddleware.cs
index 159dce8c9..88faf2d17 100644
--- a/src/Cuemon.AspNetCore/Http/Throttling/ThrottlingSentinelMiddleware.cs
+++ b/src/Cuemon.AspNetCore/Http/Throttling/ThrottlingSentinelMiddleware.cs
@@ -1,7 +1,6 @@
using System;
using System.Threading.Tasks;
using Cuemon.AspNetCore.Http.Headers;
-using Cuemon.AspNetCore.Infrastructure;
using Cuemon.IO;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
@@ -35,25 +34,17 @@ public ThrottlingSentinelMiddleware(RequestDelegate next, Action.
///
/// The context of the current request.
- /// The dependency injected of .
+ /// The dependency injected of .
/// A task that represents the execution of this middleware.
- public override async Task InvokeAsync(HttpContext context, IThrottlingCache tc)
+ public override async Task InvokeAsync(HttpContext context, IThrottlingCache di)
{
- var exception = false;
- try
+ await Decorator.Enclose(context).InvokeThrottlerSentinelAsync(di, Options, async (message, response) =>
{
- await AspNetCoreInfrastructure.InvokeThrottlerSentinelAsync(context, tc, Options, async (message, response) =>
- {
- response.StatusCode = (int) message.StatusCode;
- Decorator.Enclose(response.Headers).TryAddOrUpdateHeaders(message.Headers);
- await Decorator.Enclose(response.Body).WriteAsync(await message.Content.ReadAsByteArrayAsync());
- });
- }
- catch (ThrottlingException)
- {
- exception = true;
- }
- if (!exception) { await Next(context).ConfigureAwait(false); }
+ response.StatusCode = (int)message.StatusCode;
+ Decorator.Enclose(response.Headers).AddOrUpdateHeaders(message.Headers);
+ await Decorator.Enclose(response.Body).WriteAsync(await message.Content.ReadAsByteArrayAsync().ConfigureAwait(false)).ConfigureAwait(false);
+ }).ConfigureAwait(false);
+ await Next(context).ConfigureAwait(false);
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore/Http/Throttling/ThrottlingSentinelOptions.cs b/src/Cuemon.AspNetCore/Http/Throttling/ThrottlingSentinelOptions.cs
index f132c457b..f3a17eec8 100644
--- a/src/Cuemon.AspNetCore/Http/Throttling/ThrottlingSentinelOptions.cs
+++ b/src/Cuemon.AspNetCore/Http/Throttling/ThrottlingSentinelOptions.cs
@@ -2,6 +2,7 @@
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
+using Cuemon.AspNetCore.Http.Headers;
using Microsoft.AspNetCore.Http;
using Microsoft.Net.Http.Headers;
@@ -35,12 +36,16 @@ public class ThrottlingSentinelOptions
/// X-RateLimit-Reset
///
/// -
+ ///
+ ///
+ ///
+ /// -
///
/// true
///
/// -
- ///
- /// ThrottlingRetryAfterHeader.DeltaSeconds
+ ///
+ ///
///
/// -
///
@@ -62,23 +67,24 @@ public class ThrottlingSentinelOptions
///
public ThrottlingSentinelOptions()
{
- RateLimitHeaderName = "X-RateLimit-Limit";
- RateLimitRemainingHeaderName = "X-RateLimit-Remaining";
- RateLimitResetHeaderName = "X-RateLimit-Reset";
+ RateLimitHeaderName = "RateLimit-Limit";
+ RateLimitRemainingHeaderName = "RateLimit-Remaining";
+ RateLimitResetHeaderName = "RateLimit-Reset";
+ RateLimitResetScope = RetryConditionScope.DeltaSeconds;
UseRetryAfterHeader = true;
- RetryAfterHeader = ThrottlingRetryAfterHeader.DeltaSeconds;
+ RetryAfterScope = RetryConditionScope.DeltaSeconds;
TooManyRequestsMessage = "Throttling rate limit quota violation. Quota limit exceeded.";
ResponseBroker = (delta, reset) =>
{
var message = new HttpResponseMessage((HttpStatusCode) StatusCodes.Status429TooManyRequests);
if (UseRetryAfterHeader)
{
- switch (RetryAfterHeader)
+ switch (RetryAfterScope)
{
- case ThrottlingRetryAfterHeader.DeltaSeconds:
+ case RetryConditionScope.DeltaSeconds:
message.Headers.Add(HeaderNames.RetryAfter, new RetryConditionHeaderValue(delta).ToString());
break;
- case ThrottlingRetryAfterHeader.HttpDate:
+ case RetryConditionScope.HttpDate:
message.Headers.Add(HeaderNames.RetryAfter, new RetryConditionHeaderValue(reset).ToString());
break;
}
@@ -130,6 +136,12 @@ public ThrottlingSentinelOptions()
/// The name of the rate limit reset HTTP header.
public string RateLimitResetHeaderName { get; set; }
+ ///
+ /// Gets or sets the preferred rate limit reset HTTP header value that conforms with RFC 7231.
+ ///
+ /// The preferred rate limit reset HTTP header value that conforms with RFC 7231.
+ public RetryConditionScope RateLimitResetScope { get; set; }
+
///
/// Gets or sets a value indicating whether to include a Retry-After HTTP header specifying how long to wait before making a new request.
///
@@ -137,9 +149,9 @@ public ThrottlingSentinelOptions()
public bool UseRetryAfterHeader { get; set; }
///
- /// Gets or sets the preferred Retry-After HTTP header value that conforms with RFC 2616.
+ /// Gets or sets the preferred Retry-After HTTP header value that conforms with RFC 7231.
///
- /// The preferred Retry-After HTTP header value that conforms with RFC 2616.
- public ThrottlingRetryAfterHeader RetryAfterHeader { get; set; }
+ /// The preferred Retry-After HTTP header value that conforms with RFC 7231.
+ public RetryConditionScope RetryAfterScope { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore/Infrastructure/AspNetCoreInfrastructure.cs b/src/Cuemon.AspNetCore/Infrastructure/AspNetCoreInfrastructure.cs
deleted file mode 100644
index b309bb34a..000000000
--- a/src/Cuemon.AspNetCore/Infrastructure/AspNetCoreInfrastructure.cs
+++ /dev/null
@@ -1,87 +0,0 @@
-using System;
-using System.Globalization;
-using System.Linq;
-using System.Net.Http;
-using System.Threading;
-using System.Threading.Tasks;
-using Cuemon.AspNetCore.Http.Headers;
-using Cuemon.AspNetCore.Http.Throttling;
-using Cuemon.Collections.Generic;
-using Microsoft.AspNetCore.Http;
-using Microsoft.Net.Http.Headers;
-
-namespace Cuemon.AspNetCore.Infrastructure
-{
- internal static class AspNetCoreInfrastructure
- {
- private static readonly SemaphoreSlim ThrottleLocker = new SemaphoreSlim(1);
-
- public static async Task InvokeUserAgentSentinelAsync(HttpContext context, UserAgentSentinelOptions options, Action transformer)
- {
- var userAgent = context.Request.Headers[HeaderNames.UserAgent].FirstOrDefault();
- if (options.RequireUserAgentHeader)
- {
- var message = options.ResponseBroker?.Invoke(userAgent);
- if (message != null)
- {
- context.Response.OnStarting(() =>
- {
- transformer?.Invoke(message, context.Response);
- return Task.CompletedTask;
- });
- throw new UserAgentException((int)message.StatusCode, await message.Content.ReadAsStringAsync().ConfigureAwait(false));
- }
- }
- }
-
- public static async Task InvokeThrottlerSentinelAsync(HttpContext context, IThrottlingCache tc, ThrottlingSentinelOptions options, Action transformer)
- {
- var utcNow = DateTime.UtcNow;
- var throttlingContext = options.ContextResolver?.Invoke(context);
- if (!string.IsNullOrWhiteSpace(throttlingContext))
- {
- try
- {
- await ThrottleLocker.WaitAsync().ConfigureAwait(false);
-
- if (!tc.TryGetValue(throttlingContext, out var tr))
- {
- tr = new ThrottleRequest(options.Quota);
- Decorator.Enclose(tc).TryAdd(throttlingContext, tr);
- }
- else
- {
- tr.Refresh();
- tr.IncrementTotal();
- }
-
- var window = new TimeRange(utcNow, tr.Expires);
- var delta = window.Duration;
- var reset = utcNow.Add(delta);
- Decorator.Enclose(context.Response.Headers).TryAddOrUpdate(options.RateLimitHeaderName, tr.Quota.RateLimit.ToString(CultureInfo.InvariantCulture));
- Decorator.Enclose(context.Response.Headers).TryAddOrUpdate(options.RateLimitRemainingHeaderName, Math.Max(tr.Quota.RateLimit - tr.Total, 0).ToString(CultureInfo.InvariantCulture));
- Decorator.Enclose(context.Response.Headers).TryAddOrUpdate(options.RateLimitResetHeaderName, Decorator.Enclose(reset).ToUnixEpochTime().ToString(CultureInfo.InvariantCulture));
- if (tr.Total > tr.Quota.RateLimit && tr.Expires > utcNow)
- {
- var message = options.ResponseBroker?.Invoke(delta, reset);
- if (message != null)
- {
- context.Response.OnStarting(() =>
- {
- transformer?.Invoke(message, context.Response);
- return Task.CompletedTask;
- });
- throw new ThrottlingException((int)message.StatusCode, await message.Content.ReadAsStringAsync().ConfigureAwait(false), tr.Quota.RateLimit, delta, reset);
- }
- }
-
- tc[throttlingContext] = tr;
- }
- finally
- {
- ThrottleLocker.Release();
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore/Properties/AssemblyInfo.cs b/src/Cuemon.AspNetCore/Properties/AssemblyInfo.cs
index af1492a49..661fc9125 100644
--- a/src/Cuemon.AspNetCore/Properties/AssemblyInfo.cs
+++ b/src/Cuemon.AspNetCore/Properties/AssemblyInfo.cs
@@ -1,6 +1,4 @@
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
+using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
-[assembly: Guid("31f1ce52-3e05-495f-8359-dd708905d7d6")]
-[assembly: InternalsVisibleTo("Cuemon.AspNetCore.Mvc, PublicKey=00240000048000009400000006020000002400005253413100040000010001002F66D8473F676F4E7B47400527D33951A774422DFFC3DF6D7F87C82E5694E9F3AA626D36BEBEA428AD5B800EFCF6CE87B73268F5A0125A7D38739D344703A1C48785AC1A45B1C27EDFDF2EB30BA2B3E3CEA92E5981C30F3A95685A680B7EBEE66F422D176CD1623019D5A05770B9BA498144B1134593BEA6F674F334CF2B90B0")]
\ No newline at end of file
+[assembly: Guid("31f1ce52-3e05-495f-8359-dd708905d7d6")]
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore/Properties/PackageReleaseNotes.txt b/src/Cuemon.AspNetCore/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..e74706340
--- /dev/null
+++ b/src/Cuemon.AspNetCore/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,23 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET Core 3.0, NET 5.0
+
+# Upgrade Steps
+- Any former extension methods of the Cuemon.AspNetCore namespace was merged into the Cuemon.Extensions.AspNetCore namespace
+
+# Breaking Changes
+- MOVED HttpExceptionDescriptor class from the Cuemon.AspNetCore.Http namespace to Cuemon.AspNetCore.Diagnostics namespace
+- REMOVED ThrottlingRetryAfterHeader enum from the Cuemon.AspNetCore.Http.Throttling namespace
+- CHANGED ThrottlingSentinelOptions class in the Cuemon.AspNetCore.Http.Throttling namespace to be more compliant with industry standards
+- RENAMED ApplicationBuilderFactory class in the Cuemon.AspNetCore.Builder namespace to MiddlewareBuilderFactory
+
+# New Features
+- ADDED IServerTiming interface in the Cuemon.AspNetCore.Diagnostics namespace that represents the Server Timing as per W3C Working Draft 28 July 2020 (https://www.w3.org/TR/2020/WD-server-timing-20200728/)
+- ADDED ServerTiming class in the Cuemon.AspNetCore.Diagnostics namespace that provides a default implementation of the IServerTiming interface
+- ADDED ServerTimingMetric class in the Cuemon.AspNetCore.Diagnostics namespace that represents a HTTP Server-Timing header field entry to communicate one metric and description for the given request-response cycle
+- ADDED RetryConditionScope enum in the Cuemon.AspNetCore.Http.Headers namespace that specifies a set of values defining what value to use with a given HTTP header in regards to a retry condition
+- ADDED CacheBusting class in the Cuemon.AspNetCore.Configuration namespace that represents a way to provide cache-busting capabilities
+- ADDED CacheBustingOptions class in the Cuemon.AspNetCore.Configuration namespace that specifies options related to CacheBusting
+- ADDED DynamicCacheBusting class in the Cuemon.AspNetCore.Configuration namespace that provides cache-busting capabilities on a duration based interval
+- ADDED DynamicCacheBustingOptions class in the Cuemon.AspNetCore.Configuration namespace that specifies options related to DynamicCacheBusting
+- ADDED ICacheBusting interface in the Cuemon.AspNetCore.Configuration namespace that is an interface to provide cache-busting capabilities
+
\ No newline at end of file
diff --git a/src/Cuemon.Core/ActionFactory.cs b/src/Cuemon.Core/ActionFactory.cs
index 3bdc44bfa..c194a33dd 100644
--- a/src/Cuemon.Core/ActionFactory.cs
+++ b/src/Cuemon.Core/ActionFactory.cs
@@ -509,7 +509,7 @@ public void ExecuteMethod()
///
/// A new that is a copy of this instance.
/// When thread safety is required this is the method to invoke.
- public ActionFactory Clone()
+ public override TemplateFactory Clone()
{
return new ActionFactory(Method, GenericArguments.Clone() as TTuple);
}
diff --git a/src/Cuemon.Core/Collections/Generic/PagedSettings.cs b/src/Cuemon.Core/Collections/Generic/PagedSettings.cs
index 30aad9b53..1d43cb114 100644
--- a/src/Cuemon.Core/Collections/Generic/PagedSettings.cs
+++ b/src/Cuemon.Core/Collections/Generic/PagedSettings.cs
@@ -1,21 +1,17 @@
-namespace Cuemon.Collections.Generic
+using System;
+
+namespace Cuemon.Collections.Generic
{
///
- /// Specifies a set of features to support on the object. This class cannot be inherited.
+ /// Specifies a set of features to support on the object.
///
- public sealed class PagedSettings
+ public class PagedSettings : IEquatable
{
- private static int DefaultPageSizeValue = 25;
-
///
/// Gets or sets the default page size of the class. Default is 25.
///
/// The default page size of the class.
- public static int DefaultPageSize
- {
- get { return DefaultPageSizeValue; }
- set { DefaultPageSizeValue = value; }
- }
+ public static int DefaultPageSize { get; set; } = 25;
#region Constructors
///
@@ -41,6 +37,31 @@ public override int GetHashCode()
return Generate.HashCode32(PageSize, PageNumber, (int)SortOrderDirection, Data.GetHashCode()) ^ Generate.HashCode32(string.Concat(SearchCriteria, SortOrderBy));
}
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ /// true if the current object is equal to the other parameter; otherwise, false.
+ public virtual bool Equals(PagedSettings other)
+ {
+ if (ReferenceEquals(null, other)) { return false; }
+ if (ReferenceEquals(this, other)) { return true; }
+ return PageSize == other.PageSize && PageNumber.Equals(other.PageNumber) && SortOrderDirection.Equals(other.SortOrderDirection) && Data.GetHashCode().Equals(other.Data.GetHashCode()) && SearchCriteria.Equals(other.SearchCriteria) && SortOrderBy.Equals(other.SortOrderBy);
+ }
+
+ ///
+ /// Determines whether the specified is equal to this instance.
+ ///
+ /// The object to compare with the current object.
+ /// true if the specified is equal to this instance; otherwise, false.
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj)) { return false; }
+ if (ReferenceEquals(this, obj)) { return true; }
+ if (obj.GetType() != this.GetType()) { return false; }
+ return Equals((PagedSettings) obj);
+ }
+
#endregion
#region Properties
diff --git a/src/Cuemon.Core/Cuemon.Core.csproj b/src/Cuemon.Core/Cuemon.Core.csproj
index 6947dc04a..8990527b2 100644
--- a/src/Cuemon.Core/Cuemon.Core.csproj
+++ b/src/Cuemon.Core/Cuemon.Core.csproj
@@ -1,37 +1,16 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
000bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon
Cuemon
Cuemon.Core
Cuemon
- The Cuemon.Core assembly is the patriarch of the Cuemon family and provides fundamental-, utility- and base-classes that define commonly-used value and reference data types, events and event handlers, interfaces, attribute, and feature rich delegates to greatly support functional programming. A great addition to the well established System namespace to make your daily operations easier to work with.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
+ The Cuemon namespace contains fundamental factories, classes and base classes that define invaluable reference and value types that greatly extends the System namespace. Abundant support for delegates and functional programming.
+ action-factory bit-unit byte-unit calculator configure configure-revert configure-exchange configurable condition options-pattern data-reader decorator delimited-string disposable finalize-disposable safe-invoke safe-invoke-async func-factory patterns reference-project clean-architecture clean-code task-action-factory task-func-factory template template-factory time-range time-unit validator guard text-encoding parser-factory security aes-cryptor cyclic-redundancy-check fowler-noll-vo-hash hash-factory hash-result hmac-message-digest hmac-secure-hash-algorithm keyed-crypto-hash keyed-crypto-algorithm message-digest non-crypto-algorithm secure-hash-algorithm unkeyed-crypto-hash
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Cuemon.Core/Data/Integrity/ChecksumBuilder.cs b/src/Cuemon.Core/Data/Integrity/ChecksumBuilder.cs
deleted file mode 100644
index 0de4f9fc3..000000000
--- a/src/Cuemon.Core/Data/Integrity/ChecksumBuilder.cs
+++ /dev/null
@@ -1,188 +0,0 @@
-using System;
-using System.Collections.Generic;
-using Cuemon.Integrity;
-using Cuemon.Security.Cryptography;
-
-namespace Cuemon.Data.Integrity
-{
- ///
- /// Provides a way to fluently represent checksum values of arbitrary data.
- ///
- public class ChecksumBuilder : IDataIntegrity, IEquatable
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public ChecksumBuilder() : this((byte[])null)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// A value containing a byte-for-byte checksum of the data this instance represents.
- /// The which need to be configured.
- public ChecksumBuilder(double checksum, Action setup = null) : this(Convertible.GetBytes(checksum), setup)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// A value containing a byte-for-byte checksum of the data this instance represents.
- /// The which need to be configured.
- public ChecksumBuilder(short checksum, Action setup = null) : this(Convertible.GetBytes(checksum), setup)
- {
- }
-
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// A value containing a byte-for-byte checksum of the data this instance represents.
- /// The which need to be configured.
- public ChecksumBuilder(string checksum, Action setup = null) : this(Generate.HashCode64(checksum), setup)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// A value containing a byte-for-byte checksum of the data this instance represents.
- /// The which need to be configured.
- public ChecksumBuilder(int checksum, Action setup = null) : this(Convertible.GetBytes(checksum), setup)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// A value containing a byte-for-byte checksum of the data this instance represents.
- /// The which need to be configured.
- public ChecksumBuilder(long checksum, Action setup = null) : this(Convertible.GetBytes(checksum), setup)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// A value containing a byte-for-byte checksum of the data this instance represents.
- /// The which need to be configured.
- public ChecksumBuilder(float checksum, Action setup = null) : this(Convertible.GetBytes(checksum), setup)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// A value containing a byte-for-byte checksum of the data this instance represents.
- /// The which need to be configured.
- public ChecksumBuilder(ushort checksum, Action setup = null) : this(Convertible.GetBytes(checksum), setup)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// A value containing a byte-for-byte checksum of the data this instance represents.
- /// The which need to be configured.
- public ChecksumBuilder(uint checksum, Action setup = null) : this(Convertible.GetBytes(checksum), setup)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// A value containing a byte-for-byte checksum of the data this instance represents.
- /// The which need to be configured.
- public ChecksumBuilder(ulong checksum, Action setup = null) : this(Convertible.GetBytes(checksum), setup)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// An array of bytes containing a checksum of the data this instance represents.
- /// The which may be configured.
- public ChecksumBuilder(byte[] checksum, Action setup = null)
- {
- var options = Patterns.Configure(setup);
- Algorithm = options.Algorithm;
- Bytes = checksum == null ? new List() : new List(checksum);
- }
-
- ///
- /// Gets the hash algorithm to use for the checksum computation.
- ///
- /// The hash algorithm to use for the checksum computation.
- public CryptoAlgorithm Algorithm { get; protected set; }
-
- ///
- /// Gets a byte array that is the result of the associated .
- ///
- /// The byte array that is the result of the associated .
- protected List Bytes { get; set; }
-
- ///
- /// Gets a containing a computed hash value of the data this instance represents.
- ///
- /// A containing a computed hash value of the data this instance represents.
- public HashResult Checksum => ComputedHash ?? (ComputedHash = HashFactory.CreateCrypto(Algorithm).ComputeHash(Bytes.ToArray()));
-
- ///
- /// Gets or sets the computed checksum of .
- ///
- /// The computed checksum of .
- protected HashResult ComputedHash { get; set; }
-
- ///
- /// Provides a way to append additional checksum to the representation of this instance.
- ///
- /// A containing a checksum of the additional data this instance must represent.
- public void AppendChecksum(byte[] checksum)
- {
- ComputedHash = null;
- Bytes.AddRange(checksum);
- }
-
- ///
- /// Returns a hash code for this instance.
- ///
- /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
- public override int GetHashCode()
- {
- return Generate.HashCode32(Checksum.ToHexadecimalString());
- }
-
- ///
- /// Determines whether the specified is equal to this instance.
- ///
- /// The to compare with the current .
- /// true if the specified is equal to this instance; otherwise, false.
- public override bool Equals(object obj)
- {
- if (!(obj is ChecksumBuilder builder)) { return false; }
- return Equals(builder);
- }
-
- ///
- /// Indicates whether the current object is equal to another object of the same type.
- ///
- /// An object to compare with this object.
- /// true if the current object is equal to the other parameter; otherwise, false.
- public virtual bool Equals(ChecksumBuilder other)
- {
- if (other == null) { return false; }
- return Checksum.GetHashCode() == other.Checksum.GetHashCode();
- }
-
- ///
- /// Converts the the of this instance to its equivalent hexadecimal representation.
- ///
- /// A hexadecimal representation of this instance.
- public override string ToString()
- {
- return Checksum.ToHexadecimalString();
- }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Data/Integrity/ChecksumBuilderOptions.cs b/src/Cuemon.Core/Data/Integrity/ChecksumBuilderOptions.cs
deleted file mode 100644
index eb787a2de..000000000
--- a/src/Cuemon.Core/Data/Integrity/ChecksumBuilderOptions.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-using Cuemon.Data.Integrity;
-using Cuemon.Security.Cryptography;
-
-namespace Cuemon.Integrity
-{
- ///
- /// Configuration options for .
- ///
- public class ChecksumBuilderOptions
- {
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The following table shows the initial property values for an instance of .
- ///
- ///
- /// Property
- /// Initial Value
- ///
- /// -
- ///
- ///
- ///
- ///
- ///
- public ChecksumBuilderOptions()
- {
- Algorithm = CryptoAlgorithm.Md5;
- }
-
- ///
- /// Gets or sets the hash algorithm to use for the checksum computation.
- ///
- /// The hash algorithm to use for the checksum computation.
- public CryptoAlgorithm Algorithm { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.Core/DelimitedString.cs b/src/Cuemon.Core/DelimitedString.cs
index fc3875444..658854431 100644
--- a/src/Cuemon.Core/DelimitedString.cs
+++ b/src/Cuemon.Core/DelimitedString.cs
@@ -2,14 +2,13 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
-using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace Cuemon
{
///
- /// Provides a set of static methods to break a delimited string into substrings.
+ /// Provides a set of static methods to convert a sequence into a delimited string and break a delimited string into substrings.
///
public static class DelimitedString
{
@@ -46,7 +45,7 @@ public static string Create(IEnumerable source, ActionThe which may be configured.
/// A that contain the substrings of delimited by a and optionally surrounded within .
///
- /// This method was inspired by two articles on StackOverflow @ http://stackoverflow.com/questions/2807536/split-string-in-c-sharp and https://stackoverflow.com/questions/3776458/split-a-comma-separated-string-with-both-quoted-and-unquoted-strings.
+ /// This method was inspired by two articles on StackOverflow @ http://stackoverflow.com/questions/2807536/split-string-in-c-sharp, https://stackoverflow.com/questions/3776458/split-a-comma-separated-string-with-both-quoted-and-unquoted-strings and https://stackoverflow.com/questions/6542996/how-to-split-csv-whose-columns-may-contain.
/// The default implementation conforms with the RFC-4180 standard.
///
///
@@ -62,13 +61,13 @@ public static string[] Split(string value, Action setup
var key = string.Concat(delimiter, "<-dq->", qualifier);
if (!CompiledSplitExpressions.TryGetValue(key, out var compiledSplit))
{
- compiledSplit = new Regex(string.Format(CultureInfo.InvariantCulture, "(?:^|{0})({1}(?:[^{1}]+|{1}{1})*{1}|[^{0}]*)", Regex.Escape(delimiter), Regex.Escape(qualifier)), RegexOptions.IgnoreCase | RegexOptions.Compiled, TimeSpan.FromSeconds(2));
+ compiledSplit = new Regex(string.Format(CultureInfo.InvariantCulture, "{0}(?=(?:[^{1}]*{1}[^{1}]*{1})*(?![^{1}]*{1}))", delimiter, qualifier), RegexOptions.IgnoreCase | RegexOptions.Compiled, TimeSpan.FromSeconds(2));
CompiledSplitExpressions.TryAdd(key, compiledSplit);
}
try
{
- return compiledSplit.Matches(value).Cast().Where(m => m.Length > 0).Select(m => m.Value.TrimStart(delimiter.ToCharArray())).ToArray();
+ return compiledSplit.Split(value);
}
catch (RegexMatchTimeoutException)
{
diff --git a/src/Cuemon.Core/Disposable.cs b/src/Cuemon.Core/Disposable.cs
index aa9ae86dd..49c800546 100644
--- a/src/Cuemon.Core/Disposable.cs
+++ b/src/Cuemon.Core/Disposable.cs
@@ -1,6 +1,4 @@
using System;
-using System.Threading;
-using System.Threading.Tasks;
namespace Cuemon
{
@@ -11,340 +9,6 @@ namespace Cuemon
///
public abstract class Disposable : IDisposable
{
- ///
- /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
- ///
- /// The type of the return value of the function delegate .
- /// The function delegate that initializes an object implementing the interface.
- /// The function delegate that is used to ensure that operations performed on abides CA2000.
- /// The delegate that will handle any exceptions might thrown by .
- /// The return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
- public static TResult SafeInvoke(Func initializer, Func tester, Action catcher = null) where TResult : class, IDisposable
- {
- Validator.ThrowIfNull(initializer, nameof(initializer));
- Validator.ThrowIfNull(tester, nameof(tester));
- var f1 = FuncFactory.Create(tester, default);
- var f2 = ActionFactory.Create(catcher, default);
- return SafeInvokeCore(f1, initializer, f2);
- }
-
- ///
- /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
- ///
- /// The type of the parameter of the function delegate and delegate .
- /// The type of the return value of the function delegate .
- /// The function delegate that initializes an object implementing the interface.
- /// The function delegate that is used to ensure that operations performed on abides CA2000.
- /// The parameter of the function delegate and delegate .
- /// The delegate that will handle any exceptions might thrown by .
- /// The return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
- public static TResult SafeInvoke(Func initializer, Func tester, T arg, Action catcher = null) where TResult : class, IDisposable
- {
- Validator.ThrowIfNull(initializer, nameof(initializer));
- Validator.ThrowIfNull(tester, nameof(tester));
- var f1 = FuncFactory.Create(tester, default, arg);
- var f2 = ActionFactory.Create(catcher, default, arg);
- return SafeInvokeCore(f1, initializer, f2);
- }
-
- ///
- /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
- ///
- /// The type of the first parameter of the function delegate and delegate .
- /// The type of the second parameter of the function delegate and delegate .
- /// The type of the return value of the function delegate .
- /// The function delegate that initializes an object implementing the interface.
- /// The function delegate that is used to ensure that operations performed on abides CA2000.
- /// The first parameter of the function delegate and delegate .
- /// The second parameter of the function delegate and delegate .
- /// The delegate that will handle any exceptions might thrown by .
- /// The return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
- public static TResult SafeInvoke(Func initializer, Func tester, T1 arg1, T2 arg2, Action catcher = null) where TResult : class, IDisposable
- {
- Validator.ThrowIfNull(initializer, nameof(initializer));
- Validator.ThrowIfNull(tester, nameof(tester));
- var f1 = FuncFactory.Create(tester, default, arg1, arg2);
- var f2 = ActionFactory.Create(catcher, default, arg1, arg2);
- return SafeInvokeCore(f1, initializer, f2);
- }
-
- ///
- /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
- ///
- /// The type of the first parameter of the function delegate and delegate .
- /// The type of the second parameter of the function delegate and delegate .
- /// The type of the third parameter of the function delegate and delegate .
- /// The type of the return value of the function delegate .
- /// The function delegate that initializes an object implementing the interface.
- /// The function delegate that is used to ensure that operations performed on abides CA2000.
- /// The first parameter of the function delegate and delegate .
- /// The second parameter of the function delegate and delegate .
- /// The third parameter of the function delegate and delegate .
- /// The delegate that will handle any exceptions might thrown by .
- /// The return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
- public static TResult SafeInvoke(Func initializer, Func tester, T1 arg1, T2 arg2, T3 arg3, Action catcher = null) where TResult : class, IDisposable
- {
- Validator.ThrowIfNull(initializer, nameof(initializer));
- Validator.ThrowIfNull(tester, nameof(tester));
- var f1 = FuncFactory.Create(tester, default, arg1, arg2, arg3);
- var f2 = ActionFactory.Create(catcher, default, arg1, arg2, arg3);
- return SafeInvokeCore(f1, initializer, f2);
- }
-
- ///
- /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
- ///
- /// The type of the first parameter of the function delegate and delegate .
- /// The type of the second parameter of the function delegate and delegate .
- /// The type of the third parameter of the function delegate and delegate .
- /// The type of the fourth parameter of the function delegate and delegate .
- /// The type of the return value of the function delegate .
- /// The function delegate that initializes an object implementing the interface.
- /// The function delegate that is used to ensure that operations performed on abides CA2000.
- /// The first parameter of the function delegate and delegate .
- /// The second parameter of the function delegate and delegate .
- /// The third parameter of the function delegate and delegate .
- /// The fourth parameter of the function delegate and delegate .
- /// The delegate that will handle any exceptions might thrown by .
- /// The return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
- public static TResult SafeInvoke(Func initializer, Func tester, T1 arg1, T2 arg2, T3 arg3, T4 arg4, Action catcher = null) where TResult : class, IDisposable
- {
- Validator.ThrowIfNull(initializer, nameof(initializer));
- Validator.ThrowIfNull(tester, nameof(tester));
- var f1 = FuncFactory.Create(tester, default, arg1, arg2, arg3, arg4);
- var f2 = ActionFactory.Create(catcher, default, arg1, arg2, arg3, arg4);
- return SafeInvokeCore(f1, initializer, f2);
- }
-
- ///
- /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
- ///
- /// The type of the first parameter of the function delegate and delegate .
- /// The type of the second parameter of the function delegate and delegate .
- /// The type of the third parameter of the function delegate and delegate .
- /// The type of the fourth parameter of the function delegate and delegate .
- /// The type of the fifth parameter of the function delegate and delegate .
- /// The type of the return value of the function delegate .
- /// The function delegate that initializes an object implementing the interface.
- /// The function delegate that is used to ensure that operations performed on abides CA2000.
- /// The first parameter of the function delegate and delegate .
- /// The second parameter of the function delegate and delegate .
- /// The third parameter of the function delegate and delegate .
- /// The fourth parameter of the function delegate and delegate .
- /// The fifth parameter of the function delegate and delegate .
- /// The delegate that will handle any exceptions might thrown by .
- /// The return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
- public static TResult SafeInvoke(Func initializer, Func tester, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, Action catcher = null) where TResult : class, IDisposable
- {
- Validator.ThrowIfNull(initializer, nameof(initializer));
- Validator.ThrowIfNull(tester, nameof(tester));
- var f1 = FuncFactory.Create(tester, default, arg1, arg2, arg3, arg4, arg5);
- var f2 = ActionFactory.Create(catcher, default, arg1, arg2, arg3, arg4, arg5);
- return SafeInvokeCore(f1, initializer, f2);
- }
-
- ///
- /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
- ///
- /// The type of the return value of the function delegate .
- /// The function delegate that initializes an object implementing the interface.
- /// The function delegate that is used to ensure that operations performed on abides CA2000.
- /// The token to monitor for cancellation requests. The default value is .
- /// The function delegate that will handle any exceptions might thrown by .
- /// A task that represents the asynchronous operation. The task result contains the return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
- public static Task SafeInvokeAsync(Func initializer, Func> tester, CancellationToken ct = default, Func catcher = null) where TResult : class, IDisposable
- {
- Validator.ThrowIfNull(initializer, nameof(initializer));
- Validator.ThrowIfNull(tester, nameof(tester));
- var f1 = TaskFuncFactory.Create(tester, default);
- var f2 = TaskActionFactory.Create(catcher, default);
- return SafeInvokeAsyncCore(f1, initializer, f2, ct);
- }
-
- ///
- /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
- ///
- /// The type of the parameter of the function delegate and delegate .
- /// The type of the return value of the function delegate .
- /// The function delegate that initializes an object implementing the interface.
- /// The function delegate that is used to ensure that operations performed on abides CA2000.
- /// The parameter of the function delegate and delegate .
- /// The token to monitor for cancellation requests. The default value is .
- /// The function delegate that will handle any exceptions might thrown by .
- /// A task that represents the asynchronous operation. The task result contains the return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
- public static Task SafeInvokeAsync(Func initializer, Func> tester, T arg, CancellationToken ct = default, Func catcher = null) where TResult : class, IDisposable
- {
- Validator.ThrowIfNull(initializer, nameof(initializer));
- Validator.ThrowIfNull(tester, nameof(tester));
- var f1 = TaskFuncFactory.Create(tester, default, arg);
- var f2 = TaskActionFactory.Create(catcher, default, arg);
- return SafeInvokeAsyncCore(f1, initializer, f2, ct);
- }
-
- ///
- /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
- ///
- /// The type of the first parameter of the function delegate and delegate .
- /// The type of the second parameter of the function delegate and delegate .
- /// The type of the return value of the function delegate .
- /// The function delegate that initializes an object implementing the interface.
- /// The function delegate that is used to ensure that operations performed on abides CA2000.
- /// The first parameter of the function delegate and delegate .
- /// The second parameter of the function delegate and delegate .
- /// The token to monitor for cancellation requests. The default value is .
- /// The function delegate that will handle any exceptions might thrown by .
- /// A task that represents the asynchronous operation. The task result contains the return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
- public static Task SafeInvokeAsync(Func initializer, Func> tester, T1 arg1, T2 arg2, CancellationToken ct = default, Func catcher = null) where TResult : class, IDisposable
- {
- Validator.ThrowIfNull(initializer, nameof(initializer));
- Validator.ThrowIfNull(tester, nameof(tester));
- var f1 = TaskFuncFactory.Create(tester, default, arg1, arg2);
- var f2 = TaskActionFactory.Create(catcher, default, arg1, arg2);
- return SafeInvokeAsyncCore(f1, initializer, f2, ct);
- }
-
- ///
- /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
- ///
- /// The type of the first parameter of the function delegate and delegate .
- /// The type of the second parameter of the function delegate and delegate .
- /// The type of the third parameter of the function delegate and delegate .
- /// The type of the return value of the function delegate .
- /// The function delegate that initializes an object implementing the interface.
- /// The function delegate that is used to ensure that operations performed on abides CA2000.
- /// The first parameter of the function delegate and delegate .
- /// The second parameter of the function delegate and delegate .
- /// The third parameter of the function delegate and delegate .
- /// The token to monitor for cancellation requests. The default value is .
- /// The function delegate that will handle any exceptions might thrown by .
- /// A task that represents the asynchronous operation. The task result contains the return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
- public static Task SafeInvokeAsync(Func initializer, Func> tester, T1 arg1, T2 arg2, T3 arg3, CancellationToken ct = default, Func catcher = null) where TResult : class, IDisposable
- {
- Validator.ThrowIfNull(initializer, nameof(initializer));
- Validator.ThrowIfNull(tester, nameof(tester));
- var f1 = TaskFuncFactory.Create(tester, default, arg1, arg2, arg3);
- var f2 = TaskActionFactory.Create(catcher, default, arg1, arg2, arg3);
- return SafeInvokeAsyncCore(f1, initializer, f2, ct);
- }
-
- ///
- /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
- ///
- /// The type of the first parameter of the function delegate and delegate .
- /// The type of the second parameter of the function delegate and delegate .
- /// The type of the third parameter of the function delegate and delegate .
- /// The type of the fourth parameter of the function delegate and delegate .
- /// The type of the return value of the function delegate .
- /// The function delegate that initializes an object implementing the interface.
- /// The function delegate that is used to ensure that operations performed on abides CA2000.
- /// The first parameter of the function delegate and delegate .
- /// The second parameter of the function delegate and delegate .
- /// The third parameter of the function delegate and delegate .
- /// The fourth parameter of the function delegate and delegate .
- /// The token to monitor for cancellation requests. The default value is .
- /// The function delegate that will handle any exceptions might thrown by .
- /// A task that represents the asynchronous operation. The task result contains the return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
- public static Task SafeInvokeAsync(Func initializer, Func> tester, T1 arg1, T2 arg2, T3 arg3, T4 arg4, CancellationToken ct = default, Func catcher = null) where TResult : class, IDisposable
- {
- Validator.ThrowIfNull(initializer, nameof(initializer));
- Validator.ThrowIfNull(tester, nameof(tester));
- var f1 = TaskFuncFactory.Create(tester, default, arg1, arg2, arg3, arg4);
- var f2 = TaskActionFactory.Create(catcher, default, arg1, arg2, arg3, arg4);
- return SafeInvokeAsyncCore(f1, initializer, f2, ct);
- }
-
- ///
- /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
- ///
- /// The type of the first parameter of the function delegate and delegate .
- /// The type of the second parameter of the function delegate and delegate .
- /// The type of the third parameter of the function delegate and delegate .
- /// The type of the fourth parameter of the function delegate and delegate .
- /// The type of the fifth parameter of the function delegate and delegate .
- /// The type of the return value of the function delegate .
- /// The function delegate that initializes an object implementing the interface.
- /// The function delegate that is used to ensure that operations performed on abides CA2000.
- /// The first parameter of the function delegate and delegate .
- /// The second parameter of the function delegate and delegate .
- /// The third parameter of the function delegate and delegate .
- /// The fourth parameter of the function delegate and delegate .
- /// The fifth parameter of the function delegate and delegate .
- /// The token to monitor for cancellation requests. The default value is .
- /// The function delegate that will handle any exceptions might thrown by .
- /// A task that represents the asynchronous operation. The task result contains the return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
- public static Task SafeInvokeAsync(Func initializer, Func> tester, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, CancellationToken ct = default, Func catcher = null) where TResult : class, IDisposable
- {
- Validator.ThrowIfNull(initializer, nameof(initializer));
- Validator.ThrowIfNull(tester, nameof(tester));
- var f1 = TaskFuncFactory.Create(tester, default, arg1, arg2, arg3, arg4, arg5);
- var f2 = TaskActionFactory.Create(catcher, default, arg1, arg2, arg3, arg4, arg5);
- return SafeInvokeAsyncCore(f1, initializer, f2, ct);
- }
-
- private static TResult SafeInvokeCore(FuncFactory testerFactory, Func initializer, ActionFactory catcherFactory)
- where TResult : class, IDisposable
- where TTester : Template
- where TCatcher : Template
- {
- TResult result = null;
- try
- {
- testerFactory.GenericArguments.Arg1 = initializer();
- testerFactory.GenericArguments.Arg1 = testerFactory.ExecuteMethod();
- result = testerFactory.GenericArguments.Arg1;
- testerFactory.GenericArguments.Arg1 = null;
- }
- catch (Exception e)
- {
- if (!catcherFactory.HasDelegate)
- {
- throw;
- }
- else
- {
- catcherFactory.GenericArguments.Arg1 = e;
- catcherFactory.ExecuteMethod();
- }
- }
- finally
- {
- testerFactory.GenericArguments.Arg1?.Dispose();
- }
- return result;
- }
-
- private static async Task SafeInvokeAsyncCore(TaskFuncFactory testerFactory, Func initializer, TaskActionFactory catcherFactory, CancellationToken ct)
- where TResult : class, IDisposable
- where TTester : Template
- where TCatcher : Template
- {
- TResult result = null;
- try
- {
- testerFactory.GenericArguments.Arg1 = initializer();
- testerFactory.GenericArguments.Arg1 = await testerFactory.ExecuteMethodAsync(ct).ConfigureAwait(false);
- result = testerFactory.GenericArguments.Arg1;
- testerFactory.GenericArguments.Arg1 = null;
- }
- catch (Exception e)
- {
- if (!catcherFactory.HasDelegate)
- {
- throw;
- }
- else
- {
- catcherFactory.GenericArguments.Arg1 = e;
- await catcherFactory.ExecuteMethodAsync(ct).ConfigureAwait(false);
- }
- }
- finally
- {
- testerFactory.GenericArguments.Arg1?.Dispose();
- }
- return result;
- }
-
///
/// Gets a value indicating whether this object is disposed.
///
diff --git a/src/Cuemon.Core/DisposableOptions.cs b/src/Cuemon.Core/DisposableOptions.cs
index f8020e315..4dfba8c99 100644
--- a/src/Cuemon.Core/DisposableOptions.cs
+++ b/src/Cuemon.Core/DisposableOptions.cs
@@ -1,12 +1,11 @@
using System;
-using Cuemon.Threading;
namespace Cuemon
{
///
/// Configuration options for .
///
- public class DisposableOptions : AsyncOptions
+ public class DisposableOptions
{
///
/// Initializes a new instance of the class.
diff --git a/src/Cuemon.Core/ExceptionInsights.cs b/src/Cuemon.Core/ExceptionInsights.cs
index 759f4bf53..32f0e6b3e 100644
--- a/src/Cuemon.Core/ExceptionInsights.cs
+++ b/src/Cuemon.Core/ExceptionInsights.cs
@@ -56,7 +56,7 @@ public static T Embed(T exception, MethodBase thrower, object[] runtimeParame
{
var rp = DelimitedString.Create(MethodDescriptor.MergeParameters(descriptor, runtimeParameters), o =>
{
- o.StringConverter = pair => FormattableString.Invariant($"{pair.Key}={pair.Value}");
+ o.StringConverter = pair => FormattableString.Invariant($"{pair.Key}={pair.Value ?? "null"}");
o.Delimiter = FormattableString.Invariant($"{Alphanumeric.NewLine}");
});
builder.Append(Convert.ToBase64String(Convertible.GetBytes(FormattableString.Invariant($"{rp}"))));
@@ -72,6 +72,13 @@ public static T Embed(T exception, MethodBase thrower, object[] runtimeParame
builder.Append(".");
builder.Append(empty);
}
+ EmbedSystemSnapshot(builder, snapshot, empty);
+ if (exception.Data[Key] == null) { exception.Data.Add(Key, builder.ToString()); }
+ return exception;
+ }
+
+ private static void EmbedSystemSnapshot(StringBuilder builder, SystemSnapshot snapshot, string empty)
+ {
builder.Append(".");
if (snapshot.HasFlag(SystemSnapshot.CaptureThreadInfo))
{
@@ -102,8 +109,6 @@ public static T Embed(T exception, MethodBase thrower, object[] runtimeParame
{
builder.Append(empty);
}
- if (exception.Data[Key] == null) { exception.Data.Add(Key, builder.ToString()); }
- return exception;
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Extensions/ByteArrayDecoratorExtensions.cs b/src/Cuemon.Core/Extensions/ByteArrayDecoratorExtensions.cs
index af38a2f93..894b279b5 100644
--- a/src/Cuemon.Core/Extensions/ByteArrayDecoratorExtensions.cs
+++ b/src/Cuemon.Core/Extensions/ByteArrayDecoratorExtensions.cs
@@ -37,7 +37,7 @@ public static string ToEncodedString(this IDecorator decorator, Action decorator)
{
Validator.ThrowIfNull(decorator, nameof(decorator));
- return Disposable.SafeInvoke(() => new MemoryStream(decorator.Inner.Length), ms =>
+ return Patterns.SafeInvoke(() => new MemoryStream(decorator.Inner.Length), ms =>
{
ms.Write(decorator.Inner, 0, decorator.Inner.Length);
ms.Position = 0;
@@ -57,7 +57,7 @@ public static Stream ToStream(this IDecorator decorator)
public static Task ToStreamAsync(this IDecorator decorator, CancellationToken ct = default)
{
Validator.ThrowIfNull(decorator, nameof(decorator));
- return Disposable.SafeInvokeAsync(() => new MemoryStream(decorator.Inner.Length), async (ms, cti) =>
+ return Patterns.SafeInvokeAsync(() => new MemoryStream(decorator.Inner.Length), async (ms, cti) =>
{
await ms.WriteAsync(decorator.Inner, 0, decorator.Inner.Length, cti).ConfigureAwait(false);
ms.Position = 0;
diff --git a/src/Cuemon.Core/Extensions/Collections/Generic/DictionaryDecoratorExtensions.cs b/src/Cuemon.Core/Extensions/Collections/Generic/DictionaryDecoratorExtensions.cs
index 3c29af769..6ed5b2eb6 100644
--- a/src/Cuemon.Core/Extensions/Collections/Generic/DictionaryDecoratorExtensions.cs
+++ b/src/Cuemon.Core/Extensions/Collections/Generic/DictionaryDecoratorExtensions.cs
@@ -135,11 +135,11 @@ public static bool TryAdd(this IDecorator cannot be null -or-
/// cannot be null.
///
- public static bool TryAddOrUpdate(this IDecorator> decorator, TKey key, TValue value)
+ public static void AddOrUpdate(this IDecorator> decorator, TKey key, TValue value)
{
Validator.ThrowIfNull(decorator, nameof(decorator));
Validator.ThrowIfNull(key, nameof(key));
- return decorator.Inner.ContainsKey(key) ? Patterns.TryInvoke(() => { decorator.Inner[key] = value; }) : TryAdd(decorator, key, value);
+ Condition.FlipFlop(decorator.Inner.ContainsKey(key), () => Patterns.TryInvoke(() => { decorator.Inner[key] = value; }), () => TryAdd(decorator, key, value));
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Extensions/IO/StreamDecoratorExtensions.cs b/src/Cuemon.Core/Extensions/IO/StreamDecoratorExtensions.cs
index 5586a15c4..1e23c432f 100644
--- a/src/Cuemon.Core/Extensions/IO/StreamDecoratorExtensions.cs
+++ b/src/Cuemon.Core/Extensions/IO/StreamDecoratorExtensions.cs
@@ -1,162 +1,16 @@
using System;
-using System.ComponentModel;
using System.IO;
-using System.Threading;
-using System.Threading.Tasks;
-using Cuemon.Text;
namespace Cuemon.IO
{
///
/// Extension methods for the class tailored to adhere the decorator pattern.
+ /// This API supports the product infrastructure and is not intended to be used directly from your code.
///
///
///
public static class StreamDecoratorExtensions
{
- ///
- /// Converts the enclosed of the specified to a .
- ///
- /// The to extend.
- /// The which may be configured.
- /// A containing the result of the enclosed of the specified .
- /// will be initialized with and .
- ///
- /// cannot be null.
- ///
- ///
- /// was initialized with an invalid .
- ///
- public static string ToEncodedString(this IDecorator decorator, Action setup = null)
- {
- Validator.ThrowIfNull(decorator, nameof(decorator));
- var options = Patterns.Configure(setup);
- if (options.Encoding.Equals(EncodingOptions.DefaultEncoding)) { options.Encoding = ByteOrderMark.DetectEncodingOrDefault(decorator.Inner, options.Encoding); }
- if (options.Preamble < PreambleSequence.Keep || options.Preamble > PreambleSequence.Remove) { throw new InvalidEnumArgumentException(nameof(setup), (int)options.Preamble, typeof(PreambleSequence)); }
-
- var bytes = Decorator.Enclose(decorator.Inner).ToByteArray(o =>
- {
- o.BufferSize = options.BufferSize;
- o.LeaveOpen = options.LeaveOpen;
- });
- return Convertible.ToString(bytes, o =>
- {
- o.Encoding = options.Encoding;
- o.Preamble = options.Preamble;
- });
- }
-
- ///
- /// Converts the enclosed of the specified to a .
- ///
- /// The to extend.
- /// The which may be configured.
- /// A task that represents the asynchronous operation. The task result contains a containing the result of the enclosed of the specified .
- /// will be initialized with and .
- ///
- /// cannot be null.
- ///
- ///
- /// was initialized with an invalid .
- ///
- public static Task ToEncodedStringAsync(this IDecorator decorator, Action setup = null)
- {
- Validator.ThrowIfNull(decorator, nameof(decorator));
- var options = Patterns.Configure(setup);
- if (options.Encoding.Equals(EncodingOptions.DefaultEncoding)) { options.Encoding = ByteOrderMark.DetectEncodingOrDefault(decorator.Inner, options.Encoding); }
- if (options.Preamble < PreambleSequence.Keep || options.Preamble > PreambleSequence.Remove) { throw new InvalidEnumArgumentException(nameof(setup), (int)options.Preamble, typeof(PreambleSequence)); }
- return ToEncodedStringAsyncCore(decorator, options);
- }
-
- private static async Task ToEncodedStringAsyncCore(this IDecorator decorator, StreamReaderOptions options)
- {
- var bytes = await Decorator.Enclose(decorator.Inner).ToByteArrayAsync(o =>
- {
- o.BufferSize = options.BufferSize;
- o.LeaveOpen = options.LeaveOpen;
- o.CancellationToken = options.CancellationToken;
- }).ConfigureAwait(false);
- return Convertible.ToString(bytes, o =>
- {
- o.Encoding = options.Encoding;
- o.Preamble = options.Preamble;
- });
- }
-
- ///
- /// Converts the enclosed of the specified to its equivalent representation.
- ///
- /// The to extend.
- /// The which may be configured.
- /// A that is equivalent to the enclosed of the specified .
- ///
- /// cannot be null.
- ///
- ///
- /// The enclosed of cannot be read from.
- ///
- public static byte[] ToByteArray(this IDecorator decorator, Action setup = null)
- {
- Validator.ThrowIfNull(decorator, nameof(decorator));
- Validator.ThrowIfFalse(decorator.Inner.CanRead, nameof(decorator.Inner), "Stream cannot be read from.");
- var options = Patterns.Configure(setup);
- try
- {
- if (decorator.Inner is MemoryStream s) { return s.ToArray(); }
- using (var memoryStream = new MemoryStream(new byte[decorator.Inner.Length]))
- {
- var oldPosition = decorator.Inner.Position;
- if (decorator.Inner.CanSeek) { decorator.Inner.Position = 0; }
- decorator.Inner.CopyTo(memoryStream, options.BufferSize);
- if (decorator.Inner.CanSeek) { decorator.Inner.Position = oldPosition; }
- return memoryStream.ToArray();
- }
- }
- finally
- {
- if (!options.LeaveOpen) { decorator.Inner.Dispose(); }
- }
- }
-
- ///
- /// Converts the enclosed of the specified to its equivalent representation.
- ///
- /// The to extend.
- /// The which may be configured.
- /// A task that represents the asynchronous operation. The task result contains a that is equivalent to the enclosed of the specified .
- ///
- /// cannot be null.
- ///
- ///
- /// The enclosed of cannot be read from.
- ///
- public static Task ToByteArrayAsync(this IDecorator decorator, Action setup = null)
- {
- Validator.ThrowIfNull(decorator, nameof(decorator));
- Validator.ThrowIfFalse(decorator.Inner.CanRead, nameof(decorator.Inner), "Stream cannot be read from.");
- return ToByteArrayAsyncCore(decorator, Patterns.Configure(setup));
- }
-
- private static async Task ToByteArrayAsyncCore(this IDecorator decorator, StreamCopyOptions options)
- {
- try
- {
- if (decorator.Inner is MemoryStream s) { return s.ToArray(); }
- using (var memoryStream = new MemoryStream(new byte[decorator.Inner.Length]))
- {
- var oldPosition = decorator.Inner.Position;
- if (decorator.Inner.CanSeek) { decorator.Inner.Position = 0; }
- await decorator.Inner.CopyToAsync(memoryStream, options.BufferSize, options.CancellationToken).ConfigureAwait(false);
- if (decorator.Inner.CanSeek) { decorator.Inner.Position = oldPosition; }
- return memoryStream.ToArray();
- }
- }
- finally
- {
- if (!options.LeaveOpen) { decorator.Inner.Dispose(); }
- }
- }
-
///
/// Reads the bytes from the enclosed of the specified and writes them to the .
///
@@ -186,32 +40,49 @@ public static void CopyStream(this IDecorator decorator, Stream destinat
}
///
- /// Asynchronously reads the bytes from the enclosed of the specified and writes them to the .
+ /// Converts the enclosed of the specified to its equivalent representation. Not intended to be used directly from your code.
///
/// The to extend.
- /// The to which the contents of the current stream will be copied.
/// The size of the buffer. This value must be greater than zero. The default size is 81920.
- /// The token to monitor for cancellation requests. The default value is .
- /// if true, the enclosed of the specified will temporarily have its position changed to 0; otherwise the position is left untouched.
+ /// if true, the object is being left open; otherwise it is being closed and disposed.
///
/// cannot be null.
///
- public static async Task CopyStreamAsync(this IDecorator decorator, Stream destination, int bufferSize = 81920, CancellationToken ct = default, bool changePosition = true)
+ public static byte[] InvokeToByteArray(this IDecorator decorator, int bufferSize = 81920, bool leaveOpen = false)
{
Validator.ThrowIfNull(decorator, nameof(decorator));
- var source = decorator.Inner;
- long lastPosition = 0;
- if (changePosition && source.CanSeek)
+ Validator.ThrowIfFalse(decorator.Inner.CanRead, nameof(decorator.Inner), "Stream cannot be read from.");
+ try
{
- lastPosition = source.Position;
- if (source.CanSeek) { source.Position = 0; }
- }
+ if (decorator.Inner is MemoryStream s)
+ {
+ return s.ToArray();
+ }
+
+ using (var memoryStream = new MemoryStream(new byte[decorator.Inner.Length]))
+ {
+ var oldPosition = decorator.Inner.Position;
+ if (decorator.Inner.CanSeek)
+ {
+ decorator.Inner.Position = 0;
+ }
- await source.CopyToAsync(destination, bufferSize, ct).ConfigureAwait(false);
- await destination.FlushAsync(ct).ConfigureAwait(false);
+ decorator.Inner.CopyTo(memoryStream, bufferSize);
+ if (decorator.Inner.CanSeek)
+ {
+ decorator.Inner.Position = oldPosition;
+ }
- if (changePosition && source.CanSeek) { source.Position = lastPosition; }
- if (changePosition && destination.CanSeek) { destination.Position = 0; }
+ return memoryStream.ToArray();
+ }
+ }
+ finally
+ {
+ if (!leaveOpen)
+ {
+ decorator.Inner.Dispose();
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Extensions/Reflection/AssemblyDecoratorExtensions.cs b/src/Cuemon.Core/Extensions/Reflection/AssemblyDecoratorExtensions.cs
index 4f69f4335..8017960e4 100644
--- a/src/Cuemon.Core/Extensions/Reflection/AssemblyDecoratorExtensions.cs
+++ b/src/Cuemon.Core/Extensions/Reflection/AssemblyDecoratorExtensions.cs
@@ -62,47 +62,47 @@ public static IEnumerable GetTypes(this IDecorator decorator, st
}
///
- /// Returns a that represents the of the underlying of the .
+ /// Returns a that represents the of the underlying of the .
///
/// The to extend.
- /// A that represents the underlying of the .
+ /// A that represents the underlying of the .
///
/// cannot be null.
///
- public static Version GetAssemblyVersion(this IDecorator decorator)
+ public static VersionResult GetAssemblyVersion(this IDecorator decorator)
{
Validator.ThrowIfNull(decorator, nameof(decorator));
- return decorator.Inner.GetName().Version;
+ return new VersionResult(decorator.Inner.GetName().Version);
}
///
- /// Returns a that represents the of the underlying of the .
+ /// Returns a that represents the of the underlying of the .
///
/// The to extend.
- /// A that represents the file version of the underlying of the ; null if no could be retrieved.
+ /// A that represents the file version of the underlying of the ; null if no could be retrieved.
///
/// cannot be null.
///
- public static Version GetFileVersion(this IDecorator decorator)
+ public static VersionResult GetFileVersion(this IDecorator decorator)
{
Validator.ThrowIfNull(decorator, nameof(decorator));
var version = decorator.Inner.GetCustomAttribute();
- return version == null ? null : new Version(version.Version);
+ return new VersionResult(version.Version);
}
///
- /// Returns a that represents the of the underlying of the .
+ /// Returns a that represents the of the underlying of the .
///
/// The to extend.
- /// A that represents the product version of the underlying of the ; null if no could be retrieved.
+ /// A that represents the product version of the underlying of the ; null if no could be retrieved.
///
/// cannot be null.
///
- public static Version GetProductVersion(this IDecorator decorator)
+ public static VersionResult GetProductVersion(this IDecorator decorator)
{
Validator.ThrowIfNull(decorator, nameof(decorator));
var version = decorator.Inner.GetCustomAttribute();
- return version == null ? null : new Version(version.InformationalVersion);
+ return new VersionResult(version.InformationalVersion);
}
///
diff --git a/src/Cuemon.Core/Extensions/StringDecoratorExtensions.cs b/src/Cuemon.Core/Extensions/StringDecoratorExtensions.cs
index 8d23a921f..6ab101613 100644
--- a/src/Cuemon.Core/Extensions/StringDecoratorExtensions.cs
+++ b/src/Cuemon.Core/Extensions/StringDecoratorExtensions.cs
@@ -4,6 +4,7 @@
using System.Globalization;
using System.IO;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using Cuemon.Text;
@@ -139,7 +140,7 @@ public static string ToAsciiEncodedString(this IDecorator decorator, Act
public static Stream ToStream(this IDecorator decorator, Action setup = null)
{
Validator.ThrowIfNull(decorator, nameof(decorator));
- return Disposable.SafeInvoke(() => new MemoryStream(), ms =>
+ return Patterns.SafeInvoke(() => new MemoryStream(), ms =>
{
var bytes = Convertible.GetBytes(decorator.Inner, setup);
ms.Write(bytes, 0, bytes.Length);
@@ -152,6 +153,7 @@ public static Stream ToStream(this IDecorator decorator, Action of the specified to a .
///
/// The to extend.
+ /// The token to monitor for cancellation requests. The default value is .
/// The which may be configured.
/// A task that represents the asynchronous operation. The task result contains a containing the result of the enclosed of the specified .
/// will be initialized with and .
@@ -161,17 +163,16 @@ public static Stream ToStream(this IDecorator decorator, Action
/// was initialized with an invalid .
///
- public static Task ToStreamAsync(this IDecorator decorator, Action setup = null)
+ public static Task ToStreamAsync(this IDecorator decorator, CancellationToken ct = default, Action setup = null)
{
Validator.ThrowIfNull(decorator, nameof(decorator));
- var options = Patterns.Configure(setup);
- return Disposable.SafeInvokeAsync(() => new MemoryStream(), async (ms, ct) =>
+ return Patterns.SafeInvokeAsync(() => new MemoryStream(), async (ms, token) =>
{
var bytes = Convertible.GetBytes(decorator.Inner, setup);
- await ms.WriteAsync(bytes, 0, bytes.Length, ct).ConfigureAwait(false);
+ await ms.WriteAsync(bytes, 0, bytes.Length, token).ConfigureAwait(false);
ms.Position = 0;
return ms;
- }, options.CancellationToken);
+ }, ct);
}
///
diff --git a/src/Cuemon.Core/FuncFactory.cs b/src/Cuemon.Core/FuncFactory.cs
index 14df4e07a..afb0d6b59 100644
--- a/src/Cuemon.Core/FuncFactory.cs
+++ b/src/Cuemon.Core/FuncFactory.cs
@@ -530,7 +530,7 @@ public TResult ExecuteMethod()
///
/// A new that is a copy of this instance.
/// When thread safety is required this is the method to invoke.
- public FuncFactory Clone()
+ public override TemplateFactory Clone()
{
return new FuncFactory(Method, GenericArguments.Clone() as TTuple);
}
diff --git a/src/Cuemon.Core/Generate.cs b/src/Cuemon.Core/Generate.cs
index 8cb92d757..96b5d6ecd 100644
--- a/src/Cuemon.Core/Generate.cs
+++ b/src/Cuemon.Core/Generate.cs
@@ -9,7 +9,7 @@
using System.Threading.Tasks;
using Cuemon.Collections.Generic;
using Cuemon.Reflection;
-using Cuemon.Security.Cryptography;
+using Cuemon.Security;
namespace Cuemon
{
@@ -24,10 +24,12 @@ public static class Generate
private static readonly ThreadLocal LocalRandomizer = new ThreadLocal(() =>
{
var rnd = new byte[4];
- var rng = RandomNumberGenerator.Create();
- rng.GetBytes(rnd);
- var seed = BitConverter.ToInt32(rnd, 0);
- return new Random(seed);
+ using (var rng = RandomNumberGenerator.Create())
+ {
+ rng.GetNonZeroBytes(rnd);
+ var seed = BitConverter.ToInt32(rnd, 0);
+ return new Random(seed);
+ }
});
///
@@ -156,10 +158,10 @@ public static string RandomString(int length, params string[] values)
{
Validator.ThrowIfSequenceNullOrEmpty(values, nameof(values));
var result = new ConcurrentBag();
- Parallel.For(0, length, i =>
+ Parallel.For(0, length, i =>
{
- var index = RandomNumber(values.Length);
- var indexLength = values[index].Length;
+ var index = RandomNumber(values.Length);
+ var indexLength = values[index].Length;
result.Add(values[index][RandomNumber(indexLength)]);
});
return Decorator.Enclose(result).ToStringEquivalent();
diff --git a/src/Cuemon.Core/GlobalSuppressions.cs b/src/Cuemon.Core/GlobalSuppressions.cs
index 7554af4d8..60a79099a 100644
--- a/src/Cuemon.Core/GlobalSuppressions.cs
+++ b/src/Cuemon.Core/GlobalSuppressions.cs
@@ -46,10 +46,217 @@
[assembly: SuppressMessage("Major Code Smell", "S3445:Exceptions should not be explicitly rethrown", Justification = "This is by design; we only want the stacktrace from within the validator method.", Scope = "member", Target = "~M:Cuemon.Validator.ThrowIfUri(System.String,System.UriKind,System.String,System.String)")]
[assembly: SuppressMessage("Major Code Smell", "S3445:Exceptions should not be explicitly rethrown", Justification = "This is by design; we only want the stacktrace from within the validator method.", Scope = "member", Target = "~M:Cuemon.Validator.ThrowIfWhiteSpace(System.String,System.String,System.String)")]
[assembly: SuppressMessage("Major Code Smell", "S3881:\"IDisposable\" should be implemented correctly", Justification = "This is a base class implementation of the IDisposable interface tailored to avoid wrong implementations.", Scope = "type", Target = "~T:Cuemon.Disposable")]
-[assembly: SuppressMessage("Major Code Smell", "S2589:Boolean expressions should not be gratuitous", Justification = "Bug in Sonar?", Scope = "member", Target = "~M:Cuemon.ExceptionInsights.ToExceptionDescriptor(System.Exception,System.String,System.String,System.Uri)~Cuemon.Diagnostics.ExceptionDescriptor")]
[assembly: SuppressMessage("Minor Code Smell", "S1128:Unused \"using\" should be removed", Justification = "It is actually used when resolving extension method from System.Collections.Generic; SC just can't figure this out.")]
-[assembly: SuppressMessage("Major Code Smell", "S1168:Empty arrays and collections should be returned instead of null", Justification = "By design; property serves it purpose.", Scope = "member", Target = "~P:Cuemon.Data.ConcurrentDsvDataReader.NullRead")]
-[assembly: SuppressMessage("Critical Code Smell", "S927:parameter names should match base declaration and other partial definitions", Justification = "By design to help clarify context.", Scope = "member", Target = "~M:Cuemon.Data.ConcurrentDsvDataReader.ReadNext(System.String[])~System.String[]")]
-[assembly: SuppressMessage("Critical Code Smell", "S927:parameter names should match base declaration and other partial definitions", Justification = "By design to help clarify context.", Scope = "member", Target = "~M:Cuemon.Data.DsvDataReader.ReadNext(System.String[])~System.String[]")]
-[assembly: SuppressMessage("Major Code Smell", "S1168:Empty arrays and collections should be returned instead of null", Justification = "By design; property serves it purpose.", Scope = "member", Target = "~P:Cuemon.Data.DsvDataReader.NullRead")]
-[assembly: SuppressMessage("Minor Code Smell", "S1199:Nested code blocks should not be used", Justification = "By design.", Scope = "member", Target = "~M:Cuemon.IO.StreamFactory.CreateStreamCore``1(Cuemon.ActionFactory{``0},System.Action{Cuemon.IO.StreamWriterOptions})~System.IO.Stream")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateEighteen``18(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateEighteen``18(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "", Scope = "member", Target = "~M:Cuemon.Template.CreateEleven``11(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateFifteen``15(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateFifteen``15(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateFourteen``14(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateFourteen``14(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateNineteen``19(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17,``18)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17,``18}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateNineteen``19(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17,``18)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17,``18}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateSeventeen``17(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateSeventeen``17(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateSixteen``16(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateSixteen``16(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateThirteen``13(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateThirteen``13(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateTwelve``12(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateTwelve``12(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateTwenty``20(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17,``18,``19)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17,``18,``19}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateTwenty``20(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17,``18,``19)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17,``18,``19}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template`8.#ctor(`0,`1,`2,`3,`4,`5,`6,`7)")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`10")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`10")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`11")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`11")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`12")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`12")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`13")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`13")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`14")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`14")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`15")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`15")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`16")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`16")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`17")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`17")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`18")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`18")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`19")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`19")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`20")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`20")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`3")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`4")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`5")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`6")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`6")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`7")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`7")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`8")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`8")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "type", Target = "~T:Cuemon.Template`9")]
+[assembly: SuppressMessage("Major Code Smell", "S110:Inheritance tree of classes should not be too deep", Justification = "By design; provides invaluable information about arguments given to any factory implementation.", Scope = "type", Target = "~T:Cuemon.Template`9")]
+[assembly: SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "By design.", Scope = "member", Target = "~F:Cuemon.Convertible.EndianSensitiveByteArrayConverters")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateEight``8(``0,``1,``2,``3,``4,``5,``6,``7)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateEight``8(``0,``1,``2,``3,``4,``5,``6,``7)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateEleven``11(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateFive``5(``0,``1,``2,``3,``4)~Cuemon.Template{``0,``1,``2,``3,``4}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateFour``4(``0,``1,``2,``3)~Cuemon.Template{``0,``1,``2,``3}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateNine``9(``0,``1,``2,``3,``4,``5,``6,``7,``8)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateNine``9(``0,``1,``2,``3,``4,``5,``6,``7,``8)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateSeven``7(``0,``1,``2,``3,``4,``5,``6)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateSix``6(``0,``1,``2,``3,``4,``5)~Cuemon.Template{``0,``1,``2,``3,``4,``5}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateTen``10(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic.", Scope = "member", Target = "~M:Cuemon.Template.CreateTen``10(``0,``1,``2,``3,``4,``5,``6,``7,``8,``9)~Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``10(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``11(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``12(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``13(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``14(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``15(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``16(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``7(System.Action{``0,``1,``2,``3,``4,``5,``6},``0,``1,``2,``3,``4,``5,``6)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``8(System.Action{``0,``1,``2,``3,``4,``5,``6,``7},``0,``1,``2,``3,``4,``5,``6,``7)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``9(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8},``0,``1,``2,``3,``4,``5,``6,``7,``8)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``10(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``11(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``12(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``13(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``14(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``15(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``16(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``4(System.Action{``0,``1,``2,``3},``0,``1,``2,``3)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``5(System.Action{``0,``1,``2,``3,``4},``0,``1,``2,``3,``4)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``6(System.Action{``0,``1,``2,``3,``4,``5},``0,``1,``2,``3,``4,``5)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``7(System.Action{``0,``1,``2,``3,``4,``5,``6},``0,``1,``2,``3,``4,``5,``6)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``8(System.Action{``0,``1,``2,``3,``4,``5,``6,``7},``0,``1,``2,``3,``4,``5,``6,``7)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Action delegates.", Scope = "member", Target = "~M:Cuemon.ActionFactory.Create``9(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8},``0,``1,``2,``3,``4,``5,``6,``7,``8)~Cuemon.ActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``10(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``0,``1,``2,``3,``4,``5,``6,``7,``8)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8},``9}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``10(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``0,``1,``2,``3,``4,``5,``6,``7,``8)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8},``9}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``11(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``10}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``11(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``10}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``12(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``11}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``12(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``11}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``13(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11},``12}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``13(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11},``12}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``14(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12},``13}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``14(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12},``13}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``15(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13},``14}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``15(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13},``14}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``16(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14},``15}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``16(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14},``15}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``17(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15},``16}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``17(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15},``16}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``4(System.Func{``0,``1,``2,``3},``0,``1,``2)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2},``3}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``5(System.Func{``0,``1,``2,``3,``4},``0,``1,``2,``3)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3},``4}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``6(System.Func{``0,``1,``2,``3,``4,``5},``0,``1,``2,``3,``4)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4},``5}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``7(System.Func{``0,``1,``2,``3,``4,``5,``6},``0,``1,``2,``3,``4,``5)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5},``6}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``8(System.Func{``0,``1,``2,``3,``4,``5,``6,``7},``0,``1,``2,``3,``4,``5,``6)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6},``7}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``8(System.Func{``0,``1,``2,``3,``4,``5,``6,``7},``0,``1,``2,``3,``4,``5,``6)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6},``7}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``9(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8},``0,``1,``2,``3,``4,``5,``6,``7)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7},``8}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Func delegates.", Scope = "member", Target = "~M:Cuemon.FuncFactory.Create``9(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8},``0,``1,``2,``3,``4,``5,``6,``7)~Cuemon.FuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7},``8}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``10(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``10(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``11(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``11(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``12(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``12(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``13(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``13(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``14(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``14(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``15(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``15(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``4(System.Func{``0,``1,``2,``3,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``5(System.Func{``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``6(System.Func{``0,``1,``2,``3,``4,``5,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``7(System.Func{``0,``1,``2,``3,``4,``5,``6,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``7(System.Func{``0,``1,``2,``3,``4,``5,``6,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``8(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``8(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``9(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskActionFactory.Create``9(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8)~Cuemon.TaskActionFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``10(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Threading.CancellationToken,System.Threading.Tasks.Task{``9}},``0,``1,``2,``3,``4,``5,``6,``7,``8)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8},``9}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``11(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Threading.CancellationToken,System.Threading.Tasks.Task{``10}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``10}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``12(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,System.Threading.CancellationToken,System.Threading.Tasks.Task{``11}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``11}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``13(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,System.Threading.CancellationToken,System.Threading.Tasks.Task{``12}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11},``12}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``14(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,System.Threading.CancellationToken,System.Threading.Tasks.Task{``13}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12},``13}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``15(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,System.Threading.CancellationToken,System.Threading.Tasks.Task{``14}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13},``14}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``16(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,System.Threading.CancellationToken,System.Threading.Tasks.Task{``15}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14},``15}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``8(System.Func{``0,``1,``2,``3,``4,``5,``6,System.Threading.CancellationToken,System.Threading.Tasks.Task{``7}},``0,``1,``2,``3,``4,``5,``6)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6},``7}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``9(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,System.Threading.CancellationToken,System.Threading.Tasks.Task{``8}},``0,``1,``2,``3,``4,``5,``6,``7)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7},``8}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``10(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Threading.CancellationToken,System.Threading.Tasks.Task{``9}},``0,``1,``2,``3,``4,``5,``6,``7,``8)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8},``9}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``11(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Threading.CancellationToken,System.Threading.Tasks.Task{``10}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``10}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``12(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,System.Threading.CancellationToken,System.Threading.Tasks.Task{``11}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``11}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``13(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,System.Threading.CancellationToken,System.Threading.Tasks.Task{``12}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11},``12}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``14(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,System.Threading.CancellationToken,System.Threading.Tasks.Task{``13}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12},``13}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``15(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,System.Threading.CancellationToken,System.Threading.Tasks.Task{``14}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13},``14}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``16(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,System.Threading.CancellationToken,System.Threading.Tasks.Task{``15}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14},``15}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``4(System.Func{``0,``1,``2,System.Threading.CancellationToken,System.Threading.Tasks.Task{``3}},``0,``1,``2)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2},``3}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``5(System.Func{``0,``1,``2,``3,System.Threading.CancellationToken,System.Threading.Tasks.Task{``4}},``0,``1,``2,``3)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3},``4}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``6(System.Func{``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Threading.Tasks.Task{``5}},``0,``1,``2,``3,``4)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4},``5}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``7(System.Func{``0,``1,``2,``3,``4,``5,System.Threading.CancellationToken,System.Threading.Tasks.Task{``6}},``0,``1,``2,``3,``4,``5)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5},``6}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``8(System.Func{``0,``1,``2,``3,``4,``5,``6,System.Threading.CancellationToken,System.Threading.Tasks.Task{``7}},``0,``1,``2,``3,``4,``5,``6)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6},``7}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for Task based Func delegates.", Scope = "member", Target = "~M:Cuemon.TaskFuncFactory.Create``9(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,System.Threading.CancellationToken,System.Threading.Tasks.Task{``8}},``0,``1,``2,``3,``4,``5,``6,``7)~Cuemon.TaskFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7},``8}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "A Func designed for the Tester pattern. Microsoft allows 17 arguments in there Func impl; so do i here.", Scope = "type", Target = "~T:Cuemon.TesterFunc`10")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "A Func designed for the Tester pattern. Microsoft allows 17 arguments in there Func impl; so do i here.", Scope = "type", Target = "~T:Cuemon.TesterFunc`11")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "A Func designed for the Tester pattern. Microsoft allows 17 arguments in there Func impl; so do i here.", Scope = "type", Target = "~T:Cuemon.TesterFunc`12")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "A Func designed for the Tester pattern. Microsoft allows 17 arguments in there Func impl; so do i here.", Scope = "type", Target = "~T:Cuemon.TesterFunc`13")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "A Func designed for the Tester pattern. Microsoft allows 17 arguments in there Func impl; so do i here.", Scope = "type", Target = "~T:Cuemon.TesterFunc`14")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "A Func designed for the Tester pattern. Microsoft allows 17 arguments in there Func impl; so do i here.", Scope = "type", Target = "~T:Cuemon.TesterFunc`15")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "A Func designed for the Tester pattern. Microsoft allows 17 arguments in there Func impl; so do i here.", Scope = "type", Target = "~T:Cuemon.TesterFunc`16")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "A Func designed for the Tester pattern. Microsoft allows 17 arguments in there Func impl; so do i here.", Scope = "type", Target = "~T:Cuemon.TesterFunc`17")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "A Func designed for the Tester pattern. Microsoft allows 17 arguments in there Func impl; so do i here.", Scope = "type", Target = "~T:Cuemon.TesterFunc`18")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "A Func designed for the Tester pattern. Microsoft allows 17 arguments in there Func impl; so do i here.", Scope = "type", Target = "~T:Cuemon.TesterFunc`9")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``10(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``0,``1,``2,``3,``4,``5,``6,``7)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7},``8,``9}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``10(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``0,``1,``2,``3,``4,``5,``6,``7)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7},``8,``9}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``11(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``0,``1,``2,``3,``4,``5,``6,``7,``8)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8},``9,``10}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``11(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``0,``1,``2,``3,``4,``5,``6,``7,``8)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8},``9,``10}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``12(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``10,``11}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``12(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``10,``11}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``13(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``11,``12}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``13(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``11,``12}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``14(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11},``12,``13}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``14(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11},``12,``13}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``15(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12},``13,``14}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``15(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12},``13,``14}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``16(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13},``14,``15}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``16(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13},``14,``15}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``17(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14},``15,``16}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``17(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14},``15,``16}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``18(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15},``16,``17}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``18(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15,``16,``17},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10,``11,``12,``13,``14,``15},``16,``17}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``4(Cuemon.TesterFunc{``0,``1,``2,``3},``0,``1)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1},``2,``3}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``5(Cuemon.TesterFunc{``0,``1,``2,``3,``4},``0,``1,``2)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2},``3,``4}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``6(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5},``0,``1,``2,``3)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3},``4,``5}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``7(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6},``0,``1,``2,``3,``4)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4},``5,``6}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``8(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7},``0,``1,``2,``3,``4,``5)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5},``6,``7}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``9(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8},``0,``1,``2,``3,``4,``5,``6)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6},``7,``8}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "member", Target = "~M:Cuemon.TesterFuncFactory.Create``9(Cuemon.TesterFunc{``0,``1,``2,``3,``4,``5,``6,``7,``8},``0,``1,``2,``3,``4,``5,``6)~Cuemon.TesterFuncFactory{Cuemon.Template{``0,``1,``2,``3,``4,``5,``6},``7,``8}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; think about it as a Tuple/Variadic - but for TesterFunc delegates.", Scope = "type", Target = "~T:Cuemon.TesterFuncFactory`3")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions)..", Scope = "member", Target = "~M:Cuemon.Patterns.SafeInvoke``6(System.Func{``5},System.Func{``5,``0,``1,``2,``3,``4,``5},``0,``1,``2,``3,``4,System.Action{System.Exception,``0,``1,``2,``3,``4})~``5")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions)..", Scope = "member", Target = "~M:Cuemon.Patterns.SafeInvokeAsync``5(System.Func{``4},System.Func{``4,``0,``1,``2,``3,System.Threading.CancellationToken,System.Threading.Tasks.Task{``4}},``0,``1,``2,``3,System.Threading.CancellationToken,System.Func{System.Exception,``0,``1,``2,``3,System.Threading.CancellationToken,System.Threading.Tasks.Task})~System.Threading.Tasks.Task{``4}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions)..", Scope = "member", Target = "~M:Cuemon.Patterns.SafeInvokeAsync``6(System.Func{``5},System.Func{``5,``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Threading.Tasks.Task{``5}},``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Func{System.Exception,``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Threading.Tasks.Task})~System.Threading.Tasks.Task{``5}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions)..", Scope = "member", Target = "~M:Cuemon.Patterns.SafeInvoke``4(System.Func{``3},System.Func{``3,``0,``1,``2,``3},``0,``1,``2,System.Action{System.Exception,``0,``1,``2})~``3")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions)..", Scope = "member", Target = "~M:Cuemon.Patterns.SafeInvoke``5(System.Func{``4},System.Func{``4,``0,``1,``2,``3,``4},``0,``1,``2,``3,System.Action{System.Exception,``0,``1,``2,``3})~``4")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions)..", Scope = "member", Target = "~M:Cuemon.Patterns.SafeInvoke``6(System.Func{``5},System.Func{``5,``0,``1,``2,``3,``4,``5},``0,``1,``2,``3,``4,System.Action{System.Exception,``0,``1,``2,``3,``4})~``5")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions)..", Scope = "member", Target = "~M:Cuemon.Patterns.SafeInvokeAsync``4(System.Func{``3},System.Func{``3,``0,``1,``2,System.Threading.CancellationToken,System.Threading.Tasks.Task{``3}},``0,``1,``2,System.Threading.CancellationToken,System.Func{System.Exception,``0,``1,``2,System.Threading.CancellationToken,System.Threading.Tasks.Task})~System.Threading.Tasks.Task{``3}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions)..", Scope = "member", Target = "~M:Cuemon.Patterns.SafeInvokeAsync``5(System.Func{``4},System.Func{``4,``0,``1,``2,``3,System.Threading.CancellationToken,System.Threading.Tasks.Task{``4}},``0,``1,``2,``3,System.Threading.CancellationToken,System.Func{System.Exception,``0,``1,``2,``3,System.Threading.CancellationToken,System.Threading.Tasks.Task})~System.Threading.Tasks.Task{``4}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions)..", Scope = "member", Target = "~M:Cuemon.Patterns.SafeInvokeAsync``6(System.Func{``5},System.Func{``5,``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Threading.Tasks.Task{``5}},``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Func{System.Exception,``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Threading.Tasks.Task})~System.Threading.Tasks.Task{``5}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Condition.FlipFlop``4(System.Boolean,System.Action{``0,``1,``2,``3},System.Action{``0,``1,``2,``3},``0,``1,``2,``3)")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Condition.FlipFlop``5(System.Boolean,System.Action{``0,``1,``2,``3,``4},System.Action{``0,``1,``2,``3,``4},``0,``1,``2,``3,``4)")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Condition.FlipFlop``5(System.Boolean,System.Action{``0,``1,``2,``3,``4},System.Action{``0,``1,``2,``3,``4},``0,``1,``2,``3,``4)")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Condition.TernaryIf``4(System.Boolean,System.Func{``0,``1,``2,``3},System.Func{``0,``1,``2,``3},``0,``1,``2)~``3")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Condition.TernaryIf``5(System.Boolean,System.Func{``0,``1,``2,``3,``4},System.Func{``0,``1,``2,``3,``4},``0,``1,``2,``3)~``4")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Condition.TernaryIf``6(System.Boolean,System.Func{``0,``1,``2,``3,``4,``5},System.Func{``0,``1,``2,``3,``4,``5},``0,``1,``2,``3,``4)~``5")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Condition.TernaryIf``6(System.Boolean,System.Func{``0,``1,``2,``3,``4,``5},System.Func{``0,``1,``2,``3,``4,``5},``0,``1,``2,``3,``4)~``5")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Reflection.ActivatorFactory.CreateInstance``4(``0,``1,``2,System.Action{Cuemon.Reflection.ActivatorOptions})~``3")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Reflection.ActivatorFactory.CreateInstance``5(``0,``1,``2,``3,System.Action{Cuemon.Reflection.ActivatorOptions})~``4")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Reflection.ActivatorFactory.CreateInstance``6(``0,``1,``2,``3,``4,System.Action{Cuemon.Reflection.ActivatorOptions})~``5")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Runtime.Dependency.Create``4(``0,``1,``2)~``3")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Runtime.Dependency.Create``5(``0,``1,``2,``3)~``4")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Runtime.Dependency.Create``6(``0,``1,``2,``3,``4)~``5")]
diff --git a/src/Cuemon.Core/Globalization/IMessageLocalizer.cs b/src/Cuemon.Core/Globalization/IMessageLocalizer.cs
deleted file mode 100644
index 727e75a9f..000000000
--- a/src/Cuemon.Core/Globalization/IMessageLocalizer.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-
-namespace Cuemon.Globalization
-{
- ///
- /// Provides a generic way to support localized messages on attribute decorated methods.
- ///
- public interface IMessageLocalizer
- {
- ///
- /// Gets or sets and explicit message string.
- ///
- /// This property is intended to be used for non-localizable messages. Use and for localizable messages.
- string Message { get; set; }
-
- ///
- /// Gets or sets the resource name (property name) to use as the key for lookups on the resource type.
- ///
- /// Use this property to set the name of the property within that will provide a localized message.
- string MessageResourceName { get; set; }
-
- ///
- /// Gets or sets the resource type to use for message lookups.
- ///
- /// Use this property only in conjunction with . They are used together to retrieve localized messages at runtime.
- Type MessageResourceType { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Globalization/RegionInfoExtensions.cs b/src/Cuemon.Core/Globalization/RegionInfoExtensions.cs
deleted file mode 100644
index 2384ba98e..000000000
--- a/src/Cuemon.Core/Globalization/RegionInfoExtensions.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-
-namespace Cuemon.Globalization
-{
- ///
- /// This is an extension implementation of the class.
- ///
- public static class RegionInfoExtensions
- {
- ///
- /// Resolves a sequence of related objects for the specified .
- ///
- /// The region to resolve a sequence of objects from.
- /// An sequence of objects.
- public static IEnumerable GetCultures(this RegionInfo region)
- {
- Validator.ThrowIfNull(region, nameof(region));
- return World.SpecificCultures.Value.Where(c => c.Name.EndsWith(region.TwoLetterISORegionName));
- }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Globalization/ResourceAttribute.cs b/src/Cuemon.Core/Globalization/ResourceAttribute.cs
new file mode 100644
index 000000000..deb787904
--- /dev/null
+++ b/src/Cuemon.Core/Globalization/ResourceAttribute.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Concurrent;
+using System.Reflection;
+
+namespace Cuemon.Globalization
+{
+ ///
+ /// Provides a generic way to support localization on attribute decorated methods.
+ ///
+ ///
+ public abstract class ResourceAttribute : Attribute
+ {
+ private readonly ConcurrentDictionary _propertyInfos = new ConcurrentDictionary();
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ protected ResourceAttribute()
+ {
+ }
+
+ ///
+ /// Gets or sets the type that contains the resources for looking up localized strings.
+ ///
+ /// The type that contains the resources for looking up localized strings.
+ public Type ResourceType { get; set; }
+
+ ///
+ /// Returns the value of the specified string resource.
+ ///
+ /// The name of the resource to retrieve.
+ /// The value of the resource localized for the callers current UI culture, or null if cannot be found on the .
+ ///
+ /// You must specify a to perform the actual lookup of localized strings.
+ ///
+ ///
+ /// The specified does not contain a resource with the specified .
+ ///
+ protected string GetString(string name)
+ {
+ Validator.ThrowIfNullOrWhitespace(name, nameof(name));
+ if (ResourceType == null) { throw new InvalidOperationException("You must specify a type to perform the actual lookup of localized strings."); }
+ var cacheKey = $"{ResourceType.ToString().ToUpperInvariant()}.{name.ToUpperInvariant()}";
+ if (!_propertyInfos.TryGetValue(cacheKey, out var property))
+ {
+ property = ResourceType.GetProperty(name, BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic);
+ var getMethod = property?.GetGetMethod(true);
+ if (getMethod != null && (getMethod.IsAssembly || getMethod.IsPublic))
+ {
+ _propertyInfos.TryAdd(cacheKey, property);
+ }
+ }
+ return property == null ? throw new ArgumentException($"The specified type, '{ResourceType.FullName}', does not contain a resource with the specified '{name}'.") : property.GetValue(null, null) as string;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Globalization/World.cs b/src/Cuemon.Core/Globalization/World.cs
index d4db3ec3b..c27c7e155 100644
--- a/src/Cuemon.Core/Globalization/World.cs
+++ b/src/Cuemon.Core/Globalization/World.cs
@@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
-using System.IO;
using System.Linq;
-using System.Reflection;
-using Cuemon.Reflection;
namespace Cuemon.Globalization
{
@@ -13,40 +10,13 @@ namespace Cuemon.Globalization
///
public static class World
{
- private const int CultureTypesSpecificCultures = 2;
- private static readonly MethodInfo CultureInfoGetCultures = typeof(CultureInfo).GetMethod("GetCultures", new MemberReflection(excludeInheritancePath: true));
-
internal static readonly Lazy> SpecificCultures = new Lazy>(() =>
{
var cultures = new SortedList();
var specificCultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
- if (specificCultures != null)
- {
- foreach (var c in specificCultures)
- {
- cultures.Add(c.DisplayName, c);
- }
- return cultures.Values;
- }
-
- using (var lfdSpecificCultures = Decorator.Enclose(typeof(World).Assembly).GetManifestResources("CultureInfo.SpecificCultures.dsv", ManifestResourceMatch.ContainsName).Values.Single())
+ foreach (var c in specificCultures)
{
- using (var reader = new StreamReader(lfdSpecificCultures))
- {
- string specificCulture;
- while ((specificCulture = reader.ReadLine()) != null)
- {
- try
- {
- var c = new CultureInfo(specificCulture);
- cultures.Add(c.DisplayName, c);
- }
- catch (CultureNotFoundException)
- {
- // ignored on systems not supporting the specificCulture
- }
- }
- }
+ cultures.Add(c.DisplayName, c);
}
return cultures.Values;
});
@@ -67,5 +37,16 @@ public static class World
///
/// The .NET specific regions of the world.
public static IEnumerable Regions { get; } = SpecificRegions.Value;
+
+ ///
+ /// Resolves a sequence of related objects for the specified .
+ ///
+ /// The region to resolve a sequence of objects from.
+ /// An sequence of objects.
+ public static IEnumerable GetCultures(RegionInfo region)
+ {
+ Validator.ThrowIfNull(region, nameof(region));
+ return SpecificCultures.Value.Where(c => c.Name.EndsWith(region.TwoLetterISORegionName));
+ }
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Core/IO/StreamOptions.cs b/src/Cuemon.Core/IO/StreamOptions.cs
deleted file mode 100644
index 633d2c1b4..000000000
--- a/src/Cuemon.Core/IO/StreamOptions.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System.IO;
-
-namespace Cuemon.IO
-{
- ///
- /// Configuration options for .
- ///
- public class StreamOptions : DisposableOptions
- {
-
- ///
- /// Initializes a new instance of the class.
- ///
- public StreamOptions()
- {
- }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Patterns.cs b/src/Cuemon.Core/Patterns.cs
index 18f97cc22..56511492d 100644
--- a/src/Cuemon.Core/Patterns.cs
+++ b/src/Cuemon.Core/Patterns.cs
@@ -2,11 +2,13 @@
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
namespace Cuemon
{
///
- /// Provides a generic way to support different types of design patterns with small utility methods.
+ /// Provides a generic way to support different types of design patterns and practices with small utility methods.
///
public sealed class Patterns
{
@@ -34,13 +36,13 @@ public static bool TryInvoke(Action method)
}
catch (Exception ex)
{
- if (ex is OutOfMemoryException ||
- ex is StackOverflowException ||
- ex is SEHException ||
- ex is AccessViolationException ||
- #pragma warning disable CS0618 // Type or member is obsolete
+ if (ex is OutOfMemoryException ||
+ ex is StackOverflowException ||
+ ex is SEHException ||
+ ex is AccessViolationException ||
+#pragma warning disable CS0618 // Type or member is obsolete
ex is ExecutionEngineException) // fatal exceptions; re-throw for .NET "legacy" (.NET Core will handle these by a high-level catch-all handler)
- #pragma warning restore CS0618 // Type or member is obsolete
+#pragma warning restore CS0618 // Type or member is obsolete
{
throw;
}
@@ -66,13 +68,13 @@ public static bool TryInvoke(Func method, out TResult result)
}
catch (Exception ex)
{
- if (ex is OutOfMemoryException ||
- ex is StackOverflowException ||
- ex is SEHException ||
+ if (ex is OutOfMemoryException ||
+ ex is StackOverflowException ||
+ ex is SEHException ||
ex is AccessViolationException ||
- #pragma warning disable CS0618 // Type or member is obsolete
+#pragma warning disable CS0618 // Type or member is obsolete
ex is ExecutionEngineException) // fatal exceptions; re-throw for .NET "legacy" (.NET Core will handle these by a high-level catch-all handler)
- #pragma warning restore CS0618 // Type or member is obsolete
+#pragma warning restore CS0618 // Type or member is obsolete
{
throw;
}
@@ -166,9 +168,343 @@ public static Action ConfigureRevert(TOptions options)
return o =>
{
var to = typeof(TOptions);
- var tops= to.GetRuntimeProperties().Where(pi => pi.CanRead && pi.CanWrite).ToList();
+ var tops = to.GetRuntimeProperties().Where(pi => pi.CanRead && pi.CanWrite).ToList();
foreach (var p in tops) { p.SetValue(o, p.GetValue(options)); }
};
}
+
+ ///
+ /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
+ ///
+ /// The type of the return value of the function delegate .
+ /// The function delegate that initializes an object implementing the interface.
+ /// The function delegate that is used to ensure that operations performed on abides CA2000.
+ /// The delegate that will handle any exceptions might thrown by .
+ /// The return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
+ public static TResult SafeInvoke(Func initializer, Func tester, Action catcher = null) where TResult : class, IDisposable
+ {
+ Validator.ThrowIfNull(initializer, nameof(initializer));
+ Validator.ThrowIfNull(tester, nameof(tester));
+ var f1 = FuncFactory.Create(tester, default);
+ var f2 = ActionFactory.Create(catcher, default);
+ return SafeInvokeCore(f1, initializer, f2);
+ }
+
+ ///
+ /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
+ ///
+ /// The type of the parameter of the function delegate and delegate .
+ /// The type of the return value of the function delegate .
+ /// The function delegate that initializes an object implementing the interface.
+ /// The function delegate that is used to ensure that operations performed on abides CA2000.
+ /// The parameter of the function delegate and delegate .
+ /// The delegate that will handle any exceptions might thrown by .
+ /// The return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
+ public static TResult SafeInvoke(Func initializer, Func tester, T arg, Action catcher = null) where TResult : class, IDisposable
+ {
+ Validator.ThrowIfNull(initializer, nameof(initializer));
+ Validator.ThrowIfNull(tester, nameof(tester));
+ var f1 = FuncFactory.Create(tester, default, arg);
+ var f2 = ActionFactory.Create(catcher, default, arg);
+ return SafeInvokeCore(f1, initializer, f2);
+ }
+
+ ///
+ /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
+ ///
+ /// The type of the first parameter of the function delegate and delegate .
+ /// The type of the second parameter of the function delegate and delegate .
+ /// The type of the return value of the function delegate .
+ /// The function delegate that initializes an object implementing the interface.
+ /// The function delegate that is used to ensure that operations performed on abides CA2000.
+ /// The first parameter of the function delegate and delegate .
+ /// The second parameter of the function delegate and delegate .
+ /// The delegate that will handle any exceptions might thrown by .
+ /// The return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
+ public static TResult SafeInvoke(Func initializer, Func tester, T1 arg1, T2 arg2, Action catcher = null) where TResult : class, IDisposable
+ {
+ Validator.ThrowIfNull(initializer, nameof(initializer));
+ Validator.ThrowIfNull(tester, nameof(tester));
+ var f1 = FuncFactory.Create(tester, default, arg1, arg2);
+ var f2 = ActionFactory.Create(catcher, default, arg1, arg2);
+ return SafeInvokeCore(f1, initializer, f2);
+ }
+
+ ///
+ /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
+ ///
+ /// The type of the first parameter of the function delegate and delegate .
+ /// The type of the second parameter of the function delegate and delegate .
+ /// The type of the third parameter of the function delegate and delegate .
+ /// The type of the return value of the function delegate .
+ /// The function delegate that initializes an object implementing the interface.
+ /// The function delegate that is used to ensure that operations performed on abides CA2000.
+ /// The first parameter of the function delegate and delegate .
+ /// The second parameter of the function delegate and delegate .
+ /// The third parameter of the function delegate and delegate .
+ /// The delegate that will handle any exceptions might thrown by .
+ /// The return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
+ public static TResult SafeInvoke(Func initializer, Func tester, T1 arg1, T2 arg2, T3 arg3, Action catcher = null) where TResult : class, IDisposable
+ {
+ Validator.ThrowIfNull(initializer, nameof(initializer));
+ Validator.ThrowIfNull(tester, nameof(tester));
+ var f1 = FuncFactory.Create(tester, default, arg1, arg2, arg3);
+ var f2 = ActionFactory.Create(catcher, default, arg1, arg2, arg3);
+ return SafeInvokeCore(f1, initializer, f2);
+ }
+
+ ///
+ /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
+ ///
+ /// The type of the first parameter of the function delegate and delegate .
+ /// The type of the second parameter of the function delegate and delegate .
+ /// The type of the third parameter of the function delegate and delegate .
+ /// The type of the fourth parameter of the function delegate and delegate .
+ /// The type of the return value of the function delegate .
+ /// The function delegate that initializes an object implementing the interface.
+ /// The function delegate that is used to ensure that operations performed on abides CA2000.
+ /// The first parameter of the function delegate and delegate .
+ /// The second parameter of the function delegate and delegate .
+ /// The third parameter of the function delegate and delegate .
+ /// The fourth parameter of the function delegate and delegate .
+ /// The delegate that will handle any exceptions might thrown by .
+ /// The return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
+ public static TResult SafeInvoke(Func initializer, Func tester, T1 arg1, T2 arg2, T3 arg3, T4 arg4, Action catcher = null) where TResult : class, IDisposable
+ {
+ Validator.ThrowIfNull(initializer, nameof(initializer));
+ Validator.ThrowIfNull(tester, nameof(tester));
+ var f1 = FuncFactory.Create(tester, default, arg1, arg2, arg3, arg4);
+ var f2 = ActionFactory.Create(catcher, default, arg1, arg2, arg3, arg4);
+ return SafeInvokeCore(f1, initializer, f2);
+ }
+
+ ///
+ /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
+ ///
+ /// The type of the first parameter of the function delegate and delegate .
+ /// The type of the second parameter of the function delegate and delegate .
+ /// The type of the third parameter of the function delegate and delegate .
+ /// The type of the fourth parameter of the function delegate and delegate .
+ /// The type of the fifth parameter of the function delegate and delegate .
+ /// The type of the return value of the function delegate .
+ /// The function delegate that initializes an object implementing the interface.
+ /// The function delegate that is used to ensure that operations performed on abides CA2000.
+ /// The first parameter of the function delegate and delegate .
+ /// The second parameter of the function delegate and delegate .
+ /// The third parameter of the function delegate and delegate .
+ /// The fourth parameter of the function delegate and delegate .
+ /// The fifth parameter of the function delegate and delegate .
+ /// The delegate that will handle any exceptions might thrown by .
+ /// The return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
+ public static TResult SafeInvoke(Func initializer, Func tester, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, Action catcher = null) where TResult : class, IDisposable
+ {
+ Validator.ThrowIfNull(initializer, nameof(initializer));
+ Validator.ThrowIfNull(tester, nameof(tester));
+ var f1 = FuncFactory.Create(tester, default, arg1, arg2, arg3, arg4, arg5);
+ var f2 = ActionFactory.Create(catcher, default, arg1, arg2, arg3, arg4, arg5);
+ return SafeInvokeCore(f1, initializer, f2);
+ }
+
+ ///
+ /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
+ ///
+ /// The type of the return value of the function delegate .
+ /// The function delegate that initializes an object implementing the interface.
+ /// The function delegate that is used to ensure that operations performed on abides CA2000.
+ /// The token to monitor for cancellation requests. The default value is .
+ /// The function delegate that will handle any exceptions might thrown by .
+ /// A task that represents the asynchronous operation. The task result contains the return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
+ public static Task SafeInvokeAsync(Func initializer, Func> tester, CancellationToken ct = default, Func catcher = null) where TResult : class, IDisposable
+ {
+ Validator.ThrowIfNull(initializer, nameof(initializer));
+ Validator.ThrowIfNull(tester, nameof(tester));
+ var f1 = TaskFuncFactory.Create(tester, default);
+ var f2 = TaskActionFactory.Create(catcher, default);
+ return SafeInvokeAsyncCore(f1, initializer, f2, ct);
+ }
+
+ ///
+ /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
+ ///
+ /// The type of the parameter of the function delegate and delegate .
+ /// The type of the return value of the function delegate .
+ /// The function delegate that initializes an object implementing the interface.
+ /// The function delegate that is used to ensure that operations performed on abides CA2000.
+ /// The parameter of the function delegate and delegate .
+ /// The token to monitor for cancellation requests. The default value is .
+ /// The function delegate that will handle any exceptions might thrown by .
+ /// A task that represents the asynchronous operation. The task result contains the return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
+ public static Task SafeInvokeAsync(Func initializer, Func> tester, T arg, CancellationToken ct = default, Func catcher = null) where TResult : class, IDisposable
+ {
+ Validator.ThrowIfNull(initializer, nameof(initializer));
+ Validator.ThrowIfNull(tester, nameof(tester));
+ var f1 = TaskFuncFactory.Create(tester, default, arg);
+ var f2 = TaskActionFactory.Create(catcher, default, arg);
+ return SafeInvokeAsyncCore(f1, initializer, f2, ct);
+ }
+
+ ///
+ /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
+ ///
+ /// The type of the first parameter of the function delegate and delegate .
+ /// The type of the second parameter of the function delegate and delegate .
+ /// The type of the return value of the function delegate .
+ /// The function delegate that initializes an object implementing the interface.
+ /// The function delegate that is used to ensure that operations performed on abides CA2000.
+ /// The first parameter of the function delegate and delegate .
+ /// The second parameter of the function delegate and delegate .
+ /// The token to monitor for cancellation requests. The default value is .
+ /// The function delegate that will handle any exceptions might thrown by .
+ /// A task that represents the asynchronous operation. The task result contains the return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
+ public static Task SafeInvokeAsync(Func initializer, Func> tester, T1 arg1, T2 arg2, CancellationToken ct = default, Func catcher = null) where TResult : class, IDisposable
+ {
+ Validator.ThrowIfNull(initializer, nameof(initializer));
+ Validator.ThrowIfNull(tester, nameof(tester));
+ var f1 = TaskFuncFactory.Create(tester, default, arg1, arg2);
+ var f2 = TaskActionFactory.Create(catcher, default, arg1, arg2);
+ return SafeInvokeAsyncCore(f1, initializer, f2, ct);
+ }
+
+ ///
+ /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
+ ///
+ /// The type of the first parameter of the function delegate and delegate .
+ /// The type of the second parameter of the function delegate and delegate .
+ /// The type of the third parameter of the function delegate and delegate .
+ /// The type of the return value of the function delegate .
+ /// The function delegate that initializes an object implementing the interface.
+ /// The function delegate that is used to ensure that operations performed on abides CA2000.
+ /// The first parameter of the function delegate and delegate .
+ /// The second parameter of the function delegate and delegate .
+ /// The third parameter of the function delegate and delegate .
+ /// The token to monitor for cancellation requests. The default value is .
+ /// The function delegate that will handle any exceptions might thrown by .
+ /// A task that represents the asynchronous operation. The task result contains the return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
+ public static Task SafeInvokeAsync(Func initializer, Func> tester, T1 arg1, T2 arg2, T3 arg3, CancellationToken ct = default, Func catcher = null) where TResult : class, IDisposable
+ {
+ Validator.ThrowIfNull(initializer, nameof(initializer));
+ Validator.ThrowIfNull(tester, nameof(tester));
+ var f1 = TaskFuncFactory.Create(tester, default, arg1, arg2, arg3);
+ var f2 = TaskActionFactory.Create(catcher, default, arg1, arg2, arg3);
+ return SafeInvokeAsyncCore(f1, initializer, f2, ct);
+ }
+
+ ///
+ /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
+ ///
+ /// The type of the first parameter of the function delegate and delegate .
+ /// The type of the second parameter of the function delegate and delegate .
+ /// The type of the third parameter of the function delegate and delegate .
+ /// The type of the fourth parameter of the function delegate and delegate .
+ /// The type of the return value of the function delegate .
+ /// The function delegate that initializes an object implementing the interface.
+ /// The function delegate that is used to ensure that operations performed on abides CA2000.
+ /// The first parameter of the function delegate and delegate .
+ /// The second parameter of the function delegate and delegate .
+ /// The third parameter of the function delegate and delegate .
+ /// The fourth parameter of the function delegate and delegate .
+ /// The token to monitor for cancellation requests. The default value is .
+ /// The function delegate that will handle any exceptions might thrown by .
+ /// A task that represents the asynchronous operation. The task result contains the return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
+ public static Task SafeInvokeAsync(Func initializer, Func> tester, T1 arg1, T2 arg2, T3 arg3, T4 arg4, CancellationToken ct = default, Func catcher = null) where TResult : class, IDisposable
+ {
+ Validator.ThrowIfNull(initializer, nameof(initializer));
+ Validator.ThrowIfNull(tester, nameof(tester));
+ var f1 = TaskFuncFactory.Create(tester, default, arg1, arg2, arg3, arg4);
+ var f2 = TaskActionFactory.Create(catcher, default, arg1, arg2, arg3, arg4);
+ return SafeInvokeAsyncCore(f1, initializer, f2, ct);
+ }
+
+ ///
+ /// Provides a generic way to abide the rule description of CA2000 (Dispose objects before losing scope).
+ ///
+ /// The type of the first parameter of the function delegate and delegate .
+ /// The type of the second parameter of the function delegate and delegate .
+ /// The type of the third parameter of the function delegate and delegate .
+ /// The type of the fourth parameter of the function delegate and delegate .
+ /// The type of the fifth parameter of the function delegate and delegate .
+ /// The type of the return value of the function delegate .
+ /// The function delegate that initializes an object implementing the interface.
+ /// The function delegate that is used to ensure that operations performed on abides CA2000.
+ /// The first parameter of the function delegate and delegate .
+ /// The second parameter of the function delegate and delegate .
+ /// The third parameter of the function delegate and delegate .
+ /// The fourth parameter of the function delegate and delegate .
+ /// The fifth parameter of the function delegate and delegate .
+ /// The token to monitor for cancellation requests. The default value is .
+ /// The function delegate that will handle any exceptions might thrown by .
+ /// A task that represents the asynchronous operation. The task result contains the return value of the function delegate if the operations succeeded; otherwise null if the operation failed.
+ public static Task SafeInvokeAsync(Func initializer, Func> tester, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, CancellationToken ct = default, Func catcher = null) where TResult : class, IDisposable
+ {
+ Validator.ThrowIfNull(initializer, nameof(initializer));
+ Validator.ThrowIfNull(tester, nameof(tester));
+ var f1 = TaskFuncFactory.Create(tester, default, arg1, arg2, arg3, arg4, arg5);
+ var f2 = TaskActionFactory.Create(catcher, default, arg1, arg2, arg3, arg4, arg5);
+ return SafeInvokeAsyncCore(f1, initializer, f2, ct);
+ }
+
+ private static TResult SafeInvokeCore(FuncFactory testerFactory, Func initializer, ActionFactory catcherFactory)
+ where TResult : class, IDisposable
+ where TTester : Template
+ where TCatcher : Template
+ {
+ TResult result = null;
+ try
+ {
+ testerFactory.GenericArguments.Arg1 = initializer();
+ testerFactory.GenericArguments.Arg1 = testerFactory.ExecuteMethod();
+ result = testerFactory.GenericArguments.Arg1;
+ testerFactory.GenericArguments.Arg1 = null;
+ }
+ catch (Exception e)
+ {
+ if (!catcherFactory.HasDelegate)
+ {
+ throw;
+ }
+ else
+ {
+ catcherFactory.GenericArguments.Arg1 = e;
+ catcherFactory.ExecuteMethod();
+ }
+ }
+ finally
+ {
+ testerFactory.GenericArguments.Arg1?.Dispose();
+ }
+ return result;
+ }
+
+ private static async Task SafeInvokeAsyncCore(TaskFuncFactory testerFactory, Func initializer, TaskActionFactory catcherFactory, CancellationToken ct)
+ where TResult : class, IDisposable
+ where TTester : Template
+ where TCatcher : Template
+ {
+ TResult result = null;
+ try
+ {
+ testerFactory.GenericArguments.Arg1 = initializer();
+ testerFactory.GenericArguments.Arg1 = await testerFactory.ExecuteMethodAsync(ct).ConfigureAwait(false);
+ result = testerFactory.GenericArguments.Arg1;
+ testerFactory.GenericArguments.Arg1 = null;
+ }
+ catch (Exception e)
+ {
+ if (!catcherFactory.HasDelegate)
+ {
+ throw;
+ }
+ else
+ {
+ catcherFactory.GenericArguments.Arg1 = e;
+ await catcherFactory.ExecuteMethodAsync(ct).ConfigureAwait(false);
+ }
+ }
+ finally
+ {
+ testerFactory.GenericArguments.Arg1?.Dispose();
+ }
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Properties/PackageReleaseNotes.txt b/src/Cuemon.Core/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..dbaee21a1
--- /dev/null
+++ b/src/Cuemon.Core/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,53 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# Upgrade Steps
+- To use the earlier built-in support for transient fault handling, please refer to the Cuemon.Resilience namespace, as it has been merged and refactored out of this assembly
+- To use the earlier built-in support for time-measuring and describing exceptions, please refer to the Cuemon.Diagnostics namespace, as it has been merged and refactored out of this assembly
+- To use the earlier built-in support for a computed checksum operation, please refer to the Cuemon.Data.Integrity namespace, as it has been merged and refactored out of this and the Cuemon.Integrity assembly
+- Any former extension methods of the Cuemon namespace (and related) was either removed completely or merged into there respective Cuemon.Extensions.* namespace equivalent
+
+# Breaking Changes
+- REMOVED StringFormatter class from the Cuemon namespace
+- REMOVED StandardizedDateTimeFormatPattern enum from the Cuemon namespace
+- MOVED AsyncOptions class in the Cuemon.Threading namespace to its own assembly (by the same name and namespace)
+- REMOVED JsonWebToken class from the Cuemon.Security.Web namespace
+- REMOVED JsonWebTokenHashAlgorithm class from the Cuemon.Security.Web namespace
+- REMOVED JsonWebTokenHashAlgorithmConverter class from the Cuemon.Security.Web namespace
+- REMOVED JsonWebTokenHeader class from the Cuemon.Security.Web namespace
+- REMOVED JsonWebTokenPayload class from the Cuemon.Security.Web namespace
+- REMOVED Obfuscator class from the Cuemon.Security namespace
+- REMOVED ObfuscatorMapping class from the Cuemon.Security namespace
+- REMOVED SecurityToken class from the Cuemon.Security namespace
+- REMOVED SecurityTokenSettings class from the Cuemon.Security namespace (replaced with SignedUriOptions in the Cuemon.Extensions.Net.Security namespace)
+- REMOVED SecurityUtility class from the Cuemon.Security namespace
+- REMOVED AssemblyExtensions class from the Cuemon.Reflection namespace
+- MOVED MemberInfoExtensions class from the Cuemon.Reflection namespace to Cuemon.Extensions.Reflection namespace
+- REMOVED MethodBaseConverterExtensions class from the Cuemon.Reflection namespace
+- MOVED LatencyException class in the Cuemon namespace to its own assembly and namespace (Cuemon.Resilience)
+- MOVED TransientOperation class in the Cuemon namespace to its own assembly and namespace (Cuemon.Resilience)
+- MOVED TransientFaultEvidence class in the Cuemon namespace to its own assembly and namespace (Cuemon.Resilience)
+- MOVED TransientFaultException class in the Cuemon namespace to its own assembly and namespace (Cuemon.Resilience)
+- MOVED TransientOperation class in the Cuemon namespace to its own assembly and namespace (Cuemon.Resilience)
+- MOVED TransientOperationOptions class in the Cuemon namespace to its own assembly and namespace (Cuemon.Resilience)
+- REMOVED IMessageLocalizer interface from the Cuemon.Globalization namespace
+
+# New Features
+- ADDED ResourceAttribute class in the Cuemon.Globalization namespace that provides a generic way to support localization on attribute decorated methods
+-
+
+# Bug Fixes
+-
+-
+
+# Improvements
+-
+-
+
+# Quality Actions
+-
+-
+
+# Other Changes
+-
+-
\ No newline at end of file
diff --git a/src/Cuemon.Core/Reflection/MemberReflection.cs b/src/Cuemon.Core/Reflection/MemberReflection.cs
index 8419820a6..50cbaf754 100644
--- a/src/Cuemon.Core/Reflection/MemberReflection.cs
+++ b/src/Cuemon.Core/Reflection/MemberReflection.cs
@@ -29,12 +29,14 @@ public static implicit operator BindingFlags(MemberReflection mr)
/// if set to true non-public members are excluded from the binding constraint.
/// if set to true static members are excluded from the binding constraint.
/// if set to true derived members of a type's inheritance path are excluded from the binding constraint.
- public MemberReflection(bool excludePrivate = false, bool excludeStatic = false, bool excludeInheritancePath = false) :
+ /// if set to true public members are excluded from the binding constraint.
+ public MemberReflection(bool excludePrivate = false, bool excludeStatic = false, bool excludeInheritancePath = false, bool excludePublic = false) :
this(o =>
{
o.ExcludeInheritancePath = excludeInheritancePath;
o.ExcludePrivate = excludePrivate;
o.ExcludeStatic = excludeStatic;
+ o.ExcludePublic = excludePublic;
})
{
}
@@ -50,6 +52,7 @@ public MemberReflection(Action setup)
if (options.ExcludePrivate) { flags &= ~BindingFlags.NonPublic; }
if (options.ExcludeStatic) { flags &= ~BindingFlags.Static; }
if (options.ExcludeInheritancePath) { flags |= BindingFlags.DeclaredOnly; }
+ if (options.ExcludePublic) { flags &= ~BindingFlags.Public; }
Flags = flags;
}
diff --git a/src/Cuemon.Core/Reflection/MemberReflectionOptions.cs b/src/Cuemon.Core/Reflection/MemberReflectionOptions.cs
index d77a777aa..ece279157 100644
--- a/src/Cuemon.Core/Reflection/MemberReflectionOptions.cs
+++ b/src/Cuemon.Core/Reflection/MemberReflectionOptions.cs
@@ -27,6 +27,10 @@ public class MemberReflectionOptions
///
/// false
///
+ /// -
+ ///
+ /// false
+ ///
///
///
public MemberReflectionOptions()
@@ -34,6 +38,7 @@ public MemberReflectionOptions()
ExcludePrivate = false;
ExcludeStatic = false;
ExcludeInheritancePath = false;
+ ExcludePublic = false;
}
///
@@ -53,5 +58,11 @@ public MemberReflectionOptions()
///
/// true if derived members of a type's inheritance path are excluded from the binding constraint; otherwise, false.
public bool ExcludeInheritancePath { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether public members are excluded from the binding constraint.
+ ///
+ /// true if public members are excluded from the binding constraint; otherwise, false.
+ public bool ExcludePublic { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Reflection/VersionResult.cs b/src/Cuemon.Core/Reflection/VersionResult.cs
new file mode 100644
index 000000000..f5c3fd108
--- /dev/null
+++ b/src/Cuemon.Core/Reflection/VersionResult.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Generic;
+
+namespace Cuemon.Reflection
+{
+ ///
+ /// Represents different representations of a version scheme in a consistent way.
+ ///
+ public class VersionResult
+ {
+ private readonly Version _version;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The that represents a potential alphanumeric version.
+ public VersionResult(string alphanumericVersion)
+ {
+ AlphanumericVersion = alphanumericVersion;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The that represents a numerical version {major.minor.build.revision}.
+ public VersionResult(Version version)
+ {
+ AlphanumericVersion = version?.ToString();
+ _version = version;
+ }
+
+ ///
+ /// Gets the alphanumeric version assigned to this instance.
+ ///
+ /// The alphanumeric version assigned to this instance.
+ public string AlphanumericVersion { get; }
+
+ ///
+ /// Gets a value indicating whether this instance has alphanumeric version assigned.
+ ///
+ /// true if this instance has alphanumeric version assigned; otherwise, false.
+ public bool HasAlphanumericVersion => !string.IsNullOrEmpty(AlphanumericVersion);
+
+ ///
+ /// Determines whether this instance represents a semantic version.
+ ///
+ /// true if this instance represents a semantic version; otherwise, false.
+ public bool IsSemanticVersion()
+ {
+ if (HasAlphanumericVersion)
+ {
+ var isSemantic = true;
+ var versions = AlphanumericVersion.Split('.');
+ foreach (var version in versions)
+ {
+ isSemantic &= int.TryParse(version, out _);
+ }
+ return !isSemantic;
+ }
+ return false;
+ }
+
+ ///
+ /// Converts this instance to an equivalent object.
+ ///
+ /// An equivalent object of this instance.
+ ///
+ /// Only a non-semantic version can be converted to a object.
+ ///
+ public Version ToVersion()
+ {
+ if (HasAlphanumericVersion && _version != null) { return _version; }
+ if (HasAlphanumericVersion)
+ {
+ var versionComponents = new List();
+ var versions = AlphanumericVersion.Split('.');
+ foreach (var version in versions)
+ {
+ if (int.TryParse(version, out var v)) { versionComponents.Add(v); }
+ }
+ return new Version(DelimitedString.Create(versionComponents, o => o.Delimiter = "."));
+ }
+ throw new InvalidOperationException("Only a non-semantic version can be converted to a Version object.");
+ }
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// A that represents this instance.
+ public override string ToString()
+ {
+ return AlphanumericVersion;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheck.cs b/src/Cuemon.Core/Security/CyclicRedundancyCheck.cs
similarity index 92%
rename from src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheck.cs
rename to src/Cuemon.Core/Security/CyclicRedundancyCheck.cs
index f8a267a12..fa952a170 100644
--- a/src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheck.cs
+++ b/src/Cuemon.Core/Security/CyclicRedundancyCheck.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Represents the base class from which all implementations of the CRC (Cyclic Redundancy Check) checksum algorithm must derive.
@@ -10,9 +10,6 @@ namespace Cuemon.Security.Cryptography
public abstract class CyclicRedundancyCheck : Hash
{
private readonly Lazy> _lazyLookup;
- private readonly ulong _initialValue;
- private readonly ulong _finalXor;
-
///
/// Initializes a new instance of the class.
@@ -24,8 +21,8 @@ public abstract class CyclicRedundancyCheck : Hash
protected CyclicRedundancyCheck(ulong polynomial, ulong initialValue, ulong finalXor, Action setup) : base(setup)
{
_lazyLookup = new Lazy>(() => PolynomialTableInitializerCore(polynomial));
- _initialValue = initialValue;
- _finalXor = finalXor;
+ InitialValue = initialValue;
+ FinalXor = finalXor;
}
private List PolynomialTableInitializerCore(ulong polynomial)
@@ -70,12 +67,12 @@ private List PolynomialTableInitializerCore(ulong polynomial)
/// Gets the CRC initial value of the register.
///
/// The CRC initial value of the register.
- public ulong InitialValue => _initialValue;
+ public ulong InitialValue { get; }
///
/// Gets the CRC final value that is XORed to the final register value.
///
/// The CRC final value that is XORed to the final register value.
- public ulong FinalXor => _finalXor;
+ public ulong FinalXor { get; }
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheck32.cs b/src/Cuemon.Core/Security/CyclicRedundancyCheck32.cs
similarity index 98%
rename from src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheck32.cs
rename to src/Cuemon.Core/Security/CyclicRedundancyCheck32.cs
index 29378b6ca..f0e31694d 100644
--- a/src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheck32.cs
+++ b/src/Cuemon.Core/Security/CyclicRedundancyCheck32.cs
@@ -1,6 +1,6 @@
using System;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Provides a CRC-32 implementation of the CRC (Cyclic Redundancy Check) checksum algorithm for 32-bit hash values. This class cannot be inherited.
diff --git a/src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheck64.cs b/src/Cuemon.Core/Security/CyclicRedundancyCheck64.cs
similarity index 98%
rename from src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheck64.cs
rename to src/Cuemon.Core/Security/CyclicRedundancyCheck64.cs
index 66825b874..c71b4e327 100644
--- a/src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheck64.cs
+++ b/src/Cuemon.Core/Security/CyclicRedundancyCheck64.cs
@@ -1,6 +1,6 @@
using System;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Provides a CRC-64 implementation of the CRC (Cyclic Redundancy Check) checksum algorithm for 64-bit hash values. This class cannot be inherited.
diff --git a/src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheckAlgorithm.cs b/src/Cuemon.Core/Security/CyclicRedundancyCheckAlgorithm.cs
similarity index 97%
rename from src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheckAlgorithm.cs
rename to src/Cuemon.Core/Security/CyclicRedundancyCheckAlgorithm.cs
index 3f4b210f1..950f8d747 100644
--- a/src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheckAlgorithm.cs
+++ b/src/Cuemon.Core/Security/CyclicRedundancyCheckAlgorithm.cs
@@ -1,4 +1,4 @@
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Different models of the CRC algorithm family.
diff --git a/src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheckOptions.cs b/src/Cuemon.Core/Security/CyclicRedundancyCheckOptions.cs
similarity index 98%
rename from src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheckOptions.cs
rename to src/Cuemon.Core/Security/CyclicRedundancyCheckOptions.cs
index 288a5b4f2..9b04c4837 100644
--- a/src/Cuemon.Core/Security/Cryptography/CyclicRedundancyCheckOptions.cs
+++ b/src/Cuemon.Core/Security/CyclicRedundancyCheckOptions.cs
@@ -1,4 +1,4 @@
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Configuration options for .
diff --git a/src/Cuemon.Core/Security/Cryptography/FowlerNollVo1024.cs b/src/Cuemon.Core/Security/FowlerNollVo1024.cs
similarity index 97%
rename from src/Cuemon.Core/Security/Cryptography/FowlerNollVo1024.cs
rename to src/Cuemon.Core/Security/FowlerNollVo1024.cs
index 8a6546a29..031d979ce 100644
--- a/src/Cuemon.Core/Security/Cryptography/FowlerNollVo1024.cs
+++ b/src/Cuemon.Core/Security/FowlerNollVo1024.cs
@@ -1,7 +1,7 @@
using System;
using System.Numerics;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Provides an implementation of the FVN (Fowler–Noll–Vo) non-cryptographic hashing algorithm for 1024-bit hash values. This class cannot be inherited.
diff --git a/src/Cuemon.Core/Security/Cryptography/FowlerNollVo128.cs b/src/Cuemon.Core/Security/FowlerNollVo128.cs
similarity index 95%
rename from src/Cuemon.Core/Security/Cryptography/FowlerNollVo128.cs
rename to src/Cuemon.Core/Security/FowlerNollVo128.cs
index 2ceb65ef7..986957c52 100644
--- a/src/Cuemon.Core/Security/Cryptography/FowlerNollVo128.cs
+++ b/src/Cuemon.Core/Security/FowlerNollVo128.cs
@@ -1,7 +1,7 @@
using System;
using System.Numerics;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Provides an implementation of the FVN (Fowler–Noll–Vo) non-cryptographic hashing algorithm for 128-bit hash values. This class cannot be inherited.
diff --git a/src/Cuemon.Core/Security/Cryptography/FowlerNollVo256.cs b/src/Cuemon.Core/Security/FowlerNollVo256.cs
similarity index 95%
rename from src/Cuemon.Core/Security/Cryptography/FowlerNollVo256.cs
rename to src/Cuemon.Core/Security/FowlerNollVo256.cs
index 62a9f6407..a4bcc0be8 100644
--- a/src/Cuemon.Core/Security/Cryptography/FowlerNollVo256.cs
+++ b/src/Cuemon.Core/Security/FowlerNollVo256.cs
@@ -1,7 +1,7 @@
using System;
using System.Numerics;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Provides an implementation of the FVN (Fowler–Noll–Vo) non-cryptographic hashing algorithm for 256-bit hash values. This class cannot be inherited.
diff --git a/src/Cuemon.Core/Security/Cryptography/FowlerNollVo32.cs b/src/Cuemon.Core/Security/FowlerNollVo32.cs
similarity index 95%
rename from src/Cuemon.Core/Security/Cryptography/FowlerNollVo32.cs
rename to src/Cuemon.Core/Security/FowlerNollVo32.cs
index 69e448af8..2e75d80d9 100644
--- a/src/Cuemon.Core/Security/Cryptography/FowlerNollVo32.cs
+++ b/src/Cuemon.Core/Security/FowlerNollVo32.cs
@@ -1,7 +1,7 @@
using System;
using System.Numerics;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Provides an implementation of the FVN (Fowler–Noll–Vo) non-cryptographic hashing algorithm for 32-bit hash values. This class cannot be inherited.
diff --git a/src/Cuemon.Core/Security/Cryptography/FowlerNollVo512.cs b/src/Cuemon.Core/Security/FowlerNollVo512.cs
similarity index 96%
rename from src/Cuemon.Core/Security/Cryptography/FowlerNollVo512.cs
rename to src/Cuemon.Core/Security/FowlerNollVo512.cs
index 57e73a75e..d6be422d3 100644
--- a/src/Cuemon.Core/Security/Cryptography/FowlerNollVo512.cs
+++ b/src/Cuemon.Core/Security/FowlerNollVo512.cs
@@ -1,7 +1,7 @@
using System;
using System.Numerics;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Provides an implementation of the FVN (Fowler–Noll–Vo) non-cryptographic hashing algorithm for 512-bit hash values. This class cannot be inherited.
diff --git a/src/Cuemon.Core/Security/Cryptography/FowlerNollVo64.cs b/src/Cuemon.Core/Security/FowlerNollVo64.cs
similarity index 95%
rename from src/Cuemon.Core/Security/Cryptography/FowlerNollVo64.cs
rename to src/Cuemon.Core/Security/FowlerNollVo64.cs
index cbc648267..badb8624c 100644
--- a/src/Cuemon.Core/Security/Cryptography/FowlerNollVo64.cs
+++ b/src/Cuemon.Core/Security/FowlerNollVo64.cs
@@ -1,7 +1,7 @@
using System;
using System.Numerics;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Provides an implementation of the FVN (Fowler–Noll–Vo) non-cryptographic hashing algorithm for 64-bit hash values. This class cannot be inherited.
diff --git a/src/Cuemon.Core/Security/Cryptography/FowlerNollVoAlgorithm.cs b/src/Cuemon.Core/Security/FowlerNollVoAlgorithm.cs
similarity index 89%
rename from src/Cuemon.Core/Security/Cryptography/FowlerNollVoAlgorithm.cs
rename to src/Cuemon.Core/Security/FowlerNollVoAlgorithm.cs
index aaab74f95..a3dec618e 100644
--- a/src/Cuemon.Core/Security/Cryptography/FowlerNollVoAlgorithm.cs
+++ b/src/Cuemon.Core/Security/FowlerNollVoAlgorithm.cs
@@ -1,4 +1,4 @@
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Defines the algorithms of the Fowler-Noll-Vo hash function.
diff --git a/src/Cuemon.Core/Security/Cryptography/FowlerNollVoHash.cs b/src/Cuemon.Core/Security/FowlerNollVoHash.cs
similarity index 90%
rename from src/Cuemon.Core/Security/Cryptography/FowlerNollVoHash.cs
rename to src/Cuemon.Core/Security/FowlerNollVoHash.cs
index 5dbe8ecf2..bb4a720bd 100644
--- a/src/Cuemon.Core/Security/Cryptography/FowlerNollVoHash.cs
+++ b/src/Cuemon.Core/Security/FowlerNollVoHash.cs
@@ -1,7 +1,7 @@
using System;
using System.Numerics;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Represents the base class from which all implementations of the Fowler–Noll–Vo non-cryptographic hashing algorithm must derive.
@@ -17,9 +17,9 @@ public abstract class FowlerNollVoHash : Hash
/// The which need to be configured.
protected FowlerNollVoHash(short bits, BigInteger prime, BigInteger offsetBasis, Action setup) : base(setup)
{
+ Bits = bits;
Prime = prime;
OffsetBasis = offsetBasis;
- Bits = BigInteger.Pow(2, bits);
}
///
@@ -38,7 +38,7 @@ protected FowlerNollVoHash(short bits, BigInteger prime, BigInteger offsetBasis,
/// Gets the size of the implementation in bits.
///
/// The size of the implementation in bits.
- public BigInteger Bits { get; }
+ public short Bits { get; }
///
/// Computes the hash value for the specified .
@@ -55,7 +55,6 @@ public override HashResult ComputeHash(byte[] input)
{
hash ^= b;
hash *= Prime;
- hash %= Bits;
}
break;
default:
@@ -63,12 +62,11 @@ public override HashResult ComputeHash(byte[] input)
{
hash *= Prime;
hash ^= b;
- hash %= Bits;
}
break;
}
var result = hash.ToByteArray();
- if (Condition.IsOdd(result.Length)) { Array.Resize(ref result, result.Length - 1); }
+ Array.Resize(ref result, Bits / ByteUnit.BitsPerByte);
result = Convertible.ReverseEndianness(result, o => o.ByteOrder = Options.ByteOrder);
return new HashResult(result);
}
diff --git a/src/Cuemon.Core/Security/Cryptography/FowlerNollVoOptions.cs b/src/Cuemon.Core/Security/FowlerNollVoOptions.cs
similarity index 97%
rename from src/Cuemon.Core/Security/Cryptography/FowlerNollVoOptions.cs
rename to src/Cuemon.Core/Security/FowlerNollVoOptions.cs
index ade6c0ac2..fd9da5490 100644
--- a/src/Cuemon.Core/Security/Cryptography/FowlerNollVoOptions.cs
+++ b/src/Cuemon.Core/Security/FowlerNollVoOptions.cs
@@ -1,4 +1,4 @@
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Configuration options for .
diff --git a/src/Cuemon.Core/Security/Cryptography/Hash.cs b/src/Cuemon.Core/Security/Hash.cs
similarity index 98%
rename from src/Cuemon.Core/Security/Cryptography/Hash.cs
rename to src/Cuemon.Core/Security/Hash.cs
index 9f7e511f3..c64b10d17 100644
--- a/src/Cuemon.Core/Security/Cryptography/Hash.cs
+++ b/src/Cuemon.Core/Security/Hash.cs
@@ -6,7 +6,7 @@
using Cuemon.IO;
using Cuemon.Text;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Represents the base class from which all implementations of hash algorithms and checksums should derive.
@@ -264,7 +264,7 @@ public virtual HashResult ComputeHash(IEnumerable input)
/// A containing the computed hash code of the specified .
public virtual HashResult ComputeHash(Stream input)
{
- return ComputeHash(Disposable.SafeInvoke(() => new MemoryStream(), destination =>
+ return ComputeHash(Patterns.SafeInvoke(() => new MemoryStream(), destination =>
{
Decorator.Enclose(input).CopyStream(destination);
return destination;
diff --git a/src/Cuemon.Core/Security/Cryptography/HashFactory.cs b/src/Cuemon.Core/Security/HashFactory.cs
similarity index 60%
rename from src/Cuemon.Core/Security/Cryptography/HashFactory.cs
rename to src/Cuemon.Core/Security/HashFactory.cs
index ef8bc2ec0..e109e8b67 100644
--- a/src/Cuemon.Core/Security/Cryptography/HashFactory.cs
+++ b/src/Cuemon.Core/Security/HashFactory.cs
@@ -1,187 +1,12 @@
using System;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Provides access to factory methods for creating and configuring instances.
///
public static class HashFactory
{
- ///
- /// Creates an instance of a HMAC cryptographic implementation that derives from with the specified . Default is .
- ///
- /// The secret key for the encryption.
- /// The that defines the HMAC cryptographic implementation. Default is .
- /// The which may be configured.
- /// A implementation of the by parameter specified .
- ///
- /// cannot be null.
- ///
- public static Hash CreateHmacCrypto(byte[] secret, KeyedCryptoAlgorithm algorithm = default, Action setup = null)
- {
- switch (algorithm)
- {
- case KeyedCryptoAlgorithm.HmacMd5:
- return CreateHmacCryptoMd5(secret, setup);
- case KeyedCryptoAlgorithm.HmacSha1:
- return CreateHmacCryptoSha1(secret, setup);
- case KeyedCryptoAlgorithm.HmacSha384:
- return CreateHmacCryptoSha384(secret, setup);
- case KeyedCryptoAlgorithm.HmacSha512:
- return CreateHmacCryptoSha512(secret, setup);
- default:
- return CreateHmacCryptoSha256(secret, setup);
- }
- }
-
- ///
- /// Creates an instance of .
- ///
- /// The secret key for encryption. The key can be any length. However, the recommended size is 128 bytes. If the key is more than 128 bytes long, it is hashed (using SHA-384) to derive a 128-byte key. If it is less than 128 bytes long, it is padded to 128 bytes.
- /// The which may be configured.
- /// A implementation of .
- ///
- /// cannot be null.
- ///
- public static Hash CreateHmacCryptoSha512(byte[] secret, Action setup = null)
- {
- Validator.ThrowIfNull(secret, nameof(secret));
- return new HmacSecureHashAlgorithm512(secret, setup);
- }
-
- ///
- /// Creates an instance of .
- ///
- /// The secret key for encryption. The key can be any length. However, the recommended size is 128 bytes. If the key is more than 128 bytes long, it is hashed (using SHA-384) to derive a 128-byte key. If it is less than 128 bytes long, it is padded to 128 bytes.
- /// The which may be configured.
- /// A implementation of .
- ///
- /// cannot be null.
- ///
- public static Hash CreateHmacCryptoSha384(byte[] secret, Action setup = null)
- {
- Validator.ThrowIfNull(secret, nameof(secret));
- return new HmacSecureHashAlgorithm384(secret, setup);
- }
-
- ///
- /// Creates an instance of .
- ///
- /// The secret key for encryption. The key can be any length. However, the recommended size is 64 bytes. If the key is more than 64 bytes long, it is hashed (using SHA-256) to derive a 64-byte key. If it is less than 64 bytes long, it is padded to 64 bytes.
- /// The which may be configured.
- /// A implementation of .
- ///
- /// cannot be null.
- ///
- public static Hash CreateHmacCryptoSha256(byte[] secret, Action setup = null)
- {
- Validator.ThrowIfNull(secret, nameof(secret));
- return new HmacSecureHashAlgorithm256(secret, setup);
- }
-
- ///
- /// Creates an instance of .
- ///
- /// The secret key for encryption. The key can be any length, but if it is more than 64 bytes long it will be hashed (using SHA-1) to derive a 64-byte key. Therefore, the recommended size of the secret key is 64 bytes.
- /// The which may be configured.
- /// A implementation of .
- ///
- /// cannot be null.
- ///
- public static Hash CreateHmacCryptoSha1(byte[] secret, Action setup = null)
- {
- Validator.ThrowIfNull(secret, nameof(secret));
- return new HmacSecureHashAlgorithm1(secret, setup);
- }
-
- ///
- /// Creates an instance of .
- ///
- /// The secret key for encryption. The key can be any length, but if it is more than 64 bytes long it will be hashed (using SHA-1) to derive a 64-byte key. Therefore, the recommended size of the secret key is 64 bytes.
- /// The which may be configured.
- /// A implementation of .
- ///
- /// cannot be null.
- ///
- public static Hash CreateHmacCryptoMd5(byte[] secret, Action setup = null)
- {
- Validator.ThrowIfNull(secret, nameof(secret));
- return new HmacMessageDigest5(secret, setup);
- }
-
- ///
- /// Creates an instance of a cryptographic implementation that derives from with the specified . Default is .
- ///
- /// The that defines the cryptographic implementation. Default is .
- /// The which may be configured.
- /// A implementation of the by parameter specified .
- public static Hash CreateCrypto(CryptoAlgorithm algorithm = default, Action setup = null)
- {
- switch (algorithm)
- {
- case CryptoAlgorithm.Md5:
- return CreateCryptoMd5(setup);
- case CryptoAlgorithm.Sha1:
- return CreateCryptoSha1(setup);
- case CryptoAlgorithm.Sha384:
- return CreateCryptoSha384(setup);
- case CryptoAlgorithm.Sha512:
- return CreateCryptoSha512(setup);
- default:
- return CreateCryptoSha256(setup);
- }
- }
-
- ///
- /// Creates an instance of .
- ///
- /// The which may be configured.
- /// A implementation of .
- public static Hash CreateCryptoSha512(Action setup = null)
- {
- return new SecureHashAlgorithm512(setup);
- }
-
- ///
- /// Creates an instance of .
- ///
- /// The which may be configured.
- /// A implementation of .
- public static Hash CreateCryptoSha384(Action setup = null)
- {
- return new SecureHashAlgorithm384(setup);
- }
-
- ///
- /// Creates an instance of .
- ///
- /// The which may be configured.
- /// A implementation of .
- public static Hash CreateCryptoSha256(Action setup = null)
- {
- return new SecureHashAlgorithm256(setup);
- }
-
- ///
- /// Creates an instance of .
- ///
- /// The which may be configured.
- /// A implementation of .
- public static Hash CreateCryptoSha1(Action setup = null)
- {
- return new SecureHashAlgorithm1(setup);
- }
-
- ///
- /// Creates an instance of .
- ///
- /// The which may be configured.
- /// A implementation of .
- public static Hash CreateCryptoMd5(Action setup = null)
- {
- return new MessageDigest5(setup);
- }
-
///
/// Creates an instance of a non-cryptographic implementation that derives from with the specified . Default is using .
///
diff --git a/src/Cuemon.Core/Security/Cryptography/HashResult.cs b/src/Cuemon.Core/Security/HashResult.cs
similarity index 98%
rename from src/Cuemon.Core/Security/Cryptography/HashResult.cs
rename to src/Cuemon.Core/Security/HashResult.cs
index 91227277b..f31caf403 100644
--- a/src/Cuemon.Core/Security/Cryptography/HashResult.cs
+++ b/src/Cuemon.Core/Security/HashResult.cs
@@ -1,6 +1,6 @@
using System;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Represents the result of a computed checksum operation.
@@ -9,7 +9,6 @@ public class HashResult : IEquatable
{
private readonly byte[] _input;
-
///
/// Initializes a new instance of the class.
///
@@ -31,6 +30,7 @@ public HashResult(byte[] input)
/// The copy of the original value that reflects a computed operation.
public byte[] GetBytes()
{
+ if (_input.Length == 0) { return new byte[0]; }
var copy = new byte[_input.Length];
Array.Copy(_input, copy, copy.Length);
return copy;
diff --git a/src/Cuemon.Core/Security/Cryptography/IHash.cs b/src/Cuemon.Core/Security/IHash.cs
similarity index 88%
rename from src/Cuemon.Core/Security/Cryptography/IHash.cs
rename to src/Cuemon.Core/Security/IHash.cs
index 7eb25246c..fc2016a63 100644
--- a/src/Cuemon.Core/Security/Cryptography/IHash.cs
+++ b/src/Cuemon.Core/Security/IHash.cs
@@ -1,9 +1,9 @@
using System.IO;
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
- /// Defines the bare minimum of cryptographic transformations.
+ /// Defines the bare minimum of both non-cryptographic and cryptographic transformations.
///
public interface IHash
{
diff --git a/src/Cuemon.Core/Security/Cryptography/NonCryptoAlgorithm.cs b/src/Cuemon.Core/Security/NonCryptoAlgorithm.cs
similarity index 95%
rename from src/Cuemon.Core/Security/Cryptography/NonCryptoAlgorithm.cs
rename to src/Cuemon.Core/Security/NonCryptoAlgorithm.cs
index 165fc4134..617d7a250 100644
--- a/src/Cuemon.Core/Security/Cryptography/NonCryptoAlgorithm.cs
+++ b/src/Cuemon.Core/Security/NonCryptoAlgorithm.cs
@@ -1,4 +1,4 @@
-namespace Cuemon.Security.Cryptography
+namespace Cuemon.Security
{
///
/// Specifies the different implementations of a non-cryptographic hashing algorithm.
diff --git a/src/Cuemon.Core/StandardizedDateTimeFormatPattern.cs b/src/Cuemon.Core/StandardizedDateTimeFormatPattern.cs
deleted file mode 100644
index 5557b9f5b..000000000
--- a/src/Cuemon.Core/StandardizedDateTimeFormatPattern.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-namespace Cuemon
-{
- ///
- /// Defines some standardized patterns to use when formatting date- and time values.
- ///
- public enum StandardizedDateTimeFormatPattern
- {
- ///
- /// Displays a date using the ISO8601 basic date format, eg.: YYYYMMDD.
- ///
- Iso8601CompleteDateBasic,
- ///
- /// Displays a date using the ISO8601 extended date format (human readable), eg.: YYYY-MM-DD.
- ///
- Iso8601CompleteDateExtended,
- ///
- /// Displays a date using the ISO8601 basic date format in conjunction with the ISO8601 time format, eg.: YYYYMMDDThhmmssTZD.
- ///
- Iso8601CompleteDateTimeBasic,
- ///
- /// Displays a date using the ISO8601 extended date format (human readable) in conjunction with the ISO8601 extended time format (human readable), eg.: YYYY-MM-DDThh:mm:ssTZD.
- ///
- Iso8601CompleteDateTimeExtended
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.Core/StringFormatter.cs b/src/Cuemon.Core/StringFormatter.cs
deleted file mode 100644
index f5ca13ef5..000000000
--- a/src/Cuemon.Core/StringFormatter.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using System;
-using System.Globalization;
-
-namespace Cuemon
-{
- ///
- /// This utility class is designed to make related formating operations easier to work with.
- ///
- public static class StringFormatter
- {
- ///
- /// Returns a string expression representing a standardized date- and time value.
- ///
- /// The value to be formatted.
- /// The standardized patterns to apply on .
- /// Returns a string expression representing a date- and time value.
- public static string FromDateTime(DateTime value, StandardizedDateTimeFormatPattern pattern)
- {
- return FromDateTime(value, pattern, 0);
- }
-
- ///
- /// Returns a string expression representing a standardized date- and time value.
- ///
- /// The value to be formatted.
- /// The standardized patterns to apply on .
- /// The amount of fractional decimal places to apply to the string expression.
- /// Returns a string expression representing a date- and time value.
- public static string FromDateTime(DateTime value, StandardizedDateTimeFormatPattern pattern, byte fractionalDecimalPlaces)
- {
- switch (pattern)
- {
- case StandardizedDateTimeFormatPattern.Iso8601CompleteDateBasic:
- return value.ToString("yyyyMMdd", CultureInfo.InvariantCulture);
- case StandardizedDateTimeFormatPattern.Iso8601CompleteDateExtended:
- return value.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
- case StandardizedDateTimeFormatPattern.Iso8601CompleteDateTimeBasic:
- return value.ToString(string.Format(CultureInfo.InvariantCulture, "yyyyMMddTHHmmss{0}{1}", fractionalDecimalPlaces == 0 ? "" : string.Format(CultureInfo.InvariantCulture, ".{0}", Generate.FixedString('f', fractionalDecimalPlaces)), value.Kind == DateTimeKind.Utc ? "Z" : "zz"), CultureInfo.InvariantCulture);
- case StandardizedDateTimeFormatPattern.Iso8601CompleteDateTimeExtended:
- return value.ToString(string.Format(CultureInfo.InvariantCulture, "yyyy-MM-ddTHH:mm:ss{0}{1}", fractionalDecimalPlaces == 0 ? "" : string.Format(CultureInfo.InvariantCulture, ".{0}", Generate.FixedString('f', fractionalDecimalPlaces)), value.Kind == DateTimeKind.Utc ? "Z" : "zz"), CultureInfo.InvariantCulture);
- default:
- throw new ArgumentOutOfRangeException(nameof(pattern));
- }
- }
-
- ///
- /// Returns a string expression representing a standardized date- and time value.
- ///
- /// The value to be formatted.
- /// The standardized patterns to apply on .
- /// Returns a string expression representing a date- and time value.
- public static string FromDateTime(DateTime value, DateTimeFormatPattern pattern)
- {
- return FromDateTime(value, pattern, CultureInfo.InvariantCulture);
- }
-
- ///
- /// Returns a string expression representing a standardized date- and time value.
- ///
- /// The value to be formatted.
- /// The standardized patterns to apply on .
- /// An that supplies culture-specific formatting information.
- /// Returns a string expression representing a date- and time value.
- public static string FromDateTime(DateTime value, DateTimeFormatPattern pattern, IFormatProvider provider)
- {
- var formatInfo = DateTimeFormatInfo.GetInstance(provider);
- switch (pattern)
- {
- case DateTimeFormatPattern.LongDate:
- return value.ToString(formatInfo.LongDatePattern, formatInfo);
- case DateTimeFormatPattern.LongDateTime:
- return value.ToString(string.Format(formatInfo, "{0} {1}", formatInfo.LongDatePattern, formatInfo.LongTimePattern), formatInfo);
- case DateTimeFormatPattern.LongTime:
- return value.ToString(formatInfo.LongTimePattern, formatInfo);
- case DateTimeFormatPattern.ShortDate:
- return value.ToString(formatInfo.ShortDatePattern, formatInfo);
- case DateTimeFormatPattern.ShortDateTime:
- return value.ToString(string.Format(formatInfo, "{0} {1}", formatInfo.ShortDatePattern, formatInfo.ShortTimePattern), formatInfo);
- case DateTimeFormatPattern.ShortTime:
- return value.ToString(formatInfo.ShortTimePattern, formatInfo);
- default:
- throw new ArgumentOutOfRangeException(nameof(pattern));
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.Core/TaskActionFactory.cs b/src/Cuemon.Core/TaskActionFactory.cs
index 302135a45..2de8ef77e 100644
--- a/src/Cuemon.Core/TaskActionFactory.cs
+++ b/src/Cuemon.Core/TaskActionFactory.cs
@@ -448,9 +448,16 @@ internal TaskActionFactory(Func method, TTuple
///
/// The token to monitor for cancellation requests. The default value is .
/// A task that represents the asynchronous operation.
+ ///
+ /// No delegate was specified on the factory.
+ ///
+ ///
+ /// The was canceled.
+ ///
public Task ExecuteMethodAsync(CancellationToken ct)
{
ThrowIfNoValidDelegate(Condition.IsNull(Method));
+ ct.ThrowIfCancellationRequested();
return Method.Invoke(GenericArguments, ct);
}
@@ -459,7 +466,7 @@ public Task ExecuteMethodAsync(CancellationToken ct)
///
/// A new that is a copy of this instance.
/// When thread safety is required this is the method to invoke.
- public TaskActionFactory Clone()
+ public override TemplateFactory Clone()
{
return new TaskActionFactory(Method, GenericArguments.Clone() as TTuple);
}
diff --git a/src/Cuemon.Core/TaskFuncFactory.cs b/src/Cuemon.Core/TaskFuncFactory.cs
index 70ac1166f..f55959350 100644
--- a/src/Cuemon.Core/TaskFuncFactory.cs
+++ b/src/Cuemon.Core/TaskFuncFactory.cs
@@ -465,9 +465,16 @@ internal TaskFuncFactory(Func> method,
///
/// The token to monitor for cancellation requests. The default value is .
/// A task that represents the asynchronous operation. The task result contains the return value of the function delegate associated with this instance.
+ ///
+ /// No delegate was specified on the factory.
+ ///
+ ///
+ /// The was canceled.
+ ///
public Task ExecuteMethodAsync(CancellationToken ct)
{
ThrowIfNoValidDelegate(Condition.IsNull(Method));
+ ct.ThrowIfCancellationRequested();
return Method.Invoke(GenericArguments, ct);
}
@@ -476,7 +483,7 @@ public Task ExecuteMethodAsync(CancellationToken ct)
///
/// A new that is a copy of this instance.
/// When thread safety is required this is the method to invoke.
- public TaskFuncFactory Clone()
+ public override TemplateFactory Clone()
{
return new TaskFuncFactory(Method, GenericArguments.Clone() as TTuple);
}
diff --git a/src/Cuemon.Core/Template.cs b/src/Cuemon.Core/Template.cs
index cb3eff0c7..b47177f0e 100644
--- a/src/Cuemon.Core/Template.cs
+++ b/src/Cuemon.Core/Template.cs
@@ -1,5 +1,4 @@
-using System;
-using Cuemon.Collections.Generic;
+using Cuemon.Collections.Generic;
namespace Cuemon
{
diff --git a/src/Cuemon.Core/TemplateFactory.cs b/src/Cuemon.Core/TemplateFactory.cs
index 043a4fc99..94504d941 100644
--- a/src/Cuemon.Core/TemplateFactory.cs
+++ b/src/Cuemon.Core/TemplateFactory.cs
@@ -58,9 +58,19 @@ public override string ToString()
/// Validates and throws an if this instance has no valid delegate.
///
/// The value of a condition that can be either true or false.
+ ///
+ /// No delegate was specified on the factory.
+ ///
protected void ThrowIfNoValidDelegate(bool delegateIsNull)
{
if (!HasDelegate) { throw new InvalidOperationException(delegateIsNull ? "There is no delegate specified on the factory." : FormattableString.Invariant($"There is a delegate specified on the factory, '{Decorator.Enclose(GetType()).ToFriendlyName(o => o.FullName = true)}', but it leads to a null referenced delegate wrapper.")); }
}
+
+ ///
+ /// Creates a shallow copy of the current object.
+ ///
+ /// A new implementation that is a copy of this instance.
+ /// When thread safety is required this is the method to invoke.
+ public abstract TemplateFactory Clone();
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Core/TesterFuncFactory.cs b/src/Cuemon.Core/TesterFuncFactory.cs
index 29e6d8170..68cb80c84 100644
--- a/src/Cuemon.Core/TesterFuncFactory.cs
+++ b/src/Cuemon.Core/TesterFuncFactory.cs
@@ -563,7 +563,7 @@ public virtual TSuccess ExecuteMethod(out TResult result)
///
/// A new that is a copy of this instance.
/// When thread safety is required this is the method to invoke.
- public TesterFuncFactory Clone()
+ public override TemplateFactory Clone()
{
return new TesterFuncFactory(Method, GenericArguments.Clone() as TTuple);
}
diff --git a/src/Cuemon.Core/Text/ByteOrderMark.cs b/src/Cuemon.Core/Text/ByteOrderMark.cs
index b8e07f406..07724219e 100644
--- a/src/Cuemon.Core/Text/ByteOrderMark.cs
+++ b/src/Cuemon.Core/Text/ByteOrderMark.cs
@@ -156,9 +156,9 @@ public static Stream Remove(Stream value, Encoding encoding, Action o.LeaveOpen = option.LeaveOpen);
+ var bytes = Decorator.Enclose(value).InvokeToByteArray(leaveOpen: option.LeaveOpen);
bytes = Remove(bytes, encoding);
- return Disposable.SafeInvoke(() => new MemoryStream(bytes.Length), ms =>
+ return Patterns.SafeInvoke(() => new MemoryStream(bytes.Length), ms =>
{
ms.Write(bytes, 0, bytes.Length);
ms.Position = 0;
diff --git a/src/Cuemon.Core/Text/EncodingOptions.cs b/src/Cuemon.Core/Text/EncodingOptions.cs
index 7cc55b22e..af3d9ff36 100644
--- a/src/Cuemon.Core/Text/EncodingOptions.cs
+++ b/src/Cuemon.Core/Text/EncodingOptions.cs
@@ -1,13 +1,12 @@
using System;
using System.Text;
-using Cuemon.Threading;
namespace Cuemon.Text
{
///
/// Configuration options related to .
///
- public class EncodingOptions : AsyncOptions, IEncodingOptions
+ public class EncodingOptions : IEncodingOptions
{
private Encoding _encoding;
diff --git a/src/Cuemon.Core/Text/IConfigurableParser.cs b/src/Cuemon.Core/Text/IConfigurableParser.cs
index 912ffa723..f0060087d 100644
--- a/src/Cuemon.Core/Text/IConfigurableParser.cs
+++ b/src/Cuemon.Core/Text/IConfigurableParser.cs
@@ -4,7 +4,6 @@ namespace Cuemon.Text
{
///
/// Defines methods that converts a to an of a particular type.
- /// Implements the
///
/// The type of the delegate setup.
///
diff --git a/src/Cuemon.Core/Text/Stem.cs b/src/Cuemon.Core/Text/Stem.cs
index 3a8b128e6..89b1f68da 100644
--- a/src/Cuemon.Core/Text/Stem.cs
+++ b/src/Cuemon.Core/Text/Stem.cs
@@ -3,7 +3,7 @@
namespace Cuemon.Text
{
///
- /// Provides a way to support assigning an stem to a value.
+ /// Provides a way to support assigning a stem to a value.
///
public sealed class Stem
{
diff --git a/src/Cuemon.Core/Validator.cs b/src/Cuemon.Core/Validator.cs
index 391f8b92e..c4a785992 100644
--- a/src/Cuemon.Core/Validator.cs
+++ b/src/Cuemon.Core/Validator.cs
@@ -15,10 +15,10 @@ public sealed class Validator
private static readonly Validator ExtendedValidator = new Validator();
///
- /// Gets the singleton instance of the Validator functionality allowing for extensions methods like: Validator.Throw.IfNotValidJsonDocument().
+ /// Gets the singleton instance of the Validator functionality allowing for extensions methods like: Validator.ThrowIf.InvalidJsonDocument().
///
/// The singleton instance of the Validator functionality.
- public static Validator Throw { get; } = ExtendedValidator;
+ public static Validator ThrowIf { get; } = ExtendedValidator;
///
/// Validates and throws an (or a derived counterpart) from the specified delegate .
@@ -235,6 +235,48 @@ public static void ThrowIfFalse(bool value, string paramName, string message = "
}
}
+ ///
+ /// Validates and throws an if the specified returns true.
+ ///
+ /// The function delegate that determines if an is thrown.
+ /// The name of the parameter that caused the exception.
+ /// A message that describes the error.
+ ///
+ /// returned true.
+ ///
+ public static void ThrowIfTrue(Func predicate, string paramName, string message)
+ {
+ try
+ {
+ ThrowWhen(c => c.IsTrue(predicate).Create(() => new ArgumentException(message, paramName)).TryThrow());
+ }
+ catch (ArgumentException ex)
+ {
+ throw ExceptionInsights.Embed(ex, MethodBase.GetCurrentMethod(), Arguments.ToArray(predicate, paramName, message));
+ }
+ }
+
+ ///
+ /// Validates and throws an if the specified returns false.
+ ///
+ /// The function delegate that determines if an is thrown.
+ /// The name of the parameter that caused the exception.
+ /// A message that describes the error.
+ ///
+ /// returned false.
+ ///
+ public static void ThrowIfFalse(Func predicate, string paramName, string message)
+ {
+ try
+ {
+ ThrowWhen(c => c.IsFalse(predicate).Create(() => new ArgumentException(message, paramName)).TryThrow());
+ }
+ catch (ArgumentException ex)
+ {
+ throw ExceptionInsights.Embed(ex, MethodBase.GetCurrentMethod(), Arguments.ToArray(predicate, paramName, message));
+ }
+ }
+
///
/// Validates and throws an if the specified has no elements.
///
@@ -268,14 +310,14 @@ public static void ThrowIfSequenceEmpty(IEnumerable value, string paramNam
///
/// contains no elements.
///
- public static void ThrowIfSequenceNullOrEmpty(IEnumerable value, string paramName, string message = "Value contains no elements.")
+ public static void ThrowIfSequenceNullOrEmpty(IEnumerable value, string paramName, string message = "Value is either null or contains no elements.")
{
try
{
- ThrowIfNull(value, paramName);
- ThrowIfSequenceEmpty(value, paramName);
+ ThrowIfNull(value, paramName, message);
+ ThrowIfSequenceEmpty(value, paramName, message);
}
- catch (ArgumentException ex)
+ catch (Exception ex) when (ex is ArgumentException)
{
throw ExceptionInsights.Embed(ex, MethodBase.GetCurrentMethod(), Arguments.ToArray(value, paramName, message));
}
diff --git a/src/Cuemon.Core/Wrapper.cs b/src/Cuemon.Core/Wrapper.cs
index 4098c0f6e..0f33248f6 100644
--- a/src/Cuemon.Core/Wrapper.cs
+++ b/src/Cuemon.Core/Wrapper.cs
@@ -193,7 +193,17 @@ public TResult InstanceAs()
///
public TResult InstanceAs(IFormatProvider provider)
{
- return (TResult)Decorator.Enclose
/// The name of the column to find.
/// The column with the specified name as an .
- public override object this[string name]
- {
- get { return Fields[name]; }
- }
+ public override object this[string name] => Fields[name];
///
/// Gets the column located at the specified index.
///
/// The zero-based index of the column to get.
/// The column located at the specified index as an .
- public override object this[int i]
- {
- get { return Fields[i]; }
- }
+ public override object this[int i] => Fields[i];
///
/// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement.
///
/// The records affected.
- public override int RecordsAffected
- {
- get { return -1; }
- }
+ public override int RecordsAffected => -1;
private IOrderedDictionary Fields { get; set; }
@@ -96,18 +87,13 @@ public override int RecordsAffected
/// Gets a value that indicates whether this contains one or more rows.
///
/// true if this instance has rows; otherwise, false.
- public override bool HasRows {
- get { return Reader.HasRows; }
- }
+ public override bool HasRows => Reader.HasRows;
///
/// Gets a value indicating whether the data reader is closed.
///
/// true if this instance is closed; otherwise, false.
- public override bool IsClosed
- {
- get { return IsDisposed; }
- }
+ public override bool IsClosed => IsDisposed;
private bool IsDisposed { get; set; }
@@ -122,10 +108,8 @@ public override bool IsClosed
/// Gets the number of columns in the current row.
///
/// When not positioned in a valid recordset, 0; otherwise, the number of columns in the current record.
- public override int FieldCount
- {
- get { return Mappings.Count; }
- }
+ public override int FieldCount => Mappings.Count;
+
#endregion
#region Methods
@@ -449,10 +433,7 @@ protected override void Dispose(bool disposing)
///
/// The depth of nesting for the current row.
/// The outermost table has a depth of zero.
- public override int Depth
- {
- get { return 0; }
- }
+ public override int Depth => 0;
///
/// Populates an array of objects with the column values of the current record.
diff --git a/src/Cuemon.Core/Data/ConcurrentDsvDataReader.cs b/src/Cuemon.Data/ConcurrentDsvDataReader.cs
similarity index 100%
rename from src/Cuemon.Core/Data/ConcurrentDsvDataReader.cs
rename to src/Cuemon.Data/ConcurrentDsvDataReader.cs
diff --git a/src/Cuemon.Data/Cuemon.Data.csproj b/src/Cuemon.Data/Cuemon.Data.csproj
index 7b61dce3d..2e3ccd9e4 100644
--- a/src/Cuemon.Data/Cuemon.Data.csproj
+++ b/src/Cuemon.Data/Cuemon.Data.csproj
@@ -1,26 +1,15 @@
-
+
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
110bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon
Cuemon.Data
Cuemon.Data
- The Cuemon.Data assembly provides access to abstractions related to the System.Data namespace.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
+ 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.
+ database db abstractions dto data-transfer row column bulk-copy dsv csv xml-data-reader dsv-data-reader concurrent-dsv-data-reader in-operator token-builder
diff --git a/src/Cuemon.Data/DataManager.cs b/src/Cuemon.Data/DataManager.cs
index 172e40648..4e9c5dce7 100644
--- a/src/Cuemon.Data/DataManager.cs
+++ b/src/Cuemon.Data/DataManager.cs
@@ -186,7 +186,7 @@ public static string ReaderToString(DbDataReader value)
///
/// A value.
///
- public int Execute(IDataCommand dataCommand, params DbParameter[] parameters)
+ public int Execute(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteCore(dataCommand, parameters, dbCommand =>
{
@@ -209,7 +209,7 @@ public int Execute(IDataCommand dataCommand, params DbParameter[] parameters)
///
/// A value.
///
- public bool ExecuteExists(IDataCommand dataCommand, params DbParameter[] parameters)
+ public bool ExecuteExists(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
using (var reader = ExecuteReader(dataCommand, parameters))
{
@@ -223,7 +223,7 @@ public bool ExecuteExists(IDataCommand dataCommand, params DbParameter[] paramet
/// The data command to execute.
/// The parameters to use in the command.
///
- public abstract int ExecuteIdentityInt32(IDataCommand dataCommand, params DbParameter[] parameters);
+ public abstract int ExecuteIdentityInt32(IDataCommand dataCommand, params IDbDataParameter[] parameters);
///
/// Executes the command statement and returns an identity value as long.
@@ -231,7 +231,7 @@ public bool ExecuteExists(IDataCommand dataCommand, params DbParameter[] paramet
/// The data command to execute.
/// The parameters to use in the command.
///
- public abstract long ExecuteIdentityInt64(IDataCommand dataCommand, params DbParameter[] parameters);
+ public abstract long ExecuteIdentityInt64(IDataCommand dataCommand, params IDbDataParameter[] parameters);
///
/// Executes the command statement and returns an identity value as decimal.
@@ -239,7 +239,7 @@ public bool ExecuteExists(IDataCommand dataCommand, params DbParameter[] paramet
/// The data command to execute.
/// The parameters to use in the command.
///
- public abstract decimal ExecuteIdentityDecimal(IDataCommand dataCommand, params DbParameter[] parameters);
+ public abstract decimal ExecuteIdentityDecimal(IDataCommand dataCommand, params IDbDataParameter[] parameters);
///
/// Executes the command statement and returns an object supporting the DbDataReader interface.
@@ -249,7 +249,7 @@ public bool ExecuteExists(IDataCommand dataCommand, params DbParameter[] paramet
///
/// An object supporting the interface.
///
- public DbDataReader ExecuteReader(IDataCommand dataCommand, params DbParameter[] parameters)
+ public DbDataReader ExecuteReader(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteCore(dataCommand, parameters, dbCommand => dbCommand.ExecuteReader(CommandBehavior.CloseConnection));
}
@@ -262,7 +262,7 @@ public DbDataReader ExecuteReader(IDataCommand dataCommand, params DbParameter[]
///
/// An object.
///
- public virtual string ExecuteXmlString(IDataCommand dataCommand, params DbParameter[] parameters)
+ public virtual string ExecuteXmlString(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
using (var reader = ExecuteReader(dataCommand, parameters))
{
@@ -277,7 +277,7 @@ public virtual string ExecuteXmlString(IDataCommand dataCommand, params DbParame
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from .
- public object ExecuteScalar(IDataCommand dataCommand, params DbParameter[] parameters)
+ public object ExecuteScalar(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteCore(dataCommand, parameters, dbCommand =>
{
@@ -301,7 +301,7 @@ public object ExecuteScalar(IDataCommand dataCommand, params DbParameter[] param
/// The parameters to use in the command.
/// The first column of the first row in the result from as the specified .
/// This method uses when casting the first column of the first row in the result from .
- public object ExecuteScalarAsType(IDataCommand dataCommand, Type returnType, params DbParameter[] parameters)
+ public object ExecuteScalarAsType(IDataCommand dataCommand, Type returnType, params IDbDataParameter[] parameters)
{
return ExecuteScalarAsType(dataCommand, returnType, CultureInfo.InvariantCulture, parameters);
}
@@ -315,7 +315,7 @@ public object ExecuteScalarAsType(IDataCommand dataCommand, Type returnType, par
/// An object that supplies culture-specific formatting information.
/// The parameters to use in the command.
/// The first column of the first row in the result from as the specified .
- public object ExecuteScalarAsType(IDataCommand dataCommand, Type returnType, IFormatProvider provider, params DbParameter[] parameters)
+ public object ExecuteScalarAsType(IDataCommand dataCommand, Type returnType, IFormatProvider provider, params IDbDataParameter[] parameters)
{
return Decorator.Enclose(ExecuteScalar(dataCommand, parameters)).ChangeType(returnType, o => o.FormatProvider = provider);
}
@@ -329,7 +329,7 @@ public object ExecuteScalarAsType(IDataCommand dataCommand, Type returnType, IFo
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
/// This method uses when casting the first column of the first row in the result from .
- public TResult ExecuteScalarAs(IDataCommand dataCommand, params DbParameter[] parameters)
+ public TResult ExecuteScalarAs(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return (TResult)ExecuteScalarAsType(dataCommand, typeof(TResult), parameters);
}
@@ -343,7 +343,7 @@ public TResult ExecuteScalarAs(IDataCommand dataCommand, params DbParam
/// An object that supplies culture-specific formatting information.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public TResult ExecuteScalarAs(IDataCommand dataCommand, IFormatProvider provider, params DbParameter[] parameters)
+ public TResult ExecuteScalarAs(IDataCommand dataCommand, IFormatProvider provider, params IDbDataParameter[] parameters)
{
return (TResult)ExecuteScalarAsType(dataCommand, typeof(TResult), provider, parameters);
}
@@ -355,7 +355,7 @@ public TResult ExecuteScalarAs(IDataCommand dataCommand, IFormatProvide
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public bool ExecuteScalarAsBoolean(IDataCommand dataCommand, params DbParameter[] parameters)
+ public bool ExecuteScalarAsBoolean(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -368,7 +368,7 @@ public bool ExecuteScalarAsBoolean(IDataCommand dataCommand, params DbParameter[
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public DateTime ExecuteScalarAsDateTime(IDataCommand dataCommand, params DbParameter[] parameters)
+ public DateTime ExecuteScalarAsDateTime(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -380,7 +380,7 @@ public DateTime ExecuteScalarAsDateTime(IDataCommand dataCommand, params DbParam
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public short ExecuteScalarAsInt16(IDataCommand dataCommand, params DbParameter[] parameters)
+ public short ExecuteScalarAsInt16(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -392,7 +392,7 @@ public short ExecuteScalarAsInt16(IDataCommand dataCommand, params DbParameter[]
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public int ExecuteScalarAsInt32(IDataCommand dataCommand, params DbParameter[] parameters)
+ public int ExecuteScalarAsInt32(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -404,7 +404,7 @@ public int ExecuteScalarAsInt32(IDataCommand dataCommand, params DbParameter[] p
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public long ExecuteScalarAsInt64(IDataCommand dataCommand, params DbParameter[] parameters)
+ public long ExecuteScalarAsInt64(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -416,7 +416,7 @@ public long ExecuteScalarAsInt64(IDataCommand dataCommand, params DbParameter[]
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public byte ExecuteScalarAsByte(IDataCommand dataCommand, params DbParameter[] parameters)
+ public byte ExecuteScalarAsByte(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -428,7 +428,7 @@ public byte ExecuteScalarAsByte(IDataCommand dataCommand, params DbParameter[] p
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public sbyte ExecuteScalarAsSByte(IDataCommand dataCommand, params DbParameter[] parameters)
+ public sbyte ExecuteScalarAsSByte(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -440,7 +440,7 @@ public sbyte ExecuteScalarAsSByte(IDataCommand dataCommand, params DbParameter[]
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public decimal ExecuteScalarAsDecimal(IDataCommand dataCommand, params DbParameter[] parameters)
+ public decimal ExecuteScalarAsDecimal(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -452,7 +452,7 @@ public decimal ExecuteScalarAsDecimal(IDataCommand dataCommand, params DbParamet
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public double ExecuteScalarAsDouble(IDataCommand dataCommand, params DbParameter[] parameters)
+ public double ExecuteScalarAsDouble(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -464,7 +464,7 @@ public double ExecuteScalarAsDouble(IDataCommand dataCommand, params DbParameter
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public ushort ExecuteScalarAsUInt16(IDataCommand dataCommand, params DbParameter[] parameters)
+ public ushort ExecuteScalarAsUInt16(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -476,7 +476,7 @@ public ushort ExecuteScalarAsUInt16(IDataCommand dataCommand, params DbParameter
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public uint ExecuteScalarAsUInt32(IDataCommand dataCommand, params DbParameter[] parameters)
+ public uint ExecuteScalarAsUInt32(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -488,7 +488,7 @@ public uint ExecuteScalarAsUInt32(IDataCommand dataCommand, params DbParameter[]
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public ulong ExecuteScalarAsUInt64(IDataCommand dataCommand, params DbParameter[] parameters)
+ public ulong ExecuteScalarAsUInt64(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -500,7 +500,7 @@ public ulong ExecuteScalarAsUInt64(IDataCommand dataCommand, params DbParameter[
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public string ExecuteScalarAsString(IDataCommand dataCommand, params DbParameter[] parameters)
+ public string ExecuteScalarAsString(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -513,7 +513,7 @@ public string ExecuteScalarAsString(IDataCommand dataCommand, params DbParameter
/// The data command to execute.
/// The parameters to use in the command.
/// The first column of the first row in the result from as .
- public Guid ExecuteScalarAsGuid(IDataCommand dataCommand, params DbParameter[] parameters)
+ public Guid ExecuteScalarAsGuid(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
return ExecuteScalarAs(dataCommand, parameters);
}
@@ -526,12 +526,12 @@ public Guid ExecuteScalarAsGuid(IDataCommand dataCommand, params DbParameter[] p
/// The parameters to use in the command.
/// The function delegate that will invoke a method on the resolved from the virtual method.
/// A value of that is equal to the invoked method of the object.
- protected virtual T ExecuteCore(IDataCommand dataCommand, DbParameter[] parameters, Func commandInvoker)
+ protected virtual T ExecuteCore(IDataCommand dataCommand, IDbDataParameter[] parameters, Func commandInvoker)
{
return InvokeCommandCore(dataCommand, parameters, commandInvoker);
}
- private T InvokeCommandCore(IDataCommand dataCommand, DbParameter[] parameters, Func sqlInvoker)
+ private T InvokeCommandCore(IDataCommand dataCommand, IDbDataParameter[] parameters, Func sqlInvoker)
{
T result;
DbCommand command = null;
@@ -555,7 +555,7 @@ private T InvokeCommandCore(IDataCommand dataCommand, DbParameter[] parameter
/// The data command to execute.
/// The parameters to use in the command.
/// System.Data.Common.DbCommand
- protected virtual DbCommand ExecuteCommandCore(IDataCommand dataCommand, params DbParameter[] parameters)
+ protected virtual DbCommand ExecuteCommandCore(IDataCommand dataCommand, params IDbDataParameter[] parameters)
{
if (dataCommand == null) throw new ArgumentNullException(nameof(dataCommand));
DbCommand command = null;
@@ -585,8 +585,8 @@ private void OpenConnection(DbCommand command)
///
/// The data command to execute.
/// The parameters to use in the command.
- ///
- protected abstract DbCommand GetCommandCore(IDataCommand dataCommand, params DbParameter[] parameters);
+ /// An instance of a implementation.
+ protected abstract DbCommand GetCommandCore(IDataCommand dataCommand, params IDbDataParameter[] parameters);
#endregion
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Core/Data/DataReader.cs b/src/Cuemon.Data/DataReader.cs
similarity index 99%
rename from src/Cuemon.Core/Data/DataReader.cs
rename to src/Cuemon.Data/DataReader.cs
index cb7c40293..48eb398cc 100644
--- a/src/Cuemon.Core/Data/DataReader.cs
+++ b/src/Cuemon.Data/DataReader.cs
@@ -8,8 +8,6 @@ namespace Cuemon.Data
{
///
/// Provides a generic way of reading a forward-only stream of rows from a based data source. This is an abstract class.
- /// Implements the
- /// Implements the
///
/// The type of the value that this will read.
///
diff --git a/src/Cuemon.Data/DataTransferRow.cs b/src/Cuemon.Data/DataTransferRow.cs
index 6f7497b2f..c03a9c137 100644
--- a/src/Cuemon.Data/DataTransferRow.cs
+++ b/src/Cuemon.Data/DataTransferRow.cs
@@ -1,6 +1,5 @@
using System.Globalization;
using System.Text;
-using Cuemon.Reflection;
namespace Cuemon.Data
{
diff --git a/src/Cuemon.Data/DataTransferRowCollection.cs b/src/Cuemon.Data/DataTransferRowCollection.cs
index 591b6813a..d71243346 100644
--- a/src/Cuemon.Data/DataTransferRowCollection.cs
+++ b/src/Cuemon.Data/DataTransferRowCollection.cs
@@ -4,7 +4,6 @@
using System.Collections.ObjectModel;
using System.Data;
using System.Linq;
-using Cuemon.Reflection;
namespace Cuemon.Data
{
diff --git a/src/Cuemon.Core/Data/DsvDataReader.cs b/src/Cuemon.Data/DsvDataReader.cs
similarity index 100%
rename from src/Cuemon.Core/Data/DsvDataReader.cs
rename to src/Cuemon.Data/DsvDataReader.cs
diff --git a/src/Cuemon.Data/GlobalSuppressions.cs b/src/Cuemon.Data/GlobalSuppressions.cs
index 1767d078c..ed16c5634 100644
--- a/src/Cuemon.Data/GlobalSuppressions.cs
+++ b/src/Cuemon.Data/GlobalSuppressions.cs
@@ -6,3 +6,10 @@
using System.Diagnostics.CodeAnalysis;
[assembly: SuppressMessage("Major Bug", "S2259:Null pointers should not be dereferenced", Justification = "The variable, fieldCount, is initialized to -1 in case of record being null - hence, the for loop will never iterate.", Scope = "member", Target = "~M:Cuemon.Data.DataTransferColumnCollection.#ctor(System.Data.IDataRecord)")]
+[assembly: SuppressMessage("Major Bug", "S1751:Loops with at most one iteration should be refactored", Justification = "This is by design and how a reader is implemented. While there are lines to be read, we built a token, and the token is being read. When read, it returns true and proceeds to next line.", Scope = "member", Target = "~M:Cuemon.Data.DsvDataReader.Read~System.Boolean")]
+[assembly: SuppressMessage("Major Bug", "S1751:Loops with at most one iteration should be refactored", Justification = "This is by design and how a reader is implemented. While there are lines to be read, we built a token, and the token is being read. When read, it returns true and proceeds to next line.", Scope = "member", Target = "~M:Cuemon.Data.ConcurrentDsvDataReader.ReadAsync~System.Threading.Tasks.Task{System.Boolean}")]
+[assembly: SuppressMessage("Major Code Smell", "S1168:Empty arrays and collections should be returned instead of null", Justification = "By design; property serves it purpose.", Scope = "member", Target = "~P:Cuemon.Data.ConcurrentDsvDataReader.NullRead")]
+[assembly: SuppressMessage("Critical Code Smell", "S927:parameter names should match base declaration and other partial definitions", Justification = "By design to help clarify context.", Scope = "member", Target = "~M:Cuemon.Data.ConcurrentDsvDataReader.ReadNext(System.String[])~System.String[]")]
+[assembly: SuppressMessage("Critical Code Smell", "S927:parameter names should match base declaration and other partial definitions", Justification = "By design to help clarify context.", Scope = "member", Target = "~M:Cuemon.Data.DsvDataReader.ReadNext(System.String[])~System.String[]")]
+[assembly: SuppressMessage("Major Code Smell", "S1168:Empty arrays and collections should be returned instead of null", Justification = "By design; property serves it purpose.", Scope = "member", Target = "~P:Cuemon.Data.DsvDataReader.NullRead")]
+[assembly: SuppressMessage("Major Code Smell", "S907:\"goto\" statement should not be used", Justification = "Legacy implementation.", Scope = "member", Target = "~M:Cuemon.Data.Xml.XmlDataReader.ReadNext(System.Boolean)~System.Boolean")]
\ No newline at end of file
diff --git a/src/Cuemon.Data/InOperatorResult.cs b/src/Cuemon.Data/InOperatorResult.cs
index 337b66879..316710712 100644
--- a/src/Cuemon.Data/InOperatorResult.cs
+++ b/src/Cuemon.Data/InOperatorResult.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data;
+using System.Linq;
namespace Cuemon.Data
{
@@ -31,6 +32,15 @@ internal InOperatorResult(IEnumerable arguments, IEnumerableThe parameters for the IN operator.
public IEnumerable Parameters { get; }
+ ///
+ /// Converts the parameters for the IN operator to an .
+ ///
+ /// An array of .
+ public IDbDataParameter[] ToParametersArray()
+ {
+ return Parameters.ToArray();
+ }
+
///
/// Returns a that represents this instance.
///
diff --git a/src/Cuemon.Data/Properties/PackageReleaseNotes.txt b/src/Cuemon.Data/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..6de46a2eb
--- /dev/null
+++ b/src/Cuemon.Data/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,25 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# Upgrade Steps
+- The Cuemon.Data.XmlClient assembly and namespace was removed with this version
+- Types found in the Cuemon.Data.XmlClient namespace was merged into the Cuemon.Data.Xml namespace
+- To use the earlier built-in support for Microsoft SQL Server, please refer to the Cuemon.Data.SqlClient namespace, as it has been merged and refactored out of this assembly
+- Any former extension methods of the Cuemon.Data namespace was merged into the Cuemon.Extensions.Data namespace
+
+# Breaking Changes
+- REFACTORED XmlDataReader class in the Cuemon.Data.Xml namespace to match and inherit from DataReader
+- REFACTORED DataManager class in the Cuemon.Data namespace to have a higher cohesion and lower coupling
+- RENAMED StringDataReader class in the Cuemon.Data namespace to DataReader{T} (including major refactoring of the underlying code)
+- RENAMED DataParameterEqualityComparer class in the Cuemon.Data namespace to DbParameterEqualityComparer
+- REMOVED DataTransferSorter class from the Cuemon.Data namespace
+- REMOVED CsvDataReader class from the Cuemon.Data.CsvClient namespace (including the namespace)
+- MERGED Cuemon.Data.SqlClient namespace to its own assembly
+- REFACTORED InOperator class in the Cuemon.Data namespace to be less complex and make usage of InOperatorResult
+- REMOVED QueryUtility class from the Cuemon.Data namespace
+
+# New Features
+- ADDED ConcurrentDsvDataReader class in the Cuemon.Data namespace that provides a concurrent way of reading a forward-only stream of rows from a DSV (Delimiter Separated Values) based data source
+- ADDED DsvDataReader class in the Cuemon.Data namespace that provides a way of reading a forward-only stream of rows from a DSV (Delimiter Separated Values) based data source
+- ADDED InOperatorResult class in the Cuemon.Data namespace that provides the result of an InOperator{T} operation
+- ADDED TokenBuilder class in the Cuemon.Data namespace that represents a mutable string of characters optimized for tokens
\ No newline at end of file
diff --git a/src/Cuemon.Data/QueryBuilder.cs b/src/Cuemon.Data/QueryBuilder.cs
index 648d39217..467400cc7 100644
--- a/src/Cuemon.Data/QueryBuilder.cs
+++ b/src/Cuemon.Data/QueryBuilder.cs
@@ -155,10 +155,10 @@ public static string EncodeFragment(QueryFormat format, IEnumerable valu
}
///
- /// Create and returns the builded query from the specified .
+ /// Create and returns the query from the specified .
///
/// Type of the query to create.
- /// The builded T-SQL query.
+ /// The result of the builder as a T-SQL query.
public string GetQuery(QueryType queryType)
{
return GetQuery(queryType, null);
diff --git a/src/Cuemon.Core/Data/TokenBuilder.cs b/src/Cuemon.Data/TokenBuilder.cs
similarity index 100%
rename from src/Cuemon.Core/Data/TokenBuilder.cs
rename to src/Cuemon.Data/TokenBuilder.cs
diff --git a/src/Cuemon.Xml/XmlDataReader.cs b/src/Cuemon.Data/Xml/XmlDataReader.cs
similarity index 99%
rename from src/Cuemon.Xml/XmlDataReader.cs
rename to src/Cuemon.Data/Xml/XmlDataReader.cs
index ffaf5c632..6ba0d87c8 100644
--- a/src/Cuemon.Xml/XmlDataReader.cs
+++ b/src/Cuemon.Data/Xml/XmlDataReader.cs
@@ -2,10 +2,9 @@
using System.Collections.Specialized;
using System.Globalization;
using System.Xml;
-using Cuemon.Data;
using Cuemon.Text;
-namespace Cuemon.Xml
+namespace Cuemon.Data.Xml
{
///
/// Provides a way of reading a forward-only stream of rows from an XML based data source. This class cannot be inherited.
diff --git a/src/Cuemon.Diagnostics/Cuemon.Diagnostics.csproj b/src/Cuemon.Diagnostics/Cuemon.Diagnostics.csproj
index a69dfa3ab..3bcfbebf7 100644
--- a/src/Cuemon.Diagnostics/Cuemon.Diagnostics.csproj
+++ b/src/Cuemon.Diagnostics/Cuemon.Diagnostics.csproj
@@ -1,26 +1,15 @@
-
+
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
1a0bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon
Cuemon.Diagnostics
Cuemon.Diagnostics
- The Cuemon.Diagnostics assembly provides access to features that extends the System.Diagnostics namespace.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
+ 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.
+ time-measuring time-measure time-measure-profiler with-action with-func async-time-measuring with-action-async with-func-async profiler exception-descriptor
diff --git a/src/Cuemon.Diagnostics/ExceptionDescriptor.cs b/src/Cuemon.Diagnostics/ExceptionDescriptor.cs
index 1f6e674ac..ffde3ead7 100644
--- a/src/Cuemon.Diagnostics/ExceptionDescriptor.cs
+++ b/src/Cuemon.Diagnostics/ExceptionDescriptor.cs
@@ -44,7 +44,12 @@ public static ExceptionDescriptor Extract(Exception exception, string code = "Un
builder.AppendLine(exception.ToString());
var memberSignature = Convertible.ToString(Convert.FromBase64String(insights[IndexOfThrower]));
var runtimeParameters = Convertible.ToString(Convert.FromBase64String(insights[IndexOfRuntimeParameters]));
- ed.AddEvidence("Thrower", new MemberEvidence(memberSignature, string.IsNullOrWhiteSpace(runtimeParameters) ? null : runtimeParameters.Split(Alphanumeric.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToDictionary(k => k.Substring(0, k.IndexOf('=')), v => v.Substring(v.IndexOf('=') + 1))), evidence => evidence);
+ ed.AddEvidence("Thrower", new MemberEvidence(memberSignature, string.IsNullOrWhiteSpace(runtimeParameters) ? null : runtimeParameters.Split(Alphanumeric.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToDictionary(k => k.Substring(0, k.IndexOf('=')), v =>
+ {
+ var t = v.Substring(v.IndexOf('=') + 1);
+ if (t == "null") { return null; }
+ return t;
+ })), evidence => evidence);
TryAddEvidence(ed, "Thread", insights[IndexOfThreadInfo]);
TryAddEvidence(ed, "Process", insights[IndexOfProcessInfo]);
TryAddEvidence(ed, "Environment", insights[IndexOfEnvironmentInfo]);
@@ -176,5 +181,14 @@ public void PostInitializeWith(IEnumerable attribu
if (!string.IsNullOrWhiteSpace(attribute.HelpLink)) { HelpLink = new Uri(attribute.HelpLink); }
}
}
+
+ ///
+ /// Returns a that represents this instance.
+ ///
+ /// A that represents this instance.
+ public override string ToString()
+ {
+ return Failure.ToString();
+ }
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Diagnostics/ExceptionDescriptorAttribute.cs b/src/Cuemon.Diagnostics/ExceptionDescriptorAttribute.cs
index c01fd6d0f..443981e09 100644
--- a/src/Cuemon.Diagnostics/ExceptionDescriptorAttribute.cs
+++ b/src/Cuemon.Diagnostics/ExceptionDescriptorAttribute.cs
@@ -1,5 +1,4 @@
using System;
-using System.Reflection;
using Cuemon.Globalization;
namespace Cuemon.Diagnostics
@@ -9,9 +8,10 @@ namespace Cuemon.Diagnostics
///
///
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
- public class ExceptionDescriptorAttribute : Attribute, IMessageLocalizer
+ public class ExceptionDescriptorAttribute : ResourceAttribute
{
private string _helpLink;
+ private string _message;
///
/// Initializes a new instance of the class.
@@ -22,21 +22,6 @@ public ExceptionDescriptorAttribute(Type failureType)
Validator.ThrowIfNull(failureType, nameof(failureType));
Validator.ThrowIfNotContainsType(failureType, nameof(failureType), "The specified type is not an Exception.", typeof(Exception));
FailureType = failureType;
- Message = InitializeFromResource();
- }
-
- private string InitializeFromResource()
- {
- if (!string.IsNullOrWhiteSpace(MessageResourceName) && MessageResourceType != null)
- {
- var property = MessageResourceType.GetProperty(MessageResourceName, BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic);
- var getMethod = property?.GetGetMethod(true);
- if (getMethod != null && (getMethod.IsAssembly || getMethod.IsPublic))
- {
- return property.GetValue(null, null) as string;
- }
- }
- return null;
}
///
@@ -49,20 +34,26 @@ private string InitializeFromResource()
/// Gets or sets a default message that describes the current failure.
///
/// The default message that explains the reason for the failure.
- public string Message { get; set; }
+ public string Message
+ {
+ get
+ {
+ string localizedMessage = null;
+ if (ResourceType != null)
+ {
+ localizedMessage = GetString(MessageResourceName);
+ }
+ return localizedMessage ?? _message;
+ }
+ set => _message = value;
+ }
///
- /// Gets or sets the resource name (property name) to use as the key for lookups on the resource type.
+ /// Gets or sets the resource name (property name) to use as the key for looking up a localized message string.
///
- /// Use this property to set the name of the property within that will provide a localized message that describes the current failure.
+ /// The resource name (property name) to use as the key for looking up a localized message string that describes the current failure.
public string MessageResourceName { get; set; }
- ///
- /// Gets or sets the resource type to use for message lookups.
- ///
- /// Use this property only in conjunction with . They are used together to retrieve localized messages at runtime.
- public Type MessageResourceType { get; set; }
-
///
/// Gets or sets a link to the help page associated with this failure.
///
diff --git a/src/Cuemon.Diagnostics/GlobalSuppressions.cs b/src/Cuemon.Diagnostics/GlobalSuppressions.cs
new file mode 100644
index 000000000..c62df0804
--- /dev/null
+++ b/src/Cuemon.Diagnostics/GlobalSuppressions.cs
@@ -0,0 +1,59 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``10(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``10(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``4(System.Func{``0,``1,``2,``3,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``5(System.Func{``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``5(System.Func{``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``6(System.Func{``0,``1,``2,``3,``4,``5,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``6(System.Func{``0,``1,``2,``3,``4,``5,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``7(System.Func{``0,``1,``2,``3,``4,``5,``6,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``7(System.Func{``0,``1,``2,``3,``4,``5,``6,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``8(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``8(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``9(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithActionAsync``9(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Threading.CancellationToken,System.Threading.Tasks.Task},``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``10(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Threading.CancellationToken,System.Threading.Tasks.Task{``9}},``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``9}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``10(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Threading.CancellationToken,System.Threading.Tasks.Task{``9}},``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``9}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``11(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Threading.CancellationToken,System.Threading.Tasks.Task{``10}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``10}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``11(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Threading.CancellationToken,System.Threading.Tasks.Task{``10}},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``10}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``4(System.Func{``0,``1,``2,System.Threading.CancellationToken,System.Threading.Tasks.Task{``3}},``0,``1,``2,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``3}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``5(System.Func{``0,``1,``2,``3,System.Threading.CancellationToken,System.Threading.Tasks.Task{``4}},``0,``1,``2,``3,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``4}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``6(System.Func{``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Threading.Tasks.Task{``5}},``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``5}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``6(System.Func{``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Threading.Tasks.Task{``5}},``0,``1,``2,``3,``4,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``5}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``7(System.Func{``0,``1,``2,``3,``4,``5,System.Threading.CancellationToken,System.Threading.Tasks.Task{``6}},``0,``1,``2,``3,``4,``5,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``6}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``7(System.Func{``0,``1,``2,``3,``4,``5,System.Threading.CancellationToken,System.Threading.Tasks.Task{``6}},``0,``1,``2,``3,``4,``5,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``6}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``8(System.Func{``0,``1,``2,``3,``4,``5,``6,System.Threading.CancellationToken,System.Threading.Tasks.Task{``7}},``0,``1,``2,``3,``4,``5,``6,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``7}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``8(System.Func{``0,``1,``2,``3,``4,``5,``6,System.Threading.CancellationToken,System.Threading.Tasks.Task{``7}},``0,``1,``2,``3,``4,``5,``6,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``7}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``9(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,System.Threading.CancellationToken,System.Threading.Tasks.Task{``8}},``0,``1,``2,``3,``4,``5,``6,``7,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``8}}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFuncAsync``9(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,System.Threading.CancellationToken,System.Threading.Tasks.Task{``8}},``0,``1,``2,``3,``4,``5,``6,``7,System.Threading.CancellationToken,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~System.Threading.Tasks.Task{Cuemon.Diagnostics.TimeMeasureProfiler{``8}}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithAction``10(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithAction``10(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithAction``4(System.Action{``0,``1,``2,``3},``0,``1,``2,``3,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithAction``5(System.Action{``0,``1,``2,``3,``4},``0,``1,``2,``3,``4,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithAction``6(System.Action{``0,``1,``2,``3,``4,``5},``0,``1,``2,``3,``4,``5,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithAction``6(System.Action{``0,``1,``2,``3,``4,``5},``0,``1,``2,``3,``4,``5,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithAction``7(System.Action{``0,``1,``2,``3,``4,``5,``6},``0,``1,``2,``3,``4,``5,``6,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithAction``7(System.Action{``0,``1,``2,``3,``4,``5,``6},``0,``1,``2,``3,``4,``5,``6,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithAction``8(System.Action{``0,``1,``2,``3,``4,``5,``6,``7},``0,``1,``2,``3,``4,``5,``6,``7,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithAction``8(System.Action{``0,``1,``2,``3,``4,``5,``6,``7},``0,``1,``2,``3,``4,``5,``6,``7,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithAction``9(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8},``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithAction``9(System.Action{``0,``1,``2,``3,``4,``5,``6,``7,``8},``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``10(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``9}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``10(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9},``0,``1,``2,``3,``4,``5,``6,``7,``8,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``9}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``11(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``10}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``11(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,``10},``0,``1,``2,``3,``4,``5,``6,``7,``8,``9,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``10}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``4(System.Func{``0,``1,``2,``3},``0,``1,``2,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``3}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``5(System.Func{``0,``1,``2,``3,``4},``0,``1,``2,``3,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``4}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``6(System.Func{``0,``1,``2,``3,``4,``5},``0,``1,``2,``3,``4,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``5}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``7(System.Func{``0,``1,``2,``3,``4,``5,``6},``0,``1,``2,``3,``4,``5,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``6}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``7(System.Func{``0,``1,``2,``3,``4,``5,``6},``0,``1,``2,``3,``4,``5,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``6}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``8(System.Func{``0,``1,``2,``3,``4,``5,``6,``7},``0,``1,``2,``3,``4,``5,``6,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``7}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``8(System.Func{``0,``1,``2,``3,``4,``5,``6,``7},``0,``1,``2,``3,``4,``5,``6,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``7}")]
+[assembly: SuppressMessage("Major Code Smell", "S107:Methods should not have too many parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``9(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8},``0,``1,``2,``3,``4,``5,``6,``7,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``8}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 10 generic arguments.", Scope = "member", Target = "~M:Cuemon.Diagnostics.TimeMeasure.WithFunc``9(System.Func{``0,``1,``2,``3,``4,``5,``6,``7,``8},``0,``1,``2,``3,``4,``5,``6,``7,System.Action{Cuemon.Diagnostics.TimeMeasureOptions})~Cuemon.Diagnostics.TimeMeasureProfiler{``8}")]
diff --git a/src/Cuemon.Diagnostics/Properties/PackageReleaseNotes.txt b/src/Cuemon.Diagnostics/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..43c958c62
--- /dev/null
+++ b/src/Cuemon.Diagnostics/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,13 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# Breaking Changes
+- REMOVED EventLogEntryType enum from the Cuemon.Diagnostics namespace as it is now (finally) part of .NET Platform Extensions and .NET Core
+- CHANGED ExceptionDescriptorAttribute class in the Cuemon.Diagnostics namespace to have a more simple and streamlined design
+- CHANGED TimeMeasure class in the Cuemon.Diagnostics namespace to fully support the Task-based Asynchronous Pattern (TAP) with cancellation
+
+# New Features
+- ADDED ExceptionDescriptorOptions class into Cuemon.Diagnostics namespace that specifies configuration options for serializer implementations
+
+# Improvements
+- EXTENDED ExceptionDescriptor class in the Cuemon.Diagnostics namespace with a new static method: Extract
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Authentication/ApplicationBuilderExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Authentication/ApplicationBuilderExtensions.cs
new file mode 100644
index 000000000..2440e9715
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Authentication/ApplicationBuilderExtensions.cs
@@ -0,0 +1,48 @@
+using System;
+using Cuemon.AspNetCore.Authentication.Basic;
+using Cuemon.AspNetCore.Authentication.Digest;
+using Cuemon.AspNetCore.Authentication.Hmac;
+using Cuemon.AspNetCore.Builder;
+using Microsoft.AspNetCore.Builder;
+
+namespace Cuemon.Extensions.AspNetCore.Authentication
+{
+ ///
+ /// Extension methods for the interface.
+ ///
+ public static class ApplicationBuilderExtensions
+ {
+ ///
+ /// Adds a HTTP Basic Authentication scheme to the request execution pipeline.
+ ///
+ /// The type that provides the mechanisms to configure an application’s request pipeline.
+ /// The HTTP middleware which may be configured.
+ /// A reference to after the operation has completed.
+ public static IApplicationBuilder UseBasicAuthentication(this IApplicationBuilder builder, Action setup = null)
+ {
+ return MiddlewareBuilderFactory.UseConfigurableMiddleware(builder, setup);
+ }
+
+ ///
+ /// Adds a HTTP Digest Authentication scheme to the request execution pipeline.
+ ///
+ /// The type that provides the mechanisms to configure an application’s request pipeline.
+ /// The HTTP middleware which may be configured.
+ /// A reference to after the operation has completed.
+ public static IApplicationBuilder UseDigestAccessAuthentication(this IApplicationBuilder builder, Action setup = null)
+ {
+ return MiddlewareBuilderFactory.UseConfigurableMiddleware(builder, setup);
+ }
+
+ ///
+ /// Adds a HTTP HMAC Authentication scheme to the request execution pipeline.
+ ///
+ /// The type that provides the mechanisms to configure an application’s request pipeline.
+ /// The HTTP middleware which may be configured.
+ /// A reference to after the operation has completed.
+ public static IApplicationBuilder UseHmacAuthentication(this IApplicationBuilder builder, Action setup = null)
+ {
+ return MiddlewareBuilderFactory.UseConfigurableMiddleware(builder, setup);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Authentication/Cuemon.Extensions.AspNetCore.Authentication.csproj b/src/Cuemon.Extensions.AspNetCore.Authentication/Cuemon.Extensions.AspNetCore.Authentication.csproj
new file mode 100644
index 000000000..ea3ab0dae
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Authentication/Cuemon.Extensions.AspNetCore.Authentication.csproj
@@ -0,0 +1,19 @@
+
+
+
+ net5.0;netcoreapp3.0;netstandard2.0
+ 220bdf91-e7c7-4cb4-a39d-e1a5374c5602
+
+
+
+ Cuemon.Extensions.AspNetCore.Authentication
+ Cuemon.Extensions.AspNetCore.Authentication
+ The Cuemon.Extensions.AspNetCore.Authentication namespace contains both types and extension methods that complements the Cuemon.AspNetCore namespace while being an addition to the Microsoft.AspNetCore namespace. Provides an in-memory implementation of a throttling cache for ASP.NET Core.
+ extension-methods extensions memory-throttling-cache use-hosting-environment-header use-correlation-identifier-header use-request-identifier-header use-user-agent-sentinel use-custom-throttling-sentinel
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Authentication/Properties/AssemblyInfo.cs b/src/Cuemon.Extensions.AspNetCore.Authentication/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..354bcf016
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Authentication/Properties/AssemblyInfo.cs
@@ -0,0 +1,4 @@
+using System.Runtime.InteropServices;
+
+[assembly: ComVisible(false)]
+[assembly: Guid("5e2ba4d0-1e7d-4ea1-9ca8-9133d7fa2319")]
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Authentication/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.AspNetCore.Authentication/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..9dd2cf1b0
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Authentication/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,9 @@
+Version: 6.0.0
+Availability: NET Standard 2.0
+
+# Breaking Changes
+-
+
+# New Features
+-
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Authentication/ServiceCollectionExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Authentication/ServiceCollectionExtensions.cs
new file mode 100644
index 000000000..cc23303e4
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Authentication/ServiceCollectionExtensions.cs
@@ -0,0 +1,23 @@
+using Cuemon.AspNetCore.Authentication;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Cuemon.Extensions.AspNetCore.Authentication
+{
+ ///
+ /// Extension methods for the interface.
+ ///
+ public static class ServiceCollectionExtensions
+ {
+ ///
+ /// Adds a service to the specified .
+ ///
+ /// The to add services to.
+ /// An that can be used to further configure other services.
+ public static IServiceCollection AddInMemoryDigestAuthenticationNonceTracker(this IServiceCollection services)
+ {
+ Validator.ThrowIfNull(services, nameof(services));
+ services.AddSingleton();
+ return services;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Bootstrapper.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Bootstrapper.cs
new file mode 100644
index 000000000..60d9d849d
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Bootstrapper.cs
@@ -0,0 +1,30 @@
+using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.Converters;
+using Cuemon.Extensions.Newtonsoft.Json.Formatters;
+
+namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json
+{
+ internal static class Bootstrapper
+ {
+ private static readonly object PadLock = new object();
+ private static bool _initialized;
+
+ internal static void Initialize()
+ {
+ if (!_initialized)
+ {
+ lock (PadLock)
+ {
+ if (!_initialized)
+ {
+ _initialized = true;
+ JsonFormatterOptions.DefaultConverters += list =>
+ {
+ list.AddHttpExceptionDescriptorConverter()
+ .AddStringValuesConverter();
+ };
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/Converters/JsonConverterCollectionExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Converters/JsonConverterCollectionExtensions.cs
similarity index 97%
rename from src/Cuemon.AspNetCore.Mvc.Formatters.Json/Converters/JsonConverterCollectionExtensions.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Converters/JsonConverterCollectionExtensions.cs
index 9c63ce0b2..a580e2e0b 100644
--- a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/Converters/JsonConverterCollectionExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Converters/JsonConverterCollectionExtensions.cs
@@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Cuemon.AspNetCore.Http;
+using Cuemon.AspNetCore.Diagnostics;
using Cuemon.Diagnostics;
using Cuemon.Extensions.Newtonsoft.Json;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
-namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json.Converters
+namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.Converters
{
///
/// Extension methods for the class.
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.csproj b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.csproj
new file mode 100644
index 000000000..87db9ccfe
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json.csproj
@@ -0,0 +1,25 @@
+
+
+
+ net5.0;netcoreapp3.0;netstandard2.0
+ a60adf91-e7c7-4cb4-a39d-e1a5374c5602
+
+
+
+ Cuemon
+ Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json
+ Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json
+ The Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json namespace contains both types and extension methods that complements the Cuemon.Extensions.Newtonsoft.Json namespace while being an addition to the Microsoft.AspNetCore.Mvc namespace. Provides JSON formatters for ASP.NET Core that is powered by Newtonsoft.Json.
+ extension-methods extensions json-converters add-json-serialization-formatters add-json-formatter-options
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonSerializationInputFormatter.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/JsonSerializationInputFormatter.cs
similarity index 62%
rename from src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonSerializationInputFormatter.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/JsonSerializationInputFormatter.cs
index 40fb17982..1b9f678f6 100644
--- a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonSerializationInputFormatter.cs
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/JsonSerializationInputFormatter.cs
@@ -1,11 +1,12 @@
-using System.Text;
+using System.IO;
+using System.Text;
using System.Threading.Tasks;
+using Cuemon.AspNetCore.Mvc.Filters.Diagnostics;
using Cuemon.Extensions.Newtonsoft.Json.Formatters;
-using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
-namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json
+namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json
{
///
/// This class handles deserialization of JSON to objects using .
@@ -30,15 +31,21 @@ public JsonSerializationInputFormatter(JsonFormatterOptions formatterOptions)
/// The .
/// The used to read the request body.
/// A that on completion deserializes the request body.
- public override Task ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
+ public override async Task ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
{
Validator.ThrowIfNull(context, nameof(context));
Validator.ThrowIfNull(encoding, nameof(encoding));
- context.HttpContext.Request.EnableBuffering();
+ var requestBody = new MemoryStream();
+ #if NETCOREAPP
+ await context.HttpContext.Request.BodyReader.CopyToAsync(requestBody).ConfigureAwait(false);
+ #else
+ await context.HttpContext.Request.Body.CopyToAsync(requestBody).ConfigureAwait(false);
+ #endif
+ requestBody.Position = 0;
var formatter = new JsonFormatter(FormatterOptions);
- var deserializedObject = formatter.Deserialize(context.HttpContext.Request.Body, context.ModelType);
- context.HttpContext.Request.Body.Position = 0;
- return InputFormatterResult.SuccessAsync(deserializedObject);
+ var deserializedObject = formatter.Deserialize(requestBody, context.ModelType);
+ context.HttpContext.Items.Add(FaultDescriptorFilter.HttpContextItemsKeyForCapturedRequestBody, requestBody);
+ return await InputFormatterResult.SuccessAsync(deserializedObject).ConfigureAwait(false);
}
private JsonFormatterOptions FormatterOptions { get; }
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonSerializationMvcOptionsSetup.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/JsonSerializationMvcOptionsSetup.cs
similarity index 92%
rename from src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonSerializationMvcOptionsSetup.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/JsonSerializationMvcOptionsSetup.cs
index b96c65aa5..aef5f4dc6 100644
--- a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonSerializationMvcOptionsSetup.cs
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/JsonSerializationMvcOptionsSetup.cs
@@ -2,7 +2,7 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
-namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json
+namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json
{
///
/// A implementation which will add the JSON serializer formatters to .
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonSerializationOutputFormatter.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/JsonSerializationOutputFormatter.cs
similarity index 97%
rename from src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonSerializationOutputFormatter.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/JsonSerializationOutputFormatter.cs
index f769b41c8..26246af1e 100644
--- a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonSerializationOutputFormatter.cs
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/JsonSerializationOutputFormatter.cs
@@ -6,7 +6,7 @@
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
-namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json
+namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json
{
///
/// This class handles serialization of objects to JSON using .
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonSerializerSettingsExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/JsonSerializerSettingsExtensions.cs
similarity index 97%
rename from src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonSerializerSettingsExtensions.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/JsonSerializerSettingsExtensions.cs
index 1520b8a2b..ed8d8368b 100644
--- a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonSerializerSettingsExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/JsonSerializerSettingsExtensions.cs
@@ -1,7 +1,7 @@
using System;
using Newtonsoft.Json;
-namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json
+namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json
{
///
/// Extension methods for the class.
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonMvcCoreBuilderExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/MvcBuilderExtensions.cs
similarity index 54%
rename from src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonMvcCoreBuilderExtensions.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/MvcBuilderExtensions.cs
index 216046f24..68fcd48ff 100644
--- a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/JsonMvcCoreBuilderExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/MvcBuilderExtensions.cs
@@ -5,30 +5,26 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
-namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Json
+namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json
{
///
- /// Extension methods for adding JSON formatters to MVC.
+ /// Extension methods for the interface.
///
- public static class JsonMvcCoreBuilderExtensions
+ public static class MvcBuilderExtensions
{
- ///
- /// Adds the JSON Serializer formatters to MVC.
- ///
- /// The .
- /// The .
- public static IMvcCoreBuilder AddJsonSerializationFormatters(this IMvcCoreBuilder builder)
+ static MvcBuilderExtensions()
{
- Validator.ThrowIfNull(builder, nameof(builder));
- builder.Services.TryAddEnumerable(ServiceDescriptor.Transient, JsonSerializationMvcOptionsSetup>());
- return builder;
+ Bootstrapper.Initialize();
}
///
- /// Adds the JSON Serializer formatters to MVC.
+ /// Adds the JSON serializer formatters to MVC.
///
/// The .
- /// The .
+ /// A reference to after the operation has completed.
+ ///
+ /// cannot be null.
+ ///
public static IMvcBuilder AddJsonSerializationFormatters(this IMvcBuilder builder)
{
Validator.ThrowIfNull(builder, nameof(builder));
@@ -37,16 +33,20 @@ public static IMvcBuilder AddJsonSerializationFormatters(this IMvcBuilder builde
}
///
- /// Adds configuration of for the application.
+ /// Adds the JSON serializer formatters to MVC.
///
/// The .
/// The which need to be configured.
- /// The .
- public static IMvcCoreBuilder AddJsonFormatterOptions(this IMvcCoreBuilder builder, Action setup)
+ /// A reference to after the operation has completed.
+ ///
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
+ public static IMvcBuilder AddJsonSerializationFormatters(this IMvcBuilder builder, Action setup)
{
Validator.ThrowIfNull(builder, nameof(builder));
- Validator.ThrowIfNull(setup, nameof(setup));
- builder.Services.Configure(setup);
+ AddJsonSerializationFormatters(builder);
+ AddJsonFormatterOptions(builder, setup);
return builder;
}
@@ -55,7 +55,11 @@ public static IMvcCoreBuilder AddJsonFormatterOptions(this IMvcCoreBuilder build
///
/// The .
/// The which need to be configured.
- /// The .
+ /// A reference to after the operation has completed.
+ ///
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
public static IMvcBuilder AddJsonFormatterOptions(this IMvcBuilder builder, Action setup)
{
Validator.ThrowIfNull(builder, nameof(builder));
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/MvcCoreBuilderExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/MvcCoreBuilderExtensions.cs
new file mode 100644
index 000000000..efddefe38
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/MvcCoreBuilderExtensions.cs
@@ -0,0 +1,71 @@
+using System;
+using Cuemon.Extensions.Newtonsoft.Json.Formatters;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Options;
+
+namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json
+{
+ ///
+ /// Extension methods for the interface.
+ ///
+ public static class MvcCoreBuilderExtensions
+ {
+ static MvcCoreBuilderExtensions()
+ {
+ Bootstrapper.Initialize();
+ }
+
+ ///
+ /// Adds the JSON serializer formatters to MVC.
+ ///
+ /// The .
+ /// A reference to after the operation has completed.
+ ///
+ /// cannot be null.
+ ///
+ public static IMvcCoreBuilder AddJsonSerializationFormatters(this IMvcCoreBuilder builder)
+ {
+ Validator.ThrowIfNull(builder, nameof(builder));
+ builder.Services.TryAddEnumerable(ServiceDescriptor.Transient, JsonSerializationMvcOptionsSetup>());
+ return builder;
+ }
+
+ ///
+ /// Adds the JSON serializer formatters to MVC.
+ ///
+ /// The .
+ /// The which need to be configured.
+ /// A reference to after the operation has completed.
+ ///
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
+ public static IMvcCoreBuilder AddJsonSerializationFormatters(this IMvcCoreBuilder builder, Action setup)
+ {
+ Validator.ThrowIfNull(builder, nameof(builder));
+ AddJsonSerializationFormatters(builder);
+ AddJsonFormatterOptions(builder, setup);
+ return builder;
+ }
+
+ ///
+ /// Adds configuration of for the application.
+ ///
+ /// The .
+ /// The which need to be configured.
+ /// A reference to after the operation has completed.
+ ///
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
+ public static IMvcCoreBuilder AddJsonFormatterOptions(this IMvcCoreBuilder builder, Action setup)
+ {
+ Validator.ThrowIfNull(builder, nameof(builder));
+ Validator.ThrowIfNull(setup, nameof(setup));
+ builder.Services.Configure(setup);
+ return builder;
+ }
+ }
+}
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Json/Properties/AssemblyInfo.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Properties/AssemblyInfo.cs
similarity index 100%
rename from src/Cuemon.AspNetCore.Mvc.Formatters.Json/Properties/AssemblyInfo.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Properties/AssemblyInfo.cs
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..ca7cb9e9f
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,13 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET Core 3.0, NET 5.0
+
+# Upgrade Steps
+- The Cuemon.AspNetCore.Mvc.Formatters.Json namespace was removed with this version
+- Any types found in the Cuemon.AspNetCore.Mvc.Formatters.Json namespace was merged into the Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json namespace
+
+# Breaking Changes
+- REMOVED DefaultJsonSerializerSettings class from the Cuemon.Extensions.AspNetCore.Mvc.Formatters.Newtonsoft.Json namespace as the default settings is given by JsonFormatterOptions
+
+# Improvements
+- COMPATIBLE with the changes applied to NET Core 3 in regards to only allowing asynchronous I/O
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Bootstrapper.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Bootstrapper.cs
new file mode 100644
index 000000000..8b3675953
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Bootstrapper.cs
@@ -0,0 +1,34 @@
+using Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Converters;
+using Cuemon.Xml.Serialization.Formatters;
+
+namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml
+{
+ internal static class Bootstrapper
+ {
+ private static readonly object PadLock = new object();
+ private static bool _initialized = false;
+
+ internal static void Initialize()
+ {
+ if (!_initialized)
+ {
+ lock (PadLock)
+ {
+ if (!_initialized)
+ {
+ _initialized = true;
+ XmlFormatterOptions.DefaultConverters += list =>
+ {
+ list.AddHttpExceptionDescriptorConverter()
+ .AddStringValuesConverter()
+ .AddHeaderDictionaryConverter()
+ .AddFormCollectionConverter()
+ .AddQueryCollectionConverter()
+ .AddCookieCollectionConverter();
+ };
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/Converters/XmlConverterExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Converters/XmlConverterExtensions.cs
similarity index 92%
rename from src/Cuemon.AspNetCore.Mvc.Formatters.Xml/Converters/XmlConverterExtensions.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Converters/XmlConverterExtensions.cs
index 22fc9539c..b38221ddc 100644
--- a/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/Converters/XmlConverterExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Converters/XmlConverterExtensions.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
-using Cuemon.AspNetCore.Http;
+using Cuemon.AspNetCore.Diagnostics;
using Cuemon.Diagnostics;
using Cuemon.Extensions.Xml;
using Cuemon.Extensions.Xml.Serialization.Converters;
@@ -18,19 +18,6 @@ namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Converters
///
public static class XmlConverterExtensions
{
- static XmlConverterExtensions()
- {
- XmlSerializerOptions.DefaultConverters += list =>
- {
- list.AddHttpExceptionDescriptorConverter()
- .AddStringValuesConverter()
- .AddHeaderDictionaryConverter()
- .AddFormCollectionConverter()
- .AddQueryCollectionConverter()
- .AddCookieCollectionConverter();
- };
- }
-
///
/// Adds an XML converter to the list.
///
@@ -61,7 +48,7 @@ public static IList AddHttpExceptionDescriptorConverter(this IList
foreach (var evidence in descriptor.Evidence)
{
if (evidence.Value == null) { continue; }
- writer.WriteObject(evidence.Value, evidence.Value.GetType(), o => o.RootName = new XmlQualifiedEntity(evidence.Key));
+ writer.WriteObject(evidence.Value, evidence.Value.GetType(), o => o.Settings.RootName = new XmlQualifiedEntity(evidence.Key));
}
writer.WriteEndElement();
}
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.csproj b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.csproj
new file mode 100644
index 000000000..9abe18c18
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.csproj
@@ -0,0 +1,24 @@
+
+
+
+ net5.0;netcoreapp3.0;netstandard2.0
+ a70adf91-e7c7-4cb4-a39d-e1a5374c5602
+
+
+
+ Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml
+ Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml
+ 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.
+ extension-methods extensions xml-converters add-xml-serialization-formatters add-xml-formatter-options
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/GlobalSuppressions.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/GlobalSuppressions.cs
new file mode 100644
index 000000000..7e95c24bf
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/GlobalSuppressions.cs
@@ -0,0 +1,8 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "Clear enough; XML Converter.", Scope = "member", Target = "~M:Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml.Converters.XmlConverterExtensions.AddHttpExceptionDescriptorConverter(System.Collections.Generic.IList{Cuemon.Xml.Serialization.Converters.XmlConverter},System.Action{Cuemon.Diagnostics.ExceptionDescriptorOptions})~System.Collections.Generic.IList{Cuemon.Xml.Serialization.Converters.XmlConverter}")]
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/MvcBuilderExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/MvcBuilderExtensions.cs
new file mode 100644
index 000000000..8a423d27e
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/MvcBuilderExtensions.cs
@@ -0,0 +1,72 @@
+using System;
+using Cuemon.Xml.Serialization.Formatters;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Options;
+
+namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml
+{
+ ///
+ /// Extension methods for the interface.
+ ///
+ public static class MvcBuilderExtensions
+ {
+ static MvcBuilderExtensions()
+ {
+ Bootstrapper.Initialize();
+ }
+
+ ///
+ /// Adds the XML serializer formatters to MVC.
+ ///
+ /// The to extend.
+ /// A reference to after the operation has completed.
+ ///
+ /// cannot be null.
+ ///
+ public static IMvcBuilder AddXmlSerializationFormatters(this IMvcBuilder builder)
+ {
+ Validator.ThrowIfNull(builder, nameof(builder));
+ builder.Services.TryAddEnumerable(ServiceDescriptor.Transient, XmlSerializationMvcOptionsSetup>());
+ return builder;
+ }
+
+ ///
+ /// Adds the XML serializer formatters to MVC.
+ ///
+ /// The to extend.
+ /// The which need to be configured.
+ /// A reference to after the operation has completed.
+ ///
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
+ public static IMvcBuilder AddXmlSerializationFormatters(this IMvcBuilder builder, Action setup)
+ {
+ Validator.ThrowIfNull(builder, nameof(builder));
+ AddXmlSerializationFormatters(builder);
+ AddXmlFormatterOptions(builder, setup);
+ return builder;
+ }
+
+
+ ///
+ /// Adds configuration of for the application.
+ ///
+ /// The to extend.
+ /// The which need to be configured.
+ /// A reference to after the operation has completed.
+ ///
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
+ public static IMvcBuilder AddXmlFormatterOptions(this IMvcBuilder builder, Action setup)
+ {
+ Validator.ThrowIfNull(builder, nameof(builder));
+ Validator.ThrowIfNull(setup, nameof(setup));
+ builder.Services.Configure(setup);
+ return builder;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/MvcCoreBuilderExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/MvcCoreBuilderExtensions.cs
new file mode 100644
index 000000000..7c6ba3f9d
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/MvcCoreBuilderExtensions.cs
@@ -0,0 +1,72 @@
+using System;
+using Cuemon.Xml.Serialization.Formatters;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Options;
+
+namespace Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml
+{
+ ///
+ /// Extension methods for the interface.
+ ///
+ public static class MvcCoreBuilderExtensions
+ {
+ static MvcCoreBuilderExtensions()
+ {
+ Bootstrapper.Initialize();
+ }
+
+ ///
+ /// Adds the XML serializer formatters to MVC.
+ ///
+ /// The .
+ /// A reference to after the operation has completed.
+ ///
+ /// cannot be null.
+ ///
+ public static IMvcCoreBuilder AddXmlSerializationFormatters(this IMvcCoreBuilder builder)
+ {
+ Validator.ThrowIfNull(builder, nameof(builder));
+ builder.Services.TryAddEnumerable(ServiceDescriptor.Transient, XmlSerializationMvcOptionsSetup>());
+ return builder;
+ }
+
+ ///
+ /// Adds the XML serializer formatters to MVC.
+ ///
+ /// The .
+ /// The which need to be configured.
+ /// A reference to after the operation has completed.
+ ///
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
+ public static IMvcCoreBuilder AddXmlSerializationFormatters(this IMvcCoreBuilder builder, Action setup)
+ {
+ Validator.ThrowIfNull(builder, nameof(builder));
+ AddXmlSerializationFormatters(builder);
+ AddXmlFormatterOptions(builder, setup);
+ return builder;
+ }
+
+ ///
+ /// Adds configuration of for the application.
+ ///
+ /// The .
+ /// The which need to be configured.
+ /// A reference to after the operation has completed.
+ ///
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
+ public static IMvcCoreBuilder AddXmlFormatterOptions(this IMvcCoreBuilder builder, Action setup)
+ {
+ Validator.ThrowIfNull(builder, nameof(builder));
+ Validator.ThrowIfNull(setup, nameof(setup));
+ AddXmlSerializationFormatters(builder);
+ builder.Services.Configure(setup);
+ return builder;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/Properties/AssemblyInfo.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Properties/AssemblyInfo.cs
similarity index 100%
rename from src/Cuemon.AspNetCore.Mvc.Formatters.Xml/Properties/AssemblyInfo.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Properties/AssemblyInfo.cs
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..eeb529b0a
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,10 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET Core 3.0, NET 5.0
+
+# Upgrade Steps
+- The Cuemon.AspNetCore.Mvc.Formatters.Xml namespace was removed with this version
+- Any types found in the Cuemon.AspNetCore.Mvc.Formatters.Xml namespace was merged into the Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml namespace
+
+# Improvements
+- COMPATIBLE with the changes applied to NET Core 3 in regards to only allowing asynchronous I/O
+
\ No newline at end of file
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/XmlSerializationInputFormatter.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/XmlSerializationInputFormatter.cs
similarity index 64%
rename from src/Cuemon.AspNetCore.Mvc.Formatters.Xml/XmlSerializationInputFormatter.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/XmlSerializationInputFormatter.cs
index bed6bba4d..28eaec2bf 100644
--- a/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/XmlSerializationInputFormatter.cs
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/XmlSerializationInputFormatter.cs
@@ -1,7 +1,8 @@
-using System.Text;
+using System.IO;
+using System.Text;
using System.Threading.Tasks;
+using Cuemon.AspNetCore.Mvc.Filters.Diagnostics;
using Cuemon.Xml.Serialization.Formatters;
-using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
@@ -30,15 +31,21 @@ public XmlSerializationInputFormatter(XmlFormatterOptions formatterOptions)
/// The .
/// The used to read the request body.
/// A that on completion deserializes the request body.
- public override Task ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
+ public override async Task ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
{
Validator.ThrowIfNull(context, nameof(context));
Validator.ThrowIfNull(encoding, nameof(encoding));
- context.HttpContext.Request.EnableBuffering();
+ var requestBody = new MemoryStream();
+ #if NETCOREAPP
+ await context.HttpContext.Request.BodyReader.CopyToAsync(requestBody).ConfigureAwait(false);
+ #else
+ await context.HttpContext.Request.Body.CopyToAsync(requestBody).ConfigureAwait(false);
+ #endif
+ requestBody.Position = 0;
var formatter = new XmlFormatter(FormatterOptions);
- var deserializedObject = formatter.Deserialize(context.HttpContext.Request.Body, context.ModelType);
- context.HttpContext.Request.Body.Position = 0;
- return InputFormatterResult.SuccessAsync(deserializedObject);
+ var deserializedObject = formatter.Deserialize(requestBody, context.ModelType);
+ context.HttpContext.Items.Add(FaultDescriptorFilter.HttpContextItemsKeyForCapturedRequestBody, requestBody);
+ return await InputFormatterResult.SuccessAsync(deserializedObject).ConfigureAwait(false);
}
private XmlFormatterOptions FormatterOptions { get; }
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/XmlSerializationMvcOptionsSetup.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/XmlSerializationMvcOptionsSetup.cs
similarity index 100%
rename from src/Cuemon.AspNetCore.Mvc.Formatters.Xml/XmlSerializationMvcOptionsSetup.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/XmlSerializationMvcOptionsSetup.cs
diff --git a/src/Cuemon.AspNetCore.Mvc.Formatters.Xml/XmlSerializationOutputFormatter.cs b/src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/XmlSerializationOutputFormatter.cs
similarity index 100%
rename from src/Cuemon.AspNetCore.Mvc.Formatters.Xml/XmlSerializationOutputFormatter.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/XmlSerializationOutputFormatter.cs
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/CacheableObjectResultExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Mvc/CacheableObjectResultExtensions.cs
index 21d0899c3..4caaea804 100644
--- a/src/Cuemon.Extensions.AspNetCore.Mvc/CacheableObjectResultExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc/CacheableObjectResultExtensions.cs
@@ -1,7 +1,6 @@
using System;
using Cuemon.AspNetCore.Mvc;
using Cuemon.AspNetCore.Mvc.Filters.Cacheable;
-using Cuemon.Data;
using Cuemon.Data.Integrity;
namespace Cuemon.Extensions.AspNetCore.Mvc
@@ -54,7 +53,7 @@ public static ICacheableObjectResult MakeCacheable(this object instance, FuncAn implementation.
///
///
- ///
+ ///
///
///
///
@@ -110,7 +109,7 @@ public static ICacheableObjectResult MakeCacheable(this T instance, FuncAn implementation.
///
///
- ///
+ ///
///
///
///
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/CacheBusting.cs b/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/CacheBusting.cs
deleted file mode 100644
index f47b9bd6d..000000000
--- a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/CacheBusting.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Cuemon.AspNetCore.Configuration;
-
-namespace Cuemon.Extensions.AspNetCore.Mvc.Configuration
-{
- ///
- /// Represents a way to provide cache-busting capabilities.
- ///
- public abstract class CacheBusting : ICacheBusting
- {
- ///
- /// Gets the version to be a part of the link you need cache-busting compatible.
- ///
- /// The version to be a part of the link you need cache-busting compatible.
- public abstract string Version { get; }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/Cuemon.Extensions.AspNetCore.Mvc.csproj b/src/Cuemon.Extensions.AspNetCore.Mvc/Cuemon.Extensions.AspNetCore.Mvc.csproj
index 0771f747b..c998d3a12 100644
--- a/src/Cuemon.Extensions.AspNetCore.Mvc/Cuemon.Extensions.AspNetCore.Mvc.csproj
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc/Cuemon.Extensions.AspNetCore.Mvc.csproj
@@ -1,32 +1,15 @@
- netcoreapp3.0;netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netcoreapp3.0;netstandard2.0
a50adf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon .NET Standard
Cuemon.Extensions.AspNetCore.Mvc
Cuemon.Extensions.AspNetCore.Mvc
- The Cuemon.Extensions.AspNetCore.Mvc assembly provides extension methods and general improvement to the Cuemon.AspNetCore assembly.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ The Cuemon.Extensions.AspNetCore.Mvc namespace contains both types and extension methods that complements the Cuemon.AspNetCore.Mvc namespace while being an addition to the Microsoft.AspNetCore.Mvc namespace. Provides a set of different cache busting strategies for ASP.NET Core MVC that can be easily customized.
+ extension-methods extensions add-assembly-cache-busting add-cache-busting add-dynamic-cache-busting use-when make-cacheable
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/Filters/Cacheable/CacheableAsyncResultFilterListExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Mvc/Filters/Cacheable/CacheableAsyncResultFilterExtensions.cs
similarity index 95%
rename from src/Cuemon.Extensions.AspNetCore.Mvc/Filters/Cacheable/CacheableAsyncResultFilterListExtensions.cs
rename to src/Cuemon.Extensions.AspNetCore.Mvc/Filters/Cacheable/CacheableAsyncResultFilterExtensions.cs
index cc7ef0862..8b2db73ba 100644
--- a/src/Cuemon.Extensions.AspNetCore.Mvc/Filters/Cacheable/CacheableAsyncResultFilterListExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc/Filters/Cacheable/CacheableAsyncResultFilterExtensions.cs
@@ -6,9 +6,9 @@
namespace Cuemon.Extensions.AspNetCore.Mvc.Filters.Cacheable
{
///
- /// Extension methods for the interface.
+ /// Extension methods for the interface.
///
- public static class CacheableAsyncResultFilterListExtensions
+ public static class CacheableAsyncResultFilterExtensions
{
///
/// Adds a HTTP related filter to the list.
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/Filters/Diagnostics/FaultResolverExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Mvc/Filters/Diagnostics/FaultResolverExtensions.cs
index ab44cfee7..beffff694 100644
--- a/src/Cuemon.Extensions.AspNetCore.Mvc/Filters/Diagnostics/FaultResolverExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc/Filters/Diagnostics/FaultResolverExtensions.cs
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
+using Cuemon.AspNetCore.Diagnostics;
using Cuemon.AspNetCore.Http;
-using Cuemon.AspNetCore.Mvc.Extensions.Filters.Diagnostics;
using Cuemon.AspNetCore.Mvc.Filters.Diagnostics;
namespace Cuemon.Extensions.AspNetCore.Mvc.Filters.Diagnostics
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.AspNetCore.Mvc/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..7120475f1
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,9 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET Core 3.0, NET 5.0
+
+# Breaking Changes
+- RENAMED ToCacheableObjectResult{T} --> MakeCacheable{T} on the CacheableObjectResultExtensions class in the Cuemon.Extensions.AspNetCore.Mvc namespace (also included a non-generic variant: MakeCacheable)
+
+# New Features
+- ADDED ServiceCollectionExtensions class in the Cuemon.Extensions.AspNetCore.Mvc.Configuration namespace that consist of extension methods for the IServiceCollection interface: AddAssemblyCacheBusting, AddDynamicCacheBusting, AddCacheBusting{T}
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/ViewDataDictionaryExtensions.cs b/src/Cuemon.Extensions.AspNetCore.Mvc/ViewDataDictionaryExtensions.cs
index f453ca8b1..36407f579 100644
--- a/src/Cuemon.Extensions.AspNetCore.Mvc/ViewDataDictionaryExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore.Mvc/ViewDataDictionaryExtensions.cs
@@ -42,7 +42,7 @@ public static void AddBreadcrumbs(this ViewDataDictionary viewData, Controlle
list.Add(bc);
}
- Decorator.Enclose(viewData).TryAddOrUpdate(BreadcrumbKey, list);
+ Decorator.Enclose(viewData).AddOrUpdate(BreadcrumbKey, list);
}
///
diff --git a/src/Cuemon.Extensions.AspNetCore/Builder/ApplicationBuilderExtensions.cs b/src/Cuemon.Extensions.AspNetCore/Builder/ApplicationBuilderExtensions.cs
deleted file mode 100644
index a2197e4bf..000000000
--- a/src/Cuemon.Extensions.AspNetCore/Builder/ApplicationBuilderExtensions.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using System;
-using Cuemon.AspNetCore.Builder;
-using Cuemon.AspNetCore.Hosting;
-using Cuemon.AspNetCore.Http.Headers;
-using Cuemon.AspNetCore.Http.Throttling;
-using Microsoft.AspNetCore.Builder;
-
-namespace Cuemon.Extensions.AspNetCore.Builder
-{
- ///
- /// Extension methods for the interface.
- ///
- public static class ApplicationBuilderExtensions
- {
- ///
- /// Adds a hosting environment HTTP header to the request execution pipeline.
- ///
- /// The type that provides the mechanisms to configure an application’s request pipeline.
- /// The middleware which need to be configured.
- /// A reference to this instance after the operation has completed.
- public static IApplicationBuilder UseHostingEnvironmentHeader(this IApplicationBuilder builder, Action setup = null)
- {
- return ApplicationBuilderFactory.UseMiddlewareConfigurable(builder, setup);
- }
-
- ///
- /// Adds a correlation identifier HTTP header to the request execution pipeline.
- ///
- /// The type that provides the mechanisms to configure an application’s request pipeline.
- /// The middleware which need to be configured.
- /// A reference to this instance after the operation has completed.
- /// Default HTTP header name is X-Correlation-ID.
- public static IApplicationBuilder UseCorrelationIdentifierHeader(this IApplicationBuilder builder, Action setup = null)
- {
- return ApplicationBuilderFactory.UseMiddlewareConfigurable(builder, setup);
- }
-
- ///
- /// Adds a request identifier HTTP header to the request execution pipeline.
- ///
- /// The type that provides the mechanisms to configure an application’s request pipeline.
- /// The middleware which need to be configured.
- /// A reference to this instance after the operation has completed.
- /// Default HTTP header name is X-Request-ID.
- public static IApplicationBuilder UseRequestIdentifierHeader(this IApplicationBuilder builder, Action setup = null)
- {
- return ApplicationBuilderFactory.UseMiddlewareConfigurable(builder, setup);
- }
-
- ///
- /// Adds a HTTP User-Agent header parser to the request execution pipeline.
- ///
- /// The type that provides the mechanisms to configure an application’s request pipeline.
- /// The middleware which need to be configured.
- /// A reference to this instance after the operation has completed.
- public static IApplicationBuilder UseUserAgentSentinel(this IApplicationBuilder builder, Action setup = null)
- {
- return ApplicationBuilderFactory.UseMiddlewareConfigurable(builder, setup);
- }
-
- ///
- /// Adds a custom rate limiting / throttling to the request execution pipeline.
- ///
- /// The type that provides the mechanisms to configure an application’s request pipeline.
- /// The middleware which need to be configured.
- /// A reference to this instance after the operation has completed.
- public static IApplicationBuilder UseCustomThrottlingSentinel(this IApplicationBuilder builder, Action setup)
- {
- return ApplicationBuilderFactory.UseMiddlewareConfigurable(builder, setup);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/AssemblyCacheBusting.cs b/src/Cuemon.Extensions.AspNetCore/Configuration/AssemblyCacheBusting.cs
similarity index 70%
rename from src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/AssemblyCacheBusting.cs
rename to src/Cuemon.Extensions.AspNetCore/Configuration/AssemblyCacheBusting.cs
index d37c6e999..8d365ee78 100644
--- a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/AssemblyCacheBusting.cs
+++ b/src/Cuemon.Extensions.AspNetCore/Configuration/AssemblyCacheBusting.cs
@@ -1,8 +1,10 @@
using System;
+using Cuemon.AspNetCore.Configuration;
using Cuemon.Extensions.Data.Integrity;
+using Cuemon.Security.Cryptography;
using Microsoft.Extensions.Options;
-namespace Cuemon.Extensions.AspNetCore.Mvc.Configuration
+namespace Cuemon.Extensions.AspNetCore.Configuration
{
///
/// Provides cache-busting capabilities from an Assembly. This class cannot be inherited.
@@ -17,7 +19,10 @@ public sealed class AssemblyCacheBusting : CacheBusting
public AssemblyCacheBusting(IOptions setup)
{
var options = setup.Value;
- var version = options.Assembly?.GetCacheValidator(options.ReadByteForByteChecksum, o => o.Algorithm = options.Algorithm).Checksum.ToHexadecimalString() ?? Guid.NewGuid().ToString("N"); // fallback to Guid.NewGuid
+ var version = options.Assembly?.GetCacheValidator(() => UnkeyedHashFactory.CreateCrypto(options.Algorithm), o =>
+ {
+ if (options.ReadByteForByteChecksum) { o.BytesToRead = int.MaxValue; }
+ }).Checksum.ToHexadecimalString() ?? Guid.NewGuid().ToString("N"); // fallback to Guid.NewGuid
Version = Decorator.Enclose(version).ToCasing(options.PreferredCasing);
}
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/AssemblyCacheBustingOptions.cs b/src/Cuemon.Extensions.AspNetCore/Configuration/AssemblyCacheBustingOptions.cs
similarity index 89%
rename from src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/AssemblyCacheBustingOptions.cs
rename to src/Cuemon.Extensions.AspNetCore/Configuration/AssemblyCacheBustingOptions.cs
index ce5337805..37da94a29 100644
--- a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/AssemblyCacheBustingOptions.cs
+++ b/src/Cuemon.Extensions.AspNetCore/Configuration/AssemblyCacheBustingOptions.cs
@@ -1,7 +1,8 @@
using System.Reflection;
+using Cuemon.AspNetCore.Configuration;
using Cuemon.Security.Cryptography;
-namespace Cuemon.Extensions.AspNetCore.Mvc.Configuration
+namespace Cuemon.Extensions.AspNetCore.Configuration
{
///
/// Specifies options that is related to operations.
@@ -25,7 +26,7 @@ public class AssemblyCacheBustingOptions : CacheBustingOptions
///
/// -
///
- ///
+ ///
///
/// -
///
@@ -36,7 +37,7 @@ public class AssemblyCacheBustingOptions : CacheBustingOptions
public AssemblyCacheBustingOptions()
{
Assembly = Assembly.GetEntryAssembly();
- Algorithm = CryptoAlgorithm.Md5;
+ Algorithm = UnkeyedCryptoAlgorithm.Md5;
ReadByteForByteChecksum = false;
}
@@ -50,7 +51,7 @@ public AssemblyCacheBustingOptions()
/// Gets or sets the hash algorithm to use for the computation of .
///
/// The hash algorithm to use for the computation of .
- public CryptoAlgorithm Algorithm { get; set; }
+ public UnkeyedCryptoAlgorithm Algorithm { get; set; }
///
/// Gets or sets a value indicating whether the will be read byte-for-byte when computing the checksum.
diff --git a/src/Cuemon.Extensions.AspNetCore/Configuration/ServiceCollectionExtensions.cs b/src/Cuemon.Extensions.AspNetCore/Configuration/ServiceCollectionExtensions.cs
new file mode 100644
index 000000000..43beb86a2
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore/Configuration/ServiceCollectionExtensions.cs
@@ -0,0 +1,43 @@
+using Cuemon.AspNetCore.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Cuemon.Extensions.AspNetCore.Configuration
+{
+ ///
+ /// Extension methods for the interface.
+ ///
+ public static class ServiceCollectionExtensions
+ {
+ ///
+ /// Adds an service to the specified .
+ ///
+ /// The to add services to.
+ /// An that can be used to further configure other services.
+ public static IServiceCollection AddAssemblyCacheBusting(this IServiceCollection services)
+ {
+ return services.AddCacheBusting();
+ }
+
+ ///
+ /// Adds a service to the specified .
+ ///
+ /// The to add services to.
+ /// An that can be used to further configure other services.
+ public static IServiceCollection AddDynamicCacheBusting(this IServiceCollection services)
+ {
+ return services.AddCacheBusting();
+ }
+
+ ///
+ /// Adds a cache-busting service to the specified .
+ ///
+ /// The to add services to.
+ /// An that can be used to further configure other services.
+ public static IServiceCollection AddCacheBusting(this IServiceCollection services) where T : class, ICacheBusting
+ {
+ Validator.ThrowIfNull(services, nameof(services));
+ services.AddSingleton();
+ return services;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore/Cuemon.Extensions.AspNetCore.csproj b/src/Cuemon.Extensions.AspNetCore/Cuemon.Extensions.AspNetCore.csproj
index 257dab972..dfc529316 100644
--- a/src/Cuemon.Extensions.AspNetCore/Cuemon.Extensions.AspNetCore.csproj
+++ b/src/Cuemon.Extensions.AspNetCore/Cuemon.Extensions.AspNetCore.csproj
@@ -1,32 +1,15 @@
- netcoreapp3.0;netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netcoreapp3.0;netstandard2.0
a40adf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon .NET Standard
Cuemon.Extensions.AspNetCore
Cuemon.Extensions.AspNetCore
- The Cuemon.Extensions.AspNetCore assembly provides extension methods and general improvement to the Cuemon.AspNetCore assembly.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ The Cuemon.Extensions.AspNetCore namespace contains both types and extension methods that complements the Cuemon.AspNetCore namespace while being an addition to the Microsoft.AspNetCore namespace. Provides an in-memory implementation of a throttling cache for ASP.NET Core.
+ extension-methods extensions memory-throttling-cache use-hosting-environment-header use-correlation-identifier-header use-request-identifier-header use-user-agent-sentinel use-custom-throttling-sentinel
@@ -36,9 +19,7 @@
-
-
-
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore/Data/Integrity/CacheValidatorExtensions.cs b/src/Cuemon.Extensions.AspNetCore/Data/Integrity/CacheValidatorExtensions.cs
index c46f2a205..30fe1927c 100644
--- a/src/Cuemon.Extensions.AspNetCore/Data/Integrity/CacheValidatorExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore/Data/Integrity/CacheValidatorExtensions.cs
@@ -16,7 +16,7 @@ public static class CacheValidatorExtensions
public static EntityTagHeaderValue ToEntityTag(this CacheValidator validator)
{
Validator.ThrowIfNull(validator, nameof(validator));
- return validator.ToEntityTagHeaderValue(validator.Strength != EntityDataIntegrityStrength.Strong);
+ return validator.ToEntityTagHeaderValue(validator.Validation != EntityDataIntegrityValidation.Strong);
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/ServiceCollectionExtensions.cs b/src/Cuemon.Extensions.AspNetCore/Diagnostics/ServiceCollectionExtensions.cs
similarity index 58%
rename from src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/ServiceCollectionExtensions.cs
rename to src/Cuemon.Extensions.AspNetCore/Diagnostics/ServiceCollectionExtensions.cs
index c0e6c67f1..06384cf3e 100644
--- a/src/Cuemon.Extensions.AspNetCore.Mvc/Configuration/ServiceCollectionExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore/Diagnostics/ServiceCollectionExtensions.cs
@@ -1,7 +1,8 @@
-using Cuemon.AspNetCore.Configuration;
+using Cuemon.AspNetCore.Diagnostics;
+using Cuemon.AspNetCore.Http.Throttling;
using Microsoft.Extensions.DependencyInjection;
-namespace Cuemon.Extensions.AspNetCore.Mvc.Configuration
+namespace Cuemon.Extensions.AspNetCore.Diagnostics
{
///
/// Extension methods for the interface.
@@ -9,24 +10,24 @@ namespace Cuemon.Extensions.AspNetCore.Mvc.Configuration
public static class ServiceCollectionExtensions
{
///
- /// Adds a cache-busting service to the specified based on a default instance of .
+ /// Adds a service to the specified .
///
/// The to add services to.
/// An that can be used to further configure other services.
- public static IServiceCollection AddCacheBusting(this IServiceCollection services)
+ public static IServiceCollection AddServerTiming(this IServiceCollection services)
{
- return services.AddCacheBusting();
+ return services.AddServerTiming();
}
///
- /// Adds a cache-busting service to the specified .
+ /// Adds a throttling cache service to the specified .
///
/// The to add services to.
/// An that can be used to further configure other services.
- public static IServiceCollection AddCacheBusting(this IServiceCollection services) where T : CacheBusting
+ public static IServiceCollection AddServerTiming(this IServiceCollection services) where T : class, IServerTiming
{
Validator.ThrowIfNull(services, nameof(services));
- services.AddSingleton();
+ services.AddScoped();
return services;
}
}
diff --git a/src/Cuemon.Extensions.AspNetCore/Hosting/ApplicationBuilderExtensions.cs b/src/Cuemon.Extensions.AspNetCore/Hosting/ApplicationBuilderExtensions.cs
new file mode 100644
index 000000000..34ef1a4c8
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore/Hosting/ApplicationBuilderExtensions.cs
@@ -0,0 +1,25 @@
+using System;
+using Cuemon.AspNetCore.Builder;
+using Cuemon.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Builder;
+
+namespace Cuemon.Extensions.AspNetCore.Hosting
+{
+ ///
+ /// Extension methods for the interface.
+ ///
+ public static class ApplicationBuilderExtensions
+ {
+ ///
+ /// Adds a hosting environment HTTP header to the request execution pipeline.
+ ///
+ /// The type that provides the mechanisms to configure an application’s request pipeline.
+ /// The middleware which may be configured.
+ /// A reference to this instance after the operation has completed.
+ /// Default HTTP header name is X-Hosting-Environment.
+ public static IApplicationBuilder UseHostingEnvironment(this IApplicationBuilder builder, Action setup = null)
+ {
+ return MiddlewareBuilderFactory.UseConfigurableMiddleware(builder, setup);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore/Http/HeaderDictionaryExtensions.cs b/src/Cuemon.Extensions.AspNetCore/Http/HeaderDictionaryExtensions.cs
index 2e180577d..8574127cc 100644
--- a/src/Cuemon.Extensions.AspNetCore/Http/HeaderDictionaryExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore/Http/HeaderDictionaryExtensions.cs
@@ -17,10 +17,10 @@ public static class HeaderDictionaryExtensions
/// The string to use as the key of the element to add.
/// The string to use as the value of the element to add.
/// if set to true an ASCII encoding conversion is applied to the .
- public static bool TryAddOrUpdateHeader(this IHeaderDictionary dictionary, string key, StringValues value, bool useAsciiEncodingConversion = true)
+ public static void AddOrUpdateHeader(this IHeaderDictionary dictionary, string key, StringValues value, bool useAsciiEncodingConversion = true)
{
Validator.ThrowIfNull(dictionary, nameof(dictionary));
- return Decorator.Enclose(dictionary).TryAddOrUpdateHeader(key, value, useAsciiEncodingConversion);
+ Decorator.Enclose(dictionary).AddOrUpdateHeader(key, value, useAsciiEncodingConversion);
}
///
@@ -30,7 +30,7 @@ public static bool TryAddOrUpdateHeader(this IHeaderDictionary dictionary, strin
/// The to copy.
public static void AddOrUpdateHeaders(this IHeaderDictionary dictionary, HttpResponseHeaders responseHeaders)
{
- Decorator.Enclose(dictionary).TryAddOrUpdateHeaders(responseHeaders);
+ Decorator.Enclose(dictionary).AddOrUpdateHeaders(responseHeaders);
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore/Http/Headers/ApplicationBuilderExtensions.cs b/src/Cuemon.Extensions.AspNetCore/Http/Headers/ApplicationBuilderExtensions.cs
new file mode 100644
index 000000000..dca7921fe
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore/Http/Headers/ApplicationBuilderExtensions.cs
@@ -0,0 +1,48 @@
+using System;
+using Cuemon.AspNetCore.Builder;
+using Cuemon.AspNetCore.Http.Headers;
+using Microsoft.AspNetCore.Builder;
+
+namespace Cuemon.Extensions.AspNetCore.Http.Headers
+{
+ ///
+ /// Extension methods for the interface.
+ ///
+ public static class ApplicationBuilderExtensions
+ {
+ ///
+ /// Adds a correlation identifier HTTP header to the request execution pipeline.
+ ///
+ /// The type that provides the mechanisms to configure an application’s request pipeline.
+ /// The middleware which may be configured.
+ /// A reference to this instance after the operation has completed.
+ /// Default HTTP header name is X-Correlation-ID.
+ public static IApplicationBuilder UseCorrelationIdentifier(this IApplicationBuilder builder, Action setup = null)
+ {
+ return MiddlewareBuilderFactory.UseConfigurableMiddleware(builder, setup);
+ }
+
+ ///
+ /// Adds a request identifier HTTP header to the request execution pipeline.
+ ///
+ /// The type that provides the mechanisms to configure an application’s request pipeline.
+ /// The middleware which may be configured.
+ /// A reference to this instance after the operation has completed.
+ /// Default HTTP header name is X-Request-ID.
+ public static IApplicationBuilder UseRequestIdentifier(this IApplicationBuilder builder, Action setup = null)
+ {
+ return MiddlewareBuilderFactory.UseConfigurableMiddleware(builder, setup);
+ }
+
+ ///
+ /// Adds a HTTP User-Agent header parser to the request execution pipeline.
+ ///
+ /// The type that provides the mechanisms to configure an application’s request pipeline.
+ /// The middleware which may be configured.
+ /// A reference to this instance after the operation has completed.
+ public static IApplicationBuilder UseUserAgentSentinel(this IApplicationBuilder builder, Action setup = null)
+ {
+ return MiddlewareBuilderFactory.UseConfigurableMiddleware(builder, setup);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore/Http/HttpResponseExtensions.cs b/src/Cuemon.Extensions.AspNetCore/Http/HttpResponseExtensions.cs
index aa9fae794..b5944ac03 100644
--- a/src/Cuemon.Extensions.AspNetCore/Http/HttpResponseExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore/Http/HttpResponseExtensions.cs
@@ -24,10 +24,10 @@ public static class HttpResponseExtensions
/// cannot be null -or-
/// cannot be null.
///
- public static void TryAddOrUpdateEntityTagHeader(this HttpResponse response, HttpRequest request, ChecksumBuilder builder, bool isWeak = false)
+ public static void AddOrUpdateEntityTagHeader(this HttpResponse response, HttpRequest request, ChecksumBuilder builder, bool isWeak = false)
{
Validator.ThrowIfNull(response, nameof(response));
- Decorator.Enclose(response).TryAddOrUpdateEntityTagHeader(request, builder, isWeak);
+ Decorator.Enclose(response).AddOrUpdateEntityTagHeader(request, builder, isWeak);
}
///
@@ -40,10 +40,10 @@ public static void TryAddOrUpdateEntityTagHeader(this HttpResponse response, Htt
/// cannot be null -or-
/// cannot be null.
///
- public static void TryAddOrUpdateLastModifiedHeader(this HttpResponse response, HttpRequest request, DateTime lastModified)
+ public static void AddOrUpdateLastModifiedHeader(this HttpResponse response, HttpRequest request, DateTime lastModified)
{
Validator.ThrowIfNull(response, nameof(response));
- Decorator.Enclose(response).TryAddOrUpdateLastModifiedHeader(request, lastModified);
+ Decorator.Enclose(response).AddOrUpdateLastModifiedHeader(request, lastModified);
}
///
diff --git a/src/Cuemon.Extensions.AspNetCore/Http/Throttling/ApplicationBuilderExtensions.cs b/src/Cuemon.Extensions.AspNetCore/Http/Throttling/ApplicationBuilderExtensions.cs
new file mode 100644
index 000000000..d47730c00
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore/Http/Throttling/ApplicationBuilderExtensions.cs
@@ -0,0 +1,24 @@
+using System;
+using Cuemon.AspNetCore.Builder;
+using Cuemon.AspNetCore.Http.Throttling;
+using Microsoft.AspNetCore.Builder;
+
+namespace Cuemon.Extensions.AspNetCore.Http.Throttling
+{
+ ///
+ /// Extension methods for the interface.
+ ///
+ public static class ApplicationBuilderExtensions
+ {
+ ///
+ /// Adds a HTTP requests rate limiting / throttling guard to the request execution pipeline.
+ ///
+ /// The type that provides the mechanisms to configure an application’s request pipeline.
+ /// The middleware which may be configured.
+ /// A reference to after the operation has completed.
+ public static IApplicationBuilder UseThrottlingSentinel(this IApplicationBuilder builder, Action setup = null)
+ {
+ return MiddlewareBuilderFactory.UseConfigurableMiddleware(builder, setup);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore/Http/Throttling/ServiceCollectionExtensions.cs b/src/Cuemon.Extensions.AspNetCore/Http/Throttling/ServiceCollectionExtensions.cs
index 52b8da531..06decdfeb 100644
--- a/src/Cuemon.Extensions.AspNetCore/Http/Throttling/ServiceCollectionExtensions.cs
+++ b/src/Cuemon.Extensions.AspNetCore/Http/Throttling/ServiceCollectionExtensions.cs
@@ -9,13 +9,24 @@ namespace Cuemon.Extensions.AspNetCore.Http.Throttling
public static class ServiceCollectionExtensions
{
///
- /// Adds a memory-based throttling cache service to the specified .
+ /// Adds a service to the specified .
///
/// The to add services to.
/// An that can be used to further configure other services.
- public static IServiceCollection AddMemoryThrottling(this IServiceCollection services)
+ public static IServiceCollection AddMemoryThrottlingCache(this IServiceCollection services)
{
- services.AddSingleton();
+ return services.AddThrottlingCache();
+ }
+
+ ///
+ /// Adds a throttling cache service to the specified .
+ ///
+ /// The to add services to.
+ /// An that can be used to further configure other services.
+ public static IServiceCollection AddThrottlingCache(this IServiceCollection services) where T : class, IThrottlingCache
+ {
+ Validator.ThrowIfNull(services, nameof(services));
+ services.AddSingleton();
return services;
}
}
diff --git a/src/Cuemon.Extensions.AspNetCore/Properties/AssemblyInfo.cs b/src/Cuemon.Extensions.AspNetCore/Properties/AssemblyInfo.cs
index f6682d1b8..3ffaab395 100644
--- a/src/Cuemon.Extensions.AspNetCore/Properties/AssemblyInfo.cs
+++ b/src/Cuemon.Extensions.AspNetCore/Properties/AssemblyInfo.cs
@@ -1,6 +1,4 @@
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
+using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
-[assembly: Guid("51e5cc05-3039-437a-8bdf-f489e9986921")]
-[assembly: InternalsVisibleTo("Cuemon.Extensions.AspNetCore.Mvc, PublicKey=00240000048000009400000006020000002400005253413100040000010001002F66D8473F676F4E7B47400527D33951A774422DFFC3DF6D7F87C82E5694E9F3AA626D36BEBEA428AD5B800EFCF6CE87B73268F5A0125A7D38739D344703A1C48785AC1A45B1C27EDFDF2EB30BA2B3E3CEA92E5981C30F3A95685A680B7EBEE66F422D176CD1623019D5A05770B9BA498144B1134593BEA6F674F334CF2B90B0")]
\ No newline at end of file
+[assembly: Guid("51e5cc05-3039-437a-8bdf-f489e9986921")]
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.AspNetCore/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.AspNetCore/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..ec0962c3b
--- /dev/null
+++ b/src/Cuemon.Extensions.AspNetCore/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,23 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET Core 3.0, NET 5.0
+
+# Upgrade Steps
+- HttpResponseMessageExtensions class was not merged to this assembly
+
+# Breaking Changes
+- RENAMED UseHostingEnvironmentHeader --> UseHostingEnvironment on the ApplicationBuilderExtensions class in the Cuemon.Extensions.AspNetCore.Builder namespace
+- RENAMED UseCorrelationIdentifierHeader --> UseCorrelationIdentifier on the ApplicationBuilderExtensions class in the Cuemon.Extensions.AspNetCore.Builder namespace
+- RENAMED UseRequestIdentifierHeader --> UseRequestIdentifier on the ApplicationBuilderExtensions class in the Cuemon.Extensions.AspNetCore.Builder namespace
+- RENAMED UseCustomThrottlingSentinel --> UseThrottlingSentinel on the ApplicationBuilderExtensions class in the Cuemon.Extensions.AspNetCore.Builder namespace
+- RENAMED ToEntityTag --> ToEntityTagHeaderValue on the ChecksumBuilderExtensions class in the Cuemon.Extensions.AspNetCore.Data.Integrity namespace
+- RENAMED AddMemoryThrottling --> AddMemoryThrottlingCache on the ServiceCollectionExtensions class in the Cuemon.Extensions.AspNetCore.Http.Throttling namespace
+- RENAMED SetEntityTagHeaderInformation --> AddOrUpdateEntityTagHeader on the HttpResponseExtensions class in the Cuemon.Extensions.AspNetCore.Http namespace
+- RENAMED SetLastModifiedHeaderInformation --> AddOrUpdateLastModifiedHeader on the HttpResponseExtensions class in the Cuemon.Extensions.AspNetCore.Http namespace
+- REMOVED IsSuccessStatusCode from the HttpResponseExtensions class in the Cuemon.Extensions.AspNetCore.Http namespace
+- REMOVED IsNotModifiedStatusCode from the HttpResponseExtensions class in the Cuemon.Extensions.AspNetCore.Http namespace
+
+# New Features
+- EXTENDED ServiceCollectionExtensions class in the Cuemon.Extensions.AspNetCore.Http.Throttling namespace with one new extension method for the IServiceCollection interface: AddThrottlingCache{T}
+- EXTENDED HttpResponseExtensions class in the Cuemon.Extensions.AspNetCore.Http namespace with one new extension method for the HttpResponse class: OnStartingInvokeTransformer
+- ADDED Int32Extensions class in the Cuemon.Extensions.AspNetCore.Http namespace that consist of extension methods for the Int32 struct: IsInformationStatusCode, IsSuccessStatusCode, IsRedirectionStatusCode, IsNotModifiedStatusCode, IsClientErrorStatusCode, IsServerErrorStatusCode
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Collections.Generic/CollectionExtensions.cs b/src/Cuemon.Extensions.Collections.Generic/CollectionExtensions.cs
index 76d641297..58c31d2ea 100644
--- a/src/Cuemon.Extensions.Collections.Generic/CollectionExtensions.cs
+++ b/src/Cuemon.Extensions.Collections.Generic/CollectionExtensions.cs
@@ -12,7 +12,7 @@ public static class CollectionExtensions
/// Extends the specified to support iterating in partitions.
///
/// The type of elements in the .
- /// The collection to extend.
+ /// The to extend.
/// The size of the partitions.
/// An instance of .
public static PartitionerCollection ToPartitioner(this ICollection collection, int partitionSize = 128)
@@ -24,7 +24,7 @@ public static PartitionerCollection ToPartitioner(this ICollection coll
/// Adds the elements of the specified to the .
///
/// The type of elements in the .
- /// The collection to extend.
+ /// The to extend.
/// The sequence of elements that should be added to .
public static void AddRange(this ICollection collection, params T[] source)
{
@@ -35,7 +35,7 @@ public static void AddRange(this ICollection collection, params T[] source
/// Adds the elements of the specified to the .
///
/// The type of elements in the .
- /// The collection to extend.
+ /// The to extend.
/// The sequence of elements that should be added to .
public static void AddRange(this ICollection collection, IEnumerable source)
{
diff --git a/src/Cuemon.Extensions.Collections.Generic/Cuemon.Extensions.Collections.Generic.csproj b/src/Cuemon.Extensions.Collections.Generic/Cuemon.Extensions.Collections.Generic.csproj
index 4c23d8675..d80c4c7ea 100644
--- a/src/Cuemon.Extensions.Collections.Generic/Cuemon.Extensions.Collections.Generic.csproj
+++ b/src/Cuemon.Extensions.Collections.Generic/Cuemon.Extensions.Collections.Generic.csproj
@@ -1,32 +1,15 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
190bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon
Cuemon.Extensions.Collections.Generic
Cuemon.Extensions.Collections.Generic
- The Cuemon.Extensions.Collections.Generic assembly provides extensions methods to the System.Collections.Generic namespace.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ 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.
+ extension-methods extensions to-partitioner chunk shuffle random-or-default yield
diff --git a/src/Cuemon.Extensions.Collections.Generic/DictionaryExtensions.cs b/src/Cuemon.Extensions.Collections.Generic/DictionaryExtensions.cs
index f4b7cf10b..6e415d416 100644
--- a/src/Cuemon.Extensions.Collections.Generic/DictionaryExtensions.cs
+++ b/src/Cuemon.Extensions.Collections.Generic/DictionaryExtensions.cs
@@ -14,7 +14,7 @@ public static class DictionaryExtensions
///
/// The type of the keys in the .
/// The type of the values in the .
- /// The dictionary to extend.
+ /// The to extend.
/// The key of the value to get.
/// Either the value associated with the specified or default() when the key does not exists.
///
@@ -32,7 +32,7 @@ public static TValue GetValueOrDefault(this IDictionary
/// The type of the keys in the .
/// The type of the values in the .
- /// The dictionary to extend.
+ /// The to extend.
/// The key of the value to get.
/// The function delegate that will provide a default value when the does not exists in the .
/// Either the value associated with the specified or a default value through when the key does not exists.
@@ -52,7 +52,7 @@ public static TValue GetValueOrDefault(this IDictionary
/// The type of the keys in the .
/// The type of the values in the .
- /// The dictionary to extend.
+ /// The to extend.
/// The key of the value to get.
/// The function delegate that will resolve an alternate key from the specified .
/// When this method returns, contains the value associated with the specified or the alternate key resolved from , if the key is found; otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized.
@@ -71,7 +71,7 @@ public static bool TryGetValueOrFallback(this IDictionary
/// The of the key in the resulting .
/// The of the value in the resulting .
- /// An to convert into a equivalent sequence.
+ /// The to extend.
/// A equivalent sequence of .
///
/// is null.
@@ -85,7 +85,7 @@ public static IEnumerable> ToEnumerable
///
/// Attempts to add the specified and to the .
///
- /// The dictionary to extend.
+ /// The to extend.
/// The key of the element to add.
/// The value of the element to add.
/// The function delegate that specifies the condition for adding the element.
@@ -104,7 +104,7 @@ public static bool TryAdd(this IDictionary dictionar
///
/// Attempts to add the specified and to the .
///
- /// The dictionary to extend.
+ /// The to extend.
/// The key of the element to add.
/// The value of the element to add.
/// true if the key/value pair was added to the enclosed of the successfully; otherwise, false.
@@ -121,17 +121,17 @@ public static bool TryAdd(this IDictionary dictionar
///
/// Attempts to add or update an existing element with the provided to the with the specified .
///
- /// The dictionary to extend.
+ /// The to extend.
/// The key of the element to add or update.
/// The value of the element to add or update.
///
/// cannot be null -or-
/// cannot be null.
///
- public static bool TryAddOrUpdate(this IDictionary dictionary, TKey key, TValue value)
+ public static void AddOrUpdate(this IDictionary dictionary, TKey key, TValue value)
{
Validator.ThrowIfNull(dictionary, nameof(dictionary));
- return Decorator.Enclose(dictionary).TryAddOrUpdate(key, value);
+ Decorator.Enclose(dictionary).AddOrUpdate(key, value);
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Collections.Generic/EnumerableExtensions.cs b/src/Cuemon.Extensions.Collections.Generic/EnumerableExtensions.cs
index 6d62d1a11..8eeb217b0 100644
--- a/src/Cuemon.Extensions.Collections.Generic/EnumerableExtensions.cs
+++ b/src/Cuemon.Extensions.Collections.Generic/EnumerableExtensions.cs
@@ -13,8 +13,8 @@ public static class EnumerableExtensions
///
/// Returns a chunked sequence with a maximum of the specified . Default is 128.
///
- /// The type of the elements of .
- /// An to chunk into smaller slices for a batch run or similar.
+ /// The type of the elements of .
+ /// An to extend.
/// The amount of elements to process at a time.
/// An that contains no more than the specified of elements from the sequence.
///
@@ -24,20 +24,20 @@ public static class EnumerableExtensions
/// is less or equal to 0.
///
/// The original is reduced equivalent to the number of elements in the returned sequence.
- public static PartitionerEnumerable Chunk(this IEnumerable source, int size = 128)
+ public static PartitionerEnumerable Chunk(this IEnumerable source, int size = 128)
{
Validator.ThrowIfNull(source, nameof(source));
Validator.ThrowIfLowerThanOrEqual(0, size, nameof(size));
- return new PartitionerEnumerable(source, size);
+ return new PartitionerEnumerable(source, size);
}
///
/// Shuffles the specified like a deck of cards.
///
- /// The elements to be shuffled in the randomization process.
- /// A sequence of with the shuffled .
+ /// An to extend.
+ /// A sequence of with the shuffled .
/// Fisher–Yates shuffle: https://en.wikipedia.org/wiki/Fisher–Yates_shuffle
- public static IEnumerable Shuffle(this IEnumerable source)
+ public static IEnumerable Shuffle(this IEnumerable source)
{
return source.Shuffle(Generate.RandomNumber);
}
@@ -45,11 +45,11 @@ public static IEnumerable Shuffle(this IEnumerable so
///
/// Shuffles the specified like a deck of cards.
///
- /// The elements to be shuffled in the randomization process.
+ /// An to extend.
/// The function delegate that will handle the randomization of .
- /// A sequence of with the shuffled .
+ /// A sequence of with the shuffled .
/// Fisher–Yates shuffle: https://en.wikipedia.org/wiki/Fisher–Yates_shuffle
- public static IEnumerable Shuffle(this IEnumerable source, Func randomizer)
+ public static IEnumerable Shuffle(this IEnumerable source, Func randomizer)
{
Validator.ThrowIfNull(source, nameof(source));
Validator.ThrowIfNull(randomizer, nameof(randomizer));
@@ -68,22 +68,22 @@ public static IEnumerable Shuffle(this IEnumerable so
///
/// Returns ascending sorted elements from a sequence by using the default comparer to compare values.
///
- /// The type of the elements of .
- /// A sequence of values to order.
+ /// The type of the elements of .
+ /// An to extend.
/// An that contains ascending sorted elements from the source sequence.
- public static IEnumerable OrderBy(this IEnumerable source)
+ public static IEnumerable OrderBy(this IEnumerable source)
{
- return source.OrderBy(Comparer.Default);
+ return source.OrderBy(Comparer.Default);
}
///
/// Returns ascending sorted elements from a sequence by using a specified to compare values.
///
- /// The type of the elements of .
- /// A sequence of values to order.
+ /// The type of the elements of .
+ /// An to extend.
/// An to compare values.
/// An that contains ascending sorted elements from the source sequence.
- public static IEnumerable OrderBy(this IEnumerable source, IComparer comparer)
+ public static IEnumerable OrderBy(this IEnumerable source, IComparer comparer)
{
Validator.ThrowIfNull(source, nameof(source));
Validator.ThrowIfNull(comparer, nameof(comparer));
@@ -93,22 +93,22 @@ public static IEnumerable OrderBy(this IEnumerable so
///
/// Returns descending sorted elements from a sequence by using the default comparer to compare values.
///
- /// The type of the elements of .
- /// A sequence of values to order.
+ /// The type of the elements of .
+ /// An to extend.
/// An that contains descending sorted elements from the source sequence.
- public static IEnumerable OrderByDescending(this IEnumerable source)
+ public static IEnumerable OrderByDescending(this IEnumerable source)
{
- return source.OrderByDescending(Comparer.Default);
+ return source.OrderByDescending(Comparer.Default);
}
///
/// Returns descending sorted elements from a sequence by using a specified to compare values.
///
- /// The type of the elements of .
- /// A sequence of values to order.
+ /// The type of the elements of .
+ /// An to extend.
/// An to compare values.
/// An that contains descending sorted elements from the source sequence.
- public static IEnumerable OrderByDescending(this IEnumerable source, IComparer comparer)
+ public static IEnumerable OrderByDescending(this IEnumerable source, IComparer comparer)
{
Validator.ThrowIfNull(source, nameof(source));
Validator.ThrowIfNull(comparer, nameof(comparer));
@@ -118,13 +118,13 @@ public static IEnumerable OrderByDescending(this IEnumerable
/// Returns a random element of a sequence of elements, or a default value if no element is found.
///
- /// The type of the elements of .
- /// The to return a random element of.
+ /// The type of the elements of .
+ /// An to extend.
/// default if is empty; otherwise, a random element of .
- public static TSource RandomOrDefault(this IEnumerable source)
+ public static T RandomOrDefault(this IEnumerable source)
{
Validator.ThrowIfNull(source, nameof(source));
- var collection = source as ICollection ?? new List(source);
+ var collection = source as ICollection ?? new List(source);
return collection.Count == 0 ? default : collection.ElementAt(Generate.RandomNumber(collection.Count));
}
@@ -144,7 +144,7 @@ public static IEnumerable Yield(this T value)
///
/// The type of keys in the .
/// The type of values in the .
- /// The sequence to create a from.
+ /// An to extend.
/// A that is equivalent to the specified sequence.
///
/// is null.
@@ -162,7 +162,7 @@ public static IDictionary ToDictionary(this IEnumera
///
/// The type of keys in the .
/// The type of values in the .
- /// The sequence to create a from.
+ /// An to extend.
/// The implementation to use when comparing keys.
/// A that is equivalent to the specified sequence.
///
@@ -187,23 +187,23 @@ public static IDictionary ToDictionary(this IEnumera
///
/// Extends the specified to support iterating in partitions.
///
- /// The type of elements in the .
- /// The sequence to extend.
+ /// The type of elements in the .
+ /// An to extend.
/// The size of the partitions.
/// An instance of .
- public static PartitionerEnumerable ToPartitioner(this IEnumerable source, int partitionSize = 128)
+ public static PartitionerEnumerable ToPartitioner(this IEnumerable source, int partitionSize = 128)
{
- return new PartitionerEnumerable(source, partitionSize);
+ return new PartitionerEnumerable(source, partitionSize);
}
///
/// Converts the specified to a paged data sequence.
///
- /// The type of the elements of .
- /// The source of the sequence to make pageable.
+ /// The type of the elements of .
+ /// An to extend.
/// An instance of .
/// The starting page is set to 1 and the page size is determined by .
- public static PagedCollection ToPagedCollection(this IEnumerable source)
+ public static PagedCollection ToPagedCollection(this IEnumerable source)
{
return ToPagedCollection(source, 1);
}
@@ -211,12 +211,12 @@ public static PagedCollection ToPagedCollection(this IEnumerab
///
/// Converts the specified to a paged data sequence initialized with starting .
///
- /// The type of the elements of .
- /// The source of the sequence to make pageable.
+ /// The type of the elements of .
+ /// An to extend.
/// The page number to start with.
/// An instance of .
/// The page size is determined by .
- public static PagedCollection ToPagedCollection(this IEnumerable source, int pageNumber)
+ public static PagedCollection ToPagedCollection(this IEnumerable source, int pageNumber)
{
return ToPagedCollection(source, pageNumber, PagedSettings.DefaultPageSize);
}
@@ -224,12 +224,12 @@ public static PagedCollection ToPagedCollection(this IEnumerab
///
/// Converts the specified to a paged data sequence initialized with starting and .
///
- /// The type of the elements of .
- /// The source of the sequence to make pageable.
+ /// The type of the elements of .
+ /// An to extend.
/// The page number to start with.
/// The number of elements a page can contain.
/// An instance of .
- public static PagedCollection ToPagedCollection(this IEnumerable source, int pageNumber, int pageSize)
+ public static PagedCollection ToPagedCollection(this IEnumerable source, int pageNumber, int pageSize)
{
return ToPagedCollection(source, new PagedSettings() { PageNumber = pageNumber, PageSize = pageSize });
}
@@ -237,25 +237,25 @@ public static PagedCollection ToPagedCollection(this IEnumerab
///
/// Converts the specified to a paged data sequence initialized with .
///
- /// The type of the elements of .
- /// The source of the sequence to make pageable.
+ /// The type of the elements of .
+ /// An to extend.
/// The settings that specifies the conditions of the converted .
/// An instance of initialized with .
- public static PagedCollection ToPagedCollection(this IEnumerable source, PagedSettings settings)
+ public static PagedCollection ToPagedCollection(this IEnumerable source, PagedSettings settings)
{
- return new PagedCollection(source, settings);
+ return new PagedCollection(source, settings);
}
///
/// Converts the specified to a paged data sequence initialized with starting and .
///
- /// The type of the elements of .
- /// The source of the sequence to make pageable.
+ /// The type of the elements of .
+ /// An to extend.
/// The page number to start with.
/// The number of elements a page can contain.
/// The total number of elements in the sequence.
/// An instance of .
- public static PagedCollection ToPagedCollection(this IEnumerable source, int pageNumber, int pageSize, int totalElementCount)
+ public static PagedCollection ToPagedCollection(this IEnumerable source, int pageNumber, int pageSize, int totalElementCount)
{
return ToPagedCollection(source, new PagedSettings() { PageNumber = pageNumber, PageSize = pageSize }, totalElementCount);
}
@@ -263,14 +263,14 @@ public static PagedCollection ToPagedCollection(this IEnumerab
///
/// Converts the specified to a paged data sequence initialized with .
///
- /// The type of the elements of .
- /// The source of the sequence to make pageable.
+ /// The type of the elements of .
+ /// An to extend.
/// The settings that specifies the conditions of the converted .
/// The total number of elements in the sequence.
/// An instance of initialized with .
- public static PagedCollection ToPagedCollection(this IEnumerable source, PagedSettings settings, int totalElementCount)
+ public static PagedCollection ToPagedCollection(this IEnumerable source, PagedSettings settings, int totalElementCount)
{
- return new PagedCollection(source, settings, totalElementCount);
+ return new PagedCollection(source, settings, totalElementCount);
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Collections.Generic/ListExtensions.cs b/src/Cuemon.Extensions.Collections.Generic/ListExtensions.cs
index 57f850791..c1d611813 100644
--- a/src/Cuemon.Extensions.Collections.Generic/ListExtensions.cs
+++ b/src/Cuemon.Extensions.Collections.Generic/ListExtensions.cs
@@ -12,7 +12,7 @@ public static class ListExtensions
/// Removes the first occurrence of a specific object from the .
///
/// The type of elements in the .
- /// The extended list.
+ /// The to extend.
/// The function delegate that defines the conditions of the element to remove.
/// true if item was successfully removed from the , false otherwise.
public static bool Remove(this IList list, Func predicate)
@@ -29,64 +29,64 @@ public static bool Remove(this IList list, Func predicate)
}
///
- /// Determines whether the of the is within the range of the .
+ /// Determines whether the of the is within the range of the .
///
- /// The type of elements in the .
- /// The elements of the .
+ /// The type of elements in the .
+ /// The to extend.
/// The index to find.
- /// true if the specified is within the range of the ; otherwise, false.
+ /// true if the specified is within the range of the ; otherwise, false.
///
- /// is null.
+ /// is null.
///
- public static bool HasIndex(this IList elements, int index)
+ public static bool HasIndex(this IList list, int index)
{
- Validator.ThrowIfNull(elements, nameof(elements));
- return ((elements.Count - 1) >= index);
+ Validator.ThrowIfNull(list, nameof(list));
+ return ((list.Count - 1) >= index);
}
///
- /// Returns the next element of relative to , or the last element of if is equal or greater than .
+ /// Returns the next element of relative to , or the last element of if is equal or greater than .
///
- /// The type of elements in the .
- /// The elements, relative to , to return the next element of.
+ /// The type of elements in the .
+ /// The to extend.
/// The index of which to advance to the next element from.
///
- /// is null.
+ /// is null.
///
///
/// is less than 0.
///
- /// default(TSource) if is equal or greater than ; otherwise the next element of relative to .
- public static TSource Next(this IList elements, int index)
+ /// default(TSource) if is equal or greater than ; otherwise the next element of relative to .
+ public static T Next(this IList list, int index)
{
- Validator.ThrowIfNull(elements, nameof(elements));
+ Validator.ThrowIfNull(list, nameof(list));
Validator.ThrowIfLowerThan(index, 0, nameof(index));
var nextIndex = index + 1;
- if (nextIndex >= elements.Count) { return default; }
- return elements[nextIndex];
+ if (nextIndex >= list.Count) { return default; }
+ return list[nextIndex];
}
///
- /// Returns the previous element of relative to , or the first or last element of if is equal, greater or lower than .
+ /// Returns the previous element of relative to , or the first or last element of if is equal, greater or lower than .
///
- /// The type of elements in the .
- /// The elements, relative to , to return the previous element of.
+ /// The type of elements in the .
+ /// The to extend.
/// The index of which to advance to the previous element from.
///
- /// is null.
+ /// is null.
///
///
/// is less than 0.
///
- /// default(TSource) if is equal, greater or lower than ; otherwise the previous element of relative to .
- public static TSource Previous(this IList elements, int index)
+ /// default(TSource) if is equal, greater or lower than ; otherwise the previous element of relative to .
+ public static T Previous(this IList list, int index)
{
- Validator.ThrowIfNull(elements, nameof(elements));
+ Validator.ThrowIfNull(list, nameof(list));
Validator.ThrowIfLowerThan(index, 0, nameof(index));
var previousIndex = index - 1;
if (previousIndex < 0) { return default; }
- if (previousIndex >= elements.Count) { return default; }
- return elements[previousIndex];
+ if (previousIndex >= list.Count) { return default; }
+ return list[previousIndex];
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Collections.Generic/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Collections.Generic/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..9ec26be35
--- /dev/null
+++ b/src/Cuemon.Extensions.Collections.Generic/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,9 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# New Features
+- ADDED CollectionExtensions class in the Cuemon.Extensions.Collections.Generic namespace that consist of extension methods for the ICollection{T} interface: ToPartitioner{T}, AddRange{T}
+- ADDED DictionaryExtensions class in the Cuemon.Extensions.Collections.Generic namespace that consist of extension methods for the IDictionary{TKey, TValue} interface: GetValueOrDefault{TKey, TValue}, TryGetValueOrFallback{TKey, TValue}, ToEnumerable{TKey, TValue}, TryAdd{TKey, TValue}, TryAddOrUpdate{TKey, TValue}
+- ADDED EnumerableExtensions class in the Cuemon.Extensions.Collections.Generic namespace that consist of extension methods for the IEnumerable{T} interface: Chunk{T}, Shuffle{T}, OrderBy{T}, OrderByDescending{T}, RandomOrDefault{T}, Yield{T}, ToDictionary{TKey, TValue}, ToPartitioner{T}, ToPagedCollection{T}
+- ADDED ListExtensions class in the Cuemon.Extensions.Collections.Generic namespace that consist of extension methods for the IList{T} interface: Remove{T}, HasIndex{T}, Next{T}, Previous{T}
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Collections.Specialized/Cuemon.Extensions.Collections.Specialized.csproj b/src/Cuemon.Extensions.Collections.Specialized/Cuemon.Extensions.Collections.Specialized.csproj
index 35701dc3c..c83ad2017 100644
--- a/src/Cuemon.Extensions.Collections.Specialized/Cuemon.Extensions.Collections.Specialized.csproj
+++ b/src/Cuemon.Extensions.Collections.Specialized/Cuemon.Extensions.Collections.Specialized.csproj
@@ -1,32 +1,15 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
010bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon .NET Standard
Cuemon.Extensions.Collections.Specialized
Cuemon.Extensions.Collections.Specialized
- The Cuemon.Extensions.Collections.Specialized assembly is a member of the Cuemon .NET Standard family and provides enhancements to the System.Collections.Specialized assembly.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ 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.
+ extension-methods extensions to-name-value-collection to-dictionary
diff --git a/src/Cuemon.Extensions.Collections.Specialized/DictionaryExtensions.cs b/src/Cuemon.Extensions.Collections.Specialized/DictionaryExtensions.cs
index fbd81622b..a6e143006 100644
--- a/src/Cuemon.Extensions.Collections.Specialized/DictionaryExtensions.cs
+++ b/src/Cuemon.Extensions.Collections.Specialized/DictionaryExtensions.cs
@@ -13,7 +13,7 @@ public static class DictionaryExtensions
///
/// Creates a from the specified .
///
- /// An to convert into an equivalent.
+ /// An to extend.
/// The which may be configured.
/// A that is equivalent to the specified .
///
diff --git a/src/Cuemon.Extensions.Collections.Specialized/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Collections.Specialized/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..1cfc9a51f
--- /dev/null
+++ b/src/Cuemon.Extensions.Collections.Specialized/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,7 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# New Features
+- ADDED DictionaryExtensions class in the Cuemon.Extensions.Collections.Specialized namespace that consist of extension methods for the IDictionary{string, string[]} interface: ToNameValueCollection
+- ADDED NameValueCollectionExtensions class in the Cuemon.Extensions.Collections.Specialized namespace that consist of extension methods for the NameValueCollection class: ContainsKey, ToDictionary
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Core/ConditionExtensions.cs b/src/Cuemon.Extensions.Core/ConditionExtensions.cs
index bde1b8ae3..039b91def 100644
--- a/src/Cuemon.Extensions.Core/ConditionExtensions.cs
+++ b/src/Cuemon.Extensions.Core/ConditionExtensions.cs
@@ -10,33 +10,17 @@ public static class ConditionExtensions
///
/// Determines whether there is a set difference between and .
///
- /// The to extend.
+ /// The to extend.
/// The value where characters that are not also in will be returned.
/// The value to compare with .
/// The set difference between and or if no difference.
///
/// true if there is a set difference between and ; otherwise false.
///
- public static bool HasDifference(this Condition condition, string first, string second, out string difference)
+ public static bool HasDifference(this Condition _, string first, string second, out string difference)
{
difference = first.Difference(second);
return difference.Any();
}
-
- ///
- /// Determines whether there is a distinct set difference between and .
- ///
- /// The to extend.
- /// The value where distinct characters that are not also in will be returned.
- /// The value to distinctively compare with .
- /// The distinct set difference between and or if no difference.
- ///
- /// true if there is a distinct set difference between and ; otherwise false.
- ///
- public static bool HasDistinctDifference(this Condition condition, string first, string second, out string difference)
- {
- difference = first.DistinctDifference(second);
- return difference.Any();
- }
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Core/Cuemon.Extensions.Core.csproj b/src/Cuemon.Extensions.Core/Cuemon.Extensions.Core.csproj
index 5c77a6457..1331aec56 100644
--- a/src/Cuemon.Extensions.Core/Cuemon.Extensions.Core.csproj
+++ b/src/Cuemon.Extensions.Core/Cuemon.Extensions.Core.csproj
@@ -1,33 +1,16 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
020bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon .NET Standard
Cuemon.Extensions
Cuemon.Extensions.Core
Cuemon.Extensions
- The Cuemon.Extensions.Core assembly is a member of the Cuemon .NET Standard family which provides extension methods to the Cuemon.Core assembly.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ The Cuemon.Extensions namespace contains extension methods that complements the Cuemon namespace while being an addition to the System namespace.
+ extension-methods extensions to-byte-array flatten to-encoded-string configure create-instance action-delegate options-pattern
diff --git a/src/Cuemon.Extensions.Core/GlobalSuppressions.cs b/src/Cuemon.Extensions.Core/GlobalSuppressions.cs
index d4253e350..60bba6569 100644
--- a/src/Cuemon.Extensions.Core/GlobalSuppressions.cs
+++ b/src/Cuemon.Extensions.Core/GlobalSuppressions.cs
@@ -4,7 +4,5 @@
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
-[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S3445:Exceptions should not be explicitly rethrown", Justification = "This is by design; we only want the stacktrace from within the validator method.", Scope = "member", Target = "~M:Cuemon.Extensions.ValidatorExtensions.IfHasDifference(Cuemon.Validator,System.String,System.String,System.String,System.String)")]
-[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S3445:Exceptions should not be explicitly rethrown", Justification = "This is by design; we only want the stacktrace from within the validator method.", Scope = "member", Target = "~M:Cuemon.Extensions.ValidatorExtensions.IfHasDistinctDifference(Cuemon.Validator,System.String,System.String,System.String,System.String)")]
-[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S3445:Exceptions should not be explicitly rethrown", Justification = "This is by design; we only want the stacktrace from within the validator method.", Scope = "member", Target = "~M:Cuemon.Extensions.ValidatorExtensions.IfHasNotDifference(Cuemon.Validator,System.String,System.String,System.String,System.String)")]
-[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S3445:Exceptions should not be explicitly rethrown", Justification = "This is by design; we only want the stacktrace from within the validator method.", Scope = "member", Target = "~M:Cuemon.Extensions.ValidatorExtensions.IfHasNotDistinctDifference(Cuemon.Validator,System.String,System.String,System.String,System.String)")]
\ No newline at end of file
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S3445:Exceptions should not be explicitly rethrown", Justification = "This is by design; we only want the stacktrace from within the validator method.", Scope = "member", Target = "~M:Cuemon.Extensions.ValidatorExtensions.HasDifference(Cuemon.Validator,System.String,System.String,System.String,System.String)")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S3445:Exceptions should not be explicitly rethrown", Justification = "This is by design; we only want the stacktrace from within the validator method.", Scope = "member", Target = "~M:Cuemon.Extensions.ValidatorExtensions.NoDifference(Cuemon.Validator,System.String,System.String,System.String,System.String)")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S3445:Exceptions should not be explicitly rethrown", Justification = "This is by design; we only want the stacktrace from within the validator method.", Scope = "member", Target = "~M:Cuemon.Extensions.ValidatorExtensions.IfHasNotDistinctDifference(Cuemon.Validator,System.String,System.String,System.String,System.String)")]
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Core/ObjectExtensions.cs b/src/Cuemon.Extensions.Core/ObjectExtensions.cs
index d4597b3b4..f9b6ed8ad 100644
--- a/src/Cuemon.Extensions.Core/ObjectExtensions.cs
+++ b/src/Cuemon.Extensions.Core/ObjectExtensions.cs
@@ -65,7 +65,7 @@ public static int GetHashCode32(this IEnumerable convertibles) where T : I
///
/// A sequence of objects implementing the interface.
/// A 64-bit signed integer that is the hash code of .
- public static long GetHashCode64(this IEnumerable convertibles) where T : struct, IConvertible
+ public static long GetHashCode64(this IEnumerable convertibles) where T : IConvertible
{
return Generate.HashCode64(convertibles.Cast());
}
@@ -101,21 +101,14 @@ public static T Adjust(this T value, Func tweaker)
///
/// Determines whether the specified source is a nullable .
///
- /// The type of the of .
- /// The source type to check for nullable .
+ /// The type of the of .
+ /// The source type to check for nullable .
///
/// true if the specified source is nullable; otherwise, false.
///
- public static bool IsNullable(this T source) { return false; }
-
- ///
- /// Determines whether the specified source is a nullable .
- ///
- /// The type of the of .
- /// The source type to check for nullable .
- ///
- /// true if the specified source is nullable; otherwise, false.
- ///
- public static bool IsNullable(this T? source) where T : struct { return true; }
+ public static bool IsNullable(this T _)
+ {
+ return typeof(T).IsNullable();
+ }
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Core/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Core/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..8dd068359
--- /dev/null
+++ b/src/Cuemon.Extensions.Core/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,19 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# New Features
+- ADDED ActionExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the Action delegate: Configure{TOptions}, CreateInstance{T}
+- ADDED ByteExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the Byte struct: ToEncodedString, ToHexadecimalString, ToBinaryString, ToUrlEncodedBase64String, ToBase64String, TryDetectUnicodeEncoding
+- ADDED CharExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the Char struct: ToEnumerable, FromChars
+- ADDED ConditionExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the Condition class: HasDifference
+- ADDED DateTimeExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the DateTime struct: ToUnixEpochTime, ToUtcKind, ToLocalKind, ToDefaultKind, IsWithinRange, IsTimeOfDayNight, IsTimeOfDayMorning, IsTimeOfDayForenoon, IsTimeOfDayAfternoon, IsTimeOfDayEvening, Floor, Ceiling, Round
+- ADDED DoubleExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the Double struct: FromUnixEpochTime, ToTimeSpan, Factorial, RoundOff
+- ADDED ExceptionExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the Exception class: Flatten
+- ADDED IntegerExtensions class in the Cuemon.Extensions namespace that consist of extension methods for signed integers: Min, Max, IsPrime, IsCountableSequence, IsEven, IsOdd
+- ADDED MappingExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the Mapping class: Add
+- ADDED ObjectExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the Object class: UseWrapper{T}, As{T}, GetHashCode32{T}, GetHashCode64{T}, ToDelimitedString{T}, Adjust{T}, IsNullable{T}
+- ADDED StringExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the String class: Difference, ToCharArray, ToByteArray, FromUrlEncodedBase64, ToGuid, FromBinaryDigits, FromBase64, Join, ToCasing, ToUri, IsNullOrEmpty, IsNullOrWhiteSpace, IsEmailAddress, IsGuid, IsHex, IsNumeric, IsBase64, IsCountableSequence, SplitDelimited, Count, RemoveAll, ReplaceAll, JsEscape, JsUnescape, ContainsAny, ContainsAll, EqualsAny, StartsWith, TrimAll, IsSequenceOf{T}, FromHexadecimal, ToHexadecimal, ToEnum{TEnum}, ToTimeSpan, SubstringBefore, Chunk, SuffixWith, SuffixWithForwardingSlash, PrefixWith
+- ADDED TimeSpanExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the TimeSpan struct: GetTotalNanoseconds, GetTotalMicroseconds, Floor, Ceiling, Round
+- ADDED TypeExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the Type class: ToFriendlyName, ToTypeCode, HasEqualityComparerImplementation, HasComparableImplementation, HasComparerImplementation, HasEnumerableImplementation, HasDictionaryImplementation, HasKeyValuePairImplementation, IsNullable, HasAnonymousCharacteristics, IsComplex, IsSimple, GetDefaultValue, HasTypes, HasInterfaces, HasAttributes
+- ADDED ValidatorExtensions class in the Cuemon.Extensions namespace that consist of extension methods for the Validator class: HasDifference, NoDifference
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Core/StringExtensions.cs b/src/Cuemon.Extensions.Core/StringExtensions.cs
index c474a9fc6..2e08a0273 100644
--- a/src/Cuemon.Extensions.Core/StringExtensions.cs
+++ b/src/Cuemon.Extensions.Core/StringExtensions.cs
@@ -21,26 +21,10 @@ public static class StringExtensions
/// The value to compare with .
/// >A that contains the set difference between and or if no difference.
public static string Difference(this string first, string second)
- {
- return DifferenceCore(first, second);
- }
-
- ///
- /// Returns the distinct set difference between and or if no difference.
- ///
- /// The value where distinct characters that are not also in will be returned.
- /// The value to distinctively compare with .
- /// >A that contains the distinct set difference between and or if no difference.
- public static string DistinctDifference(this string first, string second)
- {
- return DifferenceCore(first, second, true);
- }
-
- private static string DifferenceCore(string first, string second, bool distinct = false)
{
if (first == null) { first = string.Empty; }
if (second == null) { second = string.Empty; }
- return distinct ? string.Concat(second.Distinct().Except(first.Distinct())) : string.Concat(second.Except(first));
+ return string.Concat(second.Except(first));
}
///
@@ -96,7 +80,7 @@ public static byte[] ToByteArray(this string input, Action setu
/// has illegal base64 characters.
///
///
- public static byte[] FromUrlEncodedBase64String(this string input)
+ public static byte[] FromUrlEncodedBase64(this string input)
{
return ParserFactory.FromUrlEncodedBase64().Parse(input);
}
@@ -117,7 +101,7 @@ public static byte[] FromUrlEncodedBase64String(this string input)
/// The specified was not recognized to be a GUID.
///
///
- public static Guid ToGuid(string input, Action setup = null)
+ public static Guid ToGuid(this string input, Action setup = null)
{
return ParserFactory.FromGuid().Parse(input, setup);
}
@@ -483,7 +467,7 @@ public static string JsEscape(this string value)
{
if (DoEscapeOrUnescape(character))
{
- builder.AppendFormat(CultureInfo.InvariantCulture, character < byte.MaxValue ? "%{0:x2}" : "%u{0:x4}", (uint)character);
+ builder.AppendFormat(CultureInfo.InvariantCulture, character < byte.MaxValue ? "%{0:X2}" : "%u{0:X4}", (uint)character);
}
else
{
@@ -513,7 +497,7 @@ public static string JsUnescape(this string value)
{
if (DoEscapeOrUnescape(i))
{
- builder.Replace(string.Format(CultureInfo.InvariantCulture, "%{0:x2}", i), Convert.ToChar(i).ToString());
+ builder.Replace(string.Format(CultureInfo.InvariantCulture, "%{0:X2}", i), Convert.ToChar(i).ToString());
}
}
return builder.ToString();
diff --git a/src/Cuemon.Extensions.Core/TypeExtensions.cs b/src/Cuemon.Extensions.Core/TypeExtensions.cs
index 427920d57..d9441e242 100644
--- a/src/Cuemon.Extensions.Core/TypeExtensions.cs
+++ b/src/Cuemon.Extensions.Core/TypeExtensions.cs
@@ -131,7 +131,8 @@ public static bool HasKeyValuePairImplementation(this Type type)
public static bool IsNullable(this Type type)
{
Validator.ThrowIfNull(type, nameof(type));
- return Decorator.Enclose(type).IsNullable();
+ if (!type.IsValueType) { return false; }
+ return Nullable.GetUnderlyingType(type) != null;
}
///
@@ -204,7 +205,7 @@ public static bool HasTypes(this Type type, params Type[] targets)
}
///
- /// Determines whether the specified contains one or more of the target types specified throughout this member's inheritance chain.
+ /// Determines whether the specified contains one or more of the target interfaces specified throughout this member's inheritance chain.
///
/// The to extend.
/// The target interface types to be matched against.
diff --git a/src/Cuemon.Extensions.Core/ValidatorExtensions.cs b/src/Cuemon.Extensions.Core/ValidatorExtensions.cs
index e3d29cc6e..e72933724 100644
--- a/src/Cuemon.Extensions.Core/ValidatorExtensions.cs
+++ b/src/Cuemon.Extensions.Core/ValidatorExtensions.cs
@@ -18,7 +18,7 @@ public static class ValidatorExtensions
///
/// There is a difference between and .
///
- public static void IfHasDifference(this Validator validator, string first, string second, string paramName, string message = null)
+ public static void HasDifference(this Validator validator, string first, string second, string paramName, string message = null)
{
if (message == null) { message = FormattableString.Invariant($"Specified arguments has a difference between {nameof(second)} and {nameof(first)}."); }
try
@@ -31,30 +31,6 @@ public static void IfHasDifference(this Validator validator, string first, strin
}
}
- ///
- /// Validates and throws an if there is a distinct difference between and .
- ///
- /// The to extend.
- /// The value that specifies valid characters.
- /// The value to distinctively compare with .
- /// The name of the parameter that caused the exception.
- /// A message that describes the error.
- ///
- /// There is a distinct difference between and .
- ///
- public static void IfHasDistinctDifference(this Validator validator, string first, string second, string paramName, string message = null)
- {
- if (message == null) { message = FormattableString.Invariant($"Specified arguments has a distinct difference between {nameof(second)} and {nameof(first)}."); }
- try
- {
- validator.ThrowWhenCondition(c => c.IsTrue((out string invalidCharacters) => Condition.Query.HasDistinctDifference(first, second, out invalidCharacters)).Create(invalidCharacters => new ArgumentOutOfRangeException(paramName, invalidCharacters, message)).TryThrow());
- }
- catch (ArgumentOutOfRangeException ex)
- {
- throw ex;
- }
- }
-
///
/// Validates and throws an if there is no difference between and .
///
@@ -66,7 +42,7 @@ public static void IfHasDistinctDifference(this Validator validator, string firs
///
/// There is no difference between and .
///
- public static void IfHasNotDifference(this Validator validator, string first, string second, string paramName, string message = null)
+ public static void NoDifference(this Validator validator, string first, string second, string paramName, string message = null)
{
if (message == null) { message = FormattableString.Invariant($"Specified arguments does not have a difference between {nameof(second)} and {nameof(first)}."); }
try
@@ -78,29 +54,5 @@ public static void IfHasNotDifference(this Validator validator, string first, st
throw ex;
}
}
-
- ///
- /// Validates and throws an if there is not a distinct difference between and .
- ///
- /// The to extend.
- /// The value that specifies valid characters.
- /// The value to distinctively compare with .
- /// The name of the parameter that caused the exception.
- /// A message that describes the error.
- ///
- /// There is not a distinct difference between and .
- ///
- public static void IfHasNotDistinctDifference(this Validator validator, string first, string second, string paramName, string message = null)
- {
- if (message == null) { message = FormattableString.Invariant($"Specified arguments does not have a distinct difference between {nameof(second)} and {nameof(first)}."); }
- try
- {
- validator.ThrowWhenCondition(c => c.IsFalse(() => Condition.Query.HasDistinctDifference(first, second, out _)).Create(() => new ArgumentOutOfRangeException(paramName, message)).TryThrow());
- }
- catch (ArgumentOutOfRangeException ex)
- {
- throw ex;
- }
- }
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Data.Integrity/AssemblyExtensions.cs b/src/Cuemon.Extensions.Data.Integrity/AssemblyExtensions.cs
index 1fb2bc2f9..05fe491fa 100644
--- a/src/Cuemon.Extensions.Data.Integrity/AssemblyExtensions.cs
+++ b/src/Cuemon.Extensions.Data.Integrity/AssemblyExtensions.cs
@@ -2,7 +2,7 @@
using System.IO;
using System.Reflection;
using Cuemon.Data.Integrity;
-using Cuemon.IO;
+using Cuemon.Security;
namespace Cuemon.Extensions.Data.Integrity
{
@@ -15,20 +15,17 @@ public static class AssemblyExtensions
/// Returns a from the specified .
///
/// The assembly to resolve a from.
- /// true to read the byte-for-byte to promote a strong integrity checksum; false to read common properties of the for a weak (but reliable) integrity checksum.
- /// The which may be configured.
- /// A that fully represents the integrity of the specified .
- public static CacheValidator GetCacheValidator(this Assembly assembly, bool readByteForByteChecksum = false, Action setup = null)
+ /// The function delegate that is invoked to produce the .
+ /// The which may be configured.
+ /// A that represents the integrity of the specified .
+ public static CacheValidator GetCacheValidator(this Assembly assembly, Func hashFactory = null, Action setup = null)
{
if (assembly == null || assembly.IsDynamic) { return CacheValidator.Default; }
var assemblyHashCode64 = Generate.HashCode64(assembly.FullName);
var assemblyLocation = assembly.Location;
- return string.IsNullOrEmpty(assemblyLocation) ? new CacheValidator(DateTime.MinValue, DateTime.MaxValue, assemblyHashCode64, setup) : new FileInfo(assemblyLocation).GetCacheValidator(Patterns.ConfigureExchange(setup, (cvo, fco) =>
- {
- fco.BytesToRead = readByteForByteChecksum ? int.MaxValue : 0;
- fco.Algorithm = cvo.Algorithm;
- fco.Method = cvo.Method;
- })).CombineWith(assemblyHashCode64);
+ return string.IsNullOrEmpty(assemblyLocation)
+ ? new CacheValidator(new EntityInfo(DateTime.MinValue, DateTime.MaxValue, Convertible.GetBytes(assemblyHashCode64)), hashFactory)
+ : new FileInfo(assemblyLocation).GetCacheValidator(hashFactory, setup).CombineWith(assemblyHashCode64);
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Data.Integrity/ChecksumBuilderExtensions.cs b/src/Cuemon.Extensions.Data.Integrity/ChecksumBuilderExtensions.cs
index 0a2df9302..3b98a4dbd 100644
--- a/src/Cuemon.Extensions.Data.Integrity/ChecksumBuilderExtensions.cs
+++ b/src/Cuemon.Extensions.Data.Integrity/ChecksumBuilderExtensions.cs
@@ -1,6 +1,4 @@
-using System.Collections.Generic;
-using System.Linq;
-using Cuemon.Data.Integrity;
+using Cuemon.Data.Integrity;
namespace Cuemon.Extensions.Data.Integrity
{
@@ -13,128 +11,120 @@ public static class ChecksumBuilderExtensions
/// Combines the to the representation of this instance.
///
/// The type of the .
- /// An instance of a .
- /// A array that contains zero or more checksum of the additional data this instance must represent.
- /// An updated instance the specified of .
- public static T CombineWith(this T cb, params double[] additionalChecksum) where T : ChecksumBuilder
+ /// The to extend.
+ /// A value containing a checksum of the additional data this instance must represent.
+ /// An updated instance of the specified of .
+ public static T CombineWith(this T cb, double additionalChecksum) where T : ChecksumBuilder
{
- return CombineWith(cb, additionalChecksum?.SelectMany(x => Convertible.GetBytes(x)).ToArray());
+ return Decorator.Enclose(cb).CombineWith(additionalChecksum);
}
///
/// Combines the to the representation of this instance.
///
/// The type of the .
- /// An instance of a .
- /// An array that contains zero or more checksum of the additional data this instance must represent.
- /// An updated instance the specified of .
- public static T CombineWith(this T cb, params short[] additionalChecksum) where T : ChecksumBuilder
+ /// The to extend.
+ /// An value containing a checksum of the additional data this instance must represent.
+ /// An updated instance of the specified of .
+ public static T CombineWith(this T cb, short additionalChecksum) where T : ChecksumBuilder
{
- return CombineWith(cb, additionalChecksum?.SelectMany(x => Convertible.GetBytes(x)).ToArray());
+ return Decorator.Enclose(cb).CombineWith(additionalChecksum);
}
///
/// Combines the to the representation of this instance.
///
/// The type of the .
- /// An instance of a .
- /// A array that contains zero or more checksum of the additional data this instance must represent.
- /// An updated instance the specified of .
- public static T CombineWith(this T cb, params string[] additionalChecksum) where T : ChecksumBuilder
+ /// The to extend.
+ /// A value containing a checksum of the additional data this instance must represent.
+ /// An updated instance of the specified of .
+ public static T CombineWith(this T cb, string additionalChecksum) where T : ChecksumBuilder
{
- List result = new List();
- for (int i = 0; i < additionalChecksum.Length; i++)
- {
- result.Add(Generate.HashCode64(additionalChecksum[i]));
- }
- return CombineWith(cb, result.ToArray());
+ return Decorator.Enclose(cb).CombineWith(additionalChecksum);
}
///
/// Combines the to the representation of this instance.
///
/// The type of the .
- /// An instance of a .
- /// An array that contains zero or more checksum of the additional data this instance must represent.
- /// An updated instance the specified of .
- public static T CombineWith(this T cb, params int[] additionalChecksum) where T : ChecksumBuilder
+ /// The to extend.
+ /// An value containing a checksum of the additional data this instance must represent.
+ /// An updated instance of the specified of .
+ public static T CombineWith(this T cb, int additionalChecksum) where T : ChecksumBuilder
{
- return CombineWith(cb, additionalChecksum?.SelectMany(x => Convertible.GetBytes(x)).ToArray());
+ return Decorator.Enclose(cb).CombineWith(additionalChecksum);
}
///
/// Combines the to the representation of this instance.
///
/// The type of the .
- /// An instance of a .
- /// An array that contains zero or more checksum of the additional data this instance must represent.
- /// An updated instance the specified of .
- public static T CombineWith(this T cb, params long[] additionalChecksum) where T : ChecksumBuilder
+ /// The to extend.
+ /// An value containing a checksum of the additional data this instance must represent.
+ /// An updated instance of the specified of .
+ public static T CombineWith(this T cb, long additionalChecksum) where T : ChecksumBuilder
{
- return CombineWith(cb, additionalChecksum?.SelectMany(x => Convertible.GetBytes(x)).ToArray());
+ return Decorator.Enclose(cb).CombineWith(additionalChecksum);
}
///
/// Combines the to the representation of this instance.
///
/// The type of the .
- /// An instance of a .
- /// A array that contains zero or more checksum of the additional data this instance must represent.
- /// An updated instance the specified of .
- public static T CombineWith(this T cb, params float[] additionalChecksum) where T : ChecksumBuilder
+ /// The to extend.
+ /// A value containing a checksum of the additional data this instance must represent.
+ /// An updated instance of the specified of .
+ public static T CombineWith(this T cb, float additionalChecksum) where T : ChecksumBuilder
{
- return CombineWith(cb, additionalChecksum?.SelectMany(x => Convertible.GetBytes(x)).ToArray());
+ return Decorator.Enclose(cb).CombineWith(additionalChecksum);
}
///
/// Combines the to the representation of this instance.
///
/// The type of the .
- /// An instance of a .
- /// An array that contains zero or more checksum of the additional data this instance must represent.
- /// An updated instance the specified of .
- public static T CombineWith(this T cb, params ushort[] additionalChecksum) where T : ChecksumBuilder
+ /// The to extend.
+ /// An value containing a checksum of the additional data this instance must represent.
+ /// An updated instance of the specified of .
+ public static T CombineWith(this T cb, ushort additionalChecksum) where T : ChecksumBuilder
{
- return CombineWith(cb, additionalChecksum?.SelectMany(x => Convertible.GetBytes(x)).ToArray());
+ return Decorator.Enclose(cb).CombineWith(additionalChecksum);
}
///
/// Combines the to the representation of this instance.
///
/// The type of the .
- /// An instance of a .
- /// An array that contains zero or more checksum of the additional data this instance must represent.
- /// An updated instance the specified of .
- public static T CombineWith(this T cb, params uint[] additionalChecksum) where T : ChecksumBuilder
+ /// The to extend.
+ /// An value containing a checksum of the additional data this instance must represent.
+ /// An updated instance of the specified of .
+ public static T CombineWith(this T cb, uint additionalChecksum) where T : ChecksumBuilder
{
- return CombineWith(cb, additionalChecksum?.SelectMany(x => Convertible.GetBytes(x)).ToArray());
+ return Decorator.Enclose(cb).CombineWith(additionalChecksum);
}
///
/// Combines the to the representation of this instance.
///
/// The type of the .
- /// An instance of a .
- /// An array that contains zero or more checksum of the additional data this instance must represent.
- /// An updated instance the specified of .
- public static T CombineWith(this T cb, params ulong[] additionalChecksum) where T : ChecksumBuilder
+ /// The to extend.
+ /// An value containing a checksum of the additional data this instance must represent.
+ /// An updated instance of the specified of .
+ public static T CombineWith(this T cb, ulong additionalChecksum) where T : ChecksumBuilder
{
- return CombineWith(cb, additionalChecksum?.SelectMany(x => Convertible.GetBytes(x)).ToArray());
+ return Decorator.Enclose(cb).CombineWith(additionalChecksum);
}
///
/// Combines the to the representation of this instance.
///
/// The type of the .
- /// An instance of a .
+ /// The to extend.
/// An array of bytes containing a checksum of the additional data this instance must represent.
- /// An updated instance the specified of .
- public static T CombineWith(this T cb, params byte[] additionalChecksum) where T : ChecksumBuilder
+ /// An updated instance of the specified of .
+ public static T CombineWith(this T cb, byte[] additionalChecksum) where T : ChecksumBuilder
{
- if (additionalChecksum == null) { return cb; }
- if (additionalChecksum.Length == 0) { return cb; }
- cb.AppendChecksum(additionalChecksum);
- return cb;
+ return Decorator.Enclose(cb).CombineWith(additionalChecksum);
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Data.Integrity/Cuemon.Extensions.Data.Integrity.csproj b/src/Cuemon.Extensions.Data.Integrity/Cuemon.Extensions.Data.Integrity.csproj
index 36adf2a50..4d17509fc 100644
--- a/src/Cuemon.Extensions.Data.Integrity/Cuemon.Extensions.Data.Integrity.csproj
+++ b/src/Cuemon.Extensions.Data.Integrity/Cuemon.Extensions.Data.Integrity.csproj
@@ -1,32 +1,15 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
050bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon
Cuemon.Extensions.Data.Integrity
Cuemon.Extensions.Data.Integrity
- The Cuemon.Extensions.Data.Integrity assembly provides extension methods to the Cuemon.Data.Integrity namespace.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ The Cuemon.Extensions.Data.Integrity namespace contains extension methods that complements the Cuemon.Data.Integrity namespace.
+ extension-methods extensions get-cache-validator combine-with
diff --git a/src/Cuemon.Extensions.Data.Integrity/DateTimeExtensions.cs b/src/Cuemon.Extensions.Data.Integrity/DateTimeExtensions.cs
index c00a44293..314eb3b02 100644
--- a/src/Cuemon.Extensions.Data.Integrity/DateTimeExtensions.cs
+++ b/src/Cuemon.Extensions.Data.Integrity/DateTimeExtensions.cs
@@ -1,5 +1,6 @@
using System;
using Cuemon.Data.Integrity;
+using Cuemon.Security;
namespace Cuemon.Extensions.Data.Integrity
{
@@ -8,145 +9,18 @@ namespace Cuemon.Extensions.Data.Integrity
///
public static class DateTimeExtensions
{
- ///
- /// Returns a from the specified parameters.
- ///
- /// A value for when data this represents was first created.
- /// The which need to be configured.
- /// A that fully represents the integrity of the specified parameters.
- public static CacheValidator GetCacheValidator(this DateTime created, Action setup = null)
- {
- return new CacheValidator(created, setup);
- }
-
///
/// Returns a from the specified parameters.
///
/// A value for when data this represents was first created.
/// A value for when data this represents was last modified.
- /// The which need to be configured.
- /// A that fully represents the integrity of the specified parameters.
- public static CacheValidator GetCacheValidator(this DateTime created, DateTime modified, Action setup = null)
+ /// The function delegate that is invoked to produce the . Default is .
+ /// A enumeration value that indicates how a checksum is manipulated. Default is .
+ /// A that represents the integrity of the specified parameters.
+ public static CacheValidator GetCacheValidator(this DateTime created, DateTime? modified = null, Func hashFactory = null, EntityDataIntegrityMethod method = EntityDataIntegrityMethod.Unaltered)
{
- return new CacheValidator(created, modified, setup);
- }
-
- ///
- /// Returns a from the specified parameters.
- ///
- /// A value for when data this represents was first created.
- /// A value for when data this represents was last modified.
- /// A value containing a byte-for-byte checksum of the data this represents.
- /// The which need to be configured.
- /// A that fully represents the integrity of the specified parameters.
- public static CacheValidator GetCacheValidator(this DateTime created, DateTime modified, double checksum, Action setup = null)
- {
- return new CacheValidator(created, modified, checksum, setup);
- }
-
-
- ///
- /// Returns a from the specified parameters.
- ///
- /// A value for when data this represents was first created.
- /// A value for when data this represents was last modified.
- /// A value containing a byte-for-byte checksum of the data this represents.
- /// The which need to be configured.
- /// A that fully represents the integrity of the specified parameters.
- public static CacheValidator GetCacheValidator(this DateTime created, DateTime modified, short checksum, Action setup = null)
- {
- return new CacheValidator(created, modified, checksum, setup);
- }
-
- ///
- /// Returns a from the specified parameters.
- ///
- /// A value for when data this represents was first created.
- /// A value for when data this represents was last modified.
- /// A value containing a byte-for-byte checksum of the data this represents.
- /// The which need to be configured.
- /// A that fully represents the integrity of the specified parameters.
- public static CacheValidator GetCacheValidator(this DateTime created, DateTime modified, string checksum, Action setup = null)
- {
- return new CacheValidator(created, modified, checksum, setup);
- }
-
- ///
- /// Returns a from the specified parameters.
- ///
- /// A value for when data this represents was first created.
- /// A value for when data this represents was last modified.
- /// A value containing a byte-for-byte checksum of the data this represents.
- /// The which need to be configured.
- /// A that fully represents the integrity of the specified parameters.
- public static CacheValidator GetCacheValidator(this DateTime created, DateTime modified, int checksum, Action setup = null)
- {
- return new CacheValidator(created, modified, checksum, setup);
- }
-
- ///
- /// Returns a from the specified parameters.
- ///
- /// A value for when data this represents was first created.
- /// A value for when data this represents was last modified.
- /// A value containing a byte-for-byte checksum of the data this represents.
- /// The which need to be configured.
- /// A that fully represents the integrity of the specified parameters.
- public static CacheValidator GetCacheValidator(this DateTime created, DateTime modified, long checksum, Action setup = null)
- {
- return new CacheValidator(created, modified, checksum, setup);
- }
-
- ///
- /// Returns a from the specified parameters.
- ///
- /// A value for when data this represents was first created.
- /// A value for when data this represents was last modified.
- /// A value containing a byte-for-byte checksum of the data this represents.
- /// The which need to be configured.
- /// A that fully represents the integrity of the specified parameters.
- public static CacheValidator GetCacheValidator(this DateTime created, DateTime modified, float checksum, Action setup = null)
- {
- return new CacheValidator(created, modified, checksum, setup);
- }
-
- ///
- /// Returns a from the specified parameters.
- ///
- /// A value for when data this represents was first created.
- /// A value for when data this represents was last modified.
- /// A value containing a byte-for-byte checksum of the data this represents.
- /// The which need to be configured.
- /// A that fully represents the integrity of the specified parameters.
- public static CacheValidator GetCacheValidator(this DateTime created, DateTime modified, ushort checksum, Action setup = null)
- {
- return new CacheValidator(created, modified, checksum, setup);
- }
-
- ///
- /// Returns a from the specified parameters.
- ///
- /// A value for when data this represents was first created.
- /// A value for when data this represents was last modified.
- /// A value containing a byte-for-byte checksum of the data this represents.
- /// The which need to be configured.
- /// A that fully represents the integrity of the specified parameters.
- public static CacheValidator GetCacheValidator(this DateTime created, DateTime modified, uint checksum, Action setup = null)
- {
- return new CacheValidator(created, modified, checksum, setup);
- }
-
- ///
- /// Returns a from the specified parameters.
- ///
- /// A value for when data this represents was first created.
- /// A value for when data this represents was last modified.
- /// A value containing a byte-for-byte checksum of the data this represents.
- /// The which need to be configured.
- /// A that fully represents the integrity of the specified parameters.
- public static CacheValidator GetCacheValidator(this DateTime created, DateTime modified, ulong checksum, Action setup = null)
- {
- return new CacheValidator(created, modified, checksum, setup);
+ if (hashFactory == null) { hashFactory = () => HashFactory.CreateFnv128(); }
+ return new CacheValidator(new EntityInfo(created, modified), hashFactory, method);
}
///
@@ -155,11 +29,14 @@ public static CacheValidator GetCacheValidator(this DateTime created, DateTime m
/// A value for when data this represents was first created.
/// A value for when data this represents was last modified.
/// An array of bytes containing a checksum of the data this represents.
- /// The which need to be configured.
- /// A that fully represents the integrity of the specified parameters.
- public static CacheValidator GetCacheValidator(this DateTime created, DateTime modified, byte[] checksum, Action setup = null)
- {
- return new CacheValidator(created, modified, checksum, setup);
+ /// A enumeration value that indicates the validation strength of the specified . Default is .
+ /// The function delegate that is invoked to produce the . Default is .
+ /// A enumeration value that indicates how a checksum is manipulated. Default is .
+ /// A that represents the integrity of the specified parameters.
+ public static CacheValidator GetCacheValidator(this DateTime created, DateTime modified, byte[] checksum, EntityDataIntegrityValidation validation = EntityDataIntegrityValidation.Weak, Func hashFactory = null, EntityDataIntegrityMethod method = EntityDataIntegrityMethod.Unaltered)
+ {
+ if (hashFactory == null) { hashFactory = () => HashFactory.CreateFnv128(); }
+ return new CacheValidator(new EntityInfo(created, modified, checksum, validation), hashFactory, method);
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Data.Integrity/FileInfoExtensions.cs b/src/Cuemon.Extensions.Data.Integrity/FileInfoExtensions.cs
index 9d28e3498..f6efa7137 100644
--- a/src/Cuemon.Extensions.Data.Integrity/FileInfoExtensions.cs
+++ b/src/Cuemon.Extensions.Data.Integrity/FileInfoExtensions.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using Cuemon.Data.Integrity;
+using Cuemon.Security;
namespace Cuemon.Extensions.Data.Integrity
{
@@ -13,18 +14,19 @@ public static class FileInfoExtensions
/// Returns a from the specified .
///
/// The to extend.
+ /// The function delegate that is invoked to produce the . Default is .
/// The which may be configured.
/// A that represents either a weak, medium or strong integrity check of the specified .
///
/// is null.
///
/// Should the specified trigger any sort of exception, a is returned.
- public static CacheValidator GetCacheValidator(this FileInfo file, Action setup = null)
+ public static CacheValidator GetCacheValidator(this FileInfo file, Func hashFactory = null, Action setup = null)
{
Validator.ThrowIfNull(file, nameof(file));
try
{
- return CacheValidatorFactory.CreateValidator(file, setup);
+ return CacheValidatorFactory.CreateValidator(file, hashFactory, setup);
}
catch (Exception)
{
diff --git a/src/Cuemon.Extensions.Data.Integrity/GlobalSuppressions.cs b/src/Cuemon.Extensions.Data.Integrity/GlobalSuppressions.cs
deleted file mode 100644
index 5a887d01a..000000000
--- a/src/Cuemon.Extensions.Data.Integrity/GlobalSuppressions.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-// This file is used by Code Analysis to maintain SuppressMessage
-// attributes that are applied to this project.
-// Project-level suppressions either have no target or are given
-// a specific target and scoped to a namespace, type, member, etc.
-
-using System.Diagnostics.CodeAnalysis;
-
-[assembly: SuppressMessage("Major Code Smell", "S3358:Ternary operators should not be nested", Justification = "Not difficult to understand.", Scope = "member", Target = "~M:Cuemon.Extensions.Integrity.AssemblyExtensions.GetCacheValidator(System.Reflection.Assembly,System.Boolean,System.Action{Cuemon.Integrity.CacheValidatorOptions})~Cuemon.Integrity.CacheValidator")]
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Data.Integrity/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Data.Integrity/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..4d092ab8c
--- /dev/null
+++ b/src/Cuemon.Extensions.Data.Integrity/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,9 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# New Features
+- ADDED AssemblyExtensions class in the Cuemon.Extensions.Data.Integrity namespace that consist of extension methods for the Assembly class: GetCacheValidator
+- ADDED ChecksumBuilderExtensions class in the Cuemon.Extensions.Data.Integrity namespace that consist of extension methods for the ChecksumBuilder class: CombineWith{T}
+- ADDED DateTimeExtensions class in the Cuemon.Extensions.Data.Integrity namespace that consist of extension methods for the DateTime struct: GetCacheValidator
+- ADDED FileInfoExtensions class in the Cuemon.Extensions.Data.Integrity namespace that consist of extension methods for the FileInfo class: GetCacheValidator
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Data/Cuemon.Extensions.Data.csproj b/src/Cuemon.Extensions.Data/Cuemon.Extensions.Data.csproj
index 28b73bfbb..e39dc4ce0 100644
--- a/src/Cuemon.Extensions.Data/Cuemon.Extensions.Data.csproj
+++ b/src/Cuemon.Extensions.Data/Cuemon.Extensions.Data.csproj
@@ -1,10 +1,7 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
100bdf91-e7c7-4cb4-a39d-e1a5374c5602
@@ -12,15 +9,8 @@
Cuemon
Cuemon.Extensions.Data
Cuemon.Extensions.Data
- The Cuemon.Extensions.Data assembly provides extension methods related to the Cuemon.Data namespace.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
+ The Cuemon.Extensions.Data namespace contains extension methods that complements the Cuemon.Data namespace while being an addition to the System.Data namespace.
+ extension-methods extensions to-rows to-columns embed
diff --git a/src/Cuemon.Extensions.Data/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Data/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..fa83bbf7c
--- /dev/null
+++ b/src/Cuemon.Extensions.Data/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,7 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# New Features
+- ADDED DataTransferExtensions class in the Cuemon.Extensions.Data namespace that consist of extension methods for the IDataReader interface: ToColumns, ToRows
+- ADDED QueryFormatExtensions class in the Cuemon.Extensions.Data namespace that consist of extension methods for the QueryFormat enum: Embed
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.DependencyInjection/Cuemon.Extensions.DependencyInjection.csproj b/src/Cuemon.Extensions.DependencyInjection/Cuemon.Extensions.DependencyInjection.csproj
index 58275a69b..8c18dcfef 100644
--- a/src/Cuemon.Extensions.DependencyInjection/Cuemon.Extensions.DependencyInjection.csproj
+++ b/src/Cuemon.Extensions.DependencyInjection/Cuemon.Extensions.DependencyInjection.csproj
@@ -1,37 +1,25 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
040bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon .NET Standard
Cuemon.Extensions.DependencyInjection
Cuemon.Extensions.DependencyInjection
- The Cuemon.Extensions.DependencyInjection assembly provides extension methods to the Microsoft.Extensions.DependencyInjection package.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
+ The Cuemon.Extensions.DependencyInjection namespace contains extension methods that complements the Microsoft.Extensions.DependencyInjection namespace.
+ extension-methods extensions add tryadd
-
- https://opensource.org/licenses/MIT
- https://www.cuemon.net/
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
-
+
+
+
+
-
-
-
+
+
+
diff --git a/src/Cuemon.Extensions.DependencyInjection/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.DependencyInjection/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..3129c1978
--- /dev/null
+++ b/src/Cuemon.Extensions.DependencyInjection/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,6 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# New Features
+- ADDED ServiceCollectionExtensions class in the Cuemon.Extensions.DependencyInjection namespace that consist of extension methods for the IServiceCollection interface: Add, Add{TOptions}, Add{TService, TImplementation}, Add{TService, TImplementation, TOptions}, TryAdd, TryAdd{TOptions}, TryAdd{TService, TImplementation}, TryAdd{TService, TImplementation, TOptions}
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.DependencyInjection/ServiceCollectionExtensions.cs b/src/Cuemon.Extensions.DependencyInjection/ServiceCollectionExtensions.cs
index 09e687f9b..a9db04406 100644
--- a/src/Cuemon.Extensions.DependencyInjection/ServiceCollectionExtensions.cs
+++ b/src/Cuemon.Extensions.DependencyInjection/ServiceCollectionExtensions.cs
@@ -163,5 +163,168 @@ private static void AddServices(this IServiceCollection services, Type service,
break;
}
}
+
+ ///
+ /// Adds the specified with the and to the .
+ ///
+ /// The type of the service to add.
+ /// The type of the implementation to use.
+ /// The to add the service to.
+ /// The function delegate that creates the service.
+ /// The lifetime of the service.
+ /// A reference to after the operation has completed.
+ public static IServiceCollection Add(this IServiceCollection services, Func implementationFactory, ServiceLifetime lifetime)
+ where TService : class
+ where TImplementation : class, TService
+ {
+ return services.Add(typeof(TService), implementationFactory, lifetime);
+ }
+
+ ///
+ /// Adds the specified with the and to the .
+ ///
+ /// The type of the service to add.
+ /// The type of the implementation to use.
+ /// The type of the configured options.
+ /// The to add the service to.
+ /// The function delegate that creates the service.
+ /// The lifetime of the service.
+ /// The which need to be configured.
+ /// A reference to after the operation has completed.
+ public static IServiceCollection Add(this IServiceCollection services, Func implementationFactory, ServiceLifetime lifetime, Action setup)
+ where TService : class
+ where TImplementation : class, TService
+ where TOptions : class, new()
+ {
+ return services.Add(typeof(TService), implementationFactory, lifetime, setup);
+ }
+
+ ///
+ /// Adds the specified with the and to the .
+ ///
+ /// The to add the service to.
+ /// The type of the service to register.
+ /// The function delegate that creates the service.
+ /// The lifetime of the service.
+ /// A reference to after the operation has completed.
+ public static IServiceCollection Add(this IServiceCollection services, Type service, Func implementationFactory, ServiceLifetime lifetime)
+ {
+ Validator.ThrowIfNull(services, nameof(services));
+ services.AddServices(service, implementationFactory, lifetime, false);
+ return services;
+ }
+
+ ///
+ /// Adds the specified with the and to the .
+ ///
+ /// The type of the configured options.
+ /// The to add the service to.
+ /// The type of the service to register.
+ /// The function delegate that creates the service.
+ /// The lifetime of the service.
+ /// The which need to be configured.
+ /// A reference to after the operation has completed.
+ public static IServiceCollection Add(this IServiceCollection services, Type service, Func implementationFactory, ServiceLifetime lifetime, Action setup)
+ where TOptions : class, new()
+ {
+ Validator.ThrowIfNull(services, nameof(services));
+ Validator.ThrowIfNull(setup, nameof(setup));
+ services.AddServices(service, implementationFactory, lifetime, false);
+ services.Configure(setup);
+ return services;
+ }
+
+ ///
+ /// Adds the specified with the and to the if the service type has not already been registered.
+ ///
+ /// The type of the service to add.
+ /// The type of the implementation to use.
+ /// The to add the service to.
+ /// The function delegate that creates the service.
+ /// The lifetime of the service.
+ /// A reference to after the operation has completed.
+ public static IServiceCollection TryAdd(this IServiceCollection services, Func implementationFactory, ServiceLifetime lifetime)
+ where TService : class
+ where TImplementation : class, TService
+ {
+ Validator.ThrowIfNull(services, nameof(services));
+ Validator.ThrowIfNull(implementationFactory, nameof(implementationFactory));
+ return services.TryAdd(typeof(TService), implementationFactory, lifetime);
+ }
+
+ ///
+ /// Adds the specified with the and to the if the service type has not already been registered.
+ ///
+ /// The type of the service to add.
+ /// The type of the implementation to use.
+ /// The type of the configured options.
+ /// The to add the service to.
+ /// The function delegate that creates the service.
+ /// The lifetime of the service.
+ /// The which need to be configured.
+ /// A reference to after the operation has completed.
+ public static IServiceCollection TryAdd(this IServiceCollection services, Func implementationFactory, ServiceLifetime lifetime, Action setup)
+ where TService : class
+ where TImplementation : class, TService
+ where TOptions : class, new()
+ {
+ Validator.ThrowIfNull(services, nameof(services));
+ Validator.ThrowIfNull(implementationFactory, nameof(implementationFactory));
+ Validator.ThrowIfNull(setup, nameof(setup));
+ return services.TryAdd(typeof(TService), implementationFactory, lifetime, setup);
+ }
+
+ ///
+ /// Adds the specified with the and to the if the service type has not already been registered.
+ ///
+ /// The to add the service to.
+ /// The type of the service to register.
+ /// The function delegate that creates the service.
+ /// The lifetime of the service.
+ /// A reference to after the operation has completed.
+ public static IServiceCollection TryAdd(this IServiceCollection services, Type service, Func implementationFactory, ServiceLifetime lifetime)
+ {
+ Validator.ThrowIfNull(services, nameof(services));
+ Validator.ThrowIfNull(implementationFactory, nameof(implementationFactory));
+ services.AddServices(service, implementationFactory, lifetime, true);
+ return services;
+ }
+
+ ///
+ /// Adds the specified with the and to the if the service type has not already been registered.
+ ///
+ /// The type of the configured options.
+ /// The to add the service to.
+ /// The type of the service to register.
+ /// The function delegate that creates the service.
+ /// The lifetime of the service.
+ /// The which need to be configured.
+ /// A reference to after the operation has completed.
+ public static IServiceCollection TryAdd(this IServiceCollection services, Type service, Func implementationFactory, ServiceLifetime lifetime, Action setup)
+ where TOptions : class, new()
+ {
+ Validator.ThrowIfNull(services, nameof(services));
+ Validator.ThrowIfNull(implementationFactory, nameof(implementationFactory));
+ Validator.ThrowIfNull(setup, nameof(setup));
+ services.AddServices(service, implementationFactory, lifetime, true);
+ services.Configure(setup);
+ return services;
+ }
+
+ private static void AddServices(this IServiceCollection services, Type service, Func implementationFactory, ServiceLifetime lifetime, bool useTesterDoerPattern)
+ {
+ switch (lifetime)
+ {
+ case ServiceLifetime.Scoped:
+ Condition.FlipFlop(useTesterDoerPattern, () => services.TryAddScoped(service, implementationFactory), () => services.AddScoped(service, implementationFactory));
+ break;
+ case ServiceLifetime.Singleton:
+ Condition.FlipFlop(useTesterDoerPattern, () => services.TryAddSingleton(service, implementationFactory), () => services.AddSingleton(service, implementationFactory));
+ break;
+ case ServiceLifetime.Transient:
+ Condition.FlipFlop(useTesterDoerPattern, () => services.TryAddTransient(service, implementationFactory), () => services.AddTransient(service, implementationFactory));
+ break;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Diagnostics/Cuemon.Extensions.Diagnostics.csproj b/src/Cuemon.Extensions.Diagnostics/Cuemon.Extensions.Diagnostics.csproj
index 91d4b068a..dc46f5f81 100644
--- a/src/Cuemon.Extensions.Diagnostics/Cuemon.Extensions.Diagnostics.csproj
+++ b/src/Cuemon.Extensions.Diagnostics/Cuemon.Extensions.Diagnostics.csproj
@@ -1,26 +1,15 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
0f0bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon
Cuemon.Extensions.Diagnostics
Cuemon.Extensions.Diagnostics
- The Cuemon.Extensions.Diagnostics assembly provides extension methods for diagnostics related implementations.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
+ The Cuemon.Extensions.Diagnostics namespace contains extension methods that complements the Cuemon.Diagnostics namespace while being an addition to the System.Diagnostics namespace.
+ extension-methods extensions to-insights-string to-product-version to-file-version
diff --git a/src/Cuemon.Extensions.Diagnostics/FileVersionInfoExtensions.cs b/src/Cuemon.Extensions.Diagnostics/FileVersionInfoExtensions.cs
index 9fb12f80c..9b1eeba98 100644
--- a/src/Cuemon.Extensions.Diagnostics/FileVersionInfoExtensions.cs
+++ b/src/Cuemon.Extensions.Diagnostics/FileVersionInfoExtensions.cs
@@ -1,5 +1,6 @@
using System;
using System.Diagnostics;
+using Cuemon.Reflection;
namespace Cuemon.Extensions.Diagnostics
{
@@ -9,32 +10,30 @@ namespace Cuemon.Extensions.Diagnostics
public static class FileVersionInfoExtensions
{
///
- /// Returns a from the specified .
+ /// Returns a from the specified .
///
/// An instance of .
- /// A that represents the product version that the is distributed with.
- /// Should the specified not contain any product version, a initialized to 0.0.0.0 is returned.
- public static Version ToProductVersion(this FileVersionInfo fvi)
+ /// A that represents the product version that the is distributed with.
+ public static VersionResult ToProductVersion(this FileVersionInfo fvi)
{
return ToVersion(fvi, info => info.ProductVersion);
}
///
- /// Returns a from the specified .
+ /// Returns a from the specified .
///
/// An instance of .
- /// A that represents the file version that the is distributed with.
- /// Should the specified not contain any file version, a initialized to 0.0.0.0 is returned.
- public static Version ToFileVersion(this FileVersionInfo fvi)
+ /// A that represents the file version that the is distributed with.
+ public static VersionResult ToFileVersion(this FileVersionInfo fvi)
{
return ToVersion(fvi, info => info.FileVersion);
}
- private static Version ToVersion(this FileVersionInfo fvi, Func propertySelector)
+ private static VersionResult ToVersion(this FileVersionInfo fvi, Func propertySelector)
{
Validator.ThrowIfNull(fvi, nameof(fvi));
var version = propertySelector(fvi);
- return new Version(string.IsNullOrWhiteSpace(version) ? "0.0.0.0" : version);
+ return new VersionResult(version);
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Diagnostics/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Diagnostics/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..59d238596
--- /dev/null
+++ b/src/Cuemon.Extensions.Diagnostics/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,7 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# New Features
+- ADDED ExceptionDescriptorExtensions class in the Cuemon.Extensions.Diagnostics namespace that consist of extension methods for the ExceptionDescriptor class: ToInsightsString
+- ADDED FileVersionInfoExtensions class in the Cuemon.Extensions.Diagnostics namespace that consist of extension methods for the FileVersionInfo class: ToProductVersion, ToFileVersion
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Hosting/Cuemon.Extensions.Hosting.csproj b/src/Cuemon.Extensions.Hosting/Cuemon.Extensions.Hosting.csproj
new file mode 100644
index 000000000..20b41f1d9
--- /dev/null
+++ b/src/Cuemon.Extensions.Hosting/Cuemon.Extensions.Hosting.csproj
@@ -0,0 +1,31 @@
+
+
+
+ net5.0;netcoreapp3.0;netstandard2.0
+ 1d0bdf91-e7c7-4cb4-a39d-e1a5374c5602
+
+
+
+ Cuemon.Extensions.Hosting
+ Cuemon.Extensions.Hosting
+ The Cuemon.Extensions.Hosting namespace contains extension methods and features related to the Microsoft.Extensions.Hosting namespace.
+ extension-methods extensions local-development non-production host hosting
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Hosting/HostEnvironmentExtensions.cs b/src/Cuemon.Extensions.Hosting/HostEnvironmentExtensions.cs
new file mode 100644
index 000000000..7791b89b5
--- /dev/null
+++ b/src/Cuemon.Extensions.Hosting/HostEnvironmentExtensions.cs
@@ -0,0 +1,33 @@
+#if NETCOREAPP
+using Microsoft.Extensions.Hosting;
+
+namespace Cuemon.Extensions.Hosting
+{
+
+ ///
+ /// Extension methods for the interface.
+ ///
+ public static class HostEnvironmentExtensions
+ {
+ ///
+ /// Determines whether the specified is equal to LocalDevelopment.
+ ///
+ /// The to extend.
+ /// true if is LocalDevelopment; otherwise false
+ public static bool IsLocalDevelopment(this IHostEnvironment environment)
+ {
+ return environment.IsEnvironment("LocalDevelopment");
+ }
+
+ ///
+ /// Determines whether the specified is different from Production.
+ ///
+ /// The to extend.
+ /// true if is not Production; otherwise false
+ public static bool IsNonProduction(this IHostEnvironment environment)
+ {
+ return !environment.IsProduction();
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Hosting/HostingEnvironmentExtensions.cs b/src/Cuemon.Extensions.Hosting/HostingEnvironmentExtensions.cs
new file mode 100644
index 000000000..983a99d9d
--- /dev/null
+++ b/src/Cuemon.Extensions.Hosting/HostingEnvironmentExtensions.cs
@@ -0,0 +1,32 @@
+#if NETSTANDARD
+using Microsoft.Extensions.Hosting;
+
+namespace Cuemon.Extensions.Hosting
+{
+ ///
+ /// Extension methods for the interface.
+ ///
+ public static class HostingEnvironmentExtensions
+ {
+ ///
+ /// Determines whether the specified is equal to LocalDevelopment.
+ ///
+ /// The to extend.
+ /// true if is LocalDevelopment; otherwise false
+ public static bool IsLocalDevelopment(this IHostingEnvironment environment)
+ {
+ return environment.IsEnvironment("LocalDevelopment");
+ }
+
+ ///
+ /// Determines whether the specified is different from Production.
+ ///
+ /// The to extend.
+ /// true if is not Production; otherwise false
+ public static bool IsNonProduction(this IHostingEnvironment environment)
+ {
+ return !environment.IsProduction();
+ }
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Hosting/Properties/AssemblyInfo.cs b/src/Cuemon.Extensions.Hosting/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..c24d01879
--- /dev/null
+++ b/src/Cuemon.Extensions.Hosting/Properties/AssemblyInfo.cs
@@ -0,0 +1,4 @@
+using System.Runtime.InteropServices;
+
+[assembly: ComVisible(false)]
+[assembly: Guid("e9bc4285-5627-4b81-b00b-712b38757ede")]
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Hosting/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Hosting/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..53e029c08
--- /dev/null
+++ b/src/Cuemon.Extensions.Hosting/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,6 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET Core 3.0, NET 5.0
+
+# New Features
+- Added extension methods for IHostEnvironment: IsLocalDevelopment and IsNonProduction
+- Added extension methods for IHostingEnvironment: IsLocalDevelopment and IsNonProduction
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.IO/Cuemon.Extensions.IO.csproj b/src/Cuemon.Extensions.IO/Cuemon.Extensions.IO.csproj
index 58e53ad13..fe7b399df 100644
--- a/src/Cuemon.Extensions.IO/Cuemon.Extensions.IO.csproj
+++ b/src/Cuemon.Extensions.IO/Cuemon.Extensions.IO.csproj
@@ -1,32 +1,15 @@
- netstandard2.0;netstandard2.1
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.1;netstandard2.0
060bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon .NET Standard
Cuemon.Extensions.IO
Cuemon.Extensions.IO
- The Cuemon.Extensions.IO assembly provides extension methods to the System.IO namespace.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ The Cuemon.Extensions.IO namespace contains extension methods that complements the Cuemon.IO namespace while being an addition to the System.IO namespace.
+ extension-methods extensions concat to-byte-array to-byte-array-async write-async to-encoded-string to-encoded-string-async compress-brotli compress-brotli-async compress-deflate compress-deflate-async compress-gzip compress-gzip-async
diff --git a/src/Cuemon.Extensions.IO/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.IO/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..0650ff211
--- /dev/null
+++ b/src/Cuemon.Extensions.IO/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,9 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET Standard 2.1, NET 5.0
+
+# New Features
+- ADDED ByteArrayExtensions class in the Cuemon.Extensions.IO namespace that consist of extension methods for the byte[] struct: ToStream, ToStreamAsync
+- ADDED StreamExtensions class in the Cuemon.Extensions.IO namespace that consist of extension methods for the Stream class: Concat, ToCharArray, ToByteArray, ToByteArrayAsync, WriteAsync, TryDetectUnicodeEncoding, ToEncodedString, ToEncodedStringAsync, CompressBrotli, CompressBrotliAsync, CompressDeflate, CompressDeflateAsync, CompressGZip, CompressGZipAsync, DecompressBrotli, DecompressBrotliAsync, DecompressDeflate, DecompressDeflateAsync, DecompressGZip, DecompressGZipAsync
+- ADDED StringExtensions class in the Cuemon.Extensions.IO namespace that consist of extension methods for the String class: ToStream, ToStreamAsync, ToTextReader
+- ADDED TextReaderExtensions class in the Cuemon.Extensions.IO namespace that consist of extension methods for the TextReader class: CopyToAsync, ReadAllLines, ReadAllLinesAsync
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.IO/StreamExtensions.cs b/src/Cuemon.Extensions.IO/StreamExtensions.cs
index b8d2452eb..17a017158 100644
--- a/src/Cuemon.Extensions.IO/StreamExtensions.cs
+++ b/src/Cuemon.Extensions.IO/StreamExtensions.cs
@@ -106,7 +106,7 @@ public static byte[] ToByteArray(this Stream input, Action se
/// Converts the specified to its equivalent representation.
///
/// The to extend.
- /// The which may be configured.
+ /// The which may be configured.
/// A task that represents the asynchronous operation. The task result contains a that is equivalent to .
///
/// cannot be null.
@@ -114,7 +114,7 @@ public static byte[] ToByteArray(this Stream input, Action se
///
/// cannot be read from.
///
- public static Task ToByteArrayAsync(this Stream input, Action setup = null)
+ public static Task ToByteArrayAsync(this Stream input, Action setup = null)
{
Validator.ThrowIfNull(input, nameof(input));
Validator.ThrowIfFalse(input.CanRead, nameof(input), "Stream cannot be read from.");
@@ -182,7 +182,7 @@ public static string ToEncodedString(this Stream value, Action to a .
///
/// The to extend.
- /// The which may be configured.
+ /// The which may be configured.
/// A task that represents the asynchronous operation. The task result contains a containing the result of the specified .
/// will be initialized with and .
///
@@ -191,7 +191,7 @@ public static string ToEncodedString(this Stream value, Action
/// was initialized with an invalid .
///
- public static Task ToEncodedStringAsync(this Stream value, Action setup = null)
+ public static Task ToEncodedStringAsync(this Stream value, Action setup = null)
{
Validator.ThrowIfNull(value, nameof(value));
return Decorator.Enclose(value).ToEncodedStringAsync(setup);
@@ -220,7 +220,7 @@ public static Stream CompressBrotli(this Stream value, Action using the BROTLI algorithm.
///
/// The to extend.
- /// The which may be configured.
+ /// The which may be configured.
/// A DEFLATE compressed of the .
/// A task that represents the asynchronous operation. The task result contains a BROTLI compressed of the specified .
///
@@ -229,7 +229,7 @@ public static Stream CompressBrotli(this Stream value, Action
/// does not support write operations such as compression.
///
- public static Task CompressBrotliAsync(this Stream value, Action setup = null)
+ public static Task CompressBrotliAsync(this Stream value, Action setup = null)
{
Validator.ThrowIfNull(value, nameof(value));
return Decorator.Enclose(value).CompressBrotliAsync(setup);
@@ -258,7 +258,7 @@ public static Stream CompressDeflate(this Stream value, Action using the DEFLATE algorithm.
///
/// The to extend.
- /// The which may be configured.
+ /// The which may be configured.
/// A DEFLATE compressed of the .
/// A task that represents the asynchronous operation. The task result contains a DEFLATE compressed of the specified .
///
@@ -267,7 +267,7 @@ public static Stream CompressDeflate(this Stream value, Action
/// does not support write operations such as compression.
///
- public static Task CompressDeflateAsync(this Stream value, Action setup = null)
+ public static Task CompressDeflateAsync(this Stream value, Action setup = null)
{
Validator.ThrowIfNull(value, nameof(value));
return Decorator.Enclose(value).CompressDeflateAsync(setup);
@@ -295,7 +295,7 @@ public static Stream CompressGZip(this Stream value, Action using the GZIP algorithm.
///
/// The to extend.
- /// The which may be configured.
+ /// The which may be configured.
/// A DEFLATE compressed of the .
/// A task that represents the asynchronous operation. The task result contains a GZIP compressed of the specified .
///
@@ -304,7 +304,7 @@ public static Stream CompressGZip(this Stream value, Action
/// does not support write operations such as compression.
///
- public static Task CompressGZipAsync(this Stream value, Action setup = null)
+ public static Task CompressGZipAsync(this Stream value, Action setup = null)
{
Validator.ThrowIfNull(value, nameof(value));
return Decorator.Enclose(value).CompressGZipAsync(setup);
@@ -336,7 +336,7 @@ public static Stream DecompressBrotli(this Stream value, Action using the BROTLI data format specification.
///
/// The to extend.
- /// The which may be configured.
+ /// The which may be configured.
/// A decompressed of the .
/// A task that represents the asynchronous operation. The task result contains a decompressed of the specified .
///
@@ -348,7 +348,7 @@ public static Stream DecompressBrotli(this Stream value, Action
/// was compressed using an unsupported compression method.
///
- public static Task DecompressBrotliAsync(this Stream value, Action setup = null)
+ public static Task DecompressBrotliAsync(this Stream value, Action setup = null)
{
Validator.ThrowIfNull(value, nameof(value));
return Decorator.Enclose(value).DecompressBrotliAsync(setup);
@@ -380,7 +380,7 @@ public static Stream DecompressDeflate(this Stream value, Action using the DEFLATE data format specification.
///
/// The to extend.
- /// The which may be configured.
+ /// The which may be configured.
/// A decompressed of the .
/// A task that represents the asynchronous operation. The task result contains a decompressed of the specified .
///
@@ -392,7 +392,7 @@ public static Stream DecompressDeflate(this Stream value, Action
/// was compressed using an unsupported compression method.
///
- public static Task DecompressDeflateAsync(this Stream value, Action setup = null)
+ public static Task DecompressDeflateAsync(this Stream value, Action setup = null)
{
Validator.ThrowIfNull(value, nameof(value));
return Decorator.Enclose(value).DecompressDeflateAsync(setup);
@@ -423,7 +423,7 @@ public static Stream DecompressGZip(this Stream value, Action
/// Decompresses the using the GZIP data format specification.
///
///
The
to extend.
- ///
The
which may be configured.
+ ///
The
which may be configured.
///
A decompressed of the .
///
A task that represents the asynchronous operation. The task result contains a decompressed of the specified .
///
@@ -435,7 +435,7 @@ public static Stream DecompressGZip(this Stream value, Action
///
/// was compressed using an unsupported compression method.
///
- public static Task DecompressGZipAsync(this Stream value, Action setup = null)
+ public static Task DecompressGZipAsync(this Stream value, Action setup = null)
{
Validator.ThrowIfNull(value, nameof(value));
return Decorator.Enclose(value).DecompressGZipAsync(setup);
diff --git a/src/Cuemon.Extensions.IO/StringExtensions.cs b/src/Cuemon.Extensions.IO/StringExtensions.cs
index 98ef14c8b..59ac845fd 100644
--- a/src/Cuemon.Extensions.IO/StringExtensions.cs
+++ b/src/Cuemon.Extensions.IO/StringExtensions.cs
@@ -1,6 +1,7 @@
using System;
using System.ComponentModel;
using System.IO;
+using System.Threading;
using System.Threading.Tasks;
using Cuemon.Text;
@@ -33,6 +34,7 @@ public static Stream ToStream(this string value, Action setup =
/// Converts the specified to a .
///
/// The to extend.
+ /// The token to monitor for cancellation requests. The default value is .
/// The which may be configured.
/// A task that represents the asynchronous operation. The task result contains a containing the result of the specified .
/// will be initialized with and .
@@ -42,9 +44,9 @@ public static Stream ToStream(this string value, Action setup =
///
/// was initialized with an invalid .
///
- public static Task ToStreamAsync(this string value, Action setup = null)
+ public static Task ToStreamAsync(this string value, CancellationToken ct = default, Action setup = null)
{
- return Decorator.Enclose(value).ToStreamAsync(setup);
+ return Decorator.Enclose(value).ToStreamAsync(ct, setup);
}
///
diff --git a/src/Cuemon.Extensions.Net/Cuemon.Extensions.Net.csproj b/src/Cuemon.Extensions.Net/Cuemon.Extensions.Net.csproj
index fe5915404..d64eb54b9 100644
--- a/src/Cuemon.Extensions.Net/Cuemon.Extensions.Net.csproj
+++ b/src/Cuemon.Extensions.Net/Cuemon.Extensions.Net.csproj
@@ -1,44 +1,28 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
070bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon
Cuemon.Extensions.Net
Cuemon.Extensions.Net
- The Cuemon.Extensions.Net assembly provides extensions methods (query-string parsing, encoding, decoding, security and http communication) and features related to the System.Net namespace. A versatile HttpManager that transparently promotes the HttpClient is included along with a lightweight SMTP Client.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
+ 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 HttpClient instances while also including a simple and lightweight implementation of the IHttpClientFactory interface named SlimHttpClientFactory.
+ extension-methods extensions to-signed-uri validate-signed-uri http-manager-factory slim-http-client-factory i-http-client-factory
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
-
-
-
-
+
+
-
-
+
+
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Net/Http/HttpMethodExtensions.cs b/src/Cuemon.Extensions.Net/Http/HttpMethodExtensions.cs
index c4d7270d7..223be3203 100644
--- a/src/Cuemon.Extensions.Net/Http/HttpMethodExtensions.cs
+++ b/src/Cuemon.Extensions.Net/Http/HttpMethodExtensions.cs
@@ -1,4 +1,5 @@
-using System.Net.Http;
+using System;
+using System.Net.Http;
using Cuemon.Net.Http;
namespace Cuemon.Extensions.Net.Http
@@ -13,6 +14,9 @@ public static class HttpMethodExtensions
///
/// The to be converted.
/// A representation of the specified .
+ ///
+ /// cannot be null.
+ ///
public static HttpMethods ToHttpMethod(this HttpMethod method)
{
return HttpMethodConverter.ToHttpMethod(method);
diff --git a/src/Cuemon.Extensions.Net/Http/SlimHttpClientFactory.cs b/src/Cuemon.Extensions.Net/Http/SlimHttpClientFactory.cs
index c3640b278..13389610d 100644
--- a/src/Cuemon.Extensions.Net/Http/SlimHttpClientFactory.cs
+++ b/src/Cuemon.Extensions.Net/Http/SlimHttpClientFactory.cs
@@ -9,8 +9,6 @@ namespace Cuemon.Extensions.Net.Http
{
///
/// Provides a simple and lightweight implementation of the interface.
- /// Implements the
- /// Implements the
///
///
///
diff --git a/src/Cuemon.Extensions.Net/Http/UriExtensions.cs b/src/Cuemon.Extensions.Net/Http/UriExtensions.cs
index e2268726c..86efc14c7 100644
--- a/src/Cuemon.Extensions.Net/Http/UriExtensions.cs
+++ b/src/Cuemon.Extensions.Net/Http/UriExtensions.cs
@@ -6,6 +6,7 @@
using System.Threading;
using System.Threading.Tasks;
using Cuemon.Net.Http;
+using HttpRequestOptions = Cuemon.Net.Http.HttpRequestOptions;
namespace Cuemon.Extensions.Net.Http
{
@@ -39,9 +40,12 @@ public static IHttpClientFactory DefaultHttpClientFactory
///
/// Send a DELETE request to the specified Uri as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null.
+ ///
public static async Task HttpDeleteAsync(this Uri location, CancellationToken ct = default)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpDeleteAsync(location, ct).ConfigureAwait(false);
@@ -50,9 +54,12 @@ public static async Task HttpDeleteAsync(this Uri location,
///
/// Send a GET request to the specified Uri as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null.
+ ///
public static async Task HttpGetAsync(this Uri location, CancellationToken ct = default)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpGetAsync(location, ct).ConfigureAwait(false);
@@ -61,9 +68,12 @@ public static async Task HttpGetAsync(this Uri location, Ca
///
/// Send a HEAD request to the specified Uri as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null.
+ ///
public static async Task HttpHeadAsync(this Uri location, CancellationToken ct = default)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpHeadAsync(location, ct).ConfigureAwait(false);
@@ -72,9 +82,12 @@ public static async Task HttpHeadAsync(this Uri location, C
///
/// Send an OPTIONS request to the specified Uri as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null.
+ ///
public static async Task HttpOptionsAsync(this Uri location, CancellationToken ct = default)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpOptionsAsync(location, ct).ConfigureAwait(false);
@@ -83,11 +96,14 @@ public static async Task HttpOptionsAsync(this Uri location
///
/// Send a POST request to the specified Uri as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The Content-Type header of the HTTP request sent to the server.
/// The HTTP request content sent to the server.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null.
+ ///
public static async Task HttpPostAsync(this Uri location, string contentType, Stream content, CancellationToken ct = default)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpPostAsync(location, contentType, content, ct).ConfigureAwait(false);
@@ -96,11 +112,14 @@ public static async Task HttpPostAsync(this Uri location, s
///
/// Send a POST request to the specified Uri as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The Content-Type header of the HTTP request sent to the server.
/// The HTTP request content sent to the server.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null.
+ ///
public static async Task HttpPostAsync(this Uri location, MediaTypeHeaderValue contentType, Stream content, CancellationToken ct = default)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpPostAsync(location, contentType, content, ct).ConfigureAwait(false);
@@ -109,11 +128,14 @@ public static async Task HttpPostAsync(this Uri location, M
///
/// Send a PUT request to the specified Uri as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The Content-Type header of the HTTP request sent to the server.
/// The HTTP request content sent to the server.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null.
+ ///
public static async Task HttpPutAsync(this Uri location, string contentType, Stream content, CancellationToken ct = default)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpPutAsync(location, contentType, content, ct).ConfigureAwait(false);
@@ -122,11 +144,14 @@ public static async Task HttpPutAsync(this Uri location, st
///
/// Send a PUT request to the specified Uri as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The Content-Type header of the HTTP request sent to the server.
/// The HTTP request content sent to the server.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null.
+ ///
public static async Task HttpPutAsync(this Uri location, MediaTypeHeaderValue contentType, Stream content, CancellationToken ct = default)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpPutAsync(location, contentType, content, ct).ConfigureAwait(false);
@@ -135,11 +160,14 @@ public static async Task HttpPutAsync(this Uri location, Me
///
/// Send a PATCH request to the specified Uri as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The Content-Type header of the HTTP request sent to the server.
/// The HTTP request content sent to the server.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null.
+ ///
public static async Task HttpPatchAsync(this Uri location, string contentType, Stream content, CancellationToken ct = default)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpPatchAsync(location, contentType, content, ct).ConfigureAwait(false);
@@ -148,11 +176,14 @@ public static async Task HttpPatchAsync(this Uri location,
///
/// Send a PATCH request to the specified Uri as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The Content-Type header of the HTTP request sent to the server.
/// The HTTP request content sent to the server.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null.
+ ///
public static async Task HttpPatchAsync(this Uri location, MediaTypeHeaderValue contentType, Stream content, CancellationToken ct = default)
{
@@ -162,9 +193,12 @@ public static async Task HttpPatchAsync(this Uri location,
///
/// Send a TRACE request to the specified Uri as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null.
+ ///
public static async Task HttpTraceAsync(this Uri location, CancellationToken ct = default)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpTraceAsync(location, ct).ConfigureAwait(false);
@@ -173,12 +207,18 @@ public static async Task HttpTraceAsync(this Uri location,
///
/// Send a request as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The HTTP method.
/// The Content-Type header of the HTTP request sent to the server.
/// The HTTP request content sent to the server.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null -or-
+ /// cannot be null -or-
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
public static async Task HttpAsync(this Uri location, HttpMethod method, string contentType, Stream content, CancellationToken ct = default)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpAsync(method, location, contentType, content, ct).ConfigureAwait(false);
@@ -187,12 +227,18 @@ public static async Task HttpAsync(this Uri location, HttpM
///
/// Send a request as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The HTTP method.
/// The Content-Type header of the HTTP request sent to the server.
/// The HTTP request content sent to the server.
/// The cancellation token to cancel operation.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null -or-
+ /// cannot be null -or-
+ /// cannot be null -or-
+ /// cannot be null.
+ ///
public static async Task HttpAsync(this Uri location, HttpMethod method, MediaTypeHeaderValue contentType, Stream content, CancellationToken ct = default)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpAsync(method, location, contentType, content, ct).ConfigureAwait(false);
@@ -201,9 +247,12 @@ public static async Task HttpAsync(this Uri location, HttpM
///
/// Send a request as an asynchronous operation.
///
- /// The to request.
+ /// The to extend.
/// The which need to be configured.
/// The task object representing the asynchronous operation.
+ ///
+ /// cannot be null.
+ ///
public static async Task HttpAsync(this Uri location, Action setup)
{
return await HttpManagerFactory.CreateManager(DefaultHttpClientFactory, HandlerName).HttpAsync(location, setup).ConfigureAwait(false);
diff --git a/src/Cuemon.Net/HttpStatusCodeExtensions.cs b/src/Cuemon.Extensions.Net/HttpStatusCodeExtensions.cs
similarity index 99%
rename from src/Cuemon.Net/HttpStatusCodeExtensions.cs
rename to src/Cuemon.Extensions.Net/HttpStatusCodeExtensions.cs
index b297eb90f..81cff4f40 100644
--- a/src/Cuemon.Net/HttpStatusCodeExtensions.cs
+++ b/src/Cuemon.Extensions.Net/HttpStatusCodeExtensions.cs
@@ -1,6 +1,6 @@
using System.Net;
-namespace Cuemon.Net
+namespace Cuemon.Extensions.Net
{
///
/// Extension methods for the enum.
diff --git a/src/Cuemon.Extensions.Net/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Net/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..f4e18a0c7
--- /dev/null
+++ b/src/Cuemon.Extensions.Net/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,17 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# New Features
+- ADDED HttpManagerFactory class in the Cuemon.Extensions.Net.Http namespace that provides access to factory methods for creating and configuring HttpManager instances
+- ADDED HttpMethodExtensions class in the Cuemon.Extensions.Net.Http namespace that consist of extension methods for the HttpMethod class: ToHttpMethod
+- ADDED SlimHttpClientFactory class in the Cuemon.Extensions.Net.Http namespace that provides a simple and lightweight implementation of the IHttpClientFactory interface
+- ADDED SlimHttpClientFactoryOptions class in the Cuemon.Extensions.Net.Http namespace that specifies options related to SlimHttpClientFactory
+- ADDED StringExtensions class in the Cuemon.Extensions.Net.Http namespace that consist of extension methods for the Uri class: HttpDeleteAsync, HttpGetAsync, HttpHeadAsync, HttpOptionsAsync, HttpPostAsync, HttpPutAsync, HttpPatchAsync, HttpTraceAsync, HttpAsync
+- ADDED SignedUriOptions class in the Cuemon.Extensions.Net.Security namespace that specifies options related to ToSignedUri extensions
+- ADDED StringExtensions class in the Cuemon.Extensions.Net.Security namespace that consist of extension methods for the String class: ToSignedUri, ValidateSignedUri
+- ADDED UriExtensions class in the Cuemon.Extensions.Net.Security namespace that consist of extension methods for the Uri class: ToSignedUri, ValidateSignedUri
+- ADDED ByteArrayExtensions class in the Cuemon.Extensions.Net namespace that consist of extension methods for the byte[] struct: UrlEncode
+- ADDED DictionaryExtensions class in the Cuemon.Extensions.Net namespace that consist of extension methods for the IDictionary{string, string[]} interface: ToQueryString
+- ADDED NameValueCollectionExtensions class in the Cuemon.Extensions.Net namespace that consist of extension methods for the NameValueCollection class: ToQueryString
+- ADDED StringExtensions class in the Cuemon.Extensions.Net namespace that consist of extension methods for the String class: UrlEncode, UrlDecode
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Net/Security/StringExtensions.cs b/src/Cuemon.Extensions.Net/Security/StringExtensions.cs
index 677abd417..9860e6d53 100644
--- a/src/Cuemon.Extensions.Net/Security/StringExtensions.cs
+++ b/src/Cuemon.Extensions.Net/Security/StringExtensions.cs
@@ -39,7 +39,7 @@ public static Uri ToSignedUri(this string uriString, byte[] secret, DateTime? st
if (start.HasValue) { qsc.Add(options.StartFieldName, Decorator.Enclose(start.Value).ToUtcKind().ToString("s") + "Z"); }
if (expiry.HasValue) { qsc.Add(options.ExpiryFieldName, Decorator.Enclose(expiry.Value).ToUtcKind().ToString("s") + "Z"); }
uriString = FormattableString.Invariant($"{uriString.SkipQueryString()}{qsc.ToQueryString(options.UrlEncode)}");
- qsc.Add(options.SignatureFieldName, HashFactory.CreateHmacCrypto(secret, options.Algorithm).ComputeHash(options.CanonicalRepresentationBuilder(uriString)).ToUrlEncodedBase64String());
+ qsc.Add(options.SignatureFieldName, KeyedHashFactory.CreateHmacCrypto(secret, options.Algorithm).ComputeHash(options.CanonicalRepresentationBuilder(uriString)).ToUrlEncodedBase64String());
return new Uri(FormattableString.Invariant($"{uriString.SkipQueryString()}{qsc.ToQueryString(options.UrlEncode)}"));
}
@@ -71,7 +71,7 @@ public static void ValidateSignedUri(this string signedUriString, byte[] secret,
if (string.IsNullOrWhiteSpace(signature)) { throw new SecurityException(message); }
qsc.Remove(options.SignatureFieldName);
- var computedSignature = HashFactory.CreateHmacCrypto(secret, options.Algorithm).ComputeHash(options.CanonicalRepresentationBuilder(FormattableString.Invariant($"{signedUriString.SkipQueryString()}{qsc.ToQueryString()}"))).ToUrlEncodedBase64String();
+ var computedSignature = KeyedHashFactory.CreateHmacCrypto(secret, options.Algorithm).ComputeHash(options.CanonicalRepresentationBuilder(FormattableString.Invariant($"{signedUriString.SkipQueryString()}{qsc.ToQueryString()}"))).ToUrlEncodedBase64String();
if (!signature.Equals(computedSignature, StringComparison.Ordinal)) { throw new SecurityException(message); }
}
diff --git a/src/Cuemon.Extensions.Newtonsoft.Json/Converters/JsonConverterCollectionExtensions.cs b/src/Cuemon.Extensions.Newtonsoft.Json/Converters/JsonConverterCollectionExtensions.cs
index dfab20d48..03707bb44 100644
--- a/src/Cuemon.Extensions.Newtonsoft.Json/Converters/JsonConverterCollectionExtensions.cs
+++ b/src/Cuemon.Extensions.Newtonsoft.Json/Converters/JsonConverterCollectionExtensions.cs
@@ -218,10 +218,15 @@ private static void WriteExceptionCore(JsonWriter writer, Exception exception, b
private static void WriteInnerExceptions(JsonWriter writer, Exception exception, bool includeStackTrace)
{
- var aggregated = exception as AggregateException;
var innerExceptions = new List();
- if (aggregated != null) { innerExceptions.AddRange(aggregated.Flatten().InnerExceptions); }
- if (exception.InnerException != null) { innerExceptions.Add(exception.InnerException); }
+ if (exception is AggregateException aggregated)
+ {
+ innerExceptions.AddRange(aggregated.Flatten().InnerExceptions);
+ }
+ else
+ {
+ if (exception.InnerException != null) { innerExceptions.Add(exception.InnerException); }
+ }
if (innerExceptions.Count > 0)
{
var endElementsToWrite = 0;
diff --git a/src/Cuemon.Extensions.Newtonsoft.Json/Cuemon.Extensions.Newtonsoft.Json.csproj b/src/Cuemon.Extensions.Newtonsoft.Json/Cuemon.Extensions.Newtonsoft.Json.csproj
index f75c0622f..0f6938ea2 100644
--- a/src/Cuemon.Extensions.Newtonsoft.Json/Cuemon.Extensions.Newtonsoft.Json.csproj
+++ b/src/Cuemon.Extensions.Newtonsoft.Json/Cuemon.Extensions.Newtonsoft.Json.csproj
@@ -1,36 +1,20 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
080bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon .NET Standard
Cuemon.Extensions.Newtonsoft.Json
Cuemon.Extensions.Newtonsoft.Json
- The Cuemon.Extensions.Newtonsoft.Json assembly provides extension methods and general improvements to the Newtonsoft.Json package.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ The Cuemon.Extensions.Newtonsoft.Json namespace contains both types and extension methods that complements the Newtonsoft.Json namespace by adding new ways of working with JSON; both in terms of serialization and parsing.
+ extension-methods extensions jdata jdata-result json-converter json-formatter dynamic-contract-resolver dynamic-json-converter
+
diff --git a/src/Cuemon.Extensions.Newtonsoft.Json/Formatters/JsonFormatterOptions.cs b/src/Cuemon.Extensions.Newtonsoft.Json/Formatters/JsonFormatterOptions.cs
index 56686b7a2..2b9d7d9ad 100644
--- a/src/Cuemon.Extensions.Newtonsoft.Json/Formatters/JsonFormatterOptions.cs
+++ b/src/Cuemon.Extensions.Newtonsoft.Json/Formatters/JsonFormatterOptions.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using Cuemon.Diagnostics;
using Cuemon.Extensions.Newtonsoft.Json.Converters;
using Newtonsoft.Json;
@@ -11,6 +12,17 @@ namespace Cuemon.Extensions.Newtonsoft.Json.Formatters
///
public class JsonFormatterOptions
{
+ static JsonFormatterOptions()
+ {
+ DefaultConverters = list =>
+ {
+ list.AddStringFlagsEnumConverter();
+ list.AddStringEnumConverter();
+ list.AddTimeSpanConverter();
+ list.AddDataPairConverter();
+ };
+ }
+
///
/// Initializes a new instance of the class.
///
@@ -60,18 +72,21 @@ public JsonFormatterOptions()
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
- Settings.Converters.AddStringFlagsEnumConverter();
- Settings.Converters.AddStringEnumConverter();
Settings.Converters.AddExceptionConverter(() => IncludeExceptionStackTrace);
Settings.Converters.AddExceptionDescriptorConverter(o =>
{
o.IncludeEvidence = IncludeExceptionDescriptorEvidence;
o.IncludeFailure = IncludeExceptionDescriptorFailure;
});
- Settings.Converters.AddTimeSpanConverter();
- Settings.Converters.AddDataPairConverter();
+ DefaultConverters?.Invoke(Settings.Converters);
}
+ ///
+ /// Gets or sets a delegate that is invoked when is initialized and propagates registered implementations.
+ ///
+ /// The delegate which propagates registered implementations when is initialized.
+ public static Action> DefaultConverters { get; set; }
+
///
/// Gets or sets a value indicating whether the stack of an is included in the converter that handles exceptions.
///
diff --git a/src/Cuemon.Extensions.Newtonsoft.Json/GlobalSuppressions.cs b/src/Cuemon.Extensions.Newtonsoft.Json/GlobalSuppressions.cs
index 3bf039823..ffbb6f1ba 100644
--- a/src/Cuemon.Extensions.Newtonsoft.Json/GlobalSuppressions.cs
+++ b/src/Cuemon.Extensions.Newtonsoft.Json/GlobalSuppressions.cs
@@ -5,5 +5,6 @@
using System.Diagnostics.CodeAnalysis;
-[assembly: SuppressMessage("Major Code Smell", "S3445:Exceptions should not be explicitly rethrown", Justification = "This is by design; we only want the stacktrace from within the validator method.", Scope = "member", Target = "~M:Cuemon.Extensions.Newtonsoft.Json.ValidatorExtensions.IfNotValidJsonDocument(Cuemon.Validator,Newtonsoft.Json.JsonReader@,System.String,System.String)")]
-[assembly: SuppressMessage("Major Code Smell", "S907:\"goto\" statement should not be used", Justification = "Lecacy code ;-)", Scope = "member", Target = "~M:Cuemon.Extensions.Newtonsoft.Json.JsonReaderExtensions.ToHierarchy(Newtonsoft.Json.JsonReader)~Cuemon.IHierarchy{Cuemon.DataPair}")]
\ No newline at end of file
+[assembly: SuppressMessage("Major Code Smell", "S3445:Exceptions should not be explicitly rethrown", Justification = "This is by design; we only want the stacktrace from within the validator method.", Scope = "member", Target = "~M:Cuemon.Extensions.Newtonsoft.Json.ValidatorExtensions.InvalidJsonDocument(Cuemon.Validator,Newtonsoft.Json.JsonReader@,System.String,System.String)")]
+[assembly: SuppressMessage("Major Code Smell", "S907:\"goto\" statement should not be used", Justification = "Legacy code ;-)", Scope = "member", Target = "~M:Cuemon.Extensions.Newtonsoft.Json.JsonReaderExtensions.ToHierarchy(Newtonsoft.Json.JsonReader)~Cuemon.IHierarchy{Cuemon.DataPair}")]
+[assembly: SuppressMessage("Critical Code Smell", "S3776:Cognitive Complexity of methods should not be too high", Justification = "Legacy code ;-)", Scope = "member", Target = "~M:Cuemon.Extensions.Newtonsoft.Json.JsonReaderExtensions.ToHierarchy(Newtonsoft.Json.JsonReader)~Cuemon.IHierarchy{Cuemon.DataPair}")]
diff --git a/src/Cuemon.Extensions.Newtonsoft.Json/JData.cs b/src/Cuemon.Extensions.Newtonsoft.Json/JData.cs
index a52a99c6f..6d3d9ed9e 100644
--- a/src/Cuemon.Extensions.Newtonsoft.Json/JData.cs
+++ b/src/Cuemon.Extensions.Newtonsoft.Json/JData.cs
@@ -8,7 +8,7 @@
namespace Cuemon.Extensions.Newtonsoft.Json
{
///
- /// Provides a factory based way to parse and extract values from various sources of JSON data.
+ /// Provides a factory based way to parse and extract values from various sources of JSON data. Compliant with RFC 7159 as it uses behind the scene.
///
public class JData
{
@@ -24,7 +24,6 @@ public static IEnumerable ReadAll(Stream json, Action ReadAll(string json)
public static IEnumerable ReadAll(JsonReader reader)
{
Validator.ThrowIfNull(reader, nameof(reader));
- Validator.Throw.IfNotValidJsonDocument(ref reader, nameof(reader));
+ Validator.ThrowIf.InvalidJsonDocument(ref reader, nameof(reader));
return new JData(reader).Result.Value;
}
@@ -69,7 +68,6 @@ internal JData(JsonReader reader)
var result = new List();
while (reader.Read())
{
- if (reader.Value == null) { continue; }
var jr = new JDataResult();
switch (reader.TokenType)
{
@@ -78,16 +76,20 @@ internal JData(JsonReader reader)
reader.Read();
break;
}
+
if (reader.TokenType == JsonToken.StartArray)
{
- jr.Children = FillArray(reader, jr);
+ return FillArrayHierarchy(reader, jr);
}
- else
+
+ if (reader.TokenType == JsonToken.StartObject)
{
- jr.Value = reader.Value;
+ return FillObjectHierarchy(reader, jr);
}
+
+ jr.Value = reader.Value;
jr.Path = reader.Path.RemoveBrackets();
- jr.Type = reader.ValueType ?? typeof(Array);
+ jr.Type = reader.ValueType;
result.Add(jr);
}
return result;
@@ -96,33 +98,23 @@ internal JData(JsonReader reader)
private Lazy> Result { get; }
- private List FillArray(JsonReader reader, JDataResult parent)
+
+ private List FillArrayHierarchy(JsonReader reader, JDataResult parent)
{
- var result = new List();
- while (reader.Read())
- {
- var jr = new JDataResult { Parent = parent };
- if (reader.TokenType == JsonToken.EndArray) { break; }
- if (reader.TokenType == JsonToken.StartObject)
- {
- jr.Children = FillObjectArray(reader, jr);
- }
- else
- {
- jr.Value = reader.Value;
- }
- jr.Path = reader.Path.RemoveBrackets();
- jr.Type = reader.ValueType ?? typeof(Array);
- result.Add(jr);
- }
- return result;
+ return FillHierarchy(reader, parent, r => r.TokenType == JsonToken.EndArray);
+ }
+
+ private List FillObjectHierarchy(JsonReader reader, JDataResult parent)
+ {
+ return FillHierarchy(reader, parent, r => r.TokenType == JsonToken.EndObject);
}
- private List FillObjectArray(JsonReader reader, JDataResult parent)
+ private List FillHierarchy(JsonReader reader, JDataResult parent, Func skipWhenTrue)
{
var result = new List();
while (reader.Read())
{
+ if (skipWhenTrue(reader)) { break; }
var jr = new JDataResult { Parent = parent };
switch (reader.TokenType)
{
@@ -131,23 +123,24 @@ private List FillObjectArray(JsonReader reader, JDataResult parent)
reader.Read();
break;
}
- if (reader.TokenType == JsonToken.EndObject) { break; }
if (reader.TokenType == JsonToken.StartArray)
{
- jr.Children = FillArray(reader, jr);
+ jr.Children = FillArrayHierarchy(reader, jr);
+ }
+ else if (reader.TokenType == JsonToken.StartObject)
+ {
+ jr.Children = FillObjectHierarchy(reader, jr);
}
else
{
jr.Value = reader.Value;
}
jr.Path = reader.Path.RemoveBrackets();
- jr.Type = reader.ValueType ?? typeof(Array);
+ jr.Type = reader.ValueType;
result.Add(jr);
}
return result;
}
-
-
}
internal static class RegexExtensions
diff --git a/src/Cuemon.Extensions.Newtonsoft.Json/JDataResult.cs b/src/Cuemon.Extensions.Newtonsoft.Json/JDataResult.cs
index 8b4dd0f5f..5f087f94f 100644
--- a/src/Cuemon.Extensions.Newtonsoft.Json/JDataResult.cs
+++ b/src/Cuemon.Extensions.Newtonsoft.Json/JDataResult.cs
@@ -50,7 +50,8 @@ public class JDataResult
/// A that represents this instance.
public override string ToString()
{
- return FormattableString.Invariant($"{Path} ({Type.Name.ToLowerInvariant()}), Children: {Children.Count}");
+ var path = string.IsNullOrWhiteSpace(Path) ? "" : $"{Path}, ";
+ return FormattableString.Invariant($"{path}Children: {Children.Count}");
}
}
}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Newtonsoft.Json/JDataResultExtensions.cs b/src/Cuemon.Extensions.Newtonsoft.Json/JDataResultExtensions.cs
index 7f4d2e487..0cb4cb0e1 100644
--- a/src/Cuemon.Extensions.Newtonsoft.Json/JDataResultExtensions.cs
+++ b/src/Cuemon.Extensions.Newtonsoft.Json/JDataResultExtensions.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Cuemon.Collections.Generic;
namespace Cuemon.Extensions.Newtonsoft.Json
{
@@ -10,16 +11,32 @@ namespace Cuemon.Extensions.Newtonsoft.Json
public static class JDataResultExtensions
{
///
- /// Extracts one or more values from JSON objects using the specified and delegate.
+ /// Flattens the entirety of the JSON hierarchical into an sequence.
+ ///
+ /// The to extend.
+ /// An sequence of objects.
+ public static IEnumerable Flatten(this IEnumerable source)
+ {
+ Validator.ThrowIfNull(source, nameof(source));
+ return FlattenCore(source);
+ }
+
+ private static IEnumerable FlattenCore(IEnumerable source)
+ {
+ return source.SelectMany(s => s.Children.Any() ? Arguments.Yield(s).Concat(Flatten(s.Children)) : Arguments.Yield(s));
+ }
+
+ ///
+ /// Extracts one or more values from JSON objects using the specified and delegate.
///
/// The sequence of to parse.
/// The comma-delimited property names (JSON path) to math in a JSON document.
- /// The delegate that will extract values from .
- public static void ExtractObjectValues(this IEnumerable source, string propertyNames, Action> parser)
+ /// The delegate that will extract values from .
+ public static void ExtractObjectValues(this IEnumerable source, string propertyNames, Action> extractor)
{
Validator.ThrowIfNull(source, nameof(source));
Validator.ThrowIfNullOrWhitespace(propertyNames, nameof(propertyNames));
- Validator.ThrowIfNull(parser, nameof(parser));
+ Validator.ThrowIfNull(extractor, nameof(extractor));
var names = propertyNames.Split(',').Select(s => s.Trim()).ToList();
var partial = new List();
@@ -33,23 +50,23 @@ public static void ExtractObjectValues(this IEnumerable source, str
if (partial.Count == names.Count)
{
- parser(partial.ToDictionary(jk => jk.PropertyName, jv => jv));
+ extractor(partial.ToDictionary(jk => jk.PropertyName, jv => jv));
partial.Clear();
}
}
}
///
- /// Extracts one or more values from JSON arrays using the specified and delegate.
+ /// Extracts one or more values from JSON arrays using the specified and delegate.
///
/// The sequence of to parse.
/// The comma-delimited property names (JSON path) to math in a JSON document.
- /// The delegate that will extract values from .
- public static void ExtractArrayValues(this IEnumerable source, string propertyNames, Action>> parser)
+ /// The delegate that will extract values from .
+ public static void ExtractArrayValues(this IEnumerable source, string propertyNames, Action>> extractor)
{
Validator.ThrowIfNull(source, nameof(source));
Validator.ThrowIfNullOrWhitespace(propertyNames, nameof(propertyNames));
- Validator.ThrowIfNull(parser, nameof(parser));
+ Validator.ThrowIfNull(extractor, nameof(extractor));
var names = propertyNames.Split(',').Select(s => s.Trim()).ToList();
var partial = new List();
@@ -63,7 +80,7 @@ public static void ExtractArrayValues(this IEnumerable source, stri
if (partial.Count == names.Count)
{
- parser(partial.ToDictionary(jk => jk.PropertyName, jv => jv.Children as IEnumerable));
+ extractor(partial.ToDictionary(jk => jk.PropertyName, jv => jv.Children as IEnumerable));
partial.Clear();
}
}
diff --git a/src/Cuemon.Extensions.Newtonsoft.Json/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Newtonsoft.Json/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..ac0df4f30
--- /dev/null
+++ b/src/Cuemon.Extensions.Newtonsoft.Json/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,21 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# Upgrade Steps
+- The Cuemon.Serialization.Json namespace was removed with this version
+- Any types found in the Cuemon.Serialization.Json namespace was merged into the Cuemon.Extensions.Newtonsoft.Json namespace
+
+# Breaking Changes
+- REMOVED JsonReaderParser class from the Cuemon.Extensions.Newtonsoft.Json namespace
+- RENAMED JsonReaderResult class in the Cuemon.Extensions.Newtonsoft.Json namespace to JDataResult (including some refactoring)
+- REMOVED JsonReaderResultExtensions class from the Cuemon.Extensions.Newtonsoft.Json namespace
+
+# New Features
+- CHANGED StringFlagsEnumConverter class in the Cuemon.Extensions.Newtonsoft.Json.Converters namespace to comply with Newtonsoft.Json.Serialization.NamingStrategy implementations
+- ADDED ExceptionDescriptorExtensions class in the Cuemon.Extensions.Newtonsoft.Json.Diagnostics namespace that consist of extension methods for the ExceptionDescriptor class: ToInsightsJsonString
+- EXTENDED JsonFormatterOptions class in the Cuemon.Extensions.Newtonsoft.Json namespace with several new options and a uniform way of adding default converters
+- ADDED JData class in the Cuemon.Extensions.Newtonsoft.Json namespace that provides a factory based way to parse and extract values from various sources of JSON data. Compliant with RFC 7159 as it uses JsonTextReader behind the scene
+- ADDED JDataResultExtensions class in the Cuemon.Extensions.Newtonsoft.Json namespace that consist of extension methods for the JDataResult class: ExtractArrayValues, ExtractObjectValues
+- EXTENDED JsonSerializerSettingsExtensions class in the Cuemon.Extensions.Newtonsoft.Json namespace with one new extension method for the JsonSerializerSettings class: UseCamelCase
+- ADDED ValidatorExtensions class in the Cuemon.Extensions.Newtonsoft.Json namespace that consist of extension methods for the Validator class: InvalidJsonDocument
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Newtonsoft.Json/ValidatorExtensions.cs b/src/Cuemon.Extensions.Newtonsoft.Json/ValidatorExtensions.cs
index d79ad4d48..905fb57d5 100644
--- a/src/Cuemon.Extensions.Newtonsoft.Json/ValidatorExtensions.cs
+++ b/src/Cuemon.Extensions.Newtonsoft.Json/ValidatorExtensions.cs
@@ -19,7 +19,7 @@ public static class ValidatorExtensions
///
/// must be a JSON representation that complies with RFC 8259.
///
- public static void IfNotValidJsonDocument(this Validator validator, ref JsonReader value, string paramName, string message = "Value must be a JSON representation that complies with RFC 8259.")
+ public static void InvalidJsonDocument(this Validator validator, ref JsonReader value, string paramName, string message = "Value must be a JSON representation that complies with RFC 8259.")
{
if (value == null) { return; }
var reader = value;
diff --git a/src/Cuemon.Extensions.Reflection/AssemblyExtensions.cs b/src/Cuemon.Extensions.Reflection/AssemblyExtensions.cs
index 663f4d735..bc961cf8e 100644
--- a/src/Cuemon.Extensions.Reflection/AssemblyExtensions.cs
+++ b/src/Cuemon.Extensions.Reflection/AssemblyExtensions.cs
@@ -10,37 +10,37 @@ namespace Cuemon.Extensions.Reflection
public static class AssemblyExtensions
{
///
- /// Returns a that represents the version number of the specified .
+ /// Returns a that represents the version number of the specified .
///
/// The assembly to resolve a from.
- /// A that represents the version number of the specified .
- public static Version GetAssemblyVersion(this Assembly assembly)
+ /// A that represents the version number of the specified .
+ public static VersionResult GetAssemblyVersion(this Assembly assembly)
{
return Decorator.Enclose(assembly).GetAssemblyVersion();
}
///
- /// Returns a that represents the file version number of the specified .
+ /// Returns a that represents the file version number of the specified .
///
/// The assembly to resolve a from.
- /// A that represents the file version number of the specified .
+ /// A that represents the file version number of the specified .
///
/// is null.
///
- public static Version GetFileVersion(this Assembly assembly)
+ public static VersionResult GetFileVersion(this Assembly assembly)
{
return Decorator.Enclose(assembly).GetFileVersion();
}
///
- /// Returns a that represents the version of the product this is distributed with.
+ /// Returns a that represents the version of the product this is distributed with.
///
/// The assembly to resolve a from.
- /// A that represents the version of the product this is distributed with.
+ /// A that represents the version of the product this is distributed with.
///
/// is null.
///
- public static Version GetProductVersion(this Assembly assembly)
+ public static VersionResult GetProductVersion(this Assembly assembly)
{
return Decorator.Enclose(assembly).GetProductVersion();
}
diff --git a/src/Cuemon.Extensions.Reflection/Cuemon.Extensions.Reflection.csproj b/src/Cuemon.Extensions.Reflection/Cuemon.Extensions.Reflection.csproj
index c9878269c..258d4321b 100644
--- a/src/Cuemon.Extensions.Reflection/Cuemon.Extensions.Reflection.csproj
+++ b/src/Cuemon.Extensions.Reflection/Cuemon.Extensions.Reflection.csproj
@@ -1,32 +1,15 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
090bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon .NET Standard
Cuemon.Extensions.Reflection
Cuemon.Extensions.Reflection
- The Cuemon.Extensions.Reflection assembly provides extension to the System.Reflection namespace.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ The Cuemon.Extensions.Reflection namespace contains extension methods that complements the Cuemon.Reflection namespace while being an addition to the System.Reflection namespace.
+ extension-methods extensions get-assembly-version get-file-version get-product-version is-debug-build has-attributes is-auto-property get-runtime-properties-except-of
diff --git a/src/Cuemon.Extensions.Reflection/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Reflection/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..686af98f6
--- /dev/null
+++ b/src/Cuemon.Extensions.Reflection/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,8 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# New Features
+- ADDED AssemblyExtensions class in the Cuemon.Extensions.Reflection namespace that consist of extension methods for the Assembly class: GetAssemblyVersion, GetFileVersion, GetProductVersion, IsDebugBuild
+- ADDED PropertyInfoExtensions class in the Cuemon.Extensions.Reflection namespace that consist of extension methods for the PropertyInfo class: IsAutoProperty
+- ADDED TypeExtensions class in the Cuemon.Extensions.Reflection namespace that consist of extension methods for the Type class: GetEmbeddedResources, ToMethodBase, GetRuntimePropertiesExceptOf{T}, ToFullNameIncludingAssemblyName
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Runtime.Caching/CacheEnumerableExtensions.cs b/src/Cuemon.Extensions.Runtime.Caching/CacheEnumerableExtensions.cs
new file mode 100644
index 000000000..d42fa34bf
--- /dev/null
+++ b/src/Cuemon.Extensions.Runtime.Caching/CacheEnumerableExtensions.cs
@@ -0,0 +1,743 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using Cuemon.Collections.Generic;
+using Cuemon.Reflection;
+using Cuemon.Runtime;
+using Cuemon.Runtime.Caching;
+
+namespace Cuemon.Extensions.Runtime.Caching
+{
+ ///
+ /// Extension methods for the interface.
+ ///
+ public static class CacheEnumerableExtensions
+ {
+ ///
+ /// Represents a cache with a scope of Memoization.
+ ///
+ public const string MemoizationScope = "Memoization";
+
+ private const long MemoizationNullHashCode = 854726591;
+
+ ///
+ /// Gets the value for the specified from the cache, or if the does not exists, adds a value to the cache using the specified function delegate .
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The unique identifier for the cache entry.
+ /// An implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a value for the .
+ /// The value for the specified . This will either be the existing value if the is already in the cache, or the new value returned by if the was not in the cache.
+ public static TResult GetOrAdd(this ICacheEnumerable cache, string key, IDependency dependency, Func valueFactory)
+ {
+ return GetOrAdd(cache, key, CacheEntry.NoScope, dependency, valueFactory);
+ }
+
+ ///
+ /// Gets the value for the specified from the cache, or if the does not exists, adds a value to the cache using the specified function delegate .
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The unique identifier for the cache entry.
+ /// The optional namespace that provides a scope to the cache. Default is .
+ /// An implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a value for the .
+ /// The value for the specified . This will either be the existing value if the is already in the cache, or the new value returned by if the was not in the cache.
+ public static TResult GetOrAdd(this ICacheEnumerable cache, string key, string ns, IDependency dependency, Func valueFactory)
+ {
+ return GetOrAdd(cache, key, ns, Arguments.Yield(dependency), valueFactory);
+ }
+
+ ///
+ /// Gets the value for the specified from the cache, or if the does not exists, adds a value to the cache using the specified function delegate .
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The unique identifier for the cache entry.
+ /// A sequence of implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a value for the .
+ /// The value for the specified . This will either be the existing value if the is already in the cache, or the new value returned by if the was not in the cache.
+ public static TResult GetOrAdd(this ICacheEnumerable cache, string key, IEnumerable dependencies, Func valueFactory)
+ {
+ return GetOrAdd(cache, key, CacheEntry.NoScope, dependencies, valueFactory);
+ }
+
+ ///
+ /// Gets the value for the specified from the cache, or if the does not exists, adds a value to the cache using the specified function delegate .
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The unique identifier for the cache entry.
+ /// The optional namespace that provides a scope to the cache. Default is .
+ /// A sequence of implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a value for the .
+ /// The value for the specified . This will either be the existing value if the is already in the cache, or the new value returned by if the was not in the cache.
+ public static TResult GetOrAdd(this ICacheEnumerable cache, string key, string ns, IEnumerable dependencies, Func valueFactory)
+ {
+ return GetOrAdd(cache, key, ns, new CacheInvalidation(dependencies), valueFactory);
+ }
+
+ ///
+ /// Gets the value for the specified from the cache, or if the does not exists, adds a value to the cache using the specified function delegate .
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The unique identifier for the cache entry.
+ /// The sliding expiration time from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a value for the .
+ /// The value for the specified . This will either be the existing value if the is already in the cache, or the new value returned by if the was not in the cache.
+ public static TResult GetOrAdd(this ICacheEnumerable cache, string key, TimeSpan slidingExpiration, Func valueFactory)
+ {
+ return GetOrAdd(cache, key, CacheEntry.NoScope, slidingExpiration, valueFactory);
+ }
+
+ ///
+ /// Gets the value for the specified from the cache, or if the does not exists, adds a value to the cache using the specified function delegate .
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The unique identifier for the cache entry.
+ /// The optional namespace that provides a scope to the cache. Default is .
+ /// The sliding expiration time from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a value for the .
+ /// The value for the specified . This will either be the existing value if the is already in the cache, or the new value returned by if the was not in the cache.
+ public static TResult GetOrAdd(this ICacheEnumerable cache, string key, string ns, TimeSpan slidingExpiration, Func valueFactory)
+ {
+ return GetOrAdd(cache, key, ns, new CacheInvalidation(slidingExpiration), valueFactory);
+ }
+
+ ///
+ /// Gets the value for the specified from the cache, or if the does not exists, adds a value to the cache using the specified function delegate .
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The unique identifier for the cache entry.
+ /// The absolute expiration date time value from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a value for the .
+ /// The value for the specified . This will either be the existing value if the is already in the cache, or the new value returned by if the was not in the cache.
+ public static TResult GetOrAdd(this ICacheEnumerable cache, string key, DateTime absoluteExpiration, Func valueFactory)
+ {
+ return GetOrAdd(cache, key, CacheEntry.NoScope, absoluteExpiration, valueFactory);
+ }
+
+ ///
+ /// Gets the value for the specified from the cache, or if the does not exists, adds a value to the cache using the specified function delegate .
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The unique identifier for the cache entry.
+ /// The optional namespace that provides a scope to the cache. Default is .
+ /// The absolute expiration date time value from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a value for the .
+ /// The value for the specified . This will either be the existing value if the is already in the cache, or the new value returned by if the was not in the cache.
+ public static TResult GetOrAdd(this ICacheEnumerable cache, string key, string ns, DateTime absoluteExpiration, Func valueFactory)
+ {
+ return GetOrAdd(cache, key, ns, new CacheInvalidation(absoluteExpiration), valueFactory);
+ }
+
+ ///
+ /// Gets the value for the specified from the cache, or if the does not exists, adds a value to the cache using the specified function delegate .
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The unique identifier for the cache entry.
+ /// The object that contains expiration details for a specific cache entry.
+ /// The function delegate used to provide a value for the .
+ /// The value for the specified . This will either be the existing value if the is already in the cache, or the new value returned by if the was not in the cache.
+ public static TResult GetOrAdd(this ICacheEnumerable cache, string key, CacheInvalidation invalidation, Func valueFactory)
+ {
+ return GetOrAdd(cache, key, CacheEntry.NoScope, invalidation, valueFactory);
+ }
+
+ ///
+ /// Gets the value for the specified from the cache, or if the does not exists, adds a value to the cache using the specified function delegate .
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The unique identifier for the cache entry.
+ /// The optional namespace that provides a scope to the cache. Default is .
+ /// The object that contains expiration details for a specific cache entry.
+ /// The function delegate used to provide a value for the .
+ /// The value for the specified . This will either be the existing value if the is already in the cache, or the new value returned by if the was not in the cache.
+ public static TResult GetOrAdd(this ICacheEnumerable cache, string key, string ns, CacheInvalidation invalidation, Func valueFactory)
+ {
+ Validator.ThrowIfNull(cache, nameof(cache));
+ Validator.ThrowIfNull(key, nameof(key));
+ Validator.ThrowIfNull(invalidation, nameof(invalidation));
+ Validator.ThrowIfNull(valueFactory, nameof(valueFactory));
+
+ if (!cache.TryGet(key, ns, out var value))
+ {
+ value = valueFactory();
+ cache.Add(new CacheEntry(key, value, ns), invalidation);
+ }
+ return (TResult)value;
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// An implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, IDependency dependency, Func valueFactory)
+ {
+ return Memoize(cache, Arguments.Yield(dependency), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// A sequence of implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, IEnumerable dependencies, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(dependencies), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The sliding expiration time from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, TimeSpan slidingExpiration, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(slidingExpiration), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The absolute expiration date time value from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, DateTime absoluteExpiration, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(absoluteExpiration), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The object that contains expiration details for a specific cache entry.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, CacheInvalidation invalidation, Func valueFactory)
+ {
+ return delegate
+ {
+ var key = ComputeMemoizationCacheKey(valueFactory);
+ return Memoize(cache, key, invalidation, FuncFactory.Create(valueFactory));
+ };
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// An implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, IDependency dependency, Func valueFactory)
+ {
+ return Memoize(cache, Arguments.Yield(dependency), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// A sequence of implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, IEnumerable dependencies, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(dependencies), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The sliding expiration time from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, TimeSpan slidingExpiration, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(slidingExpiration), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The absolute expiration date time value from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, DateTime absoluteExpiration, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(absoluteExpiration), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The object that contains expiration details for a specific cache entry.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, CacheInvalidation invalidation, Func valueFactory)
+ {
+ return delegate (T arg)
+ {
+ var key = ComputeMemoizationCacheKey(valueFactory, arg);
+ return Memoize(cache, key, invalidation, FuncFactory.Create(valueFactory, arg));
+ };
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// An implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, IDependency dependency, Func valueFactory)
+ {
+ return Memoize(cache, Arguments.Yield(dependency), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// A sequence of implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, IEnumerable dependencies, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(dependencies), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The sliding expiration time from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, TimeSpan slidingExpiration, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(slidingExpiration), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The absolute expiration date time value from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, DateTime absoluteExpiration, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(absoluteExpiration), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The object that contains expiration details for a specific cache entry.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, CacheInvalidation invalidation, Func valueFactory)
+ {
+ return delegate (T1 arg1, T2 arg2)
+ {
+ var key = ComputeMemoizationCacheKey(valueFactory, arg1, arg2);
+ return Memoize(cache, key, invalidation, FuncFactory.Create(valueFactory, arg1, arg2));
+ };
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// An implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, IDependency dependency, Func valueFactory)
+ {
+ return Memoize(cache, Arguments.Yield(dependency), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// A sequence of implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, IEnumerable dependencies, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(dependencies), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The sliding expiration time from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, TimeSpan slidingExpiration, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(slidingExpiration), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The absolute expiration date time value from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, DateTime absoluteExpiration, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(absoluteExpiration), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The object that contains expiration details for a specific cache entry.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, CacheInvalidation invalidation, Func valueFactory)
+ {
+ return delegate (T1 arg1, T2 arg2, T3 arg3)
+ {
+ var key = ComputeMemoizationCacheKey(valueFactory, arg1, arg2, arg3);
+ return Memoize(cache, key, invalidation, FuncFactory.Create(valueFactory, arg1, arg2, arg3));
+ };
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the fourth parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// An implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, IDependency dependency, Func valueFactory)
+ {
+ return Memoize(cache, Arguments.Yield(dependency), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the fourth parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// A sequence of implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, IEnumerable dependencies, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(dependencies), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the fourth parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The sliding expiration time from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, TimeSpan slidingExpiration, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(slidingExpiration), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the fourth parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The absolute expiration date time value from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, DateTime absoluteExpiration, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(absoluteExpiration), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the fourth parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The object that contains expiration details for a specific cache entry.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, CacheInvalidation invalidation, Func valueFactory)
+ {
+ return delegate (T1 arg1, T2 arg2, T3 arg3, T4 arg4)
+ {
+ var key = ComputeMemoizationCacheKey(valueFactory, arg1, arg2, arg3, arg4);
+ return Memoize(cache, key, invalidation, FuncFactory.Create(valueFactory, arg1, arg2, arg3, arg4));
+ };
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the fourth parameter of the delegate .
+ /// The type of the fifth parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// An implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, IDependency dependency, Func valueFactory)
+ {
+ return Memoize(cache, Arguments.Yield(dependency), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the fourth parameter of the delegate .
+ /// The type of the fifth parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// A sequence of implementations that monitors changes in the state of the data which a cache entry depends on. If a state change is registered, the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, IEnumerable dependencies, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(dependencies), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the fourth parameter of the delegate .
+ /// The type of the fifth parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The sliding expiration time from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, TimeSpan slidingExpiration, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(slidingExpiration), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the fourth parameter of the delegate .
+ /// The type of the fifth parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The absolute expiration date time value from when the cached entry becomes invalid and is removed from the cache.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, DateTime absoluteExpiration, Func valueFactory)
+ {
+ return Memoize(cache, new CacheInvalidation(absoluteExpiration), valueFactory);
+ }
+
+ ///
+ /// Memoizes the specified in the cache for fast access.
+ ///
+ /// The type of the key in the cache.
+ /// The type of the first parameter of the delegate .
+ /// The type of the second parameter of the delegate .
+ /// The type of the third parameter of the delegate .
+ /// The type of the fourth parameter of the delegate .
+ /// The type of the fifth parameter of the delegate .
+ /// The type of the value in the cache.
+ /// The to extend.
+ /// The object that contains expiration details for a specific cache entry.
+ /// The function delegate used to provide a memoized value.
+ /// A memoized function delegate that is otherwise equivalent to .
+ public static Func Memoize(this ICacheEnumerable cache, CacheInvalidation invalidation, Func valueFactory)
+ {
+ return delegate (T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
+ {
+ var key = ComputeMemoizationCacheKey(valueFactory, arg1, arg2, arg3, arg4, arg5);
+ return Memoize(cache, key, invalidation, FuncFactory.Create(valueFactory, arg1, arg2, arg3, arg4, arg5));
+ };
+ }
+
+ private static readonly object PadLock = new object();
+
+ private static TResult Memoize(ICacheEnumerable cache, string key, CacheInvalidation invalidation, FuncFactory valueFactory) where TTuple : Template
+ {
+ if (cache.TryGetCacheEntry(key, MemoizationScope, out var cacheEntry)) { return (TResult)cacheEntry.Value; }
+ lock (PadLock)
+ {
+ if (!cache.TryGet(key, MemoizationScope, out var value))
+ {
+ value = valueFactory.ExecuteMethod();
+ cache.Add(new CacheEntry(key, value, MemoizationScope), invalidation);
+ }
+ return (TResult)value;
+ }
+ }
+
+ private static string ComputeMemoizationCacheKey(Delegate del, params object[] args)
+ {
+ var result = del == null || del.GetMethodInfo() == null
+ ? MemoizationNullHashCode.GetHashCode()
+ : MethodDescriptor.Create(del.GetMethodInfo()).ToString().GetHashCode();
+
+ foreach (var arg in args)
+ {
+ var current = arg ?? MemoizationNullHashCode;
+ var bytes = current as byte[];
+ result ^= bytes == null
+ ? current.GetHashCode()
+ : Generate.HashCode32(bytes.Cast());
+ }
+
+ return result.ToString(CultureInfo.InvariantCulture);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Runtime.Caching/Cuemon.Extensions.Runtime.Caching.csproj b/src/Cuemon.Extensions.Runtime.Caching/Cuemon.Extensions.Runtime.Caching.csproj
new file mode 100644
index 000000000..1524e8f9e
--- /dev/null
+++ b/src/Cuemon.Extensions.Runtime.Caching/Cuemon.Extensions.Runtime.Caching.csproj
@@ -0,0 +1,19 @@
+
+
+
+ net5.0;netstandard2.0
+ 1f0bdf91-e7c7-4cb4-a39d-e1a5374c5602
+
+
+
+ Cuemon.Extensions.Runtime.Caching
+ Cuemon.Extensions.Runtime.Caching
+ 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.
+ extension-methods extensions memoization memoize get-or-add thread-safe caching
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Runtime.Caching/GlobalSuppressions.cs b/src/Cuemon.Extensions.Runtime.Caching/GlobalSuppressions.cs
new file mode 100644
index 000000000..b17e8ffe3
--- /dev/null
+++ b/src/Cuemon.Extensions.Runtime.Caching/GlobalSuppressions.cs
@@ -0,0 +1,27 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``4(Cuemon.Runtime.Caching.ICacheEnumerable{``0},Cuemon.Runtime.Caching.CacheInvalidation,System.Func{``1,``2,``3})~System.Func{``1,``2,``3}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``4(Cuemon.Runtime.Caching.ICacheEnumerable{``0},Cuemon.Runtime.IDependency,System.Func{``1,``2,``3})~System.Func{``1,``2,``3}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``4(Cuemon.Runtime.Caching.ICacheEnumerable{``0},System.Collections.Generic.IEnumerable{Cuemon.Runtime.IDependency},System.Func{``1,``2,``3})~System.Func{``1,``2,``3}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``4(Cuemon.Runtime.Caching.ICacheEnumerable{``0},System.DateTime,System.Func{``1,``2,``3})~System.Func{``1,``2,``3}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``4(Cuemon.Runtime.Caching.ICacheEnumerable{``0},System.TimeSpan,System.Func{``1,``2,``3})~System.Func{``1,``2,``3}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``5(Cuemon.Runtime.Caching.ICacheEnumerable{``0},Cuemon.Runtime.Caching.CacheInvalidation,System.Func{``1,``2,``3,``4})~System.Func{``1,``2,``3,``4}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``5(Cuemon.Runtime.Caching.ICacheEnumerable{``0},Cuemon.Runtime.IDependency,System.Func{``1,``2,``3,``4})~System.Func{``1,``2,``3,``4}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``5(Cuemon.Runtime.Caching.ICacheEnumerable{``0},System.Collections.Generic.IEnumerable{Cuemon.Runtime.IDependency},System.Func{``1,``2,``3,``4})~System.Func{``1,``2,``3,``4}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``5(Cuemon.Runtime.Caching.ICacheEnumerable{``0},System.DateTime,System.Func{``1,``2,``3,``4})~System.Func{``1,``2,``3,``4}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``5(Cuemon.Runtime.Caching.ICacheEnumerable{``0},System.TimeSpan,System.Func{``1,``2,``3,``4})~System.Func{``1,``2,``3,``4}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``6(Cuemon.Runtime.Caching.ICacheEnumerable{``0},Cuemon.Runtime.Caching.CacheInvalidation,System.Func{``1,``2,``3,``4,``5})~System.Func{``1,``2,``3,``4,``5}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``6(Cuemon.Runtime.Caching.ICacheEnumerable{``0},Cuemon.Runtime.IDependency,System.Func{``1,``2,``3,``4,``5})~System.Func{``1,``2,``3,``4,``5}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``6(Cuemon.Runtime.Caching.ICacheEnumerable{``0},System.Collections.Generic.IEnumerable{Cuemon.Runtime.IDependency},System.Func{``1,``2,``3,``4,``5})~System.Func{``1,``2,``3,``4,``5}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``6(Cuemon.Runtime.Caching.ICacheEnumerable{``0},System.DateTime,System.Func{``1,``2,``3,``4,``5})~System.Func{``1,``2,``3,``4,``5}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``6(Cuemon.Runtime.Caching.ICacheEnumerable{``0},System.TimeSpan,System.Func{``1,``2,``3,``4,``5})~System.Func{``1,``2,``3,``4,``5}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``7(Cuemon.Runtime.Caching.ICacheEnumerable{``0},Cuemon.Runtime.Caching.CacheInvalidation,System.Func{``1,``2,``3,``4,``5,``6})~System.Func{``1,``2,``3,``4,``5,``6}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``7(Cuemon.Runtime.Caching.ICacheEnumerable{``0},Cuemon.Runtime.IDependency,System.Func{``1,``2,``3,``4,``5,``6})~System.Func{``1,``2,``3,``4,``5,``6}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``7(Cuemon.Runtime.Caching.ICacheEnumerable{``0},System.Collections.Generic.IEnumerable{Cuemon.Runtime.IDependency},System.Func{``1,``2,``3,``4,``5,``6})~System.Func{``1,``2,``3,``4,``5,``6}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``7(Cuemon.Runtime.Caching.ICacheEnumerable{``0},System.DateTime,System.Func{``1,``2,``3,``4,``5,``6})~System.Func{``1,``2,``3,``4,``5,``6}")]
+[assembly: SuppressMessage("Major Code Smell", "S2436:Types and methods should not have too many generic parameters", Justification = "By design; allow up till 5 generic arguments (more under certain conditions).", Scope = "member", Target = "~M:Cuemon.Extensions.Runtime.Caching.CacheEnumerableExtensions.Memoize``7(Cuemon.Runtime.Caching.ICacheEnumerable{``0},System.TimeSpan,System.Func{``1,``2,``3,``4,``5,``6})~System.Func{``1,``2,``3,``4,``5,``6}")]
diff --git a/src/Cuemon.Extensions.Runtime.Caching/Properties/AssemblyInfo.cs b/src/Cuemon.Extensions.Runtime.Caching/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..d1b06c7c3
--- /dev/null
+++ b/src/Cuemon.Extensions.Runtime.Caching/Properties/AssemblyInfo.cs
@@ -0,0 +1,4 @@
+using System.Runtime.InteropServices;
+
+[assembly: ComVisible(false)]
+[assembly: Guid("7db84665-da22-440e-b60b-9ab4a48c4122")]
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Runtime.Caching/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Runtime.Caching/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..a81acd5e0
--- /dev/null
+++ b/src/Cuemon.Extensions.Runtime.Caching/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,5 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# New Features
+- ADDED CacheEnumerableExtensions class in the Cuemon.Extensions.Runtime.Caching namespace that consist of extension methods for the ICacheEnumerable{TKey} interface: GetOrAdd, Memoize
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Text/Cuemon.Extensions.Text.csproj b/src/Cuemon.Extensions.Text/Cuemon.Extensions.Text.csproj
index 1ee5e3754..3116acceb 100644
--- a/src/Cuemon.Extensions.Text/Cuemon.Extensions.Text.csproj
+++ b/src/Cuemon.Extensions.Text/Cuemon.Extensions.Text.csproj
@@ -1,32 +1,15 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
0a0bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon .NET Standard
Cuemon.Extensions.Text
Cuemon.Extensions.Text
- The Cuemon.Extensions.Text assembly provides extension methods to the Cuemon.Text namespace.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ The Cuemon.Extensions.Text namespace contains extension methods that complements the Cuemon.Text namespace while being an addition to the System namespace.
+ extension-methods extensions to-encoded-string to-ascii-encoded-string
diff --git a/src/Cuemon.Extensions.Text/EncodingOptionsExtensions.cs b/src/Cuemon.Extensions.Text/EncodingOptionsExtensions.cs
index ca5bd7831..5c741ae31 100644
--- a/src/Cuemon.Extensions.Text/EncodingOptionsExtensions.cs
+++ b/src/Cuemon.Extensions.Text/EncodingOptionsExtensions.cs
@@ -5,7 +5,7 @@
namespace Cuemon.Extensions.Text
{
///
- /// Extension methods for the class.
+ /// Extension methods for the interface.
///
public static class EncodingOptionsExtensions
{
diff --git a/src/Cuemon.Extensions.Text/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Text/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..5558e3cf6
--- /dev/null
+++ b/src/Cuemon.Extensions.Text/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,7 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# New Features
+- ADDED EncodingOptionsExtensions class in the Cuemon.Extensions.Text namespace that consist of extension methods for the EncodingOptionsExtensions class: DetectUnicodeEncoding
+- ADDED StringExtensions class in the Cuemon.Extensions.Text namespace that consist of extension methods for the string class: ToEncodedString, ToAsciiEncodedString
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Threading/Cuemon.Extensions.Threading.csproj b/src/Cuemon.Extensions.Threading/Cuemon.Extensions.Threading.csproj
index c0dc2ac85..772b88e60 100644
--- a/src/Cuemon.Extensions.Threading/Cuemon.Extensions.Threading.csproj
+++ b/src/Cuemon.Extensions.Threading/Cuemon.Extensions.Threading.csproj
@@ -1,32 +1,15 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
180bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon
Cuemon.Extensions.Threading
Cuemon.Extensions.Threading
- The Cuemon.Extensions.Threading assembly provides enhancements to the System.Threading namespace as well as extensions methods for XML scenarios such as escaping, conversions, parsing, serialization and deserialization.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ The Cuemon.Extensions.Threading namespace contains extension methods that complements the System.Threading namespace.
+ extension-methods extensions continue-with-captured-context continue-with-suppressed-context
diff --git a/src/Cuemon.Extensions.Threading/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Threading/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..910f8c3a0
--- /dev/null
+++ b/src/Cuemon.Extensions.Threading/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,6 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# New Features
+- ADDED TaskExtensions class in the Cuemon.Extensions.Threading.Tasks namespace that consist of extension methods for the Task class: ContinueWithCapturedContext, ContinueWithCapturedContext{TResult}, ContinueWithSuppressedContext, ContinueWithSuppressedContext{TResult}
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Threading/Tasks/TaskExtensions.cs b/src/Cuemon.Extensions.Threading/Tasks/TaskExtensions.cs
index a7a9d6e04..e9d6d57e2 100644
--- a/src/Cuemon.Extensions.Threading/Tasks/TaskExtensions.cs
+++ b/src/Cuemon.Extensions.Threading/Tasks/TaskExtensions.cs
@@ -4,7 +4,7 @@
namespace Cuemon.Extensions.Threading.Tasks
{
///
- /// Extension methods for the .
+ /// Extension methods for the class.
///
public static class TaskExtensions
{
diff --git a/src/Cuemon.Extensions.Xml/Cuemon.Extensions.Xml.csproj b/src/Cuemon.Extensions.Xml/Cuemon.Extensions.Xml.csproj
index bea42dad1..953ccd66b 100644
--- a/src/Cuemon.Extensions.Xml/Cuemon.Extensions.Xml.csproj
+++ b/src/Cuemon.Extensions.Xml/Cuemon.Extensions.Xml.csproj
@@ -1,35 +1,19 @@
- netstandard2.0
- true
- ..\cuemon.snk
- true
+ net5.0;netstandard2.0
0c0bdf91-e7c7-4cb4-a39d-e1a5374c5602
- Cuemon
Cuemon.Extensions.Xml
Cuemon.Extensions.Xml
- The Cuemon.Extensions.Xml assembly provides several extension methods for XML scenarios such as escaping, conversions, parsing, sanitizing, serialization and deserialization.
- Geekle
- Michael Mortensen
- Copyright © Geekle 2009-2020. All rights reserved.
- 6.0.2020.25
- 6.0.2020.25
- 6.0.2020.0
- Michael Mortensen
- en-US
-
-
-
- https://nblcdn.net/themes/cuemon.net/img/core/128x128x.png
- https://www.cuemon.net/
- https://opensource.org/licenses/MIT
+ The Cuemon.Extensions.Xml namespace contains extension methods that complements the Cuemon.Xml namespace while being an addition to the System.Xml namespace.
+ extension-methods extensions to-xml-reader copy-xml-stream try-detect-xml-encoding chunk to-stream write-object is-xml-string try-parse-xelement
+
diff --git a/src/Cuemon.Extensions.Xml/Properties/PackageReleaseNotes.txt b/src/Cuemon.Extensions.Xml/Properties/PackageReleaseNotes.txt
new file mode 100644
index 000000000..19c144274
--- /dev/null
+++ b/src/Cuemon.Extensions.Xml/Properties/PackageReleaseNotes.txt
@@ -0,0 +1,17 @@
+Version: 6.0.0
+Availability: NET Standard 2.0, NET 5.0
+
+# Breaking Changes
+- RENAMED Copy --> ToStream on the XmlReaderExtensions class in the Cuemon.Xml namespace (also removed generic type parameters)
+
+# New Features
+- ADDED XmlConverterExtensions class in the Cuemon.Extensions.Xml.Serialization.Converters namespace that consist of extension methods for the IList{XmlConverter} interface: FirstOrDefaultReaderConverter, FirstOrDefaultWriterConverter, AddXmlConverter, InsertXmlConverter, AddEnumerableConverter, AddExceptionDescriptorConverter, AddUriConverter, AddDateTimeConverter, AddTimeSpanConverter, AddStringConverter, AddExceptionConverter
+- ADDED ExceptionDescriptorExtensions class in the Cuemon.Extensions.Xml.Serialization.Diagnostics namespace that consist of extension methods for the ExceptionDescriptor class: ToInsightsXmlString
+- ADDED XmlSerializerOptionsExtensions class in the Cuemon.Extensions.Xml.Serialization namespace that consist of extension methods for the XmlSerializerOptions class: ApplyToDefaultSettings
+- ADDED ByteArrayExtensions class in the Cuemon.Extensions.Xml namespace that consist of extension methods for the byte[] struct: ToXmlReader
+- ADDED HierarchyExtensions class in the Cuemon.Extensions.Xml namespace that consist of extension methods for the IHierarchy{T} interface: IsNodeEnumerable, GetXmlRootOrElement, OrderByXmlAttributes
+- ADDED StreamExtensions class in the Cuemon.Extensions.Xml namespace that consist of extension methods for the Stream class: ToXmlReader, CopyXmlStream, TryDetectXmlEncoding
+- ADDED UriExtensions class in the Cuemon.Extensions.Xml namespace that consist of extension methods for the Uri class: ToXmlReader
+- ADDED XmlReaderExtensions class in the Cuemon.Extensions.Xml namespace that consist of extension methods for the XmlReader class: ToHierarchy, MoveToFirstElement
+- ADDED XmlWriterExtensions class in the Cuemon.Extensions.Xml namespace that consist of extension methods for the XmlWriter class: WriteObject, WriteObject{T}, WriteStartElement, WriteEncapsulatingElementWhenNotNull{T}, WriteXmlRootElement{T}
+
\ No newline at end of file
diff --git a/src/Cuemon.Extensions.Xml/StreamExtensions.cs b/src/Cuemon.Extensions.Xml/StreamExtensions.cs
index 34a711189..99393e9e2 100644
--- a/src/Cuemon.Extensions.Xml/StreamExtensions.cs
+++ b/src/Cuemon.Extensions.Xml/StreamExtensions.cs
@@ -51,7 +51,7 @@ public static Stream CopyXmlStream(this Stream value, Action
}
var options = Patterns.Configure(setup);
- return Disposable.SafeInvoke(() => new MemoryStream(), ms =>
+ return Patterns.SafeInvoke(() => new MemoryStream(), ms =>
{
var document = new XmlDocument();
document.Load(value);
@@ -94,7 +94,7 @@ public static Stream RemoveXmlNamespaceDeclarations(this Stream value, Action new MemoryStream(), ms =>
+ return Patterns.SafeInvoke(() => new MemoryStream(), ms =>
{
using (var writer = XmlWriter.Create(ms, options))
{
diff --git a/src/Cuemon.Extensions.Xml/StringExtensions.cs b/src/Cuemon.Extensions.Xml/StringExtensions.cs
index 0ff3aa3be..2cea96ee2 100644
--- a/src/Cuemon.Extensions.Xml/StringExtensions.cs
+++ b/src/Cuemon.Extensions.Xml/StringExtensions.cs
@@ -8,8 +8,6 @@ namespace Cuemon.Extensions.Xml
///
public static class StringExtensions
{
- private static readonly string[][] EscapeStringPairs = new[] { new[] { "<", ">", """, "'", "&" }, new[] {"<", ">", "\"", "'", "&"} };
-
///
/// Escapes the given XML .
///
diff --git a/src/Cuemon.Xml/XmlCopyOptions.cs b/src/Cuemon.Extensions.Xml/XmlCopyOptions.cs
similarity index 95%
rename from src/Cuemon.Xml/XmlCopyOptions.cs
rename to src/Cuemon.Extensions.Xml/XmlCopyOptions.cs
index 27fbcf933..135a37593 100644
--- a/src/Cuemon.Xml/XmlCopyOptions.cs
+++ b/src/Cuemon.Extensions.Xml/XmlCopyOptions.cs
@@ -1,7 +1,7 @@
using System;
using System.Xml;
-namespace Cuemon.Xml
+namespace Cuemon.Extensions.Xml
{
///
/// Configuration options for .
diff --git a/src/Cuemon.Extensions.Xml/XmlWriterExtensions.cs b/src/Cuemon.Extensions.Xml/XmlWriterExtensions.cs
index dca6cafa8..589575f0c 100644
--- a/src/Cuemon.Extensions.Xml/XmlWriterExtensions.cs
+++ b/src/Cuemon.Extensions.Xml/XmlWriterExtensions.cs
@@ -2,6 +2,7 @@
using System.Xml;
using Cuemon.Xml;
using Cuemon.Xml.Serialization;
+using Cuemon.Xml.Serialization.Formatters;
namespace Cuemon.Extensions.Xml
{
@@ -16,11 +17,11 @@ public static class XmlWriterExtensions
/// The type of the object to serialize.
/// The to extend.
/// The object to serialize.
- /// The which need to be configured.
+ /// The which may be configured.
///
/// cannot be null.
///
- public static void WriteObject(this XmlWriter writer, T value, Action setup = null)
+ public static void WriteObject(this XmlWriter writer, T value, Action setup = null)
{
WriteObject(writer, value, typeof(T), setup);
}
@@ -31,11 +32,11 @@ public static void WriteObject(this XmlWriter writer, T value, ActionThe