diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml
index cb3f7443..23e7af1b 100644
--- a/.github/workflows/ci-pipeline.yml
+++ b/.github/workflows/ci-pipeline.yml
@@ -12,6 +12,10 @@ on:
options:
- Debug
- Release
+ run_mac_tests:
+ type: boolean
+ description: Run the macOS test matrix despite the additional cost and runtime.
+ default: false
permissions:
contents: read
@@ -22,6 +26,7 @@ jobs:
runs-on: ubuntu-24.04
outputs:
run-privileged-jobs: ${{ steps.vars.outputs.run-privileged-jobs }}
+ run-mac-tests: ${{ steps.vars.outputs.run-mac-tests }}
strong-name-key-filename: ${{ steps.vars.outputs.strong-name-key-filename }}
build-switches: ${{ steps.vars.outputs.build-switches }}
steps:
@@ -29,6 +34,12 @@ jobs:
name: calculate workflow variables
shell: bash
run: |
+ if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.run_mac_tests }}" == "true" ]]; then
+ echo "run-mac-tests=true" >> "$GITHUB_OUTPUT"
+ else
+ echo "run-mac-tests=false" >> "$GITHUB_OUTPUT"
+ fi
+
if [[ "${{ github.event_name }}" == "pull_request" && "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]]; then
echo "run-privileged-jobs=false" >> "$GITHUB_OUTPUT"
echo "strong-name-key-filename=" >> "$GITHUB_OUTPUT"
@@ -130,6 +141,26 @@ jobs:
restore: true # apparently we need to restore for .net48
download-pattern: build-${{ matrix.configuration }}-${{ matrix.arch }}
+ test_mac:
+ if: ${{ needs.init.outputs.run-mac-tests == 'true' }}
+ name: call-test-mac
+ needs: [init, build, prepare_test]
+ strategy:
+ fail-fast: false
+ matrix:
+ arch: [X64, ARM64]
+ configuration: [Debug, Release]
+ project: ${{ fromJson(needs.prepare_test.outputs.json) }}
+ uses: codebeltnet/jobs-dotnet-test/.github/workflows/default.yml@v3
+ with:
+ runs-on: ${{ matrix.arch == 'ARM64' && 'macos-26' || 'macos-26-intel' }}
+ configuration: ${{ matrix.configuration }}
+ build-switches: -p:SkipSignAssembly=true
+ projects: ${{ matrix.project }}
+ build: true # we need to build due to xUnitv3
+ restore: true # we need to restore since we disabled caching
+ download-pattern: build-${{ matrix.configuration }}-${{ matrix.arch }}
+
integration_test:
if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }}
name: ⚗️ Integration Test
@@ -160,7 +191,7 @@ jobs:
SA_PASSWORD: ${{ secrets.SA_PASSWORD }}
- name: Download Build Artifacts
- uses: actions/download-artifact@v4
+ uses: actions/download-artifact@v8
with:
pattern: build-${{ matrix.configuration }}-X64
merge-multiple: true
@@ -270,10 +301,57 @@ jobs:
with:
command: down
+ test_qualitygate:
+ if: ${{ always() }}
+ name: test-qualitygate
+ needs: [init, test_linux, test_windows, test_mac, integration_test]
+ runs-on: ubuntu-24.04
+ steps:
+ - name: Evaluate test results
+ shell: bash
+ env:
+ RUN_MAC_TESTS: ${{ needs.init.outputs.run-mac-tests }}
+ RUN_PRIVILEGED_JOBS: ${{ needs.init.outputs.run-privileged-jobs }}
+ TEST_LINUX_RESULT: ${{ needs.test_linux.result }}
+ TEST_WINDOWS_RESULT: ${{ needs.test_windows.result }}
+ TEST_MAC_RESULT: ${{ needs.test_mac.result }}
+ INTEGRATION_TEST_RESULT: ${{ needs.integration_test.result }}
+ run: |
+ require_success() {
+ local job_name="$1"
+ local job_result="$2"
+
+ if [[ "$job_result" != "success" ]]; then
+ echo "::error::$job_name finished with '$job_result'."
+ exit 1
+ fi
+ }
+
+ require_success_or_skip() {
+ local job_name="$1"
+ local job_enabled="$2"
+ local job_result="$3"
+
+ if [[ "$job_enabled" == "true" ]]; then
+ require_success "$job_name" "$job_result"
+ return
+ fi
+
+ if [[ "$job_result" != "success" && "$job_result" != "skipped" ]]; then
+ echo "::error::$job_name finished with '$job_result' while disabled."
+ exit 1
+ fi
+ }
+
+ require_success "test_linux" "$TEST_LINUX_RESULT"
+ require_success "test_windows" "$TEST_WINDOWS_RESULT"
+ require_success_or_skip "test_mac" "$RUN_MAC_TESTS" "$TEST_MAC_RESULT"
+ require_success_or_skip "integration_test" "$RUN_PRIVILEGED_JOBS" "$INTEGRATION_TEST_RESULT"
+
sonarcloud:
- if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }}
+ if: ${{always() && needs.init.outputs.run-privileged-jobs == 'true' && needs.build.result == 'success' && needs.test_qualitygate.result == 'success'}}
name: call-sonarcloud
- needs: [init, build, test_linux, test_windows, integration_test]
+ needs: [init, build, test_qualitygate]
uses: codebeltnet/jobs-sonarcloud/.github/workflows/default.yml@v3
with:
organization: geekle
@@ -283,9 +361,9 @@ jobs:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
codecov:
- if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }}
+ if: ${{always() && needs.init.outputs.run-privileged-jobs == 'true' && needs.build.result == 'success' && needs.test_qualitygate.result == 'success'}}
name: call-codecov
- needs: [init, build, test_linux, test_windows, integration_test]
+ needs: [init, build, test_qualitygate]
uses: codebeltnet/jobs-codecov/.github/workflows/default.yml@v1
with:
repository: codebeltnet/cuemon
@@ -293,9 +371,9 @@ jobs:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
codeql:
- if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }}
+ if: ${{always() && needs.init.outputs.run-privileged-jobs == 'true' && needs.build.result == 'success' && needs.test_qualitygate.result == 'success'}}
name: call-codeql
- needs: [init, build, test_linux, test_windows, integration_test]
+ needs: [init, build, test_qualitygate]
uses: codebeltnet/jobs-codeql/.github/workflows/default.yml@v3
with:
timeout-minutes: 30
@@ -305,7 +383,7 @@ jobs:
deploy:
if: github.event_name != 'pull_request'
name: call-nuget
- needs: [build, pack, test_linux, test_windows, integration_test, sonarcloud, codecov, codeql]
+ needs: [build, pack, test_qualitygate, sonarcloud, codecov, codeql]
uses: codebeltnet/jobs-nuget-push/.github/workflows/default.yml@v3
with:
version: ${{ needs.build.outputs.version }}
diff --git a/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt
index 5745ea04..759a60fb 100644
--- a/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.AspNetCore.App/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt
index bbfb4b3d..b112e066 100644
--- a/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.AspNetCore.Authentication/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt
index b4f63733..9aebd5d2 100644
--- a/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.AspNetCore.Mvc/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt
index 5745ea04..759a60fb 100644
--- a/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.AspNetCore.Razor.TagHelpers/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt b/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt
index ec9b9f66..789d4b29 100644
--- a/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.AspNetCore/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# Bug Fixes
+- FIXED UseFaultDescriptorExceptionHandler() middleware to work correctly when request services are wrapped by external decorators or proxies
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt b/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt
index d9dd8378..629017c9 100644
--- a/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Core.App/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Core/PackageReleaseNotes.txt b/.nuget/Cuemon.Core/PackageReleaseNotes.txt
index 32c668d3..5ce59bee 100644
--- a/.nuget/Cuemon.Core/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Core/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt b/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Data.Integrity/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt b/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt
index 57f14f45..9085517d 100644
--- a/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Data.SqlClient/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Data/PackageReleaseNotes.txt b/.nuget/Cuemon.Data/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Data/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Data/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt b/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Diagnostics/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt
index 5745ea04..759a60fb 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Authentication/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt
index 5c0b0a77..4db5cdcb 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Text.Json/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt
index 2ae4eb6b..2ffdd27d 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.Formatters.Xml/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt
index 5745ea04..759a60fb 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc.RazorPages/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt
index dacdccee..05be843e 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Mvc/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt
index e31138e9..40cfb512 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Text.Json/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt
index b49caa7b..fac0d15a 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore.Xml/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt
index 53fb05cc..d32dd4e5 100644
--- a/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.AspNetCore/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10 and .NET 9
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10 and .NET 9
diff --git a/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt
index bea68480..bb342731 100644
--- a/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Collections.Generic/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Collections.Specialized/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt
index 1e5951b8..f9c45f19 100644
--- a/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Core/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Data.Integrity/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Data/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt
index 6efb784a..0880fcc5 100644
--- a/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.DependencyInjection/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# Bug Fixes
+- FIXED ServiceProviderExtensions.GetServiceDescriptors() method to properly traverse and handle wrapped service providers with cycle detection; now correctly resolves descriptors when the provider is wrapped by third-party components
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt
index bf40a7c9..cb1bbc17 100644
--- a/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Diagnostics/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt
index b726b190..aca719d1 100644
--- a/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Hosting/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt
index 0e64a85f..52515e9c 100644
--- a/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.IO/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9, .NET Standard 2.1 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9, .NET Standard 2.1 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Net/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Reflection/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Runtime.Caching/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt
index 2a349e29..1953fe47 100644
--- a/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Text.Json/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Text/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt
index afc6b75e..401aa546 100644
--- a/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Threading/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt
index 779c77e2..a4073e5f 100644
--- a/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Extensions.Xml/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.IO/PackageReleaseNotes.txt b/.nuget/Cuemon.IO/PackageReleaseNotes.txt
index 6fcdcded..875ea217 100644
--- a/.nuget/Cuemon.IO/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.IO/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Kernel/PackageReleaseNotes.txt b/.nuget/Cuemon.Kernel/PackageReleaseNotes.txt
index 26655f98..a47d657d 100644
--- a/.nuget/Cuemon.Kernel/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Kernel/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Net/PackageReleaseNotes.txt b/.nuget/Cuemon.Net/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Net/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Net/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt b/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Resilience/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt b/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt
index 923340bc..7b8b9343 100644
--- a/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Runtime.Caching/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt b/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt
index 8da7ce05..8f4574dd 100644
--- a/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Security.Cryptography/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Threading/PackageReleaseNotes.txt b/.nuget/Cuemon.Threading/PackageReleaseNotes.txt
index 46bd63f0..e17e8a95 100644
--- a/.nuget/Cuemon.Threading/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Threading/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/.nuget/Cuemon.Xml/PackageReleaseNotes.txt b/.nuget/Cuemon.Xml/PackageReleaseNotes.txt
index 98c512f3..7d819bda 100644
--- a/.nuget/Cuemon.Xml/PackageReleaseNotes.txt
+++ b/.nuget/Cuemon.Xml/PackageReleaseNotes.txt
@@ -1,3 +1,9 @@
+Version: 10.5.3
+Availability: .NET 10, .NET 9 and .NET Standard 2.0
+
+# ALM
+- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)
+
Version: 10.5.2
Availability: .NET 10, .NET 9 and .NET Standard 2.0
diff --git a/CHANGELOG.md b/CHANGELOG.md
index facbca56..70dfc9ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
For more details, please refer to `PackageReleaseNotes.txt` on a per assembly basis in the `.nuget` folder.
+## [10.5.3] - 2026-06-03
+
+This is a patch release focused on fixing request service provider resolution for wrapped providers and improving test coverage for dependency injection scenarios.
+
+### Fixed
+
+- `ServiceProviderExtensions.GetServiceDescriptors()` method to properly traverse and handle wrapped service providers, including detection and rejection of cyclic provider graphs; the method now correctly resolves descriptors when the provider is wrapped by third-party components such as AspVersioning's InjectApiVersion and throws `NotSupportedException` with descriptive messages when ambiguous or cyclic provider structures are encountered,
+- `UseFaultDescriptorExceptionHandler()` middleware to work correctly when request services are wrapped by external decorators or proxies.
+
+### Added
+
+- `ServiceProviderExtensionsTest` unit test class with comprehensive test coverage for `GetServiceDescriptors()` method, including scenarios for delegating providers, ambiguous multi-provider cases, and cyclic provider graph detection,
+- Functional test in `ApplicationBuilderExtensionsTest` to verify fault descriptor exception handling works correctly with wrapped request services.
+
## [10.5.2] - 2026-05-18
This is a service update that focuses on package dependencies.
@@ -1749,6 +1763,7 @@ This release was primarily focused on adapting a more modern way of performing C
- XmlWriterUtility class from Cuemon.Xml namespace
- XmlWriterUtilityExtensions class from the Cuemon.Xml namespace
+[10.5.3]: https://github.com/codebeltnet/cuemon/compare/v10.5.2...v10.5.3
[10.5.2]: https://github.com/codebeltnet/cuemon/compare/v10.5.1...v10.5.2
[10.5.1]: https://github.com/codebeltnet/cuemon/compare/v10.5.0...v10.5.1
[10.5.0]: https://github.com/codebeltnet/cuemon/compare/v10.4.0...v10.5.0
diff --git a/src/Cuemon.Extensions.DependencyInjection/ServiceProviderExtensions.cs b/src/Cuemon.Extensions.DependencyInjection/ServiceProviderExtensions.cs
index a9faf110..631ea73c 100644
--- a/src/Cuemon.Extensions.DependencyInjection/ServiceProviderExtensions.cs
+++ b/src/Cuemon.Extensions.DependencyInjection/ServiceProviderExtensions.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
@@ -15,23 +15,30 @@ public static class ServiceProviderExtensions
///
/// The to extend.
/// An enumeration of ALL instances from the specified .
- /// This method does not support {providerType.FullName}.
+ /// This method does not support {providerType.FullName}; or a cyclic provider graph was detected.
public static IEnumerable GetServiceDescriptors(this IServiceProvider provider)
{
Validator.ThrowIfNull(provider);
var providerType = provider.GetType();
+ var visitedProviders = new List { provider };
- if (TryLocateEmbeddedServiceProvider(provider, providerType, out var embeddedProvider))
+ while (true)
{
+ var callSiteFactory = Decorator.Enclose(providerType).GetAllProperties().SingleOrDefault(pi => pi.Name == "CallSiteFactory")?.GetValue(provider);
+ if (callSiteFactory != null)
+ {
+ var callSiteFactoryType = callSiteFactory.GetType();
+ return Decorator.Enclose(callSiteFactoryType).GetAllProperties().SingleOrDefault(pi => pi.Name == "Descriptors")?.GetValue(callSiteFactory) as IEnumerable;
+ }
+
+ if (!TryLocateEmbeddedServiceProvider(provider, providerType, out var embeddedProvider)) { break; }
+ if (visitedProviders.Any(visitedProvider => ReferenceEquals(visitedProvider, embeddedProvider.ServiceProvider)))
+ {
+ throw new NotSupportedException($"A cyclic IServiceProvider graph was detected between {providerType.FullName} and {embeddedProvider.ProviderType.FullName}.");
+ }
provider = embeddedProvider.ServiceProvider;
providerType = embeddedProvider.ProviderType;
- }
-
- var callSiteFactory = Decorator.Enclose(providerType).GetAllProperties().SingleOrDefault(pi => pi.Name == "CallSiteFactory")?.GetValue(provider);
- if (callSiteFactory != null)
- {
- var callSiteFactoryType = callSiteFactory.GetType();
- return Decorator.Enclose(callSiteFactoryType).GetAllProperties().SingleOrDefault(pi => pi.Name == "Descriptors")?.GetValue(callSiteFactory) as IEnumerable;
+ visitedProviders.Add(provider);
}
throw new NotSupportedException($"This method does not support {providerType.FullName}.");
@@ -39,10 +46,33 @@ public static IEnumerable GetServiceDescriptors(this IService
private static bool TryLocateEmbeddedServiceProvider(IServiceProvider originatingProvider, Type originatingProviderType, out (IServiceProvider ServiceProvider, Type ProviderType) embeddedProvider)
{
- if (originatingProviderType.Name == "ServiceProviderEngineScope" &&
- Decorator.Enclose(originatingProviderType).GetAllProperties().SingleOrDefault(pi => pi.Name == "RootProvider")?.GetValue(originatingProvider) is IServiceProvider rootProvider)
+ var nestedProviders = Decorator.Enclose(originatingProviderType).GetAllFields()
+ .Where(fi => !fi.IsStatic && typeof(IServiceProvider).IsAssignableFrom(fi.FieldType))
+ .Select(fi => new { fi.Name, Provider = fi.GetValue(originatingProvider) as IServiceProvider })
+ .Where(candidate => candidate.Provider != null && !ReferenceEquals(candidate.Provider, originatingProvider))
+ .ToList();
+
+ if (originatingProviderType.Name == "ServiceProviderEngineScope")
+ {
+ var rootProvider = Decorator.Enclose(originatingProviderType).GetAllProperties().SingleOrDefault(pi => pi.Name == "RootProvider")?.GetValue(originatingProvider) as IServiceProvider;
+ rootProvider ??= nestedProviders.SingleOrDefault(candidate => candidate.Name.IndexOf("RootProvider", StringComparison.OrdinalIgnoreCase) >= 0)?.Provider;
+ rootProvider ??= nestedProviders.Count == 1 ? nestedProviders[0].Provider : null;
+
+ if (rootProvider != null)
+ {
+ embeddedProvider = new ValueTuple(rootProvider, rootProvider.GetType());
+ return true;
+ }
+ }
+
+ var providers = nestedProviders.Select(candidate => candidate.Provider)
+ .Distinct()
+ .ToList();
+
+ if (providers.Count == 1)
{
- embeddedProvider = new ValueTuple(rootProvider, rootProvider.GetType());
+ var nestedProvider = providers[0];
+ embeddedProvider = new ValueTuple(nestedProvider, nestedProvider.GetType());
return true;
}
embeddedProvider = default;
diff --git a/test/Cuemon.AspNetCore.FunctionalTests/Diagnostics/ApplicationBuilderExtensionsTest.cs b/test/Cuemon.AspNetCore.FunctionalTests/Diagnostics/ApplicationBuilderExtensionsTest.cs
index 404b8088..8c16ed24 100644
--- a/test/Cuemon.AspNetCore.FunctionalTests/Diagnostics/ApplicationBuilderExtensionsTest.cs
+++ b/test/Cuemon.AspNetCore.FunctionalTests/Diagnostics/ApplicationBuilderExtensionsTest.cs
@@ -20,6 +20,41 @@ public ApplicationBuilderExtensionsTest(ITestOutputHelper output) : base(output)
{
}
+ [Fact]
+ public async Task UseFaultDescriptorExceptionHandler_ShouldCaptureException_WhenRequestServicesIsWrappedByAspVersioningInjectApiVersion()
+ {
+ using var response = await WebHostTestFactory.RunAsync(
+ services =>
+ {
+ services.AddFaultDescriptorOptions(o => o.FaultDescriptor = PreferredFaultDescriptor.ProblemDetails);
+ services.AddJsonExceptionResponseFormatter();
+ },
+ app =>
+ {
+ app.UseFaultDescriptorExceptionHandler();
+ app.Use((Func, Task>)((context, _) =>
+ {
+ context.RequestServices = new Asp.Versioning.Builder.EndpointBuilderFinalizer.InjectApiVersion(context.RequestServices);
+ throw new NotFoundException();
+ }));
+ },
+ responseFactory: client =>
+ {
+ client.DefaultRequestHeaders.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
+ return client.GetAsync("/");
+ });
+
+ var body = await response.Content.ReadAsStringAsync();
+
+ TestOutput.WriteLine(body);
+
+ Assert.Equal(404, (int)response.StatusCode);
+ Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType);
+ Assert.EndsWith("Asp.Versioning.Builder.EndpointBuilderFinalizer+InjectApiVersion", typeof(Asp.Versioning.Builder.EndpointBuilderFinalizer.InjectApiVersion).FullName, StringComparison.Ordinal);
+ Assert.Contains("\"title\": \"NotFound\"", body, StringComparison.Ordinal);
+ Assert.Contains("\"status\": 404", body, StringComparison.Ordinal);
+ }
+
[Theory]
[InlineData(FaultSensitivityDetails.All)]
[InlineData(FaultSensitivityDetails.Evidence)]
@@ -737,3 +772,24 @@ public async Task UseFaultDescriptorExceptionHandler_ShouldCaptureException_Rend
}
}
}
+
+namespace Asp.Versioning.Builder
+{
+ internal static class EndpointBuilderFinalizer
+ {
+ internal sealed class InjectApiVersion : IServiceProvider
+ {
+ private readonly IServiceProvider _serviceProvider;
+
+ public InjectApiVersion(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ }
+
+ public object GetService(Type serviceType)
+ {
+ return _serviceProvider.GetService(serviceType);
+ }
+ }
+ }
+}
diff --git a/test/Cuemon.Extensions.DependencyInjection.Tests/ServiceProviderExtensionsTest.cs b/test/Cuemon.Extensions.DependencyInjection.Tests/ServiceProviderExtensionsTest.cs
new file mode 100644
index 00000000..e3ae7c77
--- /dev/null
+++ b/test/Cuemon.Extensions.DependencyInjection.Tests/ServiceProviderExtensionsTest.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Linq;
+using Codebelt.Extensions.Xunit;
+using Microsoft.Extensions.DependencyInjection;
+using Xunit;
+
+namespace Cuemon.Extensions.DependencyInjection
+{
+ public class ServiceProviderExtensionsTest : Test
+ {
+ public ServiceProviderExtensionsTest(ITestOutputHelper output) : base(output)
+ {
+ }
+
+ [Fact]
+ public void GetServiceDescriptors_ShouldGetDescriptors_WhenProviderWrapsServiceProvider()
+ {
+ var services = new ServiceCollection();
+ services.AddSingleton(new object());
+
+ var serviceProvider = services.BuildServiceProvider();
+ var wrappedProvider = new DelegatingServiceProvider(serviceProvider);
+
+ var descriptors = wrappedProvider.GetServiceDescriptors().ToList();
+
+ Assert.Contains(descriptors, descriptor => descriptor.ServiceType == typeof(object));
+ }
+
+ [Fact]
+ public void GetServiceDescriptors_ShouldGetDescriptors_WhenProviderIsWrappedByAspVersioningInjectApiVersion()
+ {
+ var services = new ServiceCollection();
+ services.AddSingleton(new object());
+
+ var serviceProvider = services.BuildServiceProvider();
+ var wrappedProvider = new Asp.Versioning.Builder.EndpointBuilderFinalizer.InjectApiVersion(serviceProvider);
+
+ var descriptors = wrappedProvider.GetServiceDescriptors().ToList();
+
+ Assert.EndsWith("Asp.Versioning.Builder.EndpointBuilderFinalizer+InjectApiVersion", wrappedProvider.GetType().FullName, StringComparison.Ordinal);
+ Assert.Contains(descriptors, descriptor => descriptor.ServiceType == typeof(object));
+ }
+
+ [Fact]
+ public void GetServiceDescriptors_ShouldThrowNotSupportedExceptionWithUnsupportedProviderMessage_WhenProviderWrapsMultipleServiceProviders()
+ {
+ var services = new ServiceCollection();
+ var primaryProvider = services.BuildServiceProvider();
+ var secondaryProvider = services.BuildServiceProvider();
+ var wrappedProvider = new AmbiguousDelegatingServiceProvider(primaryProvider, secondaryProvider);
+
+ var exception = Assert.Throws(() => wrappedProvider.GetServiceDescriptors().ToList());
+
+ Assert.Contains("This method does not support", exception.Message, StringComparison.Ordinal);
+ Assert.Contains(typeof(AmbiguousDelegatingServiceProvider).FullName, exception.Message, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void GetServiceDescriptors_ShouldThrowNotSupportedExceptionWithCycleMessage_WhenProviderGraphIsCyclic()
+ {
+ var primaryProvider = new CyclicDelegatingServiceProvider();
+ var secondaryProvider = new CyclicDelegatingServiceProvider();
+ primaryProvider.Provider = secondaryProvider;
+ secondaryProvider.Provider = primaryProvider;
+
+ var exception = Assert.Throws(() => primaryProvider.GetServiceDescriptors().ToList());
+
+ Assert.Contains("cyclic IServiceProvider graph", exception.Message, StringComparison.Ordinal);
+ }
+
+ private sealed class DelegatingServiceProvider : IServiceProvider
+ {
+ private readonly IServiceProvider _provider;
+
+ public DelegatingServiceProvider(IServiceProvider provider)
+ {
+ _provider = provider;
+ }
+
+ public object GetService(Type serviceType)
+ {
+ return _provider.GetService(serviceType);
+ }
+ }
+
+ private sealed class CyclicDelegatingServiceProvider : IServiceProvider
+ {
+ public IServiceProvider Provider { get; set; }
+
+ public object GetService(Type serviceType)
+ {
+ return Provider.GetService(serviceType);
+ }
+ }
+
+ private sealed class AmbiguousDelegatingServiceProvider : IServiceProvider
+ {
+ private readonly IServiceProvider _primaryProvider;
+ private readonly IServiceProvider _secondaryProvider;
+
+ public AmbiguousDelegatingServiceProvider(IServiceProvider primaryProvider, IServiceProvider secondaryProvider)
+ {
+ _primaryProvider = primaryProvider;
+ _secondaryProvider = secondaryProvider;
+ }
+
+ public object GetService(Type serviceType)
+ {
+ return _primaryProvider.GetService(serviceType) ?? _secondaryProvider.GetService(serviceType);
+ }
+ }
+ }
+}
+
+namespace Asp.Versioning.Builder
+{
+ internal static class EndpointBuilderFinalizer
+ {
+ internal sealed class InjectApiVersion : IServiceProvider
+ {
+ private readonly IServiceProvider _serviceProvider;
+
+ public InjectApiVersion(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ }
+
+ public object GetService(Type serviceType)
+ {
+ return _serviceProvider.GetService(serviceType);
+ }
+ }
+ }
+}