From a087b23684791d485dd2b1b3354dbac6fac7c837 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Wed, 14 Oct 2026 21:00:10 +0000 Subject: [PATCH 01/19] Backflow from https://github.com/dotnet/dotnet / e1fc22d build 336654 Diff: https://github.com/dotnet/dotnet/compare/5b93e007dff3d0d88a73a74198c23bda4e8d3a12..e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 From: https://github.com/dotnet/dotnet/commit/5b93e007dff3d0d88a73a74198c23bda4e8d3a12 To: https://github.com/dotnet/dotnet/commit/e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 [[ commit created by automation ]] --- .../fixtures/presentation/incomplete-query.expected.txt | 1 - .../presentation/published-34643961191.expected.txt | 1 - eng/Versions.props | 5 ++--- eng/build.ps1 | 8 +------- package-lock.json | 8 ++++---- src/Components/Web.JS/JSInterop/package.json | 2 +- .../clients/ts/signalr-protocol-msgpack/package.json | 4 ++-- src/SignalR/clients/ts/signalr/package.json | 2 +- 8 files changed, 11 insertions(+), 20 deletions(-) diff --git a/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/incomplete-query.expected.txt b/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/incomplete-query.expected.txt index d69421b4fbc0..af9d7c86ebfc 100644 --- a/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/incomplete-query.expected.txt +++ b/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/incomplete-query.expected.txt @@ -56,7 +56,6 @@ Repository: `dotnet/aspnetcore`; run ID: `34643961191`; attempt: `1`. JSON SHA-256: `0f954e9a74942427466297df78038c30c5ea67d53782832daf091793b3fb0752`. -
Snapshot JSON (exact sanitized bytes) diff --git a/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/published-34643961191.expected.txt b/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/published-34643961191.expected.txt index cd8e12dc47fe..4b8cde7b976e 100644 --- a/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/published-34643961191.expected.txt +++ b/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/published-34643961191.expected.txt @@ -107,7 +107,6 @@ Repository: `dotnet/aspnetcore`; run ID: `34643961191`; attempt: `1`. JSON SHA-256: `d69fdb0a40ba4c80a7515044b256fbe9b7fe22bd2fb2890cb4bd8b0f6b4a6f3b`.
-
Snapshot JSON (exact sanitized bytes) diff --git a/eng/Versions.props b/eng/Versions.props index a2fe411a5314..796953cd79fc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -68,9 +68,8 @@ true false - - true - true + + $(DefaultNetCoreTargetFramework) - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 5.11.0-1.26420.103 5.11.0-1.26420.103 5.11.0-1.26420.103 5.11.0-1.26420.103 - 12.0.0-beta.26473.114 - 12.0.0-beta.26473.114 - 12.0.0-beta.26473.114 - 12.0.0-beta.26473.114 - 12.0.0-beta.26473.114 - 12.0.0-beta.26473.114 - 12.0.0-beta.26473.114 - 12.0.0-beta.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 8.0.0-rc.47514 - 8.0.0-rc.47514 - 8.0.0-rc.47514 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 - 12.0.0-alpha.1.26473.114 + 12.0.0-beta.26513.123 + 12.0.0-beta.26513.123 + 12.0.0-beta.26513.123 + 12.0.0-beta.26513.123 + 12.0.0-beta.26513.123 + 12.0.0-beta.26513.123 + 12.0.0-beta.26513.123 + 12.0.0-beta.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 8.1.0-rc.51423 + 8.1.0-rc.51423 + 8.1.0-rc.51423 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26513.123 10.10.1 10.10.1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c5cff3819eac..65e799a62189 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -8,333 +8,333 @@ See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md for instructions on using darc. --> - + - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 @@ -355,48 +355,48 @@ 1d599674e31ad86ca9e6e1dad7055b531e4d58e4 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 https://github.com/dotnet/extensions @@ -456,17 +456,17 @@ https://github.com/dotnet/msbuild d1cce8d7cc03c23a4f1bad8e9240714fd9d199a3 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 - + https://github.com/dotnet/dotnet - c567e8ff13b8ada7c5285c60bc2ac1111ae602e7 + e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 diff --git a/eng/common/build.ps1 b/eng/common/build.ps1 index 305132a6d6dd..64c5ed10263f 100644 --- a/eng/common/build.ps1 +++ b/eng/common/build.ps1 @@ -181,10 +181,6 @@ try { if (-not $PSBoundParameters.ContainsKey('nodeReuse')) { $nodeReuse = $false } - # MSBuild's multi-threaded mode isn't run on CI unless it was explicitly requested via -msbuildMultiThreaded. - if (-not $PSBoundParameters.ContainsKey('msbuildMultiThreaded')) { - $msbuildMultiThreaded = $false - } } if (-not [string]::IsNullOrEmpty($binaryLogName)) { diff --git a/eng/common/core-templates/job/helix-job-monitor.yml b/eng/common/core-templates/job/helix-job-monitor.yml index 7417afdf3ea4..ef8ee08fbd22 100644 --- a/eng/common/core-templates/job/helix-job-monitor.yml +++ b/eng/common/core-templates/job/helix-job-monitor.yml @@ -63,7 +63,7 @@ parameters: type: boolean default: false -# Azure service connection ID authorized for Helix. Required when +# Workload identity federation service connection name authorized for Helix. Required when # useEntraAuthentication is true. - name: azureSubscription type: string @@ -94,13 +94,12 @@ parameters: type: boolean default: false -# When true, test results are reported to Azure DevOps using the fully qualified test name -# (Namespace.Type.Method) as the stable automatedTestName and the visible title is qualified as -# well (--use-fully-qualified-test-name). Opt-in because it changes AzDO test identity and display; -# primarily useful for frameworks like MSTest whose display name is only the method name. +# When true (the default), test results are reported to Azure DevOps using the fully qualified test +# name (Namespace.Type.Method) as the stable automatedTestName and the visible title is qualified as +# well (--use-fully-qualified-test-name). Set to false to preserve framework-provided display names. - name: useFullyQualifiedTestName type: boolean - default: false + default: true # Controls per-test output attachments. Defaults to Failed. - name: testResultAttachmentMode @@ -136,6 +135,20 @@ jobs: displayName: Monitor Helix Jobs timeoutInMinutes: ${{ parameters.timeoutInMinutes }} continueOnError: ${{ parameters.continueOnError }} + variables: + HELIX_MONITOR_BASE_URI: ${{ parameters.helixBaseUri }} + HELIX_MONITOR_USE_ENTRA_AUTHENTICATION: ${{ parameters.useEntraAuthentication }} + HELIX_MONITOR_POLLING_INTERVAL_SECONDS: ${{ parameters.pollingIntervalSeconds }} + HELIX_MONITOR_FAIL_ON_FAILED_TESTS: ${{ parameters.failWorkItemsWithFailedTests }} + HELIX_MONITOR_ALLOW_NO_HELIX_JOBS: ${{ parameters.allowNoHelixJobs }} + HELIX_MONITOR_USE_FULLY_QUALIFIED_TEST_NAME: ${{ parameters.useFullyQualifiedTestName }} + HELIX_MONITOR_TIMEOUT_IN_MINUTES: ${{ parameters.timeoutInMinutes }} + HELIX_MONITOR_TEST_RESULT_UPLOAD_PARALLELISM: ${{ parameters.testResultUploadParallelism }} + HELIX_MONITOR_ORGANIZATION: ${{ parameters.organization }} + HELIX_MONITOR_REPOSITORY: ${{ parameters.repository }} + HELIX_MONITOR_TEST_RESULT_ATTACHMENT_MODE: ${{ parameters.testResultAttachmentMode }} + HELIX_MONITOR_TOOL_NUPKG_ARTIFACT_NAME: ${{ parameters.toolNupkgArtifactName }} + HELIX_MONITOR_TOOL_COMMAND: ${{ parameters.toolCommand }} ${{ if ne(length(parameters.dependsOn), 0) }}: dependsOn: ${{ parameters.dependsOn }} ${{ if ne(parameters.condition, '') }}: @@ -157,22 +170,6 @@ jobs: - pwsh: throw "azureSubscription must be set when useEntraAuthentication is true." displayName: Validate Helix Entra authentication - - ${{ if eq(parameters.useEntraAuthentication, true) }}: - - task: AzureCLI@2 - displayName: Initialize Helix Entra authentication - inputs: - azureSubscription: ${{ parameters.azureSubscription }} - addSpnToEnvironment: true - scriptType: pscore - scriptLocation: inlineScript - inlineScript: | - if ([string]::IsNullOrWhiteSpace($env:servicePrincipalId) -or [string]::IsNullOrWhiteSpace($env:tenantId)) { - throw "The Helix Azure service connection did not provide a service principal or tenant ID." - } - - Write-Host "##vso[task.setvariable variable=HelixEntraClientId]$env:servicePrincipalId" - Write-Host "##vso[task.setvariable variable=HelixEntraTenantId]$env:tenantId" - - ${{ if ne(parameters.toolNupkgArtifactName, '') }}: - task: DownloadPipelineArtifact@2 displayName: Download Helix Job Monitor artifact @@ -241,76 +238,26 @@ jobs: - bash: ./eng/common/dotnet.sh tool restore displayName: Restore Helix Job Monitor - - bash: | - set -euo pipefail - - toolArgs=( - --helix-base-uri '${{ parameters.helixBaseUri }}' - --use-entra-authentication '${{ parameters.useEntraAuthentication }}' - --polling-interval-seconds '${{ parameters.pollingIntervalSeconds }}' - --fail-on-failed-tests '${{ parameters.failWorkItemsWithFailedTests }}' - --allow-no-helix-jobs '${{ parameters.allowNoHelixJobs }}' - --use-fully-qualified-test-name '${{ parameters.useFullyQualifiedTestName }}' - --max-wait-minutes "$((${{ parameters.timeoutInMinutes }} - 5))" # Set the tool's timeout slightly lower than the Azure DevOps job timeout to allow it to exit gracefully. - --stage-name '$(System.StageName)' - --stage-attempt '$(System.StageAttempt)' - --job-attempt '$(System.JobAttempt)' - --test-result-upload-parallelism '${{ parameters.testResultUploadParallelism }}' - ) - - organization='${{ parameters.organization }}' - repository='${{ parameters.repository }}' - testResultAttachmentMode='${{ parameters.testResultAttachmentMode }}' - - # Fall back to Azure DevOps-provided environment variables when the caller did not - # supply organization / repository explicitly. BUILD_REPOSITORY_NAME is typically - # 'owner/repo' for GitHub-backed builds and 'owner-repo' for internal builds. - if [ -z "$organization" ] || [ -z "$repository" ]; then - buildRepoName="${BUILD_REPOSITORY_NAME:-}" - if [ -n "$buildRepoName" ] && [[ "$buildRepoName" == */* ]]; then - repoOwner="${buildRepoName%%/*}" - repoName="${buildRepoName#*/}" - elif [ -n "$buildRepoName" ] && [[ "$buildRepoName" == *-* ]]; then - repoOwner="${buildRepoName%%-*}" - repoName="${buildRepoName#*-}" - fi - - if [ -n "${repoOwner:-}" ] && [ -n "${repoName:-}" ]; then - if [ -z "$organization" ]; then organization="$repoOwner"; fi - if [ -z "$repository" ]; then repository="$repoName"; fi - fi - fi - - if [ -n "$organization" ]; then toolArgs+=( --organization "$organization" ); fi - if [ -n "$repository" ]; then toolArgs+=( --repository "$repository" ); fi - if [ -n "$testResultAttachmentMode" ]; then - toolArgs+=( --test-result-attachment-mode "$testResultAttachmentMode" ) - fi - - # Build.Reason and Build.SourceBranch are required to derive the Helix source filter - # the same way the Helix SDK submitter does (PR -> 'pr', internal -> 'official', - # otherwise -> 'ci'). Without these, manually-queued / scheduled / CI builds would - # be looked up under the wrong source prefix and find zero jobs. - toolArgs+=( --build-reason "$(Build.Reason)" ) - toolArgs+=( --source-branch "$(Build.SourceBranch)" ) - - if [ -n '${{ parameters.toolNupkgArtifactName }}' ]; then - # Tool was installed from a local nupkg; run the DLL via the repo-local dotnet. - export DOTNET_ROOT="$(Build.SourcesDirectory)/.dotnet" - ./eng/common/dotnet.sh exec "$(HelixJobMonitorDll)" "${toolArgs[@]}" - else - # Tool was restored from the local .config/dotnet-tools.json manifest; invoke it - # through the manifest from the repo root. - pushd "$BUILD_SOURCESDIRECTORY" > /dev/null - trap 'popd > /dev/null' EXIT - ./eng/common/dotnet.sh tool run '${{ parameters.toolCommand }}' -- "${toolArgs[@]}" - fi - displayName: Monitor Helix Jobs - env: - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - ${{ if eq(parameters.useEntraAuthentication, false) }}: + - ${{ if eq(parameters.useEntraAuthentication, true) }}: + - task: AzureCLI@2 + displayName: Monitor Helix Jobs + inputs: + azureSubscription: ${{ parameters.azureSubscription }} + keepAzSessionActive: true + scriptType: bash + scriptLocation: inlineScript + inlineScript: | + set -euo pipefail + + # AzureCLI@2 replaces SYSTEM_ACCESSTOKEN with the service connection token. + export SYSTEM_ACCESSTOKEN="$HELIX_AZDO_ACCESSTOKEN" + bash "$BUILD_SOURCESDIRECTORY/eng/common/run-helix-job-monitor.sh" + env: + HELIX_AZDO_ACCESSTOKEN: $(System.AccessToken) + + - ${{ if eq(parameters.useEntraAuthentication, false) }}: + - bash: bash "$BUILD_SOURCESDIRECTORY/eng/common/run-helix-job-monitor.sh" + displayName: Monitor Helix Jobs + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) HELIX_ACCESSTOKEN: ${{ parameters.helixAccessToken }} - ${{ if eq(parameters.useEntraAuthentication, true) }}: - AZURESUBSCRIPTION_CLIENT_ID: $(HelixEntraClientId) - AZURESUBSCRIPTION_TENANT_ID: $(HelixEntraTenantId) - AZURESUBSCRIPTION_SERVICE_CONNECTION_ID: ${{ parameters.azureSubscription }} diff --git a/eng/common/core-templates/stages/renovate.yml b/eng/common/core-templates/stages/renovate.yml index cfa9683794ad..e046d1be0302 100644 --- a/eng/common/core-templates/stages/renovate.yml +++ b/eng/common/core-templates/stages/renovate.yml @@ -60,7 +60,7 @@ parameters: # Renovate version used in the container image tag. - name: renovateVersion - default: 43 + default: 44 type: number # Pool configuration for SDL analysis. diff --git a/eng/common/core-templates/steps/astred-artifacts.yml b/eng/common/core-templates/steps/astred-artifacts.yml index ab01349d540a..86420925b440 100644 --- a/eng/common/core-templates/steps/astred-artifacts.yml +++ b/eng/common/core-templates/steps/astred-artifacts.yml @@ -47,7 +47,6 @@ steps: env: ASTRED_BINLOG_DIR: ${{ parameters.binlogDir }} ASTRED_CAPTURE_PATH: ${{ parameters.capturePath }} - condition: succeededOrFailed() continueOnError: true - pwsh: | @@ -94,12 +93,12 @@ steps: env: ASTRED_SOURCES_PATH: ${{ parameters.sourcesPath }} ASTRED_CAPTURE_PATH: ${{ parameters.capturePath }} - condition: succeededOrFailed() continueOnError: true - task: UploadAstred@0 displayName: Upload Digest to Astred - condition: and(succeededOrFailed(), eq(variables['ASTRED_DIGEST_READY'], 'true')) + condition: and(succeeded(), eq(variables['ASTRED_DIGEST_READY'], 'true')) + continueOnError: true inputs: SourcePath: ${{ parameters.capturePath }}/upload env: diff --git a/eng/common/core-templates/steps/send-to-helix.yml b/eng/common/core-templates/steps/send-to-helix.yml index 62cce4d4ea2a..dba2f1b0afad 100644 --- a/eng/common/core-templates/steps/send-to-helix.yml +++ b/eng/common/core-templates/steps/send-to-helix.yml @@ -6,7 +6,7 @@ parameters: HelixTargetQueues: '' # required -- semicolon-delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues HelixAccessToken: '' # optional -- legacy access token; not forwarded when HelixUseEntraAuthentication is true HelixUseEntraAuthentication: false # optional -- use refreshable Entra authentication instead of a PAT or anonymous access - HelixAzureSubscription: '' # required when HelixUseEntraAuthentication is true -- Azure service connection ID authorized for Helix + HelixAzureSubscription: '' # required when HelixUseEntraAuthentication is true -- workload identity federation service connection name authorized for Helix HelixProjectPath: 'eng/common/helixpublish.proj' # optional -- path to the project file to build relative to BUILD_SOURCESDIRECTORY HelixProjectArguments: '' # optional -- arguments passed to the build command HelixConfiguration: '' # optional -- additional property attached to a job @@ -41,106 +41,176 @@ steps: - ${{ if eq(parameters.HelixUseEntraAuthentication, true) }}: - task: AzureCLI@2 - displayName: Initialize Helix Entra authentication + displayName: ${{ parameters.DisplayNamePrefix }} (Windows) inputs: azureSubscription: ${{ parameters.HelixAzureSubscription }} - addSpnToEnvironment: true + keepAzSessionActive: true scriptType: pscore scriptLocation: inlineScript inlineScript: | - if ([string]::IsNullOrWhiteSpace($env:servicePrincipalId) -or [string]::IsNullOrWhiteSpace($env:tenantId)) { - throw "The Helix Azure service connection did not provide a service principal or tenant ID." - } + # AzureCLI@2 replaces SYSTEM_ACCESSTOKEN with the service connection token. + $env:SYSTEM_ACCESSTOKEN = $env:HELIX_AZDO_ACCESSTOKEN - Write-Host "##vso[task.setvariable variable=HelixEntraClientId]$env:servicePrincipalId" - Write-Host "##vso[task.setvariable variable=HelixEntraTenantId]$env:tenantId" - condition: ${{ parameters.condition }} + $(Build.SourcesDirectory)\eng\common\msbuild.ps1 ` + $(Build.SourcesDirectory)/${{ parameters.HelixProjectPath }} ` + /restore ` + /p:TreatWarningsAsErrors=false ` + /p:EnableHelixJobMonitor=${{ parameters.UseHelixMonitor }} ` + /p:HelixUseEntraAuthentication=${{ parameters.HelixUseEntraAuthentication }} ` + ${{ parameters.HelixProjectArguments }} ` + /t:Test ` + /bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog + env: + BuildConfig: $(_BuildConfig) + HelixSource: ${{ parameters.HelixSource }} + HelixType: ${{ parameters.HelixType }} + HelixBuild: ${{ parameters.HelixBuild }} + HelixConfiguration: ${{ parameters.HelixConfiguration }} + HelixTargetQueues: ${{ parameters.HelixTargetQueues }} + HelixPreCommands: ${{ parameters.HelixPreCommands }} + HelixPostCommands: ${{ parameters.HelixPostCommands }} + WorkItemDirectory: ${{ parameters.WorkItemDirectory }} + WorkItemCommand: ${{ parameters.WorkItemCommand }} + WorkItemTimeout: ${{ parameters.WorkItemTimeout }} + CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} + XUnitProjects: ${{ parameters.XUnitProjects }} + XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} + XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} + XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} + XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} + IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} + DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} + DotNetCliVersion: ${{ parameters.DotNetCliVersion }} + WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} + HelixBaseUri: ${{ parameters.HelixBaseUri }} + Creator: ${{ parameters.Creator }} + HELIX_AZDO_ACCESSTOKEN: $(System.AccessToken) + condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} + - task: AzureCLI@2 + displayName: ${{ parameters.DisplayNamePrefix }} (Unix) + inputs: + azureSubscription: ${{ parameters.HelixAzureSubscription }} + keepAzSessionActive: true + scriptType: bash + scriptLocation: inlineScript + inlineScript: | + # AzureCLI@2 replaces SYSTEM_ACCESSTOKEN with the service connection token. + export SYSTEM_ACCESSTOKEN="$HELIX_AZDO_ACCESSTOKEN" + + $(Build.SourcesDirectory)/eng/common/msbuild.sh \ + $(Build.SourcesDirectory)/${{ parameters.HelixProjectPath }} \ + /restore \ + /p:TreatWarningsAsErrors=false \ + /p:EnableHelixJobMonitor=${{ parameters.UseHelixMonitor }} \ + /p:HelixUseEntraAuthentication=${{ parameters.HelixUseEntraAuthentication }} \ + ${{ parameters.HelixProjectArguments }} \ + /t:Test \ + /bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog + env: + BuildConfig: $(_BuildConfig) + HelixSource: ${{ parameters.HelixSource }} + HelixType: ${{ parameters.HelixType }} + HelixBuild: ${{ parameters.HelixBuild }} + HelixConfiguration: ${{ parameters.HelixConfiguration }} + HelixTargetQueues: ${{ parameters.HelixTargetQueues }} + HelixPreCommands: ${{ parameters.HelixPreCommands }} + HelixPostCommands: ${{ parameters.HelixPostCommands }} + WorkItemDirectory: ${{ parameters.WorkItemDirectory }} + WorkItemCommand: ${{ parameters.WorkItemCommand }} + WorkItemTimeout: ${{ parameters.WorkItemTimeout }} + CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} + XUnitProjects: ${{ parameters.XUnitProjects }} + XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} + XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} + XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} + XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} + IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} + DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} + DotNetCliVersion: ${{ parameters.DotNetCliVersion }} + WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} + HelixBaseUri: ${{ parameters.HelixBaseUri }} + Creator: ${{ parameters.Creator }} + HELIX_AZDO_ACCESSTOKEN: $(System.AccessToken) + condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} - - powershell: > - $(Build.SourcesDirectory)\eng\common\msbuild.ps1 - $(Build.SourcesDirectory)/${{ parameters.HelixProjectPath }} - /restore - /p:TreatWarningsAsErrors=false - /p:EnableHelixJobMonitor=${{ parameters.UseHelixMonitor }} - /p:HelixUseEntraAuthentication=${{ parameters.HelixUseEntraAuthentication }} - ${{ parameters.HelixProjectArguments }} - /t:Test - /bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog - displayName: ${{ parameters.DisplayNamePrefix }} (Windows) - env: - BuildConfig: $(_BuildConfig) - HelixSource: ${{ parameters.HelixSource }} - HelixType: ${{ parameters.HelixType }} - HelixBuild: ${{ parameters.HelixBuild }} - HelixConfiguration: ${{ parameters.HelixConfiguration }} - HelixTargetQueues: ${{ parameters.HelixTargetQueues }} - ${{ if eq(parameters.HelixUseEntraAuthentication, false) }}: + - ${{ if eq(parameters.HelixUseEntraAuthentication, false) }}: + - powershell: > + $(Build.SourcesDirectory)\eng\common\msbuild.ps1 + $(Build.SourcesDirectory)/${{ parameters.HelixProjectPath }} + /restore + /p:TreatWarningsAsErrors=false + /p:EnableHelixJobMonitor=${{ parameters.UseHelixMonitor }} + /p:HelixUseEntraAuthentication=${{ parameters.HelixUseEntraAuthentication }} + ${{ parameters.HelixProjectArguments }} + /t:Test + /bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog + displayName: ${{ parameters.DisplayNamePrefix }} (Windows) + env: + BuildConfig: $(_BuildConfig) + HelixSource: ${{ parameters.HelixSource }} + HelixType: ${{ parameters.HelixType }} + HelixBuild: ${{ parameters.HelixBuild }} + HelixConfiguration: ${{ parameters.HelixConfiguration }} + HelixTargetQueues: ${{ parameters.HelixTargetQueues }} HelixAccessToken: ${{ parameters.HelixAccessToken }} - ${{ if eq(parameters.HelixUseEntraAuthentication, true) }}: - AZURESUBSCRIPTION_CLIENT_ID: $(HelixEntraClientId) - AZURESUBSCRIPTION_TENANT_ID: $(HelixEntraTenantId) - AZURESUBSCRIPTION_SERVICE_CONNECTION_ID: ${{ parameters.HelixAzureSubscription }} - HelixPreCommands: ${{ parameters.HelixPreCommands }} - HelixPostCommands: ${{ parameters.HelixPostCommands }} - WorkItemDirectory: ${{ parameters.WorkItemDirectory }} - WorkItemCommand: ${{ parameters.WorkItemCommand }} - WorkItemTimeout: ${{ parameters.WorkItemTimeout }} - CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} - XUnitProjects: ${{ parameters.XUnitProjects }} - XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} - XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} - XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} - XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} - IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} - DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} - DotNetCliVersion: ${{ parameters.DotNetCliVersion }} - WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} - HelixBaseUri: ${{ parameters.HelixBaseUri }} - Creator: ${{ parameters.Creator }} - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT')) - continueOnError: ${{ parameters.continueOnError }} - - script: > - $(Build.SourcesDirectory)/eng/common/msbuild.sh - $(Build.SourcesDirectory)/${{ parameters.HelixProjectPath }} - /restore - /p:TreatWarningsAsErrors=false - /p:EnableHelixJobMonitor=${{ parameters.UseHelixMonitor }} - /p:HelixUseEntraAuthentication=${{ parameters.HelixUseEntraAuthentication }} - ${{ parameters.HelixProjectArguments }} - /t:Test - /bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog - displayName: ${{ parameters.DisplayNamePrefix }} (Unix) - env: - BuildConfig: $(_BuildConfig) - HelixSource: ${{ parameters.HelixSource }} - HelixType: ${{ parameters.HelixType }} - HelixBuild: ${{ parameters.HelixBuild }} - HelixConfiguration: ${{ parameters.HelixConfiguration }} - HelixTargetQueues: ${{ parameters.HelixTargetQueues }} - ${{ if eq(parameters.HelixUseEntraAuthentication, false) }}: + HelixPreCommands: ${{ parameters.HelixPreCommands }} + HelixPostCommands: ${{ parameters.HelixPostCommands }} + WorkItemDirectory: ${{ parameters.WorkItemDirectory }} + WorkItemCommand: ${{ parameters.WorkItemCommand }} + WorkItemTimeout: ${{ parameters.WorkItemTimeout }} + CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} + XUnitProjects: ${{ parameters.XUnitProjects }} + XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} + XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} + XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} + XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} + IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} + DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} + DotNetCliVersion: ${{ parameters.DotNetCliVersion }} + WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} + HelixBaseUri: ${{ parameters.HelixBaseUri }} + Creator: ${{ parameters.Creator }} + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} + - script: > + $(Build.SourcesDirectory)/eng/common/msbuild.sh + $(Build.SourcesDirectory)/${{ parameters.HelixProjectPath }} + /restore + /p:TreatWarningsAsErrors=false + /p:EnableHelixJobMonitor=${{ parameters.UseHelixMonitor }} + /p:HelixUseEntraAuthentication=${{ parameters.HelixUseEntraAuthentication }} + ${{ parameters.HelixProjectArguments }} + /t:Test + /bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog + displayName: ${{ parameters.DisplayNamePrefix }} (Unix) + env: + BuildConfig: $(_BuildConfig) + HelixSource: ${{ parameters.HelixSource }} + HelixType: ${{ parameters.HelixType }} + HelixBuild: ${{ parameters.HelixBuild }} + HelixConfiguration: ${{ parameters.HelixConfiguration }} + HelixTargetQueues: ${{ parameters.HelixTargetQueues }} HelixAccessToken: ${{ parameters.HelixAccessToken }} - ${{ if eq(parameters.HelixUseEntraAuthentication, true) }}: - AZURESUBSCRIPTION_CLIENT_ID: $(HelixEntraClientId) - AZURESUBSCRIPTION_TENANT_ID: $(HelixEntraTenantId) - AZURESUBSCRIPTION_SERVICE_CONNECTION_ID: ${{ parameters.HelixAzureSubscription }} - HelixPreCommands: ${{ parameters.HelixPreCommands }} - HelixPostCommands: ${{ parameters.HelixPostCommands }} - WorkItemDirectory: ${{ parameters.WorkItemDirectory }} - WorkItemCommand: ${{ parameters.WorkItemCommand }} - WorkItemTimeout: ${{ parameters.WorkItemTimeout }} - CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} - XUnitProjects: ${{ parameters.XUnitProjects }} - XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} - XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} - XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} - XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} - IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} - DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} - DotNetCliVersion: ${{ parameters.DotNetCliVersion }} - WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} - HelixBaseUri: ${{ parameters.HelixBaseUri }} - Creator: ${{ parameters.Creator }} - SYSTEM_ACCESSTOKEN: $(System.AccessToken) - condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT')) - continueOnError: ${{ parameters.continueOnError }} + HelixPreCommands: ${{ parameters.HelixPreCommands }} + HelixPostCommands: ${{ parameters.HelixPostCommands }} + WorkItemDirectory: ${{ parameters.WorkItemDirectory }} + WorkItemCommand: ${{ parameters.WorkItemCommand }} + WorkItemTimeout: ${{ parameters.WorkItemTimeout }} + CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }} + XUnitProjects: ${{ parameters.XUnitProjects }} + XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }} + XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }} + XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }} + XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }} + IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }} + DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }} + DotNetCliVersion: ${{ parameters.DotNetCliVersion }} + WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }} + HelixBaseUri: ${{ parameters.HelixBaseUri }} + Creator: ${{ parameters.Creator }} + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT')) + continueOnError: ${{ parameters.continueOnError }} diff --git a/eng/common/cross/install-debs.py b/eng/common/cross/install-debs.py index 1d1dfabf7dc9..e2d5ef4030a0 100755 --- a/eng/common/cross/install-debs.py +++ b/eng/common/cross/install-debs.py @@ -36,6 +36,8 @@ async def download_file(session, url, dest_path, max_retries=3, retry_delay=2, t f.write(content) print(f"Downloaded {url} at {dest_path}") return + elif response.status >= 500 or response.status in (408, 429): + response.raise_for_status() else: raise Exception(f"Failed to download {url}, Status Code: {response.status}") except (asyncio.CancelledError, asyncio.TimeoutError, aiohttp.ClientError) as e: diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake index 70b71395e3ba..ba7707109000 100644 --- a/eng/common/cross/toolchain.cmake +++ b/eng/common/cross/toolchain.cmake @@ -6,6 +6,7 @@ unset(FREEBSD) unset(OPENBSD) unset(ILLUMOS) unset(ANDROID) +unset(OPENHARMONY) unset(TIZEN) unset(HAIKU) @@ -35,6 +36,8 @@ if(EXISTS ${CROSS_ROOTFS}/etc/tizen-release) set(TIZEN 1) elseif(EXISTS ${CROSS_ROOTFS}/android_platform) set(ANDROID 1) +elseif(EXISTS ${CROSS_ROOTFS}/../build/cmake/ohos.toolchain.cmake) + set(OPENHARMONY 1) endif() if(TARGET_ARCH_NAME STREQUAL "arm") @@ -204,6 +207,17 @@ if(ANDROID) # include official NDK toolchain script include(${CROSS_ROOTFS}/../build/cmake/android.toolchain.cmake) +elseif(OPENHARMONY) + if(TARGET_ARCH_NAME STREQUAL "arm") + set(OHOS_ARCH armeabi-v7a) + elseif(TARGET_ARCH_NAME STREQUAL "arm64") + set(OHOS_ARCH arm64-v8a) + elseif(TARGET_ARCH_NAME STREQUAL "x64") + set(OHOS_ARCH x86_64) + endif() + + # include official OHOS NDK toolchain script + include(${CROSS_ROOTFS}/../build/cmake/ohos.toolchain.cmake) elseif(FREEBSD OR OPENBSD) # we cross-compile by instructing clang set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN}) @@ -308,7 +322,7 @@ endif() # Specify compile options -if((TARGET_ARCH_NAME MATCHES "^(arm|arm64|armel|armv6|loongarch64|ppc64le|riscv64|s390x|x64|x86)$" AND NOT ANDROID AND NOT FREEBSD AND NOT OPENBSD) OR ILLUMOS OR HAIKU) +if((TARGET_ARCH_NAME MATCHES "^(arm|arm64|armel|armv6|loongarch64|ppc64le|riscv64|s390x|x64|x86)$" AND NOT ANDROID AND NOT OPENHARMONY AND NOT FREEBSD AND NOT OPENBSD) OR ILLUMOS OR HAIKU) set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_ASM_COMPILER_TARGET ${TOOLCHAIN}) diff --git a/eng/common/msbuild.ps1 b/eng/common/msbuild.ps1 index 8076945064db..161f8e8077c3 100644 --- a/eng/common/msbuild.ps1 +++ b/eng/common/msbuild.ps1 @@ -19,11 +19,6 @@ try { $nodeReuse = $false } - # MSBuild's multi-threaded mode isn't run on CI unless it was explicitly requested via -msbuildMultiThreaded. - if ($ci -and -not $PSBoundParameters.ContainsKey('msbuildMultiThreaded')) { - $msbuildMultiThreaded = $false - } - MSBuild @extraArgs } catch { diff --git a/eng/common/native/init-distro-rid.sh b/eng/common/native/init-distro-rid.sh index 8fc6d2fec78d..abb3e2311739 100644 --- a/eng/common/native/init-distro-rid.sh +++ b/eng/common/native/init-distro-rid.sh @@ -41,6 +41,9 @@ getNonPortableDistroRid() nonPortableRid="freebsd.$__freebsd_major_version-${targetArch}" elif [ "$targetOs" = "openbsd" ]; then nonPortableRid="openbsd.$(uname -r)-${targetArch}" + elif [ "$targetOs" = "openharmony" ] && command -v param >/dev/null && param get const.ohos.fullname 2>/dev/null | grep -qi '^openharmony'; then + __openharmony_api_version=$(param get const.ohos.apiversion | tr -d '[:space:]') + nonPortableRid="openharmony.$__openharmony_api_version-${targetArch}" elif command -v getprop >/dev/null && getprop ro.product.system.model | grep -qi android; then __android_sdk_version=$(getprop ro.build.version.sdk) nonPortableRid="android.$__android_sdk_version-${targetArch}" @@ -101,10 +104,14 @@ initDistroRidGlobal() STRINGS="$(command -v llvm-strings || true)" fi - # Check for musl-based distros (e.g. Alpine Linux, Void Linux). - if "${rootfsDir}/usr/bin/ldd" --version 2>&1 | grep -q musl || - ( [ -n "$STRINGS" ] && "$STRINGS" "${rootfsDir}/usr/bin/ldd" 2>&1 | grep -q musl ); then - __PortableTargetOS="linux-musl" + # Check for musl-based distros (e.g. Alpine Linux, Void Linux). Only linux targets + # have a musl/glibc portable flavor; skip the check for other targets so that a + # musl-based build host does not clobber their portable OS (e.g. openharmony). + if [ "$targetOs" = "linux" ]; then + if "${rootfsDir}/usr/bin/ldd" --version 2>&1 | grep -q musl || + ( [ -n "$STRINGS" ] && "$STRINGS" "${rootfsDir}/usr/bin/ldd" 2>&1 | grep -q musl ); then + __PortableTargetOS="linux-musl" + fi fi fi diff --git a/eng/common/native/init-os-and-arch.sh b/eng/common/native/init-os-and-arch.sh index 62d62fed522a..c3e212284360 100644 --- a/eng/common/native/init-os-and-arch.sh +++ b/eng/common/native/init-os-and-arch.sh @@ -7,9 +7,17 @@ if command -v getprop && getprop ro.product.system.model 2>&1 | grep -qi android OSName="android" fi +# OpenHarmony/HarmonyOS hosts report `HarmonyOS` (or `Linux` on some devices) +# from uname, so query the OHOS parameter service as well. +if command -v param >/dev/null 2>&1 && param get const.ohos.fullname 2>/dev/null | grep -qi '^openharmony'; then + OSName="openharmony" +fi + case "$OSName" in freebsd|linux|netbsd|openbsd|sunos|android|haiku) os="$OSName" ;; +harmonyos|openharmony) + os=openharmony ;; darwin) os=osx ;; *) diff --git a/eng/common/run-helix-job-monitor.sh b/eng/common/run-helix-job-monitor.sh new file mode 100644 index 000000000000..dda140bc9a4b --- /dev/null +++ b/eng/common/run-helix-job-monitor.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +set -euo pipefail + +scriptroot="$(cd -P "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +. "$scriptroot/pipeline-logging-functions.sh" + +toolArgs=( + --helix-base-uri "$HELIX_MONITOR_BASE_URI" + --use-entra-authentication "$HELIX_MONITOR_USE_ENTRA_AUTHENTICATION" + --polling-interval-seconds "$HELIX_MONITOR_POLLING_INTERVAL_SECONDS" + --fail-on-failed-tests "$HELIX_MONITOR_FAIL_ON_FAILED_TESTS" + --allow-no-helix-jobs "$HELIX_MONITOR_ALLOW_NO_HELIX_JOBS" + --use-fully-qualified-test-name "$HELIX_MONITOR_USE_FULLY_QUALIFIED_TEST_NAME" + --max-wait-minutes "$((HELIX_MONITOR_TIMEOUT_IN_MINUTES - 5))" + --stage-name "$SYSTEM_STAGENAME" + --stage-attempt "$SYSTEM_STAGEATTEMPT" + --job-attempt "$SYSTEM_JOBATTEMPT" + --test-result-upload-parallelism "$HELIX_MONITOR_TEST_RESULT_UPLOAD_PARALLELISM" +) + +organization="${HELIX_MONITOR_ORGANIZATION:-}" +repository="${HELIX_MONITOR_REPOSITORY:-}" + +# Fall back to Azure DevOps-provided environment variables when the caller did not +# supply organization or repository explicitly. +if [ -z "$organization" ] || [ -z "$repository" ]; then + buildRepoName="${BUILD_REPOSITORY_NAME:-}" + if [ -n "$buildRepoName" ] && [[ "$buildRepoName" == */* ]]; then + repoOwner="${buildRepoName%%/*}" + repoName="${buildRepoName#*/}" + elif [ -n "$buildRepoName" ] && [[ "$buildRepoName" == *-* ]]; then + repoOwner="${buildRepoName%%-*}" + repoName="${buildRepoName#*-}" + fi + + if [ -n "${repoOwner:-}" ] && [ -n "${repoName:-}" ]; then + if [ -z "$organization" ]; then organization="$repoOwner"; fi + if [ -z "$repository" ]; then repository="$repoName"; fi + fi +fi + +if [ -n "$organization" ]; then toolArgs+=( --organization "$organization" ); fi +if [ -n "$repository" ]; then toolArgs+=( --repository "$repository" ); fi +if [ -n "${HELIX_MONITOR_TEST_RESULT_ATTACHMENT_MODE:-}" ]; then + toolArgs+=( --test-result-attachment-mode "$HELIX_MONITOR_TEST_RESULT_ATTACHMENT_MODE" ) +fi + +# These values let the monitor derive the same Helix source filter as the SDK submitter. +toolArgs+=( --build-reason "$BUILD_REASON" ) +toolArgs+=( --source-branch "$BUILD_SOURCEBRANCH" ) + +cd "$BUILD_SOURCESDIRECTORY" +exitCode=0 +if [ -n "${HELIX_MONITOR_TOOL_NUPKG_ARTIFACT_NAME:-}" ]; then + export DOTNET_ROOT="$BUILD_SOURCESDIRECTORY/.dotnet" + ./eng/common/dotnet.sh exec "$HELIXJOBMONITORDLL" "${toolArgs[@]}" || exitCode=$? +else + ./eng/common/dotnet.sh tool run "$HELIX_MONITOR_TOOL_COMMAND" -- "${toolArgs[@]}" || exitCode=$? +fi + +if [ "$exitCode" -ne 0 ]; then + Write-PipelineTelemetryError -force -category 'Helix' "Helix job monitor failed (exit code '$exitCode')." + exit "$exitCode" +fi diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index cea14279b857..9cb84a8a9419 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -31,8 +31,9 @@ # Set to true to reuse msbuild nodes. Recommended to not reuse on CI. [bool]$nodeReuse = if (Test-Path variable:nodeReuse) { $nodeReuse } else { !$ci } -# Set to true to build with MSBuild's multi-threaded mode (-mt). Enabled by default for local builds and not run on CI. -[bool]$msbuildMultiThreaded = if (Test-Path variable:msbuildMultiThreaded) { $msbuildMultiThreaded } else { !$ci } +# Set to true to build with MSBuild's multi-threaded mode (-mt). Enabled by default for both local and CI builds. +# Not applied when building with msbuild.exe (VS MSBuild). +[bool]$msbuildMultiThreaded = if (Test-Path variable:msbuildMultiThreaded) { $msbuildMultiThreaded } else { $true } # Configures warning treatment in msbuild. [bool]$warnAsError = if (Test-Path variable:warnAsError) { $warnAsError } else { $true } @@ -812,8 +813,9 @@ function MSBuild() { $cmdArgs = "$($buildTool.Command) /m /nologo /clp:Summary /v:$verbosity /nr:$nodeReuse /p:ContinuousIntegrationBuild=$ci" - # Build with MSBuild's multi-threaded mode. - if ($msbuildMultiThreaded) { + # Build with MSBuild's multi-threaded mode, but not with msbuild.exe (VS MSBuild) for now. + # TODO: Enable for VS MSBuild as well: https://github.com/dotnet/dotnet/issues/9989 + if ($msbuildMultiThreaded -and [System.IO.Path]::GetFileName($buildTool.Path) -ne 'msbuild.exe') { $cmdArgs += ' -mt' } diff --git a/eng/common/tools.sh b/eng/common/tools.sh index fdbc19243f1f..3b4a5ac5142a 100755 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -60,13 +60,9 @@ else node_reuse=${node_reuse:-true} fi -# Set to true to build with MSBuild's multi-threaded mode (-mt). Enabled by default for local builds and not run on CI. +# Set to true to build with MSBuild's multi-threaded mode (-mt). Enabled by default for both local and CI builds. msbuild_multi_threaded=$(NormalizeBoolArg "${msbuild_multi_threaded:-}") -if [[ "$ci" == true ]]; then - msbuild_multi_threaded=${msbuild_multi_threaded:-false} -else - msbuild_multi_threaded=${msbuild_multi_threaded:-true} -fi +msbuild_multi_threaded=${msbuild_multi_threaded:-true} # Configures warning treatment in msbuild. warn_as_error=$(NormalizeBoolArg "${warn_as_error:-}") diff --git a/global.json b/global.json index 33e9024a4ffe..c01253732b21 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "11.0.100-rc.1.26420.103", + "version": "12.0.100-alpha.1.26480.102", "paths": [ ".dotnet", "$host$" @@ -8,7 +8,7 @@ "errorMessage": "The .NET SDK could not be found, run ./restore.cmd or ./restore.sh first." }, "tools": { - "dotnet": "11.0.100-rc.1.26420.103", + "dotnet": "12.0.100-alpha.1.26480.102", "runtimes": { "dotnet/x86": [ "$(MicrosoftInternalRuntimeAspNetCoreTransportVersion)" @@ -22,9 +22,9 @@ "jdk": "latest" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "12.0.0-beta.26473.114", - "Microsoft.DotNet.Helix.Sdk": "12.0.0-beta.26473.114", - "Microsoft.DotNet.SharedFramework.Sdk": "12.0.0-beta.26473.114", + "Microsoft.DotNet.Arcade.Sdk": "12.0.0-beta.26513.123", + "Microsoft.DotNet.Helix.Sdk": "12.0.0-beta.26513.123", + "Microsoft.DotNet.SharedFramework.Sdk": "12.0.0-beta.26513.123", "Microsoft.Build.NoTargets": "3.7.134", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.WixToolset.Sdk": "6.0.3-dotnet.6" From 9a831a30c3ac3eea98fa72debb7d8515a90ef946 Mon Sep 17 00:00:00 2001 From: Will Godbe Date: Wed, 14 Oct 2026 14:53:10 -0700 Subject: [PATCH 03/19] Fix SqlClient and PR attention checks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../fixtures/presentation/incomplete-query.expected.txt | 1 + .../fixtures/presentation/published-34643961191.expected.txt | 1 + eng/Versions.props | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/incomplete-query.expected.txt b/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/incomplete-query.expected.txt index af9d7c86ebfc..d69421b4fbc0 100644 --- a/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/incomplete-query.expected.txt +++ b/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/incomplete-query.expected.txt @@ -56,6 +56,7 @@ Repository: `dotnet/aspnetcore`; run ID: `34643961191`; attempt: `1`. JSON SHA-256: `0f954e9a74942427466297df78038c30c5ea67d53782832daf091793b3fb0752`.
+
Snapshot JSON (exact sanitized bytes) diff --git a/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/published-34643961191.expected.txt b/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/published-34643961191.expected.txt index 4b8cde7b976e..cd8e12dc47fe 100644 --- a/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/published-34643961191.expected.txt +++ b/.github/workflows/pr-attention-pulse-tests/fixtures/presentation/published-34643961191.expected.txt @@ -107,6 +107,7 @@ Repository: `dotnet/aspnetcore`; run ID: `34643961191`; attempt: `1`. JSON SHA-256: `d69fdb0a40ba4c80a7515044b256fbe9b7fe22bd2fb2890cb4bd8b0f6b4a6f3b`.
+
Snapshot JSON (exact sanitized bytes) diff --git a/eng/Versions.props b/eng/Versions.props index 796953cd79fc..38d1e4b8843f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -213,7 +213,7 @@ 2.2.3 2.3.0 - 7.1.0 + 7.1.1 1.0.0 [3.10.2,4.0.0) [3.10.2,4.0.0) From 2226e25ca2a643bd9fd15ba089adbd8f934194c9 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Mon, 19 Oct 2026 09:40:01 +0000 Subject: [PATCH 04/19] Backflow from https://github.com/dotnet/dotnet / 85ada61 build 336805 Diff: https://github.com/dotnet/dotnet/compare/e1fc22dd641fa857d198afa8ec4c96eac1ac7f29..85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea From: https://github.com/dotnet/dotnet/commit/e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 To: https://github.com/dotnet/dotnet/commit/85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea [[ commit created by automation ]] --- .../Authorization/src/AuthorizeViewCore.cs | 20 +- .../test/AuthorizeViewCoreTest.cs | 179 +++++++++ .../test/GatedTestAuthorizationService.cs | 47 +++ .../test/TrackingTestRenderer.cs | 48 +++ .../src/RazorComponentEndpointInvoker.cs | 3 +- .../EndpointHtmlRenderer.Prerendering.cs | 11 +- .../test/RazorComponentEndpointInvokerTest.cs | 139 +++++++ src/Components/test/E2ETest/Tests/AuthTest.cs | 25 ++ .../AuthTest/AsyncAuthorizationGate.cs | 46 +++ .../AuthTest/AuthRouterLayout.razor | 40 ++ .../PageRequiringSlowAsyncPolicy.razor | 4 + .../test/testassets/BasicTestApp/Program.cs | 6 + .../AuthenticationStartup.cs | 8 + .../FormPipeReaderInternalsBenchmark.cs | 6 +- .../src/FileBufferingReadStream.cs | 99 +++-- src/Http/WebUtilities/src/FormPipeReader.cs | 65 ++- .../Microsoft.AspNetCore.WebUtilities.csproj | 1 + .../test/FileBufferingReadStreamTests.cs | 48 +++ .../WebUtilities/test/FormPipeReaderTests.cs | 353 ++++++++++++++++- ...entityApiEndpointRouteBuilderExtensions.cs | 18 +- .../Pages/V4/Account/ForgotPassword.cshtml.cs | 8 +- .../Account/ResendEmailConfirmation.cshtml.cs | 8 +- .../Pages/V5/Account/ForgotPassword.cshtml.cs | 8 +- .../Account/ResendEmailConfirmation.cshtml.cs | 8 +- .../MapIdentityApiTests.cs | 162 +++++++- .../Negotiate/src/Internal/LdapAdapter.cs | 187 ++++++++- .../test/Negotiate.Test/LdapAdapterTests.cs | 146 +++++++ .../Core/src/Internal/Http/Http1Connection.cs | 4 - .../Core/src/Internal/Http/HttpProtocol.cs | 10 +- .../InMemory.FunctionalTests/RequestTests.cs | 41 ++ src/Shared/PooledMemoryStream.cs | 237 +++++++++++ .../Microsoft.AspNetCore.Shared.Tests.csproj | 1 + .../Shared.Tests/PooledMemoryStreamTests.cs | 372 ++++++++++++++++++ 33 files changed, 2230 insertions(+), 128 deletions(-) create mode 100644 src/Components/Authorization/test/AuthorizeViewCoreTest.cs create mode 100644 src/Components/Authorization/test/GatedTestAuthorizationService.cs create mode 100644 src/Components/Authorization/test/TrackingTestRenderer.cs create mode 100644 src/Components/test/testassets/BasicTestApp/AuthTest/AsyncAuthorizationGate.cs create mode 100644 src/Components/test/testassets/BasicTestApp/AuthTest/PageRequiringSlowAsyncPolicy.razor create mode 100644 src/Shared/PooledMemoryStream.cs create mode 100644 src/Shared/test/Shared.Tests/PooledMemoryStreamTests.cs diff --git a/src/Components/Authorization/src/AuthorizeViewCore.cs b/src/Components/Authorization/src/AuthorizeViewCore.cs index 1331200c888d..bee6519be599 100644 --- a/src/Components/Authorization/src/AuthorizeViewCore.cs +++ b/src/Components/Authorization/src/AuthorizeViewCore.cs @@ -16,6 +16,7 @@ public abstract class AuthorizeViewCore : ComponentBase { private AuthenticationState? currentAuthenticationState; private bool? isAuthorized; + private CancellationTokenSource? authorizationCts; /// /// The content that will be displayed if the user is authorized. @@ -85,12 +86,27 @@ protected override async Task OnParametersSetAsync() throw new InvalidOperationException($"Authorization requires a cascading parameter of type Task<{nameof(AuthenticationState)}>. Consider using {typeof(CascadingAuthenticationState).Name} to supply this."); } + // Newer parameters arriving need to cancel the evaluation in flight so that it does not apply superseded results. + authorizationCts?.Cancel(); + var cts = new CancellationTokenSource(); + authorizationCts = cts; + var cancellationToken = cts.Token; + // Clear the previous result of authorization // This will cause the Authorizing state to be displayed until the authorization has been completed isAuthorized = null; - currentAuthenticationState = await AuthenticationState; - isAuthorized = await IsAuthorizedAsync(currentAuthenticationState.User); + // Nothing in the authorization pipeline accepts a CancellationToken, so we cannot use it to abort the work. + var authenticationState = await AuthenticationState; + var authorized = await IsAuthorizedAsync(authenticationState.User); + + if (cancellationToken.IsCancellationRequested) + { + return; + } + + currentAuthenticationState = authenticationState; + isAuthorized = authorized; } /// diff --git a/src/Components/Authorization/test/AuthorizeViewCoreTest.cs b/src/Components/Authorization/test/AuthorizeViewCoreTest.cs new file mode 100644 index 000000000000..beed3789ec7e --- /dev/null +++ b/src/Components/Authorization/test/AuthorizeViewCoreTest.cs @@ -0,0 +1,179 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Security.Claims; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Components.Rendering; +using Microsoft.AspNetCore.Components.RenderTree; +using Microsoft.AspNetCore.Components.Test.Helpers; +using Microsoft.Extensions.DependencyInjection; + +namespace Microsoft.AspNetCore.Components.Authorization; + +public class AuthorizeViewCoreTest +{ + private const string LowPolicy = "LowPrivilege"; + private const string MiddlePolicy = "MiddlePrivilege"; + private const string HighPolicy = "HighPrivilege"; + + private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(10); + + private readonly GatedTestAuthorizationService _authorizationService = new(); + private readonly TaskCompletionSource _authenticationState = new(TaskCreationOptions.RunContinuationsAsynchronously); + private readonly CascadingValueSource> _authenticationStateSource; + private readonly TrackingTestRenderer _renderer; + private readonly TestComponentHost _host = new(); + + public AuthorizeViewCoreTest() + { + _authenticationStateSource = new(_authenticationState.Task, isFixed: false); + + var services = new ServiceCollection(); + services.AddSingleton(); + services.AddSingleton(_authorizationService); + services.AddCascadingValue(_ => _authenticationStateSource); + + _renderer = new TrackingTestRenderer(services.BuildServiceProvider()); + _renderer.AssignRootComponentId(_host); + } + + [Fact] + public async Task SupersededResultIsNotAppliedWhenPolicyChanges() + { + SignIn("Nellie"); + + _host.Policy = LowPolicy; + var firstParameterSet = RenderAndCapture(); + + _host.Policy = HighPolicy; + var secondParameterSet = RenderAndCapture(); + Assert.Equal([LowPolicy, HighPolicy], _authorizationService.StartedEvaluations); + + // The newest evaluation denies access, which must be the outcome that survives. + _authorizationService.Deny(HighPolicy); + await secondParameterSet.WaitAsync(Timeout); + AssertRendered("NOT AUTHORIZED:Nellie"); + + // The superseded evaluation, bound to the policy the user does satisfy, now succeeds. + _authorizationService.Grant(LowPolicy); + await firstParameterSet.WaitAsync(Timeout); + AssertRendered("NOT AUTHORIZED:Nellie"); + } + + [Fact] + public async Task SupersededResultDoesNotOverwriteNewerPrincipalOrDecision() + { + _host.Policy = LowPolicy; + var firstParameterSet = RenderAndCapture(); + + var secondParameterSet = await RefreshAuthenticationAsync("Ronaldo"); + _authorizationService.Deny(LowPolicy); + await secondParameterSet.WaitAsync(Timeout); + AssertRendered("NOT AUTHORIZED:Ronaldo"); + + // The principal and the decision must be committed together, otherwise the rendered content + // can show a principal that did not produce the displayed decision. + SignIn("Nellie"); + await firstParameterSet.WaitAsync(Timeout); + AssertRendered("NOT AUTHORIZED:Ronaldo"); + } + + [Fact] + public async Task RendersAuthorizingWhileOnlySupersededResultHasArrived() + { + SignIn("Nellie"); + + _host.Policy = LowPolicy; + var firstParameterSet = RenderAndCapture(); + + // Never settled, so the only result that could reach the output is the superseded one. + _host.Policy = HighPolicy; + _ = RenderAndCapture(); + + _authorizationService.Grant(LowPolicy); + await firstParameterSet.WaitAsync(Timeout); + AssertRendered("AUTHORIZING"); + } + + [Fact] + public async Task OnlyNewestResultIsAppliedWhenThreeEvaluationsInterleave() + { + SignIn("Nellie"); + + _host.TriggerRender(); + Assert.Empty(_authorizationService.StartedEvaluations); + AssertRendered("AUTHORIZED:Nellie"); + + _host.Policy = LowPolicy; + var firstParameterSet = RenderAndCapture(); + + _host.Policy = MiddlePolicy; + var secondParameterSet = RenderAndCapture(); + + _host.Policy = HighPolicy; + var thirdParameterSet = RenderAndCapture(); + Assert.Equal([LowPolicy, MiddlePolicy, HighPolicy], _authorizationService.StartedEvaluations); + + _authorizationService.Deny(HighPolicy); + await thirdParameterSet.WaitAsync(Timeout); + AssertRendered("NOT AUTHORIZED:Nellie"); + + _authorizationService.Grant(LowPolicy); + _authorizationService.Grant(MiddlePolicy); + await Task.WhenAll(firstParameterSet, secondParameterSet).WaitAsync(Timeout); + AssertRendered("NOT AUTHORIZED:Nellie"); + } + + private Task RenderAndCapture() + => _renderer.CaptureRenderParameterSetTask(_host); + + private void SignIn(string userName) + => _authenticationState.SetResult(CreateAuthenticationState(userName)); + + private Task RefreshAuthenticationAsync(string userName) + => _renderer.CaptureParameterSetTaskAsync( + () => _authenticationStateSource.NotifyChangedAsync(Task.FromResult(CreateAuthenticationState(userName)))); + + private static AuthenticationState CreateAuthenticationState(string userName) + => new(new ClaimsPrincipal(new TestIdentity { Name = userName })); + + private void AssertRendered(string expected) + { + var componentId = _renderer.Batches[0].GetComponentFrames().Single().ComponentId; + var frames = _renderer.GetCurrentRenderTreeFrames(componentId); + var text = frames.Array.Take(frames.Count).Single(f => f.FrameType == RenderTreeFrameType.Text); + AssertFrame.Text(text, expected); + } + + private sealed class TestComponentHost : AutoRenderComponent + { + private static readonly RenderFragment Authorized = + state => builder => builder.AddContent(0, $"AUTHORIZED:{state.User.Identity.Name}"); + + private static readonly RenderFragment NotAuthorized = + state => builder => builder.AddContent(0, $"NOT AUTHORIZED:{state.User.Identity.Name}"); + + private static readonly RenderFragment Authorizing = + builder => builder.AddContent(0, "AUTHORIZING"); + + public string Policy { get; set; } + + protected override void BuildRenderTree(RenderTreeBuilder builder) + { + builder.OpenComponent(0); + builder.AddComponentParameter(1, nameof(TestAuthorizeView.Policy), Policy); + builder.AddComponentParameter(2, nameof(AuthorizeViewCore.Authorized), Authorized); + builder.AddComponentParameter(3, nameof(AuthorizeViewCore.NotAuthorized), NotAuthorized); + builder.AddComponentParameter(4, nameof(AuthorizeViewCore.Authorizing), Authorizing); + builder.CloseComponent(); + } + } + + private sealed class TestAuthorizeView : AuthorizeViewCore + { + [Parameter] public string Policy { get; set; } + + protected override IAuthorizeData[] GetAuthorizeData() + => Policy is null ? null : [new AuthorizeAttribute { Policy = Policy }]; + } +} diff --git a/src/Components/Authorization/test/GatedTestAuthorizationService.cs b/src/Components/Authorization/test/GatedTestAuthorizationService.cs new file mode 100644 index 000000000000..8ae072b7b517 --- /dev/null +++ b/src/Components/Authorization/test/GatedTestAuthorizationService.cs @@ -0,0 +1,47 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Concurrent; +using System.Security.Claims; +using Microsoft.AspNetCore.Authorization; + +namespace Microsoft.AspNetCore.Components.Authorization; + +// An authorization service whose evaluations stay pending until the test decides the +// outcome, so overlapping evaluations can be made to complete in any order. +public class GatedTestAuthorizationService : IAuthorizationService +{ + private readonly ConcurrentDictionary> _gates = new(); + private readonly ConcurrentQueue _startedEvaluations = new(); + + public string[] StartedEvaluations => [.. _startedEvaluations]; + + public void Grant(string policyName) => GateFor(policyName).TrySetResult(true); + + public void Deny(string policyName) => GateFor(policyName).TrySetResult(false); + + public async Task AuthorizeAsync( + ClaimsPrincipal user, object resource, IEnumerable requirements) + { + var policyName = requirements.OfType().SingleOrDefault()?.PolicyName + ?? throw new InvalidOperationException( + $"{nameof(GatedTestAuthorizationService)} tells evaluations apart by policy name, so each one must " + + $"come from a named policy supplied by {nameof(TestAuthorizationPolicyProvider)}."); + + // Recorded before the first await so that a test can inspect StartedEvaluations as soon as + // the render which triggered the evaluation has returned. + _startedEvaluations.Enqueue(policyName); + + return await GateFor(policyName).Task + ? AuthorizationResult.Success() + : AuthorizationResult.Failed(); + } + + public Task AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName) + => throw new NotSupportedException(); + + private TaskCompletionSource GateFor(string policyName) + => _gates.GetOrAdd( + policyName, + static _ => new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously)); +} diff --git a/src/Components/Authorization/test/TrackingTestRenderer.cs b/src/Components/Authorization/test/TrackingTestRenderer.cs new file mode 100644 index 000000000000..32bc4c4ae8d8 --- /dev/null +++ b/src/Components/Authorization/test/TrackingTestRenderer.cs @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Concurrent; +using Microsoft.AspNetCore.Components.Rendering; +using Microsoft.AspNetCore.Components.Test.Helpers; + +namespace Microsoft.AspNetCore.Components.Authorization; + +// A renderer that records the tasks returned by calls to SetParametersAsync which do not complete synchronously. +public class TrackingTestRenderer(IServiceProvider serviceProvider) : TestRenderer(serviceProvider) +{ + private readonly ConcurrentQueue _parameterSetTasks = new(); + + protected override void AddPendingTask(ComponentState componentState, Task task) + { + _parameterSetTasks.Enqueue(task); + base.AddPendingTask(componentState, task); + } + + // Runs the component render and returns the task for the parameter set it supplied. + public Task CaptureRenderParameterSetTask(AutoRenderComponent component) + { + var countBefore = _parameterSetTasks.Count; + component.TriggerRender(); + return AssertSingleParameterSetTaskAdded(countBefore); + } + + // Runs the async trigger and returns the task for the parameter set it supplied. + public async Task CaptureParameterSetTaskAsync(Func trigger) + { + var countBefore = _parameterSetTasks.Count; + await trigger(); + return AssertSingleParameterSetTaskAdded(countBefore); + } + + private Task AssertSingleParameterSetTaskAdded(int countBefore) + { + var tasksAfter = _parameterSetTasks.ToArray(); + var added = tasksAfter.Length - countBefore; + + Assert.True( + added == 1, + $"Expected the trigger to supply exactly one parameter set that suspends, but {added} were tracked."); + + return tasksAfter[^1]; + } +} diff --git a/src/Components/Endpoints/src/RazorComponentEndpointInvoker.cs b/src/Components/Endpoints/src/RazorComponentEndpointInvoker.cs index 58d8a4e3090d..8c6aa2200124 100644 --- a/src/Components/Endpoints/src/RazorComponentEndpointInvoker.cs +++ b/src/Components/Endpoints/src/RazorComponentEndpointInvoker.cs @@ -120,7 +120,8 @@ await _renderer.InitializeStandardComponentServicesAsync( } catch (NavigationException ex) { - await EndpointHtmlRenderer.HandleNavigationException(context, ex); + // Discard the rendered output: the render tree it points at was abandoned mid-diff. + htmlContent = await EndpointHtmlRenderer.HandleNavigationException(context, ex); quiesceTask = Task.CompletedTask; } } diff --git a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.Prerendering.cs b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.Prerendering.cs index 0276cdfd1515..478e6e893c38 100644 --- a/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.Prerendering.cs +++ b/src/Components/Endpoints/src/Rendering/EndpointHtmlRenderer.Prerendering.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.ExceptionServices; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Components.Rendering; using Microsoft.AspNetCore.Components.RenderTree; @@ -198,6 +199,8 @@ public Task WaitForNonStreamingPendingTasks() async Task Execute() { + ExceptionDispatchInfo? navigationExceptionInfo = null; + while (_nonStreamingPendingTasks.Count > 0) { // Create a Task that represents the remaining ongoing work for the rendering process @@ -214,9 +217,15 @@ async Task Execute() } catch (NavigationException navigationException) { - await HandleNavigationException(_httpContext, navigationException); + // Keep draining so work queued before the redirect is still observed, but let the caller + // discard the rendered output. A navigation thrown while a component was initializing its + // children abandons that diff after the new render tree was already swapped in, leaving + // uninitialized sibling frames that must never be written. + navigationExceptionInfo ??= ExceptionDispatchInfo.Capture(navigationException); } } + + navigationExceptionInfo?.Throw(); } } diff --git a/src/Components/Endpoints/test/RazorComponentEndpointInvokerTest.cs b/src/Components/Endpoints/test/RazorComponentEndpointInvokerTest.cs index 8dc20784a35f..9ece6f053116 100644 --- a/src/Components/Endpoints/test/RazorComponentEndpointInvokerTest.cs +++ b/src/Components/Endpoints/test/RazorComponentEndpointInvokerTest.cs @@ -3,10 +3,13 @@ #nullable enable +using System.Diagnostics.CodeAnalysis; using System.Text; using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Endpoints.Tests.TestComponents; +using Microsoft.AspNetCore.Components.Rendering; +using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; @@ -14,11 +17,147 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; namespace Microsoft.AspNetCore.Components.Endpoints.Tests; public class RazorComponentEndpointInvokerTest { + [Fact] + public async Task Invoker_RedirectWhileInitializingChildren_DoesNotWriteUninitializedComponentFrames() + { + var services = CreateRedirectingPageServices(); + await using var renderer = new EndpointHtmlRenderer(services, NullLoggerFactory.Instance); + var invoker = new RazorComponentEndpointInvoker(renderer, NullLogger.Instance); + + var context = CreateRedirectingPageContext(services, typeof(RedirectingPage)); + context.Request.Method = "GET"; + + await invoker.Render(context); + + // The redirect abandons the diff after the new render tree was already swapped in, leaving the sibling + // that follows the redirecting child uninitialized. The abandoned output must be discarded rather than + // written, because that sibling still carries the default component id and walking it re-enters the root. + Assert.Equal(StatusCodes.Status302Found, context.Response.StatusCode); + Assert.Equal("https://localhost/redirected", context.Response.Headers.Location); + Assert.Empty(await ReadBody(context)); + } + + [Fact] + public async Task Invoker_RedirectWhileHandlingFormPost_DoesNotWriteUninitializedComponentFrames() + { + var services = CreateRedirectingPageServices(); + await using var renderer = new EndpointHtmlRenderer(services, NullLoggerFactory.Instance); + var invoker = new RazorComponentEndpointInvoker(renderer, NullLogger.Instance); + + var context = CreateRedirectingPageContext(services, typeof(RedirectingFormPage)); + context.Request.Method = "POST"; + context.Request.ContentType = "application/x-www-form-urlencoded"; + var form = Encoding.UTF8.GetBytes($"_handler={RedirectingFormPage.FormName}"); + context.Request.Body = new MemoryStream(form); + context.Request.ContentLength = form.Length; + + await invoker.Render(context); + + // Post/Redirect/Get: handling the submit event re-renders the page, and a child added by that render + // redirects while initializing, so the same abandoned tree has to be discarded on the form post path. + Assert.Equal(StatusCodes.Status302Found, context.Response.StatusCode); + Assert.Equal("https://localhost/redirected", context.Response.Headers.Location); + Assert.Empty(await ReadBody(context)); + } + + private static ServiceProvider CreateRedirectingPageServices() + => new ServiceCollection().AddRazorComponents() + .Services.AddAntiforgery() + .AddSingleton(new ConfigurationBuilder().Build()) + .AddSingleton(new TestWebHostEnvironment()) + .AddSingleton(sp => sp.GetRequiredService()) + .AddSingleton(new EphemeralDataProtectionProvider()) + .BuildServiceProvider(); + + private static DefaultHttpContext CreateRedirectingPageContext( + IServiceProvider services, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type pageType) + { + var context = new DefaultHttpContext { RequestServices = services }; + context.SetEndpoint(new RouteEndpoint( + _ => Task.CompletedTask, + RoutePatternFactory.Parse("/"), + 0, + new EndpointMetadataCollection( + new ComponentTypeMetadata(pageType), + new RootComponentMetadata(pageType), + new ConfiguredRenderModesMetadata([])), + "redirecting-page")); + context.Request.Scheme = "https"; + context.Request.Host = new HostString("localhost"); + context.Request.Path = "/"; + context.Response.Body = new MemoryStream(); + return context; + } + + private sealed class RedirectingPage : ComponentBase + { + private bool _loaded; + + protected override async Task OnInitializedAsync() + { + // Yield so the children below are added by a later re-render. A redirect during the initial + // synchronous render propagates out of BeginRenderingComponent instead of abandoning a diff. + await Task.Yield(); + _loaded = true; + } + + protected override void BuildRenderTree(RenderTreeBuilder builder) + { + if (_loaded) + { + AddRedirectingChildren(builder, sequence: 0); + } + } + } + + private sealed class RedirectingFormPage : ComponentBase + { + public const string FormName = "submit-form"; + + private bool _submitted; + + protected override void BuildRenderTree(RenderTreeBuilder builder) + { + builder.OpenElement(0, "form"); + builder.AddAttribute(1, "method", "post"); + builder.AddAttribute(2, "onsubmit", EventCallback.Factory.Create(this, () => { _submitted = true; })); + builder.AddNamedEvent("onsubmit", FormName); + builder.CloseElement(); + + if (_submitted) + { + AddRedirectingChildren(builder, sequence: 3); + } + } + } + + private static void AddRedirectingChildren(RenderTreeBuilder builder, int sequence) + { + builder.OpenComponent(sequence); + builder.CloseComponent(); + builder.OpenComponent(sequence + 1); + builder.CloseComponent(); + } + + private sealed class RedirectingChild : ComponentBase + { + [Inject] public NavigationManager Navigation { get; set; } = default!; + + protected override void OnInitialized() + => Navigation.NavigateTo("/redirected"); + } + + // Never gets initialized: the preceding sibling redirects while the parent's children are being created. + private sealed class UninitializedSibling : ComponentBase; + [Fact] public async Task Invoker_RejectsPostRequestsWithNonFormDataContentTypesAsync() { diff --git a/src/Components/test/E2ETest/Tests/AuthTest.cs b/src/Components/test/E2ETest/Tests/AuthTest.cs index ead4a3be97c3..152e5c55919b 100644 --- a/src/Components/test/E2ETest/Tests/AuthTest.cs +++ b/src/Components/test/E2ETest/Tests/AuthTest.cs @@ -21,6 +21,7 @@ public class AuthTest : ServerTestBase protected const string PageRequiringAuthorization = "Page requiring any authentication"; protected const string PageRequiringPolicy = "Page requiring policy"; protected const string PageRequiringRole = "Page requiring role"; + protected const string PageRequiringSlowAsyncPolicy = "Page requiring slow async policy"; public AuthTest( BrowserFixture browserFixture, @@ -220,6 +221,30 @@ public void Router_RequireRole_NotAuthorized() AssertExpectedLayoutUsed(); } + [Fact] + public void Router_SupersededAuthorizationResultIsNotAppliedToNewPage() + { + // A single AuthorizeRouteView reuses one inner component instance for every route, so an + // authorization result computed for one page must never be applied to another. + SignInAs("Bert", "IrrelevantRole"); + var appElement = MountAndNavigateToAuthTest(PageRequiringSlowAsyncPolicy); + + Browser.Contains("Authorizing", () => appElement.Text); + Browser.DoesNotExist(By.CssSelector("#slow-auth-success")); + + appElement.FindElement(By.LinkText(PageRequiringRole)).Click(); + Browser.Equal("Sorry, Bert, you're not authorized.", () => + appElement.FindElement(By.CssSelector("#auth-failure")).Text); + + appElement.FindElement(By.Id("release-slow-auth")).Click(); + Browser.Equal("True", () => appElement.FindElement(By.Id("slow-auth-settled")).Text); + + Browser.Equal("Sorry, Bert, you're not authorized.", () => + appElement.FindElement(By.CssSelector("#auth-failure")).Text); + Browser.DoesNotExist(By.CssSelector("#slow-auth-success")); + AssertExpectedLayoutUsed(); + } + private void AssertExpectedLayoutUsed() { Browser.Exists(By.Id("auth-links")); diff --git a/src/Components/test/testassets/BasicTestApp/AuthTest/AsyncAuthorizationGate.cs b/src/Components/test/testassets/BasicTestApp/AuthTest/AsyncAuthorizationGate.cs new file mode 100644 index 000000000000..fc4f7d7e1f30 --- /dev/null +++ b/src/Components/test/testassets/BasicTestApp/AuthTest/AsyncAuthorizationGate.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace BasicTestApp.AuthTest; + +// Test controlled gate that holds an authorization policy in the pending state until the test releases it, +// so that a navigation can be made while an authorization evaluation is still outstanding. +public sealed class AsyncAuthorizationGate +{ + private TaskCompletionSource _gate = Create(); + + private static TaskCompletionSource Create() + => new(TaskCreationOptions.RunContinuationsAsynchronously); + + public int StartedEvaluations { get; private set; } + + public int CompletedEvaluations { get; private set; } + + public bool IsSettled => StartedEvaluations > 0 && CompletedEvaluations == StartedEvaluations; + + public event Action OnProgressChanged; + + public void Reset() + { + var previousGate = _gate; + _gate = Create(); + previousGate.TrySetResult(); + StartedEvaluations = 0; + CompletedEvaluations = 0; + } + + public async Task WaitAsync() + { + StartedEvaluations++; + OnProgressChanged?.Invoke(); + + await _gate.Task; + + CompletedEvaluations++; + OnProgressChanged?.Invoke(); + + return true; + } + + public void Release() => _gate.TrySetResult(); +} diff --git a/src/Components/test/testassets/BasicTestApp/AuthTest/AuthRouterLayout.razor b/src/Components/test/testassets/BasicTestApp/AuthTest/AuthRouterLayout.razor index 6aa01df1f0f0..7282c9702234 100644 --- a/src/Components/test/testassets/BasicTestApp/AuthTest/AuthRouterLayout.razor +++ b/src/Components/test/testassets/BasicTestApp/AuthTest/AuthRouterLayout.razor @@ -1,4 +1,7 @@ @inherits LayoutComponentBase +@using Microsoft.Extensions.DependencyInjection +@implements IDisposable +@inject IServiceProvider Services @Body @@ -11,6 +14,43 @@
  • Page requiring any authentication
  • Page requiring policy
  • Page requiring role
  • +
  • Page requiring slow async policy
  • + +@if (_gate is not null) +{ + + @_gate.IsSettled +} + +

    To change the underlying authentication state, go here.

    + + +@code { + private AsyncAuthorizationGate _gate; + + protected override void OnInitialized() + { + // Optional, because not every host that renders this layout registers the gate. + _gate = Services.GetService(); + + if (_gate is not null) + { + _gate.Reset(); + _gate.OnProgressChanged += OnProgressChanged; + } + } + + private void OnProgressChanged() + => InvokeAsync(StateHasChanged); + + public void Dispose() + { + if (_gate is not null) + { + _gate.OnProgressChanged -= OnProgressChanged; + } + } +} diff --git a/src/Components/test/testassets/BasicTestApp/AuthTest/PageRequiringSlowAsyncPolicy.razor b/src/Components/test/testassets/BasicTestApp/AuthTest/PageRequiringSlowAsyncPolicy.razor new file mode 100644 index 000000000000..0c3b6badf757 --- /dev/null +++ b/src/Components/test/testassets/BasicTestApp/AuthTest/PageRequiringSlowAsyncPolicy.razor @@ -0,0 +1,4 @@ +@page "/PageRequiringSlowAsyncPolicy" +@using Microsoft.AspNetCore.Authorization +@attribute [Authorize(Policy = "SlowPolicyRequiringGate")] +
    Welcome to PageRequiringSlowAsyncPolicy!
    diff --git a/src/Components/test/testassets/BasicTestApp/Program.cs b/src/Components/test/testassets/BasicTestApp/Program.cs index 66b0ad80266f..e9619b663afe 100644 --- a/src/Components/test/testassets/BasicTestApp/Program.cs +++ b/src/Components/test/testassets/BasicTestApp/Program.cs @@ -37,12 +37,18 @@ public static async Task Main(string[] args) javaScriptInitializer: "myJsRootComponentInitializers.testInitializer"); builder.RootComponents.RegisterCustomElement("my-custom-element"); + var authorizationGate = new AsyncAuthorizationGate(); + builder.Services.AddSingleton(authorizationGate); + builder.Services.AddSingleton(new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); builder.Services.AddSingleton(); builder.Services.AddAuthorizationCore(options => { options.AddPolicy("NameMustStartWithB", policy => policy.RequireAssertion(ctx => ctx.User.Identity.Name?.StartsWith('B') ?? false)); + + options.AddPolicy("SlowPolicyRequiringGate", policy => + policy.RequireAssertion(_ => authorizationGate.WaitAsync())); }); builder.Services.AddScoped(); diff --git a/src/Components/test/testassets/Components.TestServer/AuthenticationStartup.cs b/src/Components/test/testassets/Components.TestServer/AuthenticationStartup.cs index f56b1f6d8070..5b3e9162c047 100644 --- a/src/Components/test/testassets/Components.TestServer/AuthenticationStartup.cs +++ b/src/Components/test/testassets/Components.TestServer/AuthenticationStartup.cs @@ -27,11 +27,19 @@ public void ConfigureServices(IServiceCollection services) services.AddServerSideBlazor(); + // Interactive host registers the gate so the authorization interleaving E2E test controls + // settling deterministically. + var authorizationGate = new BasicTestApp.AuthTest.AsyncAuthorizationGate(); + services.AddSingleton(authorizationGate); + services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(); services.AddAuthorization(options => { options.AddPolicy("NameMustStartWithB", policy => policy.RequireAssertion(ctx => ctx.User.Identity.Name?.StartsWith('B') ?? false)); + + options.AddPolicy("SlowPolicyRequiringGate", policy => + policy.RequireAssertion(_ => authorizationGate.WaitAsync())); }); } diff --git a/src/Http/WebUtilities/perf/Microbenchmarks/FormPipeReaderInternalsBenchmark.cs b/src/Http/WebUtilities/perf/Microbenchmarks/FormPipeReaderInternalsBenchmark.cs index fc3137bff938..a113757d7927 100644 --- a/src/Http/WebUtilities/perf/Microbenchmarks/FormPipeReaderInternalsBenchmark.cs +++ b/src/Http/WebUtilities/perf/Microbenchmarks/FormPipeReaderInternalsBenchmark.cs @@ -29,7 +29,8 @@ public void ReadUtf8Data() var buffer = new ReadOnlySequence(_singleUtf8); KeyValueAccumulator accum = default; - _formPipeReader.ParseFormValues(ref buffer, ref accum, isFinalBlock: true); + long scannedLength = 0; + _formPipeReader.ParseFormValues(ref buffer, ref accum, ref scannedLength, isFinalBlock: true); } [Benchmark] @@ -38,6 +39,7 @@ public void ReadUtf8MultipleBlockData() var buffer = ReadOnlySequenceFactory.CreateSegments(_firstUtf8, _secondUtf8); KeyValueAccumulator accum = default; - _formPipeReader.ParseFormValues(ref buffer, ref accum, isFinalBlock: true); + long scannedLength = 0; + _formPipeReader.ParseFormValues(ref buffer, ref accum, ref scannedLength, isFinalBlock: true); } } diff --git a/src/Http/WebUtilities/src/FileBufferingReadStream.cs b/src/Http/WebUtilities/src/FileBufferingReadStream.cs index a3ac636dee3c..7119fa04ed40 100644 --- a/src/Http/WebUtilities/src/FileBufferingReadStream.cs +++ b/src/Http/WebUtilities/src/FileBufferingReadStream.cs @@ -26,7 +26,6 @@ public class FileBufferingReadStream : Stream private string? _tempFileName; private Stream _buffer; - private byte[]? _rentedBuffer; private bool _inMemory = true; private bool _completelyBuffered; @@ -79,9 +78,7 @@ public FileBufferingReadStream( _bytePool = bytePool; if (memoryThreshold <= _maxRentedBufferSize) { - _rentedBuffer = bytePool.Rent(memoryThreshold); - _buffer = new MemoryStream(_rentedBuffer); - _buffer.SetLength(0); + _buffer = new PooledMemoryStream(bytePool, memoryThreshold); } else { @@ -131,9 +128,7 @@ public FileBufferingReadStream( _bytePool = bytePool; if (memoryThreshold <= _maxRentedBufferSize) { - _rentedBuffer = bytePool.Rent(memoryThreshold); - _buffer = new MemoryStream(_rentedBuffer); - _buffer.SetLength(0); + _buffer = new PooledMemoryStream(bytePool, memoryThreshold); } else { @@ -277,31 +272,33 @@ public override int Read(Span buffer) _inMemory = false; var oldBuffer = _buffer; _buffer = CreateTempFile(); - if (_rentedBuffer == null) + + using (oldBuffer) { - // Copy data from the in memory buffer to the file stream using a pooled buffer - oldBuffer.Position = 0; - var rentedBuffer = _bytePool.Rent(Math.Min((int)oldBuffer.Length, _maxRentedBufferSize)); - try + if (oldBuffer is PooledMemoryStream pooledBuffer) { - var copyRead = oldBuffer.Read(rentedBuffer); - while (copyRead > 0) - { - _buffer.Write(rentedBuffer.AsSpan(0, copyRead)); - copyRead = oldBuffer.Read(rentedBuffer); - } + _buffer.Write(pooledBuffer.WrittenMemory.Span); } - finally + else { - _bytePool.Return(rentedBuffer); + // Copy data from the in memory buffer to the file stream using a pooled buffer + oldBuffer.Position = 0; + var rentedBuffer = _bytePool.Rent(Math.Min((int)oldBuffer.Length, _maxRentedBufferSize)); + try + { + var copyRead = oldBuffer.Read(rentedBuffer); + while (copyRead > 0) + { + _buffer.Write(rentedBuffer.AsSpan(0, copyRead)); + copyRead = oldBuffer.Read(rentedBuffer); + } + } + finally + { + _bytePool.Return(rentedBuffer); + } } } - else - { - _buffer.Write(_rentedBuffer.AsSpan(0, (int)oldBuffer.Length)); - _bytePool.Return(_rentedBuffer); - _rentedBuffer = null; - } } if (read > 0) @@ -353,31 +350,33 @@ public override async ValueTask ReadAsync(Memory buffer, Cancellation _inMemory = false; var oldBuffer = _buffer; _buffer = CreateTempFile(); - if (_rentedBuffer == null) + + using (oldBuffer) { - oldBuffer.Position = 0; - var rentedBuffer = _bytePool.Rent(Math.Min((int)oldBuffer.Length, _maxRentedBufferSize)); - try + if (oldBuffer is PooledMemoryStream pooledBuffer) { - // oldBuffer is a MemoryStream, no need to do async reads. - var copyRead = oldBuffer.Read(rentedBuffer); - while (copyRead > 0) - { - await _buffer.WriteAsync(rentedBuffer.AsMemory(0, copyRead), cancellationToken); - copyRead = oldBuffer.Read(rentedBuffer); - } + await _buffer.WriteAsync(pooledBuffer.WrittenMemory, cancellationToken); } - finally + else { - _bytePool.Return(rentedBuffer); + oldBuffer.Position = 0; + var rentedBuffer = _bytePool.Rent(Math.Min((int)oldBuffer.Length, _maxRentedBufferSize)); + try + { + // oldBuffer is a MemoryStream, no need to do async reads. + var copyRead = oldBuffer.Read(rentedBuffer); + while (copyRead > 0) + { + await _buffer.WriteAsync(rentedBuffer.AsMemory(0, copyRead), cancellationToken); + copyRead = oldBuffer.Read(rentedBuffer); + } + } + finally + { + _bytePool.Return(rentedBuffer); + } } } - else - { - await _buffer.WriteAsync(_rentedBuffer.AsMemory(0, (int)oldBuffer.Length), cancellationToken); - _bytePool.Return(_rentedBuffer); - _rentedBuffer = null; - } } if (read > 0) @@ -468,11 +467,6 @@ protected override void Dispose(bool disposing) if (!_disposed) { _disposed = true; - if (_rentedBuffer != null) - { - _bytePool.Return(_rentedBuffer); - } - if (disposing) { _buffer.Dispose(); @@ -486,11 +480,6 @@ public override async ValueTask DisposeAsync() if (!_disposed) { _disposed = true; - if (_rentedBuffer != null) - { - _bytePool.Return(_rentedBuffer); - } - await _buffer.DisposeAsync(); } } diff --git a/src/Http/WebUtilities/src/FormPipeReader.cs b/src/Http/WebUtilities/src/FormPipeReader.cs index 7e2c8ede417a..56ddc1aa928f 100644 --- a/src/Http/WebUtilities/src/FormPipeReader.cs +++ b/src/Http/WebUtilities/src/FormPipeReader.cs @@ -91,6 +91,7 @@ public FormPipeReader(PipeReader pipeReader, Encoding encoding) public async Task> ReadFormAsync(CancellationToken cancellationToken = default) { KeyValueAccumulator accumulator = default; + long scannedLength = 0; while (true) { var readResult = await _pipeReader.ReadAsync(cancellationToken); @@ -101,7 +102,7 @@ public async Task> ReadFormAsync(CancellationTo { try { - ParseFormValues(ref buffer, ref accumulator, readResult.IsCompleted); + ParseFormValues(ref buffer, ref accumulator, ref scannedLength, readResult.IsCompleted); } catch { @@ -131,27 +132,24 @@ public async Task> ReadFormAsync(CancellationTo internal void ParseFormValues( ref ReadOnlySequence buffer, ref KeyValueAccumulator accumulator, + ref long scannedLength, bool isFinalBlock) { if (buffer.IsSingleSegment) { - ParseFormValuesFast(buffer.FirstSpan, - ref accumulator, - isFinalBlock, - out var consumed); + ParseFormValuesFast(buffer.FirstSpan, ref accumulator, ref scannedLength, isFinalBlock, out var consumed); buffer = buffer.Slice(consumed); return; } - ParseValuesSlow(ref buffer, - ref accumulator, - isFinalBlock); + ParseValuesSlow(ref buffer, ref accumulator, ref scannedLength, isFinalBlock); } // Fast parsing for single span in ReadOnlySequence private void ParseFormValuesFast(ReadOnlySpan span, ref KeyValueAccumulator accumulator, + ref long scannedLength, bool isFinalBlock, out int consumed) { @@ -161,10 +159,17 @@ private void ParseFormValuesFast(ReadOnlySpan span, var equalsDelimiter = GetEqualsForEncoding(); var andDelimiter = GetAndForEncoding(); + // The delimiter can span multiple bytes (e.g. UTF-16/UTF-32), so it may straddle the end of a read. + // 'scannedLength' therefore never covers the last delimiterOverlap bytes, which have to be rescanned. + var delimiterOverlap = andDelimiter.Length - 1; + while (span.Length > 0) { // Find the end of the key=value pair. - var ampersand = span.IndexOf(andDelimiter); + // Start the search from the scannedLength to avoid rescanning bytes we already scanned + var searchStart = (int)Math.Min(scannedLength, span.Length); + var ampersandRelative = span[searchStart..].IndexOf(andDelimiter); + var ampersand = ampersandRelative == -1 ? -1 : ampersandRelative + searchStart; ReadOnlySpan keyValuePair; int equals; var foundAmpersand = ampersand != -1; @@ -174,6 +179,8 @@ private void ParseFormValuesFast(ReadOnlySpan span, keyValuePair = span.Slice(0, ampersand); span = span.Slice(keyValuePair.Length + andDelimiter.Length); consumed += keyValuePair.Length + andDelimiter.Length; + // Reset: the new span starts fresh, nothing pre-scanned. + scannedLength = 0; } else { @@ -186,12 +193,17 @@ private void ParseFormValuesFast(ReadOnlySpan span, { ThrowKeyOrValueTooLargeException(); } + // Record how far we've scanned so the next call skips these bytes. The trailing + // delimiterOverlap bytes are left out: a multi-byte delimiter could start there and + // only be completed by the bytes that arrive next. + scannedLength = Math.Max(0, span.Length - delimiterOverlap); return; } keyValuePair = span; span = default; consumed += keyValuePair.Length; + scannedLength = 0; } equals = keyValuePair.IndexOf(equalsDelimiter); @@ -234,6 +246,7 @@ private void ParseFormValuesFast(ReadOnlySpan span, private void ParseValuesSlow( ref ReadOnlySequence buffer, ref KeyValueAccumulator accumulator, + ref long scannedLength, bool isFinalBlock) { var sequenceReader = new SequenceReader(buffer); @@ -244,7 +257,17 @@ private void ParseValuesSlow( var equalsDelimiter = GetEqualsForEncoding(); var andDelimiter = GetAndForEncoding(); - while (!sequenceReader.End) + // 'scannedLength' already excludes the trailing bytes a multi-byte delimiter could have started in, + // so everything it covers can be skipped outright. + var resumeSkipped = Math.Min(scannedLength, sequenceReader.Length); + if (resumeSkipped > 0) + { + sequenceReader.Advance(resumeSkipped); + } + + // Advancing can place the reader at the end when everything buffered was already scanned. + // Those bytes are still unconsumed, so on the final block they must be parsed as the last pair. + while (!sequenceReader.End || (isFinalBlock && consumedBytes < sequenceReader.Length)) { if (!sequenceReader.TryReadTo(out keyValuePair, andDelimiter)) { @@ -255,17 +278,31 @@ private void ParseValuesSlow( { ThrowKeyOrValueTooLargeException(); } + + // Record total bytes scanned from 'consumed' so next call skips them, minus the trailing + // bytes a multi-byte delimiter could have started in. + scannedLength = Math.Max(0, sequenceReader.Length - consumedBytes - (andDelimiter.Length - 1)); break; } - // This must be the final key=value pair - keyValuePair = buffer.Slice(sequenceReader.Position); - sequenceReader.Advance(keyValuePair.Length); + // This must be the final key=value pair; take everything from the last consumed position. + keyValuePair = buffer.Slice(consumed); + sequenceReader.Advance(sequenceReader.Remaining); + } + else if (resumeSkipped > 0) + { + // TryReadTo only returned [resumeSkipped..'&'). Reconstruct the full pair + // [consumed..'&') by prepending the already-scanned prefix. + keyValuePair = buffer.Slice(consumed, resumeSkipped + keyValuePair.Length); } + scannedLength = 0; + resumeSkipped = 0; + if (keyValuePair.IsSingleSegment) { - ParseFormValuesFast(keyValuePair.FirstSpan, ref accumulator, isFinalBlock: true, out var segmentConsumed); + var segmentScannedLength = 0L; + ParseFormValuesFast(keyValuePair.FirstSpan, ref accumulator, ref segmentScannedLength, isFinalBlock: true, out var segmentConsumed); Debug.Assert(segmentConsumed == keyValuePair.FirstSpan.Length); consumedBytes = sequenceReader.Consumed; consumed = sequenceReader.Position; diff --git a/src/Http/WebUtilities/src/Microsoft.AspNetCore.WebUtilities.csproj b/src/Http/WebUtilities/src/Microsoft.AspNetCore.WebUtilities.csproj index 71315fb0da74..7943b10ba66f 100644 --- a/src/Http/WebUtilities/src/Microsoft.AspNetCore.WebUtilities.csproj +++ b/src/Http/WebUtilities/src/Microsoft.AspNetCore.WebUtilities.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Http/WebUtilities/test/FileBufferingReadStreamTests.cs b/src/Http/WebUtilities/test/FileBufferingReadStreamTests.cs index 51ec5de92648..211ca3be1db7 100644 --- a/src/Http/WebUtilities/test/FileBufferingReadStreamTests.cs +++ b/src/Http/WebUtilities/test/FileBufferingReadStreamTests.cs @@ -458,6 +458,54 @@ public async Task FileBufferingReadStream_UsingMemoryStream_RentsAndReturnsRente Assert.False(File.Exists(tempFileName)); } + [Fact] + public async Task FileBufferingReadStream_UsingPooledMemoryStream_RentsLazilyAndGrows() + { + var inner = MakeStream(10); + var rentedSizes = new List(); + var returnedBuffers = new List(); + var arrayPool = new Mock>(); + arrayPool.Setup(p => p.Rent(It.IsAny())) + .Returns((int size) => + { + rentedSizes.Add(size); + return new byte[size]; + }); + arrayPool.Setup(p => p.Return(It.IsAny(), It.IsAny())) + .Callback((byte[] bytes, bool clear) => returnedBuffers.Add(bytes)); + + await using (var stream = new FileBufferingReadStream(inner, 16, bufferLimit: null, GetCurrentDirectory(), arrayPool.Object)) + { + Assert.Empty(rentedSizes); + + var buffer = new byte[4]; + Assert.Equal(4, await stream.ReadAsync(buffer)); + Assert.Equal([4], rentedSizes); + Assert.Empty(returnedBuffers); + + Assert.Equal(4, await stream.ReadAsync(buffer)); + Assert.Equal([4, 8], rentedSizes); + Assert.Single(returnedBuffers); + + Assert.Equal(2, await stream.ReadAsync(buffer)); + Assert.Equal([4, 8, 16], rentedSizes); + Assert.Equal(2, returnedBuffers.Count); + } + + Assert.Equal(3, returnedBuffers.Count); + } + + [Fact] + public async Task FileBufferingReadStream_UsingPooledMemoryStream_DoesNotRentForEmptyContent() + { + var inner = MakeStream(0); + var arrayPool = new Mock>(MockBehavior.Strict); + + await using var stream = new FileBufferingReadStream(inner, 16, bufferLimit: null, GetCurrentDirectory(), arrayPool.Object); + + Assert.Equal(0, await stream.ReadAsync(new byte[4])); + } + [Fact] public async Task CopyToAsyncWorks() { diff --git a/src/Http/WebUtilities/test/FormPipeReaderTests.cs b/src/Http/WebUtilities/test/FormPipeReaderTests.cs index dac33ec25aac..1b7a33ea0d17 100644 --- a/src/Http/WebUtilities/test/FormPipeReaderTests.cs +++ b/src/Http/WebUtilities/test/FormPipeReaderTests.cs @@ -216,6 +216,7 @@ public void ReadFormAsync_ChunkedDataNoDelimiter_ThrowsEarly() var bytes = CreateBytes_NoDelimiter(10 * 1024); var readOnlySequence = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(bytes); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var valueLengthLimit = 1024; var keyLengthLimit = 10; var formReader = new FormPipeReader(null!) @@ -224,7 +225,7 @@ public void ReadFormAsync_ChunkedDataNoDelimiter_ThrowsEarly() KeyLengthLimit = keyLengthLimit }; var exception = Assert.Throws( - () => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: false)); + () => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: false)); // Make sure that FormPipeReader throws an exception after hitting KeyLengthLimit + ValueLengthLimit, // Rather than after reading the entire request. Assert.Equal(string.Format( @@ -258,9 +259,10 @@ public void TryParseFormValues_SingleSegmentWorks(Encoding encoding) var readOnlySequence = new ReadOnlySequence(encoding.GetBytes("foo=bar&baz=boo")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!, encoding); - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true); + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true); Assert.True(readOnlySequence.IsEmpty); Assert.Equal(2, accumulator.KeyCount); @@ -276,9 +278,10 @@ public void TryParseFormValues_Works(Encoding encoding) var readOnlySequence = ReadOnlySequenceFactory.SingleSegmentFactory.CreateWithContent(encoding.GetBytes("foo=bar&baz=boo&t=")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!, encoding); - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true); + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true); Assert.True(readOnlySequence.IsEmpty); Assert.Equal(3, accumulator.KeyCount); @@ -295,13 +298,21 @@ public void TryParseFormValues_LimitsCanBeLarge(Encoding encoding) var readOnlySequence = ReadOnlySequenceFactory.SingleSegmentFactory.CreateWithContent(encoding.GetBytes("foo=bar&baz=boo&t=")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!, encoding); formReader.KeyLengthLimit = int.MaxValue; formReader.ValueLengthLimit = int.MaxValue; - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: false); - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true); + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: false); + + // The trailing "t=" has no delimiter yet, so it stays buffered and is scanned except for the + // trailing bytes a multi-byte '&' could have started in. + var delimiterOverlap = encoding.GetBytes("&").Length - 1; + Assert.Equal(readOnlySequence.Length - delimiterOverlap, scannedLength); + + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true); Assert.True(readOnlySequence.IsEmpty); + Assert.Equal(0L, scannedLength); Assert.Equal(3, accumulator.KeyCount); var dict = accumulator.GetResults(); @@ -317,9 +328,10 @@ public void TryParseFormValues_SplitAcrossSegmentsWorks(Encoding encoding) var readOnlySequence = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(encoding.GetBytes("foo=bar&baz=boo&t=")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!, encoding); - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true); + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true); Assert.True(readOnlySequence.IsEmpty); Assert.Equal(3, accumulator.KeyCount); @@ -336,13 +348,21 @@ public void TryParseFormValues_SplitAcrossSegmentsWorks_LimitsCanBeLarge(Encodin var readOnlySequence = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(encoding.GetBytes("foo=bar&baz=boo&t=")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!, encoding); formReader.KeyLengthLimit = int.MaxValue; formReader.ValueLengthLimit = int.MaxValue; - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: false); - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true); + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: false); + + // The trailing "t=" has no delimiter yet, so it stays buffered and is scanned except for the + // trailing bytes a multi-byte '&' could have started in. + var delimiterOverlap = encoding.GetBytes("&").Length - 1; + Assert.Equal(readOnlySequence.Length - delimiterOverlap, scannedLength); + + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true); Assert.True(readOnlySequence.IsEmpty); + Assert.Equal(0L, scannedLength); Assert.Equal(3, accumulator.KeyCount); var dict = accumulator.GetResults(); @@ -358,9 +378,10 @@ public void TryParseFormValues_MultiSegmentWithArrayPoolAcrossSegmentsWorks(Enco var readOnlySequence = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(encoding.GetBytes("foo=bar&baz=bo" + new string('a', 128))); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!, encoding); - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true); + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true); Assert.True(readOnlySequence.IsEmpty); Assert.Equal(2, accumulator.KeyCount); @@ -376,9 +397,10 @@ public void TryParseFormValues_MultiSegmentSplitAcrossSegmentsWithPlusesWorks(En var readOnlySequence = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(encoding.GetBytes("+++=+++&++++=++++&+=")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!, encoding); - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true); + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true); Assert.True(readOnlySequence.IsEmpty); Assert.Equal(3, accumulator.KeyCount); @@ -395,9 +417,10 @@ public void TryParseFormValues_DecodedPlusesWorks(Encoding encoding) var readOnlySequence = ReadOnlySequenceFactory.SingleSegmentFactory.CreateWithContent(encoding.GetBytes("++%2B=+++%2B&++++=++++&+=")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!, encoding); - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true); + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true); Assert.True(readOnlySequence.IsEmpty); Assert.Equal(3, accumulator.KeyCount); @@ -414,9 +437,10 @@ public void TryParseFormValues_SplitAcrossSegmentsThatNeedDecodingWorks(Encoding var readOnlySequence = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(encoding.GetBytes("\"%-.<>\\^_`{|}~=\"%-.<>\\^_`{|}~&\"%-.<>\\^_`{|}=wow")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!, encoding); - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true); + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true); Assert.True(readOnlySequence.IsEmpty); Assert.Equal(2, accumulator.KeyCount); @@ -431,9 +455,10 @@ public void TryParseFormValues_MultiSegmentFastPathWorks() var readOnlySequence = ReadOnlySequenceFactory.CreateSegments(Encoding.UTF8.GetBytes("foo=bar&"), Encoding.UTF8.GetBytes("baz=boo")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!); - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true); + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true); Assert.True(readOnlySequence.IsEmpty); Assert.Equal(2, accumulator.KeyCount); @@ -448,11 +473,12 @@ public void TryParseFormValues_ExceedKeyLengthThrows() var readOnlySequence = ReadOnlySequenceFactory.SingleSegmentFactory.CreateWithContent(Encoding.UTF8.GetBytes("foo=bar&baz=boo&t=")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!); formReader.KeyLengthLimit = 2; - var exception = Assert.Throws(() => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true)); + var exception = Assert.Throws(() => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true)); Assert.Equal("Form key length limit 2 exceeded.", exception.Message); } @@ -462,11 +488,12 @@ public void TryParseFormValues_ExceedKeyLengthThrowsInSplitSegment() var readOnlySequence = ReadOnlySequenceFactory.CreateSegments(Encoding.UTF8.GetBytes("fo=bar&ba"), Encoding.UTF8.GetBytes("z=boo&t=")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!); formReader.KeyLengthLimit = 2; - var exception = Assert.Throws(() => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true)); + var exception = Assert.Throws(() => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true)); Assert.Equal("Form key length limit 2 exceeded.", exception.Message); } @@ -476,11 +503,12 @@ public void TryParseFormValues_ExceedValueLengthThrows() var readOnlySequence = ReadOnlySequenceFactory.CreateSegments(Encoding.UTF8.GetBytes("foo=bar&baz=boo&t=")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!); formReader.ValueLengthLimit = 2; - var exception = Assert.Throws(() => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true)); + var exception = Assert.Throws(() => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true)); Assert.Equal("Form value length limit 2 exceeded.", exception.Message); } @@ -490,11 +518,12 @@ public void TryParseFormValues_ExceedValueLengthThrowsInSplitSegment() var readOnlySequence = ReadOnlySequenceFactory.CreateSegments(Encoding.UTF8.GetBytes("foo=ba&baz=bo"), Encoding.UTF8.GetBytes("o&t=")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!); formReader.ValueLengthLimit = 2; - var exception = Assert.Throws(() => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true)); + var exception = Assert.Throws(() => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true)); Assert.Equal("Form value length limit 2 exceeded.", exception.Message); } @@ -504,11 +533,12 @@ public void TryParseFormValues_ExceedKeyLengthThrowsInSplitSegmentEnd() var readOnlySequence = ReadOnlySequenceFactory.CreateSegments(Encoding.UTF8.GetBytes("foo=ba&baz=bo"), Encoding.UTF8.GetBytes("o&asdfasdfasd=")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!); formReader.KeyLengthLimit = 10; - var exception = Assert.Throws(() => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true)); + var exception = Assert.Throws(() => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true)); Assert.Equal("Form key length limit 10 exceeded.", exception.Message); } @@ -518,11 +548,12 @@ public void TryParseFormValues_ExceedValueLengthThrowsInSplitSegmentEnd() var readOnlySequence = ReadOnlySequenceFactory.CreateSegments(Encoding.UTF8.GetBytes("foo=ba&baz=bo"), Encoding.UTF8.GetBytes("o&t=asdfasdfasd")); KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!); formReader.ValueLengthLimit = 10; - var exception = Assert.Throws(() => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true)); + var exception = Assert.Throws(() => formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true)); Assert.Equal("Form value length limit 10 exceeded.", exception.Message); } @@ -549,13 +580,14 @@ public async Task ResetPipeWorks() public void ParseFormWithIncompleteKeyWhenIsFinalBlockSucceeds(ReadOnlySequence readOnlySequence) { KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!) { KeyLengthLimit = 3 }; - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true); + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true); Assert.True(readOnlySequence.IsEmpty); IDictionary values = accumulator.GetResults(); @@ -570,13 +602,14 @@ public void ParseFormWithIncompleteKeyWhenIsFinalBlockSucceeds(ReadOnlySequence< public void ParseFormWithIncompleteValueWhenIsFinalBlockSucceeds(ReadOnlySequence readOnlySequence) { KeyValueAccumulator accumulator = default; + long scannedLength = 0; var formReader = new FormPipeReader(null!) { ValueLengthLimit = 3 }; - formReader.ParseFormValues(ref readOnlySequence, ref accumulator, isFinalBlock: true); + formReader.ParseFormValues(ref readOnlySequence, ref accumulator, ref scannedLength, isFinalBlock: true); Assert.True(readOnlySequence.IsEmpty); IDictionary values = accumulator.GetResults(); @@ -596,6 +629,284 @@ public async Task ReadFormAsync_AccumulatesEmptyKeys() Assert.Single(formCollection); } + [Fact] + public void ParseFormValues_SingleSegment_IncrementalReads_ScansEachByteOnce() + { + var data = Encoding.UTF8.GetBytes("foo=bar&baz=boo"); + KeyValueAccumulator accumulator = default; + var formReader = new FormPipeReader(null!); + long scannedLength = 0; + var consumedOffset = 0; + long totalBytesScanned = 0; + + // Simulate a PipeReader delivering a single byte per read + for (var i = 1; i <= data.Length; i++) + { + var buffer = new ReadOnlySequence(data, consumedOffset, i - consumedOffset); + var lengthBefore = (int)buffer.Length; + + // Only the bytes that were not already scanned should be searched for '&'. + totalBytesScanned += lengthBefore - scannedLength; + + formReader.ParseFormValues(ref buffer, ref accumulator, ref scannedLength, isFinalBlock: false); + + consumedOffset += lengthBefore - (int)buffer.Length; + + // Everything still buffered has been scanned, so the next read resumes at its end. + Assert.Equal(buffer.Length, scannedLength); + } + + Assert.Equal(data.Length, totalBytesScanned); + Assert.Equal("foo=bar&".Length, consumedOffset); + + var finalBuffer = new ReadOnlySequence(data, consumedOffset, data.Length - consumedOffset); + formReader.ParseFormValues(ref finalBuffer, ref accumulator, ref scannedLength, isFinalBlock: true); + + Assert.True(finalBuffer.IsEmpty); + Assert.Equal(0L, scannedLength); + + var dict = accumulator.GetResults(); + Assert.Equal("bar", dict["foo"]); + Assert.Equal("boo", dict["baz"]); + } + + [Fact] + public void ParseFormValues_MultiSegment_IncrementalReads_ScansEachByteOnce() + { + var data = Encoding.UTF8.GetBytes("foo=bar&baz=boo"); + KeyValueAccumulator accumulator = default; + var formReader = new FormPipeReader(null!); + long scannedLength = 0; + var consumedOffset = 0; + long totalBytesScanned = 0; + + for (var i = 1; i <= data.Length; i++) + { + var buffer = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(data.AsSpan(consumedOffset, i - consumedOffset).ToArray()); + var lengthBefore = (int)buffer.Length; + + totalBytesScanned += lengthBefore - scannedLength; + + formReader.ParseFormValues(ref buffer, ref accumulator, ref scannedLength, isFinalBlock: false); + + consumedOffset += lengthBefore - (int)buffer.Length; + + Assert.Equal(buffer.Length, scannedLength); + } + + Assert.Equal(data.Length, totalBytesScanned); + Assert.Equal("foo=bar&".Length, consumedOffset); + + var finalBuffer = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(data.AsSpan(consumedOffset).ToArray()); + formReader.ParseFormValues(ref finalBuffer, ref accumulator, ref scannedLength, isFinalBlock: true); + + Assert.True(finalBuffer.IsEmpty); + Assert.Equal(0L, scannedLength); + + var dict = accumulator.GetResults(); + Assert.Equal("bar", dict["foo"]); + Assert.Equal("boo", dict["baz"]); + } + + [Fact] + public void ParseFormValues_SingleSegment_ResumedScanParsesWholeKeyValuePair() + { + KeyValueAccumulator accumulator = default; + var formReader = new FormPipeReader(null!); + long scannedLength = 0; + + var partial = new ReadOnlySequence(Encoding.UTF8.GetBytes("foo=ba")); + formReader.ParseFormValues(ref partial, ref accumulator, ref scannedLength, isFinalBlock: false); + + Assert.Equal(6L, scannedLength); + Assert.Equal(6, partial.Length); + Assert.Equal(0, accumulator.KeyCount); + + // The delimiter arrives after the already scanned bytes; the key/value before it must still be parsed. + var complete = new ReadOnlySequence(Encoding.UTF8.GetBytes("foo=bar&baz=boo")); + formReader.ParseFormValues(ref complete, ref accumulator, ref scannedLength, isFinalBlock: false); + + Assert.Equal(1, accumulator.KeyCount); + Assert.Equal("baz=boo".Length, complete.Length); + Assert.Equal(complete.Length, scannedLength); + + formReader.ParseFormValues(ref complete, ref accumulator, ref scannedLength, isFinalBlock: true); + + Assert.True(complete.IsEmpty); + var dict = accumulator.GetResults(); + Assert.Equal("bar", dict["foo"]); + Assert.Equal("boo", dict["baz"]); + } + + [Fact] + public void ParseFormValues_MultiSegment_ResumedScanParsesWholeKeyValuePair() + { + KeyValueAccumulator accumulator = default; + var formReader = new FormPipeReader(null!); + long scannedLength = 0; + + var partial = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(Encoding.UTF8.GetBytes("foo=ba")); + formReader.ParseFormValues(ref partial, ref accumulator, ref scannedLength, isFinalBlock: false); + + Assert.Equal(6L, scannedLength); + Assert.Equal(6, partial.Length); + Assert.Equal(0, accumulator.KeyCount); + + var complete = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(Encoding.UTF8.GetBytes("foo=bar&baz=boo")); + formReader.ParseFormValues(ref complete, ref accumulator, ref scannedLength, isFinalBlock: false); + + Assert.Equal(1, accumulator.KeyCount); + Assert.Equal("baz=boo".Length, complete.Length); + Assert.Equal(complete.Length, scannedLength); + + formReader.ParseFormValues(ref complete, ref accumulator, ref scannedLength, isFinalBlock: true); + + Assert.True(complete.IsEmpty); + var dict = accumulator.GetResults(); + Assert.Equal("bar", dict["foo"]); + Assert.Equal("boo", dict["baz"]); + } + + [Fact] + public void ParseFormValues_ResumedScanStillEnforcesLimits() + { + var data = CreateBytes_NoDelimiter(10 * 1024); + KeyValueAccumulator accumulator = default; + var valueLengthLimit = 1024; + var keyLengthLimit = 10; + var formReader = new FormPipeReader(null!) + { + ValueLengthLimit = valueLengthLimit, + KeyLengthLimit = keyLengthLimit + }; + long scannedLength = 0; + + var exception = Assert.Throws(() => + { + for (var i = 1; i <= data.Length; i++) + { + var buffer = new ReadOnlySequence(data, 0, i); + formReader.ParseFormValues(ref buffer, ref accumulator, ref scannedLength, isFinalBlock: false); + } + }); + + Assert.Equal(string.Format( + CultureInfo.CurrentCulture, + Resources.FormPipeReader_KeyOrValueTooLarge, + keyLengthLimit, + valueLengthLimit), exception.Message); + } + + [Fact] + public async Task ReadFormAsync_ReadsDataDeliveredOneByteAtATime() + { + var content = "foo=bar&baz=" + new string('a', 1024) + "&t="; + var formContent = Encoding.UTF8.GetBytes(content); + var bodyPipe = new Pipe(); + + var writeTask = Task.Run(async () => + { + foreach (var b in formContent) + { + await bodyPipe.Writer.WriteAsync(new[] { b }); + } + await bodyPipe.Writer.CompleteAsync(); + }); + + var formCollection = await ReadFormAsync(new FormPipeReader(bodyPipe.Reader)); + await writeTask; + + Assert.Equal("bar", formCollection["foo"].ToString()); + Assert.Equal(new string('a', 1024), formCollection["baz"].ToString()); + Assert.Equal("", formCollection["t"].ToString()); + } + + [Theory] + [MemberData(nameof(Encodings))] + public void ParseFormValues_SingleSegment_IncrementalReads_DelimiterSplitAcrossReads(Encoding encoding) + { + // For UTF-16/UTF-32 the '&' delimiter spans multiple bytes, so a read can end part way through it. + var data = encoding.GetBytes("foo=bar&baz=boo&t="); + KeyValueAccumulator accumulator = default; + var formReader = new FormPipeReader(null!, encoding); + long scannedLength = 0; + var consumedOffset = 0; + long totalBytesScanned = 0; + var delimiterOverlap = encoding.GetBytes("&").Length - 1; + + for (var i = 1; i <= data.Length; i++) + { + var buffer = new ReadOnlySequence(data, consumedOffset, i - consumedOffset); + var lengthBefore = (int)buffer.Length; + + totalBytesScanned += lengthBefore - scannedLength; + + formReader.ParseFormValues(ref buffer, ref accumulator, ref scannedLength, isFinalBlock: false); + + consumedOffset += lengthBefore - (int)buffer.Length; + + // Never claim to have scanned more than what is still buffered. + Assert.InRange(scannedLength, 0, buffer.Length); + } + + // Each byte is scanned once, plus at most the delimiter overlap re-scanned per read. + Assert.InRange(totalBytesScanned, data.Length, data.Length * (1 + delimiterOverlap)); + + var finalBuffer = new ReadOnlySequence(data, consumedOffset, data.Length - consumedOffset); + formReader.ParseFormValues(ref finalBuffer, ref accumulator, ref scannedLength, isFinalBlock: true); + + Assert.True(finalBuffer.IsEmpty); + Assert.Equal(0L, scannedLength); + + Assert.Equal(3, accumulator.KeyCount); + var dict = accumulator.GetResults(); + Assert.Equal("bar", dict["foo"]); + Assert.Equal("boo", dict["baz"]); + Assert.Equal("", dict["t"]); + } + + [Theory] + [MemberData(nameof(Encodings))] + public void ParseFormValues_MultiSegment_IncrementalReads_DelimiterSplitAcrossReads(Encoding encoding) + { + var data = encoding.GetBytes("foo=bar&baz=boo&t="); + KeyValueAccumulator accumulator = default; + var formReader = new FormPipeReader(null!, encoding); + long scannedLength = 0; + var consumedOffset = 0; + long totalBytesScanned = 0; + var delimiterOverlap = encoding.GetBytes("&").Length - 1; + + for (var i = 1; i <= data.Length; i++) + { + var buffer = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(data.AsSpan(consumedOffset, i - consumedOffset).ToArray()); + var lengthBefore = (int)buffer.Length; + + totalBytesScanned += lengthBefore - scannedLength; + + formReader.ParseFormValues(ref buffer, ref accumulator, ref scannedLength, isFinalBlock: false); + + consumedOffset += lengthBefore - (int)buffer.Length; + + Assert.InRange(scannedLength, 0, buffer.Length); + } + + // Each byte is scanned once, plus at most the delimiter overlap re-scanned per read. + Assert.InRange(totalBytesScanned, data.Length, data.Length * (1 + delimiterOverlap)); + + var finalBuffer = ReadOnlySequenceFactory.SegmentPerByteFactory.CreateWithContent(data.AsSpan(consumedOffset).ToArray()); + formReader.ParseFormValues(ref finalBuffer, ref accumulator, ref scannedLength, isFinalBlock: true); + + Assert.True(finalBuffer.IsEmpty); + Assert.Equal(0L, scannedLength); + + Assert.Equal(3, accumulator.KeyCount); + var dict = accumulator.GetResults(); + Assert.Equal("bar", dict["foo"]); + Assert.Equal("boo", dict["baz"]); + Assert.Equal("", dict["t"]); + } + public static TheoryData> IncompleteFormKeys => new TheoryData> { diff --git a/src/Identity/Core/src/IdentityApiEndpointRouteBuilderExtensions.cs b/src/Identity/Core/src/IdentityApiEndpointRouteBuilderExtensions.cs index 5a1b335110da..6b050f3a60e5 100644 --- a/src/Identity/Core/src/IdentityApiEndpointRouteBuilderExtensions.cs +++ b/src/Identity/Core/src/IdentityApiEndpointRouteBuilderExtensions.cs @@ -247,7 +247,7 @@ await signInManager.ValidateSecurityStampAsync(refreshTicket.Principal) is not T endpointBuilder.Metadata.Add(new EndpointNameMetadata(confirmEmailEndpointName)); }); - routeGroup.MapPost("/resendConfirmationEmail", async Task + routeGroup.MapPost("/resendConfirmationEmail", async Task> ([FromBody] ResendConfirmationEmailRequest resendRequest, HttpContext context, [FromServices] IServiceProvider sp) => { var userManager = sp.GetRequiredService>(); @@ -256,7 +256,13 @@ await signInManager.ValidateSecurityStampAsync(refreshTicket.Principal) is not T return TypedResults.Ok(); } - await SendConfirmationEmailAsync(user, userManager, context, resendRequest.Email); + var storedEmail = await userManager.GetEmailAsync(user); + if (string.IsNullOrEmpty(storedEmail)) + { + return CreateValidationProblem("MissingEmail", "Users must have an email."); + } + + await SendConfirmationEmailAsync(user, userManager, context, storedEmail); return TypedResults.Ok(); }); @@ -268,10 +274,16 @@ await signInManager.ValidateSecurityStampAsync(refreshTicket.Principal) is not T if (user is not null && await userManager.IsEmailConfirmedAsync(user)) { + var storedEmail = await userManager.GetEmailAsync(user); + if (string.IsNullOrEmpty(storedEmail)) + { + return CreateValidationProblem("MissingEmail", "Users must have an email."); + } + var code = await userManager.GeneratePasswordResetTokenAsync(user); code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code)); - await emailSender.SendPasswordResetCodeAsync(user, resetRequest.Email, HtmlEncoder.Default.Encode(code)); + await emailSender.SendPasswordResetCodeAsync(user, storedEmail, HtmlEncoder.Default.Encode(code)); } // Don't reveal that the user does not exist or is not confirmed, so don't return a 200 if we would have diff --git a/src/Identity/UI/src/Areas/Identity/Pages/V4/Account/ForgotPassword.cshtml.cs b/src/Identity/UI/src/Areas/Identity/Pages/V4/Account/ForgotPassword.cshtml.cs index 9ef8778f352a..f8d889d3dc02 100644 --- a/src/Identity/UI/src/Areas/Identity/Pages/V4/Account/ForgotPassword.cshtml.cs +++ b/src/Identity/UI/src/Areas/Identity/Pages/V4/Account/ForgotPassword.cshtml.cs @@ -80,7 +80,13 @@ public override async Task OnPostAsync() values: new { area = "Identity", code }, protocol: Request.Scheme)!; - await _emailSender.SendPasswordResetLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl)); + var storedEmail = await _userManager.GetEmailAsync(user); + if (string.IsNullOrEmpty(storedEmail)) + { + throw new InvalidOperationException("Users must have an email."); + } + + await _emailSender.SendPasswordResetLinkAsync(user, storedEmail, HtmlEncoder.Default.Encode(callbackUrl)); return RedirectToPage("./ForgotPasswordConfirmation"); } diff --git a/src/Identity/UI/src/Areas/Identity/Pages/V4/Account/ResendEmailConfirmation.cshtml.cs b/src/Identity/UI/src/Areas/Identity/Pages/V4/Account/ResendEmailConfirmation.cshtml.cs index c0d18466ceae..7e4d0d66d3af 100644 --- a/src/Identity/UI/src/Areas/Identity/Pages/V4/Account/ResendEmailConfirmation.cshtml.cs +++ b/src/Identity/UI/src/Areas/Identity/Pages/V4/Account/ResendEmailConfirmation.cshtml.cs @@ -91,7 +91,13 @@ public override async Task OnPostAsync() pageHandler: null, values: new { userId = userId, code = code }, protocol: Request.Scheme)!; - await _emailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl)); + var storedEmail = await _userManager.GetEmailAsync(user); + if (string.IsNullOrEmpty(storedEmail)) + { + throw new InvalidOperationException("Users must have an email."); + } + + await _emailSender.SendConfirmationLinkAsync(user, storedEmail, HtmlEncoder.Default.Encode(callbackUrl)); ModelState.AddModelError(string.Empty, "Verification email sent. Please check your email."); return Page(); diff --git a/src/Identity/UI/src/Areas/Identity/Pages/V5/Account/ForgotPassword.cshtml.cs b/src/Identity/UI/src/Areas/Identity/Pages/V5/Account/ForgotPassword.cshtml.cs index 6fea58f32175..ad6690a6f616 100644 --- a/src/Identity/UI/src/Areas/Identity/Pages/V5/Account/ForgotPassword.cshtml.cs +++ b/src/Identity/UI/src/Areas/Identity/Pages/V5/Account/ForgotPassword.cshtml.cs @@ -80,7 +80,13 @@ public override async Task OnPostAsync() values: new { area = "Identity", code }, protocol: Request.Scheme)!; - await _emailSender.SendPasswordResetLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl)); + var storedEmail = await _userManager.GetEmailAsync(user); + if (string.IsNullOrEmpty(storedEmail)) + { + throw new InvalidOperationException("Users must have an email."); + } + + await _emailSender.SendPasswordResetLinkAsync(user, storedEmail, HtmlEncoder.Default.Encode(callbackUrl)); return RedirectToPage("./ForgotPasswordConfirmation"); } diff --git a/src/Identity/UI/src/Areas/Identity/Pages/V5/Account/ResendEmailConfirmation.cshtml.cs b/src/Identity/UI/src/Areas/Identity/Pages/V5/Account/ResendEmailConfirmation.cshtml.cs index ba88ab597c83..82e098df65ae 100644 --- a/src/Identity/UI/src/Areas/Identity/Pages/V5/Account/ResendEmailConfirmation.cshtml.cs +++ b/src/Identity/UI/src/Areas/Identity/Pages/V5/Account/ResendEmailConfirmation.cshtml.cs @@ -91,7 +91,13 @@ public override async Task OnPostAsync() pageHandler: null, values: new { userId = userId, code = code }, protocol: Request.Scheme)!; - await _emailSender.SendConfirmationLinkAsync(user, Input.Email, HtmlEncoder.Default.Encode(callbackUrl)); + var storedEmail = await _userManager.GetEmailAsync(user); + if (string.IsNullOrEmpty(storedEmail)) + { + throw new InvalidOperationException("Users must have an email."); + } + + await _emailSender.SendConfirmationLinkAsync(user, storedEmail, HtmlEncoder.Default.Encode(callbackUrl)); ModelState.AddModelError(string.Empty, "Verification email sent. Please check your email."); return Page(); diff --git a/src/Identity/test/Identity.FunctionalTests/MapIdentityApiTests.cs b/src/Identity/test/Identity.FunctionalTests/MapIdentityApiTests.cs index ee1c2b4712ee..19b1bda0b906 100644 --- a/src/Identity/test/Identity.FunctionalTests/MapIdentityApiTests.cs +++ b/src/Identity/test/Identity.FunctionalTests/MapIdentityApiTests.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable enable @@ -31,6 +31,7 @@ using Microsoft.Extensions.Diagnostics.Metrics; using Microsoft.Extensions.Diagnostics.Metrics.Testing; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.Extensions.Time.Testing; using Microsoft.Net.Http.Headers; using Xunit.Sdk; @@ -1121,6 +1122,68 @@ public async Task EmailConfirmationCanBeResent() AssertOk(await client.PostAsJsonAsync("/identity/login", new { Email, Password })); } + [Fact] + public async Task ResendConfirmationEmailSendsToStoredEmail() + { + var emailSender = new TestEmailSender(); + + await using var app = await CreateAppAsync(services => + { + AddIdentityApiEndpoints(services); + services.AddSingleton(emailSender); + services.Configure(options => + { + options.SignIn.RequireConfirmedEmail = true; + }); + }); + using var client = app.GetTestClient(); + + var registeredEmail = "user@example.com"; + await RegisterAsync(client, email: registeredEmail); + + Assert.Single(emailSender.Emails); + + // Simulate a request using a different casing than what was registered. + var requestEmail = "USER@example.com"; + AssertOk(await client.PostAsJsonAsync("/identity/resendConfirmationEmail", new { Email = requestEmail })); + + // FindByEmailAsync finds the user, but the confirmation must go to the stored address. + Assert.Equal(2, emailSender.Emails.Count); + var resentEmail = emailSender.Emails[1]; + Assert.Equal("Confirm your email", resentEmail.Subject); + Assert.Equal(registeredEmail, resentEmail.Address); + Assert.NotEqual(requestEmail, resentEmail.Address); + } + + [Fact] + public async Task ResendConfirmationEmailReturnsBadRequestWhenStoredEmailIsNull() + { + var emailSender = new TestEmailSender(); + var nullEmailToggle = new NullEmailToggle(); + + await using var app = await CreateAppAsync(services => + { + AddIdentityApiEndpoints(services); + services.AddSingleton(emailSender); + services.Configure(options => + { + options.SignIn.RequireConfirmedEmail = true; + }); + services.AddSingleton(nullEmailToggle); + // Replace UserManager with one that can return null from GetEmailAsync on demand. + services.AddScoped, NullEmailUserManager>(); + }); + using var client = app.GetTestClient(); + + await RegisterAsync(client); + + // Enable the null-email simulation only after registration, which itself relies on + // GetEmailAsync to persist the user's NormalizedEmail. + nullEmailToggle.Enabled = true; + + await AssertValidationProblemAsync(await client.PostAsJsonAsync("/identity/resendConfirmationEmail", new { Email }), "MissingEmail"); + } + [Fact] public async Task AccountConfirmationEmailCanBeCustomized() { @@ -1572,6 +1635,75 @@ public async Task CanResetPassword() AssertOk(await client.PostAsJsonAsync("/identity/login", new { Email = confirmedEmail, Password = newPassword })); } + [Fact] + public async Task ForgotPasswordSendsToStoredEmail() + { + var emailSender = new TestEmailSender(); + + await using var app = await CreateAppAsync(services => + { + AddIdentityApiEndpoints(services); + services.AddSingleton(emailSender); + services.Configure(options => + { + options.SignIn.RequireConfirmedAccount = true; + }); + }); + using var client = app.GetTestClient(); + + var registeredEmail = "user@example.com"; + await RegisterAsync(client, email: registeredEmail); + await LoginWithEmailConfirmationAsync(client, emailSender, email: registeredEmail); + + // Simulate a forgot-password request using a different casing than what was registered. + var requestEmail = "USER@example.com"; + AssertOkAndEmpty(await client.PostAsJsonAsync("/identity/forgotPassword", new { Email = requestEmail })); + + // FindByEmailAsync finds the confirmed user, but the reset email must go to the stored address. + var resetEmail = emailSender.Emails.Last(); + Assert.Equal("Reset your password", resetEmail.Subject); + Assert.Equal(registeredEmail, resetEmail.Address); + Assert.NotEqual(requestEmail, resetEmail.Address); + + // Verify the reset code in that email actually works to reset the password. + var resetCode = GetPasswordResetCode(resetEmail); + var newPassword = $"{Password}!"; + AssertOkAndEmpty(await client.PostAsJsonAsync("/identity/resetPassword", + new { Email = registeredEmail, resetCode, newPassword })); + AssertOk(await client.PostAsJsonAsync("/identity/login", + new { Email = registeredEmail, Password = newPassword })); + } + + [Fact] + public async Task ForgotPasswordReturnsBadRequestWhenStoredEmailIsNull() + { + var emailSender = new TestEmailSender(); + var nullEmailToggle = new NullEmailToggle(); + + await using var app = await CreateAppAsync(services => + { + AddIdentityApiEndpoints(services); + services.AddSingleton(emailSender); + services.Configure(options => + { + options.SignIn.RequireConfirmedAccount = true; + }); + services.AddSingleton(nullEmailToggle); + // Replace UserManager with one that can return null from GetEmailAsync on demand. + services.AddScoped, NullEmailUserManager>(); + }); + using var client = app.GetTestClient(); + + // Registration and email confirmation internally rely on GetEmailAsync (e.g. to persist + // NormalizedEmail), so the null-email simulation must stay disabled until after they succeed. + await RegisterAsync(client); + await LoginWithEmailConfirmationAsync(client, emailSender); + + nullEmailToggle.Enabled = true; + + await AssertValidationProblemAsync(await client.PostAsJsonAsync("/identity/forgotPassword", new { Email }), "MissingEmail"); + } + [Theory] [MemberData(nameof(AddIdentityModes))] public async Task CanChangeEmail(string addIdentityModes) @@ -2457,4 +2589,32 @@ public Task SendPasswordResetLinkAsync(ApplicationUser user, string email, strin } private sealed record TestEmail(string Address, string Subject, string HtmlMessage); + + // Shared toggle so tests can enable the null-email simulation only once setup (registration, + // email confirmation, etc.) has completed. Those steps internally call GetEmailAsync too + // (e.g. UserManager.UpdateNormalizedEmailAsync reads it to persist NormalizedEmail), so + // suppressing it from the start would prevent FindByEmailAsync from ever locating the user. + private sealed class NullEmailToggle + { + public bool Enabled { get; set; } + } + + private sealed class NullEmailUserManager( + IUserStore store, + IOptions optionsAccessor, + IPasswordHasher passwordHasher, + IEnumerable> userValidators, + IEnumerable> passwordValidators, + ILookupNormalizer keyNormalizer, + IdentityErrorDescriber errors, + IServiceProvider services, + ILogger> logger, + NullEmailToggle nullEmailToggle) + : UserManager(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger) + { + // Simulates a broken/misconfigured store where a user has no stored email, but only + // once the toggle is enabled by the test (see NullEmailToggle above). + public override Task GetEmailAsync(ApplicationUser user) => + nullEmailToggle.Enabled ? Task.FromResult(null) : base.GetEmailAsync(user); + } } diff --git a/src/Security/Authentication/Negotiate/src/Internal/LdapAdapter.cs b/src/Security/Authentication/Negotiate/src/Internal/LdapAdapter.cs index 3e1d15c9993d..6edbdb0a5be7 100644 --- a/src/Security/Authentication/Negotiate/src/Internal/LdapAdapter.cs +++ b/src/Security/Authentication/Negotiate/src/Internal/LdapAdapter.cs @@ -1,8 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; using System.Diagnostics; using System.DirectoryServices.Protocols; +using System.Globalization; using System.Linq; using System.Security.Claims; using System.Text; @@ -14,6 +16,17 @@ namespace Microsoft.AspNetCore.Authentication.Negotiate; internal static partial class LdapAdapter { + // internal for testing + internal const string RequirePrimarySidClaimSwitchName = "Microsoft.AspNetCore.Authentication.Negotiate.RequirePrimarySidClaim"; + public static bool RequirePrimarySidClaim { get; } = AppContext.TryGetSwitch(RequirePrimarySidClaimSwitchName, out var enabled) && enabled; + + // Restores pre-fix behaviour: emit role claims for groups that are not security-enabled. + private const string AllowNonSecurityEnabledGroupClaimsSwitch = + "Microsoft.AspNetCore.Authentication.Negotiate.AllowNonSecurityEnabledGroupClaims"; + + private static readonly bool AllowNonSecurityEnabledGroupClaims = + AppContext.TryGetSwitch(AllowNonSecurityEnabledGroupClaimsSwitch, out var allow) && allow; + [GeneratedRegex(@"(?>(user, out var cachedClaims) && cachedClaims is not null) + if (settings.ClaimsCache.TryGetValue>(cacheKey, out var cachedClaims) && cachedClaims is not null) { foreach (var claim in cachedClaims) { @@ -85,6 +102,15 @@ public static async Task RetrieveClaimsAsync(LdapSettings settings, ClaimsIdenti } var userFound = searchResponse.Entries[0]; //Get the object that was found on ldap + + // Verify the objectSid from the LDAP entry matches the SID of the Kerberos-authenticated principal + var ldapObjectSidAttr = userFound.Attributes["objectSid"]; + var ldapObjectSidBytes = ldapObjectSidAttr?.Count > 0 ? (byte[])ldapObjectSidAttr[0] : null; + if (!VerifyLdapSidMatchesKerberosPrincipal(ldapObjectSidBytes, identitySid, user, logger, RequirePrimarySidClaim)) + { + return; + } + var memberof = userFound.Attributes["memberof"]; // You can access ldap Attributes with Attributes property foreach (var group in memberof) @@ -93,14 +119,9 @@ public static async Task RetrieveClaimsAsync(LdapSettings settings, ClaimsIdenti var groupDN = $"{Encoding.UTF8.GetString((byte[])group)}"; var groupCN = DistinguishedNameSeparatorRegex.Split(groupDN)[0].Substring("CN=".Length); - if (!settings.IgnoreNestedGroups) - { - GetNestedGroups(settings.LdapConnection, identity, distinguishedName, groupDN, groupCN, logger, retrievedClaims, new HashSet()); - } - else - { - retrievedClaims.Add(groupCN); - } + // Resolved via GetGroups even when nesting is disabled, so the security-enabled + // check applies to directly held groups too. + GetGroups(settings.LdapConnection, identity, distinguishedName, groupDN, groupCN, logger, retrievedClaims, new HashSet(), AllowNonSecurityEnabledGroupClaims, !settings.IgnoreNestedGroups); } var entrySize = user.Length * 2; //Approximate the size of stored key in memory cache. @@ -110,7 +131,7 @@ public static async Task RetrieveClaimsAsync(LdapSettings settings, ClaimsIdenti entrySize += claim.Length * 2; //Approximate the size of stored value in memory cache. } - settings.ClaimsCache.Set(user, + settings.ClaimsCache.Set(cacheKey, retrievedClaims, new MemoryCacheEntryOptions() .SetSize(entrySize) @@ -123,14 +144,12 @@ public static async Task RetrieveClaimsAsync(LdapSettings settings, ClaimsIdenti } } - private static void GetNestedGroups(LdapConnection connection, ClaimsIdentity principal, string distinguishedName, string groupDN, string groupCN, ILogger logger, IList retrievedClaims, HashSet processedGroups) + private static void GetGroups(LdapConnection connection, ClaimsIdentity principal, string distinguishedName, string groupDN, string groupCN, ILogger logger, IList retrievedClaims, HashSet processedGroups, bool allowNonSecurityEnabledGroupClaims, bool resolveNestedGroups) { - retrievedClaims.Add(groupCN); - // Look up the group entry by its distinguished name using base scope: // a base-scope read against the DN is the only LDAP operation that // returns exactly the intended group object. - var searchRequest = new SearchRequest(groupDN, "(objectClass=group)", SearchScope.Base); + var searchRequest = new SearchRequest(groupDN, "(objectClass=group)", SearchScope.Base, "memberof", "groupType"); SearchResponse searchResponse; try { @@ -147,6 +166,23 @@ private static void GetNestedGroups(LdapConnection connection, ClaimsIdentity pr { var group = searchResponse.Entries[0]; // Get the object that was found on ldap + var groupTypeAttr = group.Attributes["groupType"]; + var groupTypeValue = groupTypeAttr is { Count: > 0 } ? groupTypeAttr[0] : null; + + if (ShouldEmitRoleClaim(groupTypeValue, allowNonSecurityEnabledGroupClaims)) + { + retrievedClaims.Add(groupCN); + } + else + { + logger.LogDebug("LdapAdapter omitted distribution group '{GroupDN}' from role claims.", groupDN); + } + + if (!resolveNestedGroups) + { + return; + } + processedGroups.Add(groupDN); var memberof = group.Attributes["memberof"]; // You can access ldap Attributes with Attributes property @@ -163,12 +199,133 @@ private static void GetNestedGroups(LdapConnection connection, ClaimsIdentity pr return; } - GetNestedGroups(connection, principal, distinguishedName, nestedGroupDN, nestedGroupCN, logger, retrievedClaims, processedGroups); + GetGroups(connection, principal, distinguishedName, nestedGroupDN, nestedGroupCN, logger, retrievedClaims, processedGroups, allowNonSecurityEnabledGroupClaims, resolveNestedGroups); } } } } + /// + /// Verifies that the from the LDAP search result + /// represent the same account as the Kerberos-authenticated principal identified by . + /// + // internal for testing + internal static bool VerifyLdapSidMatchesKerberosPrincipal(byte[]? ldapObjectSidBytes, string? identitySid, string user, ILogger logger, bool requirePrimarySidClaim = false) + { + if (identitySid is null) + { + if (requirePrimarySidClaim) + { + logger.LogDebug("Skipping LDAP claim resolution for '{User}': the authenticated identity has no PrimarySid claim.", user); + return false; + } + + // No PrimarySid claim: either the runtime doesn't populate it, or the Kerberos ticket legitimately carried no PAC (e.g. non-AD KDC, NTLM). + return true; + } + + if (ldapObjectSidBytes is null) + { + // Valid AD user object should have objectSid attribute + logger.LogDebug("LDAP entry for '{User}' has no objectSid attribute; skipping claim resolution to prevent potential name confusion.", user); + return false; + } + + var ldapSid = ParseSidBytesToString(ldapObjectSidBytes); + if (ldapSid is null) + { + logger.LogDebug("LDAP entry for '{User}' has an objectSid attribute that could not be parsed; skipping claim resolution to prevent potential name confusion.", user); + return false; + } + + if (!string.Equals(ldapSid, identitySid, StringComparison.OrdinalIgnoreCase)) + { + logger.LogWarning("LDAP account SID '{LdapSid}' for query '{User}' does not match the Kerberos-authenticated principal SID '{IdentitySid}'. ", ldapSid, user, identitySid); + return false; + } + + return true; + } + + /// + /// Parses a binary-encoded Windows SID into its canonical string form (e.g. S-1-5-21-…-500). + /// Returns if is malformed. + /// + /// + /// The binary format is defined in MS-DTYP §2.4.2: + /// + /// Byte 0: Revision + /// Byte 1: SubAuthorityCount (N) + /// Bytes 2–7: IdentifierAuthority (6 bytes, big-endian) + /// Bytes 8+: N sub-authority values (4 bytes each, little-endian) + /// + /// This helper is cross-platform and avoids System.Security.Principal.SecurityIdentifier + /// which is Windows-only. + /// + // internal for testing + internal static string? ParseSidBytesToString(byte[] bytes) + { + if (bytes.Length < 8) + { + return null; + } + + var revision = bytes[0]; + var subAuthorityCount = bytes[1]; + + if (bytes.Length < 8 + (subAuthorityCount * 4)) + { + return null; + } + + long authority = 0; + for (var i = 2; i < 8; i++) + { + authority = (authority << 8) | bytes[i]; + } + + var sb = new StringBuilder(); + sb.Append(CultureInfo.InvariantCulture, $"S-{revision}-{authority}"); + + for (var i = 0; i < subAuthorityCount; i++) + { + var subAuth = BinaryPrimitives.ReadUInt32LittleEndian(bytes.AsSpan(8 + (i * 4))); + sb.Append(CultureInfo.InvariantCulture, $"-{subAuth}"); + } + + return sb.ToString(); + } + + /// + /// Determines whether a group should produce a role claim, honouring the + /// AllowNonSecurityEnabledGroupClaims opt-out. + /// + // internal for testing + internal static bool ShouldEmitRoleClaim(object? groupTypeValue, bool allowNonSecurityEnabledGroupClaims) + => IsSecurityGroup(groupTypeValue) || allowNonSecurityEnabledGroupClaims; + + /// + /// Evaluates the groupType attribute value (byte[] or string depending on LDAP client implementation) + /// to determine whether a group is a Security Group (0x80000000). + /// + // internal for testing + internal static bool IsSecurityGroup(object? groupTypeVal) + { + if (groupTypeVal == null) + { + return true; + } + + var typeString = groupTypeVal is byte[] b ? Encoding.UTF8.GetString(b) : groupTypeVal.ToString(); + if (int.TryParse(typeString, out int groupType)) + { + const int GROUP_TYPE_SECURITY_ENABLED = unchecked((int)0x80000000); + return (groupType & GROUP_TYPE_SECURITY_ENABLED) == GROUP_TYPE_SECURITY_ENABLED; + } + + return true; // fail open if we cannot parse + } + /// /// Escapes special characters in a value used in an LDAP search filter per RFC 4515 /// https://datatracker.ietf.org/doc/html/rfc4515#section-3 diff --git a/src/Security/Authentication/Negotiate/test/Negotiate.Test/LdapAdapterTests.cs b/src/Security/Authentication/Negotiate/test/Negotiate.Test/LdapAdapterTests.cs index bf7b4d07e200..c3c213b513b4 100644 --- a/src/Security/Authentication/Negotiate/test/Negotiate.Test/LdapAdapterTests.cs +++ b/src/Security/Authentication/Negotiate/test/Negotiate.Test/LdapAdapterTests.cs @@ -1,7 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; +using System.Globalization; +using System.Runtime.Versioning; using System.Security.Claims; +using System.Security.Principal; +using Microsoft.AspNetCore.InternalTesting; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging.Abstractions; @@ -191,4 +196,145 @@ public void EscapeLdapFilterValue_EmptyString_ReturnsEmpty() { Assert.Equal(string.Empty, LdapAdapter.EscapeLdapFilterValue(string.Empty)); } + + [Fact] + public void VerifyLdapSidMatchesKerberosPrincipal_NoIdentitySid_ReturnsTrue() + => Assert.True(LdapAdapter.VerifyLdapSidMatchesKerberosPrincipal( + ldapObjectSidBytes: SidToBytes("S-1-5-21-111-222-333-500"), + identitySid: null, + user: "Administrator@CONTOSO.COM", + logger: NullLogger.Instance)); + + [Fact] + public void VerifyLdapSidMatchesKerberosPrincipal_NoIdentitySid_RequirePrimarySidClaim_ReturnsFalse() + => Assert.False(LdapAdapter.VerifyLdapSidMatchesKerberosPrincipal( + ldapObjectSidBytes: SidToBytes("S-1-5-21-111-222-333-500"), + identitySid: null, + user: "Administrator@CONTOSO.COM", + logger: NullLogger.Instance, + requirePrimarySidClaim: true)); + + [Fact] + public void VerifyLdapSidMatchesKerberosPrincipal_NoLdapObjectSid_ReturnsFalse() + => Assert.False(LdapAdapter.VerifyLdapSidMatchesKerberosPrincipal( + ldapObjectSidBytes: null, + identitySid: "S-1-5-21-111-222-333-1105", + user: "Administrator@CONTOSO.COM", + logger: NullLogger.Instance)); + + [Fact] + public void VerifyLdapSidMatchesKerberosPrincipal_MatchingSids_ReturnsTrue() + { + // Normal case: the Kerberos-authenticated account and the LDAP entry are the same object. + const string sid = "S-1-5-21-111-222-333-1105"; + + Assert.True(LdapAdapter.VerifyLdapSidMatchesKerberosPrincipal( + ldapObjectSidBytes: SidToBytes(sid), + identitySid: sid, + user: "alice@CONTOSO.COM", + logger: NullLogger.Instance)); + } + + [Fact] + public void VerifyLdapSidMatchesKerberosPrincipal_MatchingSids_CaseInsensitive_ReturnsTrue() + { + // SID strings are case-insensitive (S-1-5-... vs s-1-5-...). + const string sid = "S-1-5-21-111-222-333-1105"; + + Assert.True(LdapAdapter.VerifyLdapSidMatchesKerberosPrincipal( + ldapObjectSidBytes: SidToBytes(sid), + identitySid: sid.ToLowerInvariant(), + user: "alice@CONTOSO.COM", + logger: NullLogger.Instance)); + } + + [Fact] + public void VerifyLdapSidMatchesKerberosPrincipal_MismatchedSids_ReturnsFalse() + => Assert.False(LdapAdapter.VerifyLdapSidMatchesKerberosPrincipal( + ldapObjectSidBytes: SidToBytes("S-1-5-21-111-222-333-500"), // Administrator + identitySid: "S-1-5-21-111-222-333-1105", // non-matching identity sid + user: "Administrator@CONTOSO.COM", + logger: NullLogger.Instance)); + + [ConditionalTheory] + [InlineData("S-1-5-21-111-222-333-500")] // well-known Administrator RID + [InlineData("S-1-5-21-111-222-333-1105")] // typical domain user RID + [InlineData("S-1-5-32-544")] // BUILTIN\Administrators (short SID) + [InlineData("S-1-5-18")] // NT AUTHORITY\SYSTEM (no sub-domain component) + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX, SkipReason = "SecurityIdentifier is Windows-only.")] + public void ParseSidBytesToString_MatchesSecurityIdentifierOnWindows(string sidString) + { + // SecurityIdentifier is the authoritative Windows implementation of MS-DTYP §2.4.2. + var bytes = SidToBytes(sidString); + var expected = new SecurityIdentifier(bytes, 0).Value; + + Assert.Equal(expected, LdapAdapter.ParseSidBytesToString(bytes), StringComparer.OrdinalIgnoreCase); + } + + // Builds a binary SID from a canonical string (e.g. "S-1-5-21-111-222-333-500") + // without relying on the Windows-only SecurityIdentifier class. + // Format: S-{rev}-{auth}-{sa0}-…-{saN} + private static byte[] SidToBytes(string sidString) + { + var parts = sidString.Split('-'); + // parts: ["S", "{rev}", "{auth}", "{sa0}", ...] + var revision = byte.Parse(parts[1], CultureInfo.InvariantCulture); + var authority = long.Parse(parts[2], CultureInfo.InvariantCulture); + var subAuthorities = parts[3..].Select(p => uint.Parse(p, CultureInfo.InvariantCulture)).ToArray(); + + var bytes = new byte[8 + (subAuthorities.Length * 4)]; + bytes[0] = revision; + bytes[1] = (byte)subAuthorities.Length; + + // Authority as 6-byte big-endian + var authCopy = authority; + for (var i = 5; i >= 0; i--) + { + bytes[2 + i] = (byte)(authCopy & 0xFF); + authCopy >>= 8; + } + + for (var i = 0; i < subAuthorities.Length; i++) + { + BinaryPrimitives.WriteUInt32LittleEndian(bytes.AsSpan(8 + (i * 4)), subAuthorities[i]); + } + + return bytes; + } + + [Theory] + // Valid Security Groups + [InlineData("-2147483646", true)] // 0x80000000 | 0x2 (Global Security) + [InlineData("-2147483644", true)] // 0x80000000 | 0x4 (Domain Local Security) + [InlineData("-2147483640", true)] // 0x80000000 | 0x8 (Universal Security) + // Valid Distribution Groups + [InlineData("2", false)] // 0x2 (Global Distribution) + [InlineData("4", false)] // 0x4 (Domain Local Distribution) + [InlineData("8", false)] // 0x8 (Universal Distribution) + // Edge cases and missing attributes fail open + [InlineData("garbage", true)] + [InlineData(null, true)] + public void IsSecurityGroup_EvaluatesGroupTypeAttributeCorrectly(string groupTypeValue, bool expectedIsSecurityGroup) + { + // Test parsing from string (common in higher level LDAP wrappers) + Assert.Equal(expectedIsSecurityGroup, LdapAdapter.IsSecurityGroup(groupTypeValue)); + + // Test parsing from byte array (how System.DirectoryServices.Protocols surfaces attributes) + if (groupTypeValue != null) + { + var byteValue = System.Text.Encoding.UTF8.GetBytes(groupTypeValue); + Assert.Equal(expectedIsSecurityGroup, LdapAdapter.IsSecurityGroup(byteValue)); + } + } + + [Theory] + [InlineData("2", false, false)] // distribution group, switch off -> no role claim + [InlineData("2", true, true)] // distribution group, switch on -> role claim restored + [InlineData("-2147483646", false, true)] // security group, switch off -> role claim + [InlineData("-2147483646", true, true)] // security group, switch on -> role claim + [InlineData(null, false, true)] // groupType absent -> fail open + public void ShouldEmitRoleClaim_HonoursGroupTypeAndOptOutSwitch(string groupTypeValue, bool allowNonSecurityEnabledGroupClaims, bool expected) + { + Assert.Equal(expected, LdapAdapter.ShouldEmitRoleClaim(groupTypeValue, allowNonSecurityEnabledGroupClaims)); + } } diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs index bf97a331e4d8..321d4d151fa1 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/Http1Connection.cs @@ -881,10 +881,6 @@ protected override void OnReset() _currentIPersistentStateFeature = this; } - protected override void OnRequestProcessingEnding() - { - } - protected override string CreateRequestId() => StringUtilities.ConcatAsHexSuffix(ConnectionId, ':', _requestCount); diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs index 804a7b99daed..583cb10505ce 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.cs @@ -429,7 +429,6 @@ public void Reset() { _preventRequestAbortedCancellation = false; - // If the connection has already been aborted, allow that to be observed during the next request. if (!_connectionAborted && _abortedCts is not null) { // _connectionAborted is terminal and only set inside the _abortLock, so if it isn't set here, @@ -453,10 +452,6 @@ public void Reset() protected abstract void ApplicationAbort(); - protected virtual void OnRequestProcessingEnding() - { - } - protected virtual void OnRequestProcessingEnded() { } @@ -517,6 +512,11 @@ protected void CancelRequestAbortedToken() } shouldScheduleCancellation = _abortedCts != null && !_preventRequestAbortedCancellation; + + // Disable keep-alive before publishing the abort. The release write and acquire read of + // volatile _connectionAborted ensure that, when draining is skipped because of an abort, + // the next request-loop condition observes _keepAlive as false. + _keepAlive = false; _connectionAborted = true; } diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestTests.cs index 3319a5e22740..505024f1de1f 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/RequestTests.cs @@ -1295,6 +1295,47 @@ await connection.Send( } } + [Fact] + public async Task InputCompletionDoesNotReparseUnreadRequestBody() + { + var requestStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var requestAborted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var allowRequestToComplete = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var connectionStopped = WaitForLogMessage(m => m.EventId.Name == "ConnectionStop"); + + var requestCount = 0; + + await using var server = new TestServer(async context => + { + Interlocked.Increment(ref requestCount); + using var registration = context.RequestAborted.Register(() => requestAborted.TrySetResult()); + requestStarted.TrySetResult(); + await allowRequestToComplete.Task.DefaultTimeout(); + }, new TestServiceContext(LoggerFactory)); + + using var connection = server.CreateConnection(); + + // The GET is entirely inside the POST body, not a pipelined request. + const string body = "GET /must-not-dispatch HTTP/1.1\r\nHost:\r\n\r\n"; + + await connection.SendAll( + "POST / HTTP/1.1", + "Host:", + $"Content-Length: {Encoding.ASCII.GetByteCount(body)}", + "", + body); + + // Ensure request cleanup observes the abort instead of relying on transport timing. + await requestStarted.Task.DefaultTimeout(); + connection.ShutdownSend(); + await requestAborted.Task.DefaultTimeout(); + + allowRequestToComplete.SetResult(); + await connectionStopped.DefaultTimeout(); + + Assert.Equal(1, requestCount); + } + [Fact] public async Task RequestHeadersAreResetOnEachRequest() { diff --git a/src/Shared/PooledMemoryStream.cs b/src/Shared/PooledMemoryStream.cs new file mode 100644 index 000000000000..b9e79aaa0552 --- /dev/null +++ b/src/Shared/PooledMemoryStream.cs @@ -0,0 +1,237 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Buffers; + +namespace Microsoft.AspNetCore.WebUtilities; + +internal sealed class PooledMemoryStream : Stream +{ + private readonly ArrayPool _bytePool; + private readonly int _maxCapacity; + private byte[]? _buffer; + private int _length; + private int _position; + private bool _disposed; + + public PooledMemoryStream(ArrayPool bytePool, int maxCapacity) + { + ArgumentNullException.ThrowIfNull(bytePool); + ArgumentOutOfRangeException.ThrowIfNegative(maxCapacity); + + _bytePool = bytePool; + _maxCapacity = maxCapacity; + } + + public override bool CanRead => !_disposed; + + public override bool CanSeek => !_disposed; + + public override bool CanWrite => !_disposed; + + public override long Length + { + get + { + ThrowIfDisposed(); + + return _length; + } + } + + public override long Position + { + get + { + ThrowIfDisposed(); + + return _position; + } + set + { + ThrowIfDisposed(); + ArgumentOutOfRangeException.ThrowIfNegative(value); + ArgumentOutOfRangeException.ThrowIfGreaterThan(value, int.MaxValue); + + _position = (int)value; + } + } + + public ReadOnlyMemory WrittenMemory + { + get + { + ThrowIfDisposed(); + + return _buffer.AsMemory(0, _length); + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + ValidateBufferArguments(buffer, offset, count); + + return Read(buffer.AsSpan(offset, count)); + } + + public override int Read(Span buffer) + { + ThrowIfDisposed(); + + var bytesToRead = Math.Min(_length - Math.Min(_position, _length), buffer.Length); + if (bytesToRead == 0) + { + return 0; + } + + _buffer.AsSpan(_position, bytesToRead).CopyTo(buffer); + _position += bytesToRead; + + return bytesToRead; + } + + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + ValidateBufferArguments(buffer, offset, count); + + return ReadAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); + } + + public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + + return new ValueTask(Read(buffer.Span)); + } + + public override void Write(byte[] buffer, int offset, int count) + { + ValidateBufferArguments(buffer, offset, count); + Write(buffer.AsSpan(offset, count)); + } + + public override void Write(ReadOnlySpan buffer) + { + ThrowIfDisposed(); + + var endPosition = checked(_position + buffer.Length); + EnsureCapacity(endPosition); + + if (_position > _length) + { + _buffer.AsSpan(_length, _position - _length).Clear(); + } + + buffer.CopyTo(_buffer.AsSpan(_position)); + _position = endPosition; + _length = Math.Max(_length, endPosition); + } + + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + ValidateBufferArguments(buffer, offset, count); + + return WriteAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); + } + + public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) + { + cancellationToken.ThrowIfCancellationRequested(); + Write(buffer.Span); + + return ValueTask.CompletedTask; + } + + public override long Seek(long offset, SeekOrigin origin) + { + ThrowIfDisposed(); + + var newPosition = origin switch + { + SeekOrigin.Begin => offset, + SeekOrigin.Current => _position + offset, + SeekOrigin.End => _length + offset, + _ => throw new ArgumentOutOfRangeException(nameof(origin)), + }; + + if (newPosition < 0) + { + throw new IOException("An attempt was made to move the position before the beginning of the stream."); + } + + Position = newPosition; + + return _position; + } + + public override void SetLength(long value) + { + ThrowIfDisposed(); + ArgumentOutOfRangeException.ThrowIfNegative(value); + ArgumentOutOfRangeException.ThrowIfGreaterThan(value, _maxCapacity); + + var length = (int)value; + EnsureCapacity(length); + if (length > _length) + { + _buffer.AsSpan(_length, length - _length).Clear(); + } + + _length = length; + _position = Math.Min(_position, _length); + } + + public override void Flush() + { + ThrowIfDisposed(); + } + + protected override void Dispose(bool disposing) + { + if (!_disposed) + { + _disposed = true; + + if (_buffer is not null) + { + _bytePool.Return(_buffer); + _buffer = null; + } + } + + base.Dispose(disposing); + } + + private void EnsureCapacity(int requiredCapacity) + { + if (requiredCapacity > _maxCapacity) + { + throw new IOException("Memory threshold exceeded."); + } + + if (_buffer is not null && requiredCapacity <= _buffer.Length) + { + return; + } + + if (requiredCapacity == 0) + { + return; + } + + var newCapacity = _buffer is null + ? requiredCapacity + : Math.Max(requiredCapacity, Math.Min(_buffer.Length * 2, _maxCapacity)); + var newBuffer = _bytePool.Rent(newCapacity); + + if (_buffer is not null) + { + _buffer.AsSpan(0, _length).CopyTo(newBuffer); + _bytePool.Return(_buffer); + } + + _buffer = newBuffer; + } + + private void ThrowIfDisposed() => ObjectDisposedException.ThrowIf(_disposed, this); +} diff --git a/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj b/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj index 31a685241adc..a39018607431 100644 --- a/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj +++ b/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj @@ -44,6 +44,7 @@ + diff --git a/src/Shared/test/Shared.Tests/PooledMemoryStreamTests.cs b/src/Shared/test/Shared.Tests/PooledMemoryStreamTests.cs new file mode 100644 index 000000000000..f8112bc48d93 --- /dev/null +++ b/src/Shared/test/Shared.Tests/PooledMemoryStreamTests.cs @@ -0,0 +1,372 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Buffers; +using Microsoft.AspNetCore.WebUtilities; +using Moq; + +namespace Microsoft.AspNetCore.Shared.Tests; + +public class PooledMemoryStreamTests +{ + [Fact] + public void Constructor_DoesNotRentUntilCapacityIsNeeded() + { + var pool = new Mock>(MockBehavior.Strict); + using var stream = new PooledMemoryStream(pool.Object, 16); + + Assert.Equal(0, stream.Length); + Assert.Equal(0, stream.Position); + Assert.True(stream.WrittenMemory.IsEmpty); + pool.Verify(p => p.Rent(It.IsAny()), Times.Never); + } + + [Fact] + public void Constructor_ValidatesArguments() + { + Assert.Throws(() => new PooledMemoryStream(null!, 1)); + Assert.Throws(() => new PooledMemoryStream(ArrayPool.Shared, -1)); + } + + [Fact] + public void Write_RentsExactInitialSizeAndGrowsGeometricallyUpToMaximum() + { + var (pool, rentedSizes, returnedBuffers) = CreateExactSizePool(); + using var stream = new PooledMemoryStream(pool.Object, 10); + + stream.Write([1, 2, 3]); + stream.WriteByte(4); + stream.Write([5, 6, 7]); + + Assert.Equal([3, 6, 10], rentedSizes); + Assert.Equal(2, returnedBuffers.Count); + Assert.Equal([1, 2, 3, 4, 5, 6, 7], stream.WrittenMemory.ToArray()); + } + + [Fact] + public void Write_WhenRequiredSizeIsMoreThanDouble_GrowsToExactRequiredSize() + { + var (pool, rentedSizes, _) = CreateExactSizePool(); + using var stream = new PooledMemoryStream(pool.Object, 20); + + stream.Write([1, 2]); + stream.SetLength(7); + + Assert.Equal([2, 7], rentedSizes); + Assert.Equal([1, 2, 0, 0, 0, 0, 0], stream.WrittenMemory.ToArray()); + } + + [Fact] + public void Growth_PreservesWrittenDataAndCurrentPosition() + { + var (pool, _, _) = CreateExactSizePool(); + using var stream = new PooledMemoryStream(pool.Object, 16); + + stream.Write([1, 2, 3, 4]); + stream.Position = 2; + stream.Write([9, 8, 7, 6]); + + Assert.Equal(6, stream.Position); + Assert.Equal(6, stream.Length); + Assert.Equal([1, 2, 9, 8, 7, 6], stream.WrittenMemory.ToArray()); + } + + [Fact] + public void Read_SupportsArrayAndSpanOverloads() + { + using var stream = CreateStreamWithData([1, 2, 3, 4, 5]); + stream.Position = 0; + var array = new byte[4]; + + var arrayRead = stream.Read(array, 1, 2); + Span span = stackalloc byte[3]; + var spanRead = stream.Read(span); + + Assert.Equal(2, arrayRead); + Assert.Equal([0, 1, 2, 0], array); + Assert.Equal(3, spanRead); + Assert.Equal([3, 4, 5], span.ToArray()); + Assert.Equal(5, stream.Position); + Assert.Equal(0, stream.Read(array, 0, array.Length)); + } + + [Fact] + public async Task ReadAsync_SupportsArrayAndMemoryOverloads() + { + await using var stream = CreateStreamWithData([1, 2, 3, 4, 5]); + stream.Position = 0; + var array = new byte[5]; + + var arrayRead = await stream.ReadAsync(array, 1, 2, CancellationToken.None); + var memoryRead = await stream.ReadAsync(array.AsMemory(3, 2)); + + Assert.Equal(2, arrayRead); + Assert.Equal(2, memoryRead); + Assert.Equal([0, 1, 2, 3, 4], array); + Assert.Equal(4, stream.Position); + } + + [Fact] + public async Task WriteAsync_SupportsArrayAndMemoryOverloads() + { + await using var stream = new PooledMemoryStream(ArrayPool.Shared, 8); + var data = new byte[] { 0, 1, 2, 3, 4 }; + + await stream.WriteAsync(data, 1, 2, CancellationToken.None); + await stream.WriteAsync(data.AsMemory(3, 2)); + + Assert.Equal([1, 2, 3, 4], stream.WrittenMemory.ToArray()); + Assert.Equal(4, stream.Position); + } + + [Theory] + [InlineData(SeekOrigin.Begin, 2, 2)] + [InlineData(SeekOrigin.Current, -1, 1)] + [InlineData(SeekOrigin.End, -2, 3)] + public void Seek_ValidOffset_UpdatesPosition(SeekOrigin origin, long offset, long expected) + { + using var stream = CreateStreamWithData([1, 2, 3, 4, 5]); + stream.Position = 2; + + var position = stream.Seek(offset, origin); + + Assert.Equal(expected, position); + Assert.Equal(expected, stream.Position); + Assert.Equal(5, stream.Length); + } + + [Fact] + public void Position_CanMovePastEndWithoutChangingLength() + { + using var stream = CreateStreamWithData([1, 2, 3]); + + stream.Position = 10; + + Assert.Equal(10, stream.Position); + Assert.Equal(3, stream.Length); + Assert.Equal(-1, stream.ReadByte()); + Assert.Equal(10, stream.Position); + } + + [Fact] + public void PositionAndSeek_ValidateBoundaries() + { + using var stream = new PooledMemoryStream(ArrayPool.Shared, 8); + + Assert.Throws(() => stream.Position = -1); + Assert.Throws(() => stream.Position = (long)int.MaxValue + 1); + Assert.Throws(() => stream.Seek(-1, SeekOrigin.Begin)); + Assert.Throws(() => stream.Seek(0, (SeekOrigin)int.MaxValue)); + } + + [Fact] + public void SparseWrite_ZeroFillsGap() + { + using var stream = CreateStreamWithData([1, 2]); + stream.Position = 5; + + stream.WriteByte(9); + + Assert.Equal(6, stream.Length); + Assert.Equal([1, 2, 0, 0, 0, 9], stream.WrittenMemory.ToArray()); + } + + [Fact] + public void SetLength_GrowsWithZerosAndShrinksPosition() + { + using var stream = CreateStreamWithData([1, 2, 3]); + + stream.SetLength(6); + Assert.Equal([1, 2, 3, 0, 0, 0], stream.WrittenMemory.ToArray()); + Assert.Equal(3, stream.Position); + + stream.Position = 5; + stream.SetLength(2); + + Assert.Equal(2, stream.Length); + Assert.Equal(2, stream.Position); + Assert.Equal([1, 2], stream.WrittenMemory.ToArray()); + } + + [Fact] + public void SetLength_ValidatesBoundaries() + { + using var stream = new PooledMemoryStream(ArrayPool.Shared, 8); + + Assert.Throws(() => stream.SetLength(-1)); + Assert.Throws(() => stream.SetLength(9)); + } + + [Fact] + public void Write_ExceedingMaximumCapacityThrowsWithoutChangingContent() + { + var (pool, rentedSizes, _) = CreateExactSizePool(); + using var stream = new PooledMemoryStream(pool.Object, 4); + stream.Write([1, 2, 3, 4]); + + var exception = Assert.Throws(() => stream.WriteByte(5)); + + Assert.Equal("Memory threshold exceeded.", exception.Message); + Assert.Equal(4, stream.Position); + Assert.Equal(4, stream.Length); + Assert.Equal([1, 2, 3, 4], stream.WrittenMemory.ToArray()); + Assert.Equal([4], rentedSizes); + } + + [Fact] + public void Write_WhenPositionPlusCountOverflowsThrowsWithoutRenting() + { + var pool = new Mock>(MockBehavior.Strict); + using var stream = new PooledMemoryStream(pool.Object, int.MaxValue); + stream.Position = int.MaxValue; + + Assert.Throws(() => stream.WriteByte(1)); + Assert.Equal(int.MaxValue, stream.Position); + Assert.Equal(0, stream.Length); + } + + [Fact] + public async Task ZeroByteOperations_DoNotRentOrChangeState() + { + var pool = new Mock>(MockBehavior.Strict); + await using var stream = new PooledMemoryStream(pool.Object, 8); + var buffer = Array.Empty(); + + stream.Write(buffer, 0, 0); + Assert.Equal(0, stream.Read(buffer, 0, 0)); + await stream.WriteAsync(buffer, CancellationToken.None); + Assert.Equal(0, await stream.ReadAsync(buffer, CancellationToken.None)); + stream.SetLength(0); + stream.Flush(); + await stream.FlushAsync(); + + Assert.Equal(0, stream.Position); + Assert.Equal(0, stream.Length); + Assert.True(stream.WrittenMemory.IsEmpty); + pool.Verify(p => p.Rent(It.IsAny()), Times.Never); + } + + [Fact] + public async Task AsyncOperations_WithCanceledTokenThrowWithoutChangingState() + { + await using var stream = CreateStreamWithData([1, 2, 3]); + stream.Position = 1; + var canceledToken = new CancellationToken(canceled: true); + + await Assert.ThrowsAsync( + async () => await stream.ReadAsync(new byte[1], canceledToken)); + await Assert.ThrowsAsync( + async () => await stream.WriteAsync(new byte[] { 9 }, canceledToken)); + + Assert.Equal(1, stream.Position); + Assert.Equal([1, 2, 3], stream.WrittenMemory.ToArray()); + } + + [Fact] + public void WrittenMemory_ContainsOnlyLogicalContentAndReflectsOverwrites() + { + using var stream = new PooledMemoryStream(ArrayPool.Shared, 16); + stream.Write([1, 2, 3, 4]); + stream.Position = 1; + stream.Write([8, 9]); + + var writtenMemory = stream.WrittenMemory; + + Assert.Equal(4, writtenMemory.Length); + Assert.Equal([1, 8, 9, 4], writtenMemory.ToArray()); + } + + [Fact] + public void WrittenMemory_CanBeCopiedWithoutChangingPositionForSpill() + { + using var stream = new PooledMemoryStream(ArrayPool.Shared, 16); + stream.Write([1, 2]); + stream.Write([3, 4, 5]); + stream.Position = 2; + using var destination = new MemoryStream(); + + destination.Write(stream.WrittenMemory.Span); + + Assert.Equal([1, 2, 3, 4, 5], destination.ToArray()); + Assert.Equal(2, stream.Position); + } + + [Fact] + public void Dispose_ReturnsEveryRentedBufferExactlyOnce() + { + var (pool, _, returnedBuffers) = CreateExactSizePool(); + var stream = new PooledMemoryStream(pool.Object, 8); + stream.Write([1, 2]); + stream.Write([3, 4, 5]); + + stream.Dispose(); + stream.Dispose(); + + Assert.Equal(2, returnedBuffers.Count); + Assert.Equal(2, returnedBuffers.Distinct().Count()); + pool.Verify(p => p.Return(It.IsAny(), false), Times.Exactly(2)); + } + + [Fact] + public async Task DisposeAsync_ReturnsBufferAndIsIdempotentWithDispose() + { + var (pool, _, returnedBuffers) = CreateExactSizePool(); + var stream = new PooledMemoryStream(pool.Object, 8); + stream.Write([1, 2, 3]); + + await stream.DisposeAsync(); + await stream.DisposeAsync(); + stream.Dispose(); + + Assert.Single(returnedBuffers); + pool.Verify(p => p.Return(It.IsAny(), false), Times.Once); + } + + [Fact] + public async Task DisposedStream_ReportsClosedAndOperationsThrow() + { + var stream = CreateStreamWithData([1, 2, 3]); + await stream.DisposeAsync(); + + Assert.False(stream.CanRead); + Assert.False(stream.CanSeek); + Assert.False(stream.CanWrite); + Assert.Throws(() => stream.Flush()); + Assert.Throws(() => _ = stream.Length); + Assert.Throws(() => _ = stream.Position); + Assert.Throws(() => stream.Position = 0); + Assert.Throws(() => _ = stream.WrittenMemory); + Assert.Throws(() => stream.Read(new byte[1], 0, 1)); + Assert.Throws(() => stream.Write(new byte[1], 0, 1)); + Assert.Throws(() => stream.Seek(0, SeekOrigin.Begin)); + Assert.Throws(() => stream.SetLength(0)); + await Assert.ThrowsAsync( + async () => await stream.ReadAsync(new byte[1], CancellationToken.None)); + await Assert.ThrowsAsync( + async () => await stream.WriteAsync(new byte[1], CancellationToken.None)); + } + + private static PooledMemoryStream CreateStreamWithData(byte[] data) + { + var stream = new PooledMemoryStream(ArrayPool.Shared, 32); + stream.Write(data); + return stream; + } + + private static (Mock> Pool, List RentedSizes, List ReturnedBuffers) CreateExactSizePool() + { + var rentedSizes = new List(); + var returnedBuffers = new List(); + var pool = new Mock>(); + pool.Setup(p => p.Rent(It.IsAny())) + .Returns((int size) => + { + rentedSizes.Add(size); + return new byte[size]; + }); + pool.Setup(p => p.Return(It.IsAny(), It.IsAny())) + .Callback((byte[] buffer, bool _) => returnedBuffers.Add(buffer)); + + return (pool, rentedSizes, returnedBuffers); + } +} From 83f41f892b7be10d3c8fb0e3bcf25ac5bbaaf1cc Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Mon, 19 Oct 2026 09:40:03 +0000 Subject: [PATCH 05/19] Update dependencies from build 336805 Updated Dependencies: Microsoft.NET.Runtime.WebAssembly.Sdk, Microsoft.NETCore.BrowserDebugHost.Transport, Microsoft.NET.Runtime.MonoAOTCompiler.Task, dotnet-ef, Microsoft.Bcl.AsyncInterfaces, Microsoft.Bcl.Cryptography, Microsoft.Bcl.TimeProvider, Microsoft.EntityFrameworkCore, Microsoft.EntityFrameworkCore.Design, Microsoft.EntityFrameworkCore.InMemory, Microsoft.EntityFrameworkCore.Relational, Microsoft.EntityFrameworkCore.Sqlite, Microsoft.EntityFrameworkCore.SqlServer, Microsoft.EntityFrameworkCore.Tools, Microsoft.Extensions.Caching.Abstractions, Microsoft.Extensions.Caching.Memory, Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Abstractions, Microsoft.Extensions.Configuration.Binder, Microsoft.Extensions.Configuration.CommandLine, Microsoft.Extensions.Configuration.EnvironmentVariables, Microsoft.Extensions.Configuration.FileExtensions, Microsoft.Extensions.Configuration.Ini, Microsoft.Extensions.Configuration.Json, Microsoft.Extensions.Configuration.UserSecrets, Microsoft.Extensions.Configuration.Xml, Microsoft.Extensions.DependencyInjection, Microsoft.Extensions.DependencyInjection.Abstractions, Microsoft.Extensions.DependencyModel, Microsoft.Extensions.Diagnostics, Microsoft.Extensions.Diagnostics.Abstractions, Microsoft.Extensions.FileProviders.Abstractions, Microsoft.Extensions.FileProviders.Composite, Microsoft.Extensions.FileProviders.Physical, Microsoft.Extensions.FileSystemGlobbing, Microsoft.Extensions.HostFactoryResolver.Sources, Microsoft.Extensions.Hosting, Microsoft.Extensions.Hosting.Abstractions, Microsoft.Extensions.Http, Microsoft.Extensions.Logging, Microsoft.Extensions.Logging.Abstractions, Microsoft.Extensions.Logging.Configuration, Microsoft.Extensions.Logging.Console, Microsoft.Extensions.Logging.Debug, Microsoft.Extensions.Logging.EventLog, Microsoft.Extensions.Logging.EventSource, Microsoft.Extensions.Logging.TraceSource, Microsoft.Extensions.Options, Microsoft.Extensions.Options.ConfigurationExtensions, Microsoft.Extensions.Options.DataAnnotations, Microsoft.Extensions.Primitives, Microsoft.Internal.Runtime.AspNetCore.Transport, Microsoft.NETCore.App.Ref, Microsoft.NETCore.Platforms, Microsoft.Web.Xdt, System.Collections.Immutable, System.Composition, System.Configuration.ConfigurationManager, System.Diagnostics.DiagnosticSource, System.Diagnostics.EventLog, System.Diagnostics.PerformanceCounter, System.DirectoryServices.Protocols, System.Formats.Asn1, System.Formats.Cbor, System.IO.Hashing, System.IO.Pipelines, System.Memory.Data, System.Net.Http.Json, System.Net.Http.WinHttpHandler, System.Net.ServerSentEvents, System.Numerics.Tensors, System.Reflection.Metadata, System.Resources.Extensions, System.Runtime.Caching, System.Security.Cryptography.Pkcs, System.Security.Cryptography.Xml, System.Security.Permissions, System.ServiceProcess.ServiceController, System.Text.Encodings.Web, System.Text.Json, System.Threading.AccessControl, System.Threading.Channels, System.Threading.RateLimiting (Version 12.0.0-alpha.1.26513.123 -> 12.0.0-alpha.1.26515.101) Microsoft.DotNet.Arcade.Sdk, Microsoft.DotNet.Build.Tasks.Archives, Microsoft.DotNet.Build.Tasks.Installers, Microsoft.DotNet.Build.Tasks.Templating, Microsoft.DotNet.Helix.JobMonitor, Microsoft.DotNet.Helix.Sdk, Microsoft.DotNet.RemoteExecutor, Microsoft.DotNet.SharedFramework.Sdk (Version 12.0.0-beta.26513.123 -> 12.0.0-beta.26515.101) NuGet.Frameworks, NuGet.Packaging, NuGet.Versioning (Version 8.1.0-rc.51423 -> 8.1.0-rc.51601) [[ commit created by automation ]] --- .config/dotnet-tools.json | 4 +- eng/Version.Details.props | 188 +++++++++---------- eng/Version.Details.xml | 378 +++++++++++++++++++------------------- global.json | 6 +- 4 files changed, 288 insertions(+), 288 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index a96e8a5d6162..0322d4d29b37 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "dotnet-ef": { - "version": "12.0.0-alpha.1.26513.123", + "version": "12.0.0-alpha.1.26515.101", "commands": [ "dotnet-ef" ] @@ -27,7 +27,7 @@ ] }, "microsoft.dotnet.helix.jobmonitor": { - "version": "12.0.0-beta.26513.123", + "version": "12.0.0-beta.26515.101", "commands": [ "dotnet-helix-job-monitor" ] diff --git a/eng/Version.Details.props b/eng/Version.Details.props index e91973f954dc..3fd7aac46451 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -6,104 +6,104 @@ This file should be imported by eng/Versions.props - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 5.11.0-1.26420.103 5.11.0-1.26420.103 5.11.0-1.26420.103 5.11.0-1.26420.103 - 12.0.0-beta.26513.123 - 12.0.0-beta.26513.123 - 12.0.0-beta.26513.123 - 12.0.0-beta.26513.123 - 12.0.0-beta.26513.123 - 12.0.0-beta.26513.123 - 12.0.0-beta.26513.123 - 12.0.0-beta.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 8.1.0-rc.51423 - 8.1.0-rc.51423 - 8.1.0-rc.51423 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 - 12.0.0-alpha.1.26513.123 + 12.0.0-beta.26515.101 + 12.0.0-beta.26515.101 + 12.0.0-beta.26515.101 + 12.0.0-beta.26515.101 + 12.0.0-beta.26515.101 + 12.0.0-beta.26515.101 + 12.0.0-beta.26515.101 + 12.0.0-beta.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 8.1.0-rc.51601 + 8.1.0-rc.51601 + 8.1.0-rc.51601 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26515.101 10.10.1 10.10.1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 65e799a62189..8851c7fa663f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -8,333 +8,333 @@ See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md for instructions on using darc. --> - + - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea @@ -355,48 +355,48 @@ 1d599674e31ad86ca9e6e1dad7055b531e4d58e4 - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea https://github.com/dotnet/extensions @@ -456,17 +456,17 @@ https://github.com/dotnet/msbuild d1cce8d7cc03c23a4f1bad8e9240714fd9d199a3 - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea - + https://github.com/dotnet/dotnet - e1fc22dd641fa857d198afa8ec4c96eac1ac7f29 + 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea diff --git a/global.json b/global.json index c01253732b21..90ca3758fa08 100644 --- a/global.json +++ b/global.json @@ -22,9 +22,9 @@ "jdk": "latest" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "12.0.0-beta.26513.123", - "Microsoft.DotNet.Helix.Sdk": "12.0.0-beta.26513.123", - "Microsoft.DotNet.SharedFramework.Sdk": "12.0.0-beta.26513.123", + "Microsoft.DotNet.Arcade.Sdk": "12.0.0-beta.26515.101", + "Microsoft.DotNet.Helix.Sdk": "12.0.0-beta.26515.101", + "Microsoft.DotNet.SharedFramework.Sdk": "12.0.0-beta.26515.101", "Microsoft.Build.NoTargets": "3.7.134", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.WixToolset.Sdk": "6.0.3-dotnet.6" From 1d2e09c353d81a531d916c7a0b4468e86e351a17 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Mon, 19 Oct 2026 10:20:16 +0000 Subject: [PATCH 06/19] Update dependencies from build 336905 Updated Dependencies: Microsoft.NET.Runtime.WebAssembly.Sdk, Microsoft.NETCore.BrowserDebugHost.Transport, Microsoft.NET.Runtime.MonoAOTCompiler.Task, dotnet-ef, Microsoft.Bcl.AsyncInterfaces, Microsoft.Bcl.Cryptography, Microsoft.Bcl.TimeProvider, Microsoft.EntityFrameworkCore, Microsoft.EntityFrameworkCore.Design, Microsoft.EntityFrameworkCore.InMemory, Microsoft.EntityFrameworkCore.Relational, Microsoft.EntityFrameworkCore.Sqlite, Microsoft.EntityFrameworkCore.SqlServer, Microsoft.EntityFrameworkCore.Tools, Microsoft.Extensions.Caching.Abstractions, Microsoft.Extensions.Caching.Memory, Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Abstractions, Microsoft.Extensions.Configuration.Binder, Microsoft.Extensions.Configuration.CommandLine, Microsoft.Extensions.Configuration.EnvironmentVariables, Microsoft.Extensions.Configuration.FileExtensions, Microsoft.Extensions.Configuration.Ini, Microsoft.Extensions.Configuration.Json, Microsoft.Extensions.Configuration.UserSecrets, Microsoft.Extensions.Configuration.Xml, Microsoft.Extensions.DependencyInjection, Microsoft.Extensions.DependencyInjection.Abstractions, Microsoft.Extensions.DependencyModel, Microsoft.Extensions.Diagnostics, Microsoft.Extensions.Diagnostics.Abstractions, Microsoft.Extensions.FileProviders.Abstractions, Microsoft.Extensions.FileProviders.Composite, Microsoft.Extensions.FileProviders.Physical, Microsoft.Extensions.FileSystemGlobbing, Microsoft.Extensions.HostFactoryResolver.Sources, Microsoft.Extensions.Hosting, Microsoft.Extensions.Hosting.Abstractions, Microsoft.Extensions.Http, Microsoft.Extensions.Logging, Microsoft.Extensions.Logging.Abstractions, Microsoft.Extensions.Logging.Configuration, Microsoft.Extensions.Logging.Console, Microsoft.Extensions.Logging.Debug, Microsoft.Extensions.Logging.EventLog, Microsoft.Extensions.Logging.EventSource, Microsoft.Extensions.Logging.TraceSource, Microsoft.Extensions.Options, Microsoft.Extensions.Options.ConfigurationExtensions, Microsoft.Extensions.Options.DataAnnotations, Microsoft.Extensions.Primitives, Microsoft.Internal.Runtime.AspNetCore.Transport, Microsoft.NETCore.App.Ref, Microsoft.NETCore.Platforms, Microsoft.Web.Xdt, System.Collections.Immutable, System.Composition, System.Configuration.ConfigurationManager, System.Diagnostics.DiagnosticSource, System.Diagnostics.EventLog, System.Diagnostics.PerformanceCounter, System.DirectoryServices.Protocols, System.Formats.Asn1, System.Formats.Cbor, System.IO.Hashing, System.IO.Pipelines, System.Memory.Data, System.Net.Http.Json, System.Net.Http.WinHttpHandler, System.Net.ServerSentEvents, System.Numerics.Tensors, System.Reflection.Metadata, System.Resources.Extensions, System.Runtime.Caching, System.Security.Cryptography.Pkcs, System.Security.Cryptography.Xml, System.Security.Permissions, System.ServiceProcess.ServiceController, System.Text.Encodings.Web, System.Text.Json, System.Threading.AccessControl, System.Threading.Channels, System.Threading.RateLimiting (Version 12.0.0-alpha.1.26515.101 -> 12.0.0-alpha.1.26516.101) Microsoft.DotNet.Arcade.Sdk, Microsoft.DotNet.Build.Tasks.Archives, Microsoft.DotNet.Build.Tasks.Installers, Microsoft.DotNet.Build.Tasks.Templating, Microsoft.DotNet.Helix.JobMonitor, Microsoft.DotNet.Helix.Sdk, Microsoft.DotNet.RemoteExecutor, Microsoft.DotNet.SharedFramework.Sdk (Version 12.0.0-beta.26515.101 -> 12.0.0-beta.26516.101) NuGet.Frameworks, NuGet.Packaging, NuGet.Versioning (Version 8.1.0-rc.51601 -> 8.1.0-rc.51701) [[ commit created by automation ]] --- .config/dotnet-tools.json | 4 +- eng/Version.Details.props | 188 ++++----- eng/Version.Details.xml | 378 +++++++++--------- global.json | 6 +- .../src/RequestLocalizationMiddleware.cs | 2 +- .../test/FunctionalTests/LocalizationTest.cs | 12 +- .../RequestLocalizationMiddlewareTest.cs | 45 +++ .../StartupCultureFallback.cs | 22 + .../Http3/Http3RequestTests.cs | 1 - src/SignalR/common/Shared/MessageBuffer.cs | 171 +++++--- .../Internal/MessageBufferTests.cs | 228 +++++++++++ 11 files changed, 709 insertions(+), 348 deletions(-) create mode 100644 src/Middleware/Localization/testassets/LocalizationWebsite/StartupCultureFallback.cs diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 0322d4d29b37..3c60bb73491d 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "dotnet-ef": { - "version": "12.0.0-alpha.1.26515.101", + "version": "12.0.0-alpha.1.26516.101", "commands": [ "dotnet-ef" ] @@ -27,7 +27,7 @@ ] }, "microsoft.dotnet.helix.jobmonitor": { - "version": "12.0.0-beta.26515.101", + "version": "12.0.0-beta.26516.101", "commands": [ "dotnet-helix-job-monitor" ] diff --git a/eng/Version.Details.props b/eng/Version.Details.props index 3fd7aac46451..acfa74d80e14 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -6,104 +6,104 @@ This file should be imported by eng/Versions.props - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 5.11.0-1.26420.103 5.11.0-1.26420.103 5.11.0-1.26420.103 5.11.0-1.26420.103 - 12.0.0-beta.26515.101 - 12.0.0-beta.26515.101 - 12.0.0-beta.26515.101 - 12.0.0-beta.26515.101 - 12.0.0-beta.26515.101 - 12.0.0-beta.26515.101 - 12.0.0-beta.26515.101 - 12.0.0-beta.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 8.1.0-rc.51601 - 8.1.0-rc.51601 - 8.1.0-rc.51601 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 - 12.0.0-alpha.1.26515.101 + 12.0.0-beta.26516.101 + 12.0.0-beta.26516.101 + 12.0.0-beta.26516.101 + 12.0.0-beta.26516.101 + 12.0.0-beta.26516.101 + 12.0.0-beta.26516.101 + 12.0.0-beta.26516.101 + 12.0.0-beta.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 8.1.0-rc.51701 + 8.1.0-rc.51701 + 8.1.0-rc.51701 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26516.101 10.10.1 10.10.1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 8851c7fa663f..5e1f515e6d80 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -8,333 +8,333 @@ See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md for instructions on using darc. --> - + - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 @@ -355,48 +355,48 @@ 1d599674e31ad86ca9e6e1dad7055b531e4d58e4 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 https://github.com/dotnet/extensions @@ -456,17 +456,17 @@ https://github.com/dotnet/msbuild d1cce8d7cc03c23a4f1bad8e9240714fd9d199a3 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 - + https://github.com/dotnet/dotnet - 85ada61bb2d484d9ddc9487b2dcb61bd0f56ccea + be06e8febe57db1ea30be9f0863133a892c01645 diff --git a/global.json b/global.json index 90ca3758fa08..34f048c5e2ec 100644 --- a/global.json +++ b/global.json @@ -22,9 +22,9 @@ "jdk": "latest" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "12.0.0-beta.26515.101", - "Microsoft.DotNet.Helix.Sdk": "12.0.0-beta.26515.101", - "Microsoft.DotNet.SharedFramework.Sdk": "12.0.0-beta.26515.101", + "Microsoft.DotNet.Arcade.Sdk": "12.0.0-beta.26516.101", + "Microsoft.DotNet.Helix.Sdk": "12.0.0-beta.26516.101", + "Microsoft.DotNet.SharedFramework.Sdk": "12.0.0-beta.26516.101", "Microsoft.Build.NoTargets": "3.7.134", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.WixToolset.Sdk": "6.0.3-dotnet.6" diff --git a/src/Middleware/Localization/src/RequestLocalizationMiddleware.cs b/src/Middleware/Localization/src/RequestLocalizationMiddleware.cs index 1c54a7beaa7b..79eaf7fb031c 100644 --- a/src/Middleware/Localization/src/RequestLocalizationMiddleware.cs +++ b/src/Middleware/Localization/src/RequestLocalizationMiddleware.cs @@ -167,7 +167,7 @@ private static void SetCurrentThreadCulture(RequestCulture requestCulture) { try { - culture = CultureInfo.GetCultureInfo(cultureName.ToString()); + culture = CultureInfo.GetCultureInfo(cultureName.ToString(), predefinedOnly: true); culture = GetCultureInfo(culture.Parent.Name, supportedCultures, fallbackToParentCultures, currentDepth + 1); } diff --git a/src/Middleware/Localization/test/FunctionalTests/LocalizationTest.cs b/src/Middleware/Localization/test/FunctionalTests/LocalizationTest.cs index e54b065f6089..ff37e45aac6d 100644 --- a/src/Middleware/Localization/test/FunctionalTests/LocalizationTest.cs +++ b/src/Middleware/Localization/test/FunctionalTests/LocalizationTest.cs @@ -58,21 +58,21 @@ public Task Localization_ResourcesInFolder_ReturnLocalizedValue() } [Fact] - public Task Localization_ResourcesInFolder_ReturnLocalizedValue_WithCultureFallback() + public Task Localization_ResourcesInFolder_ReturnNonLocalizedValue_WithNonPredefinedCulture() { return RunTest( typeof(StartupResourcesInFolder), "fr-FR-test", - "Bonjour from StartupResourcesInFolder Bonjour from Test in resources folder Bonjour from Customer in resources folder Hello"); + "Hello Hello Hello Hello"); } [Fact] - public Task Localization_ResourcesInFolder_ReturnNonLocalizedValue_CultureHierarchyTooDeep() + public Task Localization_PredefinedCultureFallsBackToParent() { return RunTest( - typeof(StartupResourcesInFolder), - "fr-FR-test-again-too-deep-to-work", - "Hello Hello Hello Hello"); + typeof(StartupCultureFallback), + "en-US", + "en en"); } [Fact] diff --git a/src/Middleware/Localization/test/UnitTests/RequestLocalizationMiddlewareTest.cs b/src/Middleware/Localization/test/UnitTests/RequestLocalizationMiddlewareTest.cs index 11811b7a22e2..e14bb907c406 100644 --- a/src/Middleware/Localization/test/UnitTests/RequestLocalizationMiddlewareTest.cs +++ b/src/Middleware/Localization/test/UnitTests/RequestLocalizationMiddlewareTest.cs @@ -14,6 +14,51 @@ namespace Microsoft.Extensions.Localization; public class RequestLocalizationMiddlewareTest { + [Fact] + public async Task RequestLocalizationMiddleware_DoesNotFallBackFromNonPredefinedCulture() + { + using var host = new HostBuilder() + .ConfigureWebHost(webHostBuilder => + { + webHostBuilder + .UseTestServer() + .Configure(app => + { + app.UseRequestLocalization(options => + { + options.SetDefaultCulture("en-US") + .AddSupportedCultures("en-US", "fr-FR") + .AddSupportedUICultures("en-US", "fr-FR") + .AddInitialRequestCultureProvider(new CookieRequestCultureProvider + { + CookieName = "Preferences" + }); + }); + + app.Run(context => + { + var requestCulture = context.Features.Get(); + + Assert.Equal("en-US", requestCulture.RequestCulture.Culture.Name); + Assert.Equal("en-US", requestCulture.RequestCulture.UICulture.Name); + + return Task.CompletedTask; + }); + }); + }).Build(); + + await host.StartAsync(); + + using var server = host.GetTestServer(); + var client = server.CreateClient(); + const string nonPredefinedCulture = "fr-FR-a0000001-b0000001-c0000001-d0000001-e0000001"; + client.DefaultRequestHeaders.Add("Cookie", new CookieHeaderValue("Preferences", $"c={nonPredefinedCulture}|uic={nonPredefinedCulture}").ToString()); + + var response = await client.GetAsync(string.Empty); + + response.EnsureSuccessStatusCode(); + } + [Theory] [InlineData("zh-Hans-CN", "zh")] [InlineData("zh-Hans", "zh")] diff --git a/src/Middleware/Localization/testassets/LocalizationWebsite/StartupCultureFallback.cs b/src/Middleware/Localization/testassets/LocalizationWebsite/StartupCultureFallback.cs new file mode 100644 index 000000000000..2a17f1aeb7c3 --- /dev/null +++ b/src/Middleware/Localization/testassets/LocalizationWebsite/StartupCultureFallback.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; +using Microsoft.AspNetCore.Localization; + +namespace LocalizationWebsite; + +public class StartupCultureFallback +{ + public void Configure(IApplicationBuilder app) + { + app.UseRequestLocalization(options => + { + options.SetDefaultCulture("fr-FR") + .AddSupportedCultures("en") + .AddSupportedUICultures("en"); + }); + + app.Run(context => context.Response.WriteAsync($"{CultureInfo.CurrentCulture.Name} {CultureInfo.CurrentUICulture.Name}")); + } +} diff --git a/src/Servers/Kestrel/test/Interop.FunctionalTests/Http3/Http3RequestTests.cs b/src/Servers/Kestrel/test/Interop.FunctionalTests/Http3/Http3RequestTests.cs index 22bc154eeb47..de4fedb50a6f 100644 --- a/src/Servers/Kestrel/test/Interop.FunctionalTests/Http3/Http3RequestTests.cs +++ b/src/Servers/Kestrel/test/Interop.FunctionalTests/Http3/Http3RequestTests.cs @@ -1904,7 +1904,6 @@ public async Task GET_ClientDisconnected_ConnectionAbortRaised() [ConditionalFact] [MsQuicSupported] - [QuarantinedTest("https://github.com/dotnet/aspnetcore/issues/69582", OperatingSystems.Linux)] public async Task ConnectionLifetimeNotificationFeature_RequestClose_ConnectionEnds() { // Arrange diff --git a/src/SignalR/common/Shared/MessageBuffer.cs b/src/SignalR/common/Shared/MessageBuffer.cs index 377d7a929ccc..8b4f0c3603fe 100644 --- a/src/SignalR/common/Shared/MessageBuffer.cs +++ b/src/SignalR/common/Shared/MessageBuffer.cs @@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.SignalR.Internal; internal sealed class MessageBuffer : IDisposable { private static readonly TaskCompletionSource _completedTCS = new TaskCompletionSource(); + private static readonly TimeSpan _backpressureTimeout = TimeSpan.FromSeconds(5); public static TimeSpan AckRate => TimeSpan.FromSeconds(1); @@ -27,6 +28,7 @@ internal sealed class MessageBuffer : IDisposable private readonly IHubProtocol _protocol; private readonly long _bufferLimit; private readonly ILogger _logger; + private readonly ConnectionContext _connection; private readonly AckMessage _ackMessage = new(0); private readonly SequenceMessage _sequenceMessage = new(0); private readonly Channel _waitForAck = Channel.CreateBounded(new BoundedChannelOptions(1) { FullMode = BoundedChannelFullMode.DropOldest }); @@ -56,6 +58,7 @@ internal sealed class MessageBuffer : IDisposable private LinkedBuffer _bufferHead; private LinkedBuffer _bufferTail; private long _bufferedByteCount; + private int _disposed; static MessageBuffer() { @@ -76,6 +79,7 @@ public MessageBuffer(ConnectionContext connection, IHubProtocol protocol, long b _bufferHead = _bufferTail = new LinkedBuffer(); + _connection = connection; _writer = connection.Transport.Output; _protocol = protocol; _bufferLimit = bufferLimit; @@ -89,36 +93,48 @@ public MessageBuffer(ConnectionContext connection, IHubProtocol protocol, long b private async Task RunTimer() { - using (_timer) + try { + using (_timer) + { #if NET8_0_OR_GREATER - while (await _timer.WaitForNextTickAsync().ConfigureAwait(false)) + while (await _timer.WaitForNextTickAsync().ConfigureAwait(false)) #else - while (await _timer) + while (await _timer) #endif - { - if (_lastAckedId < _latestReceivedSequenceId) { - // TODO: consider a minimum time between sending these? + if (_lastAckedId < _latestReceivedSequenceId) + { + // TODO: consider a minimum time between sending these? - var sequenceId = _latestReceivedSequenceId; + var sequenceId = _latestReceivedSequenceId; - _ackMessage.SequenceId = sequenceId; + _ackMessage.SequenceId = sequenceId; - await _writeLock.WaitAsync().ConfigureAwait(false); - try - { - _protocol.WriteMessage(_ackMessage, _writer); - await _writer.FlushAsync().ConfigureAwait(false); - _lastAckedId = sequenceId; - } - finally - { - _writeLock.Release(); + await _writeLock.WaitAsync().ConfigureAwait(false); + try + { + using var cts = CreateBackpressureCancellationTokenSource(); + _protocol.WriteMessage(_ackMessage, _writer); + await _writer.FlushAsync(cts.Token).ConfigureAwait(false); + _lastAckedId = sequenceId; + } + finally + { + _writeLock.Release(); + } } } } } + catch (Exception ex) + { + if (Volatile.Read(ref _disposed) == 0) + { + _logger.LogDebug(ex, "Failure while sending an acknowledgment message."); + _connection.Abort(); + } + } } public ValueTask WriteAsync(SerializedHubMessage hubMessage, CancellationToken cancellationToken) @@ -137,11 +153,7 @@ private async ValueTask WriteAsyncCore(Type hubMessageType, ReadOnl // TODO: Add backpressure based on message count if (_bufferedByteCount > _bufferLimit) { -#if NET - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5), _timeProvider); -#else - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)); -#endif + using var cts = CreateBackpressureCancellationTokenSource(); using var _ = CancellationTokenUtils.CreateLinkedToken(cts.Token, cancellationToken, out var linkedToken); // primitive backpressure if buffer is full while (await _waitForAck.Reader.WaitToReadAsync(linkedToken).ConfigureAwait(false)) @@ -266,59 +278,114 @@ internal async Task ResendAsync(PipeWriter writer) _resend = tcs; FlushResult finalResult = new(); - await _writeLock.WaitAsync().ConfigureAwait(false); + var cts = CreateBackpressureCancellationTokenSource(); try { - // Complete previous pipe so transport reader can cleanup - _writer.Complete(); - // Replace writer with new pipe that the transport will be reading from - _writer = writer; + await _writeLock.WaitAsync(cts.Token).ConfigureAwait(false); + try + { + cts = ResetBackpressureCancellationTokenSource(cts); - _sequenceMessage.SequenceId = _totalMessageCount + 1; + // Complete previous pipe so transport reader can cleanup + _writer.Complete(); + // Replace writer with new pipe that the transport will be reading from + _writer = writer; - var isFirst = true; - // Loop over all buffered messages and send them - foreach (var item in _bufferHead.GetMessages()) - { - if (item.SequenceId > 0) + _sequenceMessage.SequenceId = _totalMessageCount + 1; + + var isFirst = true; + // Loop over all buffered messages and send them + foreach (var item in _bufferHead.GetMessages()) { - // The first message we send is a SequenceMessage with the ID of the first unacked message we're sending - if (isFirst) + if (item.SequenceId > 0) { - _sequenceMessage.SequenceId = item.SequenceId; - // No need to flush since we're immediately calling WriteAsync after - _protocol.WriteMessage(_sequenceMessage, _writer); - isFirst = false; + // The first message we send is a SequenceMessage with the ID of the first unacked message we're sending + if (isFirst) + { + _sequenceMessage.SequenceId = item.SequenceId; + // No need to flush since we're immediately calling WriteAsync after + _protocol.WriteMessage(_sequenceMessage, _writer); + isFirst = false; + } + // Use WriteAsync instead of doing all Writes and then a FlushAsync so we can observe backpressure + finalResult = await _writer.WriteAsync(item.HubMessage, cts.Token).ConfigureAwait(false); + if (finalResult.IsCanceled || finalResult.IsCompleted) + { + break; + } + + cts = ResetBackpressureCancellationTokenSource(cts); } - // Use WriteAsync instead of doing all Writes and then a FlushAsync so we can observe backpressure - finalResult = await _writer.WriteAsync(item.HubMessage).ConfigureAwait(false); } - } - // There were no buffered messages, we still need to send the SequenceMessage to let the client know what ID messages will start at - if (isFirst) + // There were no buffered messages, we still need to send the SequenceMessage to let the client know what ID messages will start at + if (isFirst) + { + _protocol.WriteMessage(_sequenceMessage, _writer); + finalResult = await _writer.FlushAsync(cts.Token).ConfigureAwait(false); + } + + tcs.TrySetResult(finalResult); + } + finally { - _protocol.WriteMessage(_sequenceMessage, _writer); - finalResult = await _writer.FlushAsync().ConfigureAwait(false); + _writeLock.Release(); } } catch (Exception ex) { - tcs.SetException(ex); + tcs.TrySetException(ex); // Observe exception in case WriteAsync isn't waiting on the task _ = tcs.Task.Exception; - _logger.LogDebug(ex, "Failure while resending messages after a reconnect."); + + if (Volatile.Read(ref _disposed) == 0) + { + _logger.LogDebug(ex, "Failure while resending messages after a reconnect."); + _connection.Abort(); + } } finally { - _writeLock.Release(); - tcs.TrySetResult(finalResult); + cts.Dispose(); } } +#if NET + private CancellationTokenSource CreateBackpressureCancellationTokenSource() + { + return new CancellationTokenSource(_backpressureTimeout, _timeProvider); + } + + private CancellationTokenSource ResetBackpressureCancellationTokenSource(CancellationTokenSource cts) + { + if (cts.TryReset()) + { + cts.CancelAfter(_backpressureTimeout); + return cts; + } + + cts.Dispose(); + return CreateBackpressureCancellationTokenSource(); + } +#else + private static CancellationTokenSource CreateBackpressureCancellationTokenSource() + { + return new CancellationTokenSource(_backpressureTimeout); + } + + private static CancellationTokenSource ResetBackpressureCancellationTokenSource(CancellationTokenSource cts) + { + cts.Dispose(); + return CreateBackpressureCancellationTokenSource(); + } +#endif + public void Dispose() { - ((IDisposable)_timer).Dispose(); + if (Interlocked.Exchange(ref _disposed, 1) == 0) + { + ((IDisposable)_timer).Dispose(); + } } // Linked list of SerializedHubMessage arrays, sort of like ReadOnlySequence diff --git a/src/SignalR/server/SignalR/test/Microsoft.AspNetCore.SignalR.Tests/Internal/MessageBufferTests.cs b/src/SignalR/server/SignalR/test/Microsoft.AspNetCore.SignalR.Tests/Internal/MessageBufferTests.cs index 9a7fc5fd1629..2d1674973b37 100644 --- a/src/SignalR/server/SignalR/test/Microsoft.AspNetCore.SignalR.Tests/Internal/MessageBufferTests.cs +++ b/src/SignalR/server/SignalR/test/Microsoft.AspNetCore.SignalR.Tests/Internal/MessageBufferTests.cs @@ -545,6 +545,31 @@ public async Task AckMessagesSentAutomatically() Assert.Equal(3, ackMessage.SequenceId); } + [Fact] + public async Task AckBackpressureTimesOutReleasesWriteLockAndAbortsConnection() + { + var protocol = new JsonHubProtocol(); + var connection = new TestConnectionContext(); + var pipes = DuplexPipe.CreateConnectionPair(new PipeOptions(), new PipeOptions()); + var writer = new BlockingFlushPipeWriter(pipes.Transport.Output); + connection.Transport = new DuplexPipe(pipes.Transport.Input, writer); + var timeProvider = new FakeTimeProvider(); + using var messageBuffer = new MessageBuffer(connection, protocol, bufferLimit: 100_000, NullLogger.Instance, timeProvider); + + Assert.True(messageBuffer.ShouldProcessMessage(new StreamItemMessage("1", null))); + + timeProvider.Advance(MessageBuffer.AckRate); + await writer.FlushStarted.DefaultTimeout(); + + var ackTask = messageBuffer.AckAsync(new AckMessage(0)); + Assert.False(ackTask.IsCompleted); + + timeProvider.Advance(TimeSpan.FromSeconds(5) + TimeSpan.FromMilliseconds(1)); + + await connection.Aborted.DefaultTimeout(); + await ackTask.DefaultTimeout(); + } + [Fact] public async Task ReceiveAckDuringResendStillSendsAllMessages() { @@ -645,6 +670,114 @@ public async Task SendingAckMessageDelayedDuringResend() Assert.False(pipes.Application.Input.TryRead(out res)); } + [Fact] + public async Task ResendBackpressureTimesOutAndUnblocksPendingWrites() + { + var protocol = new JsonHubProtocol(); + var connection = new TestConnectionContext(); + var pipes = DuplexPipe.CreateConnectionPair( + new PipeOptions(), + new PipeOptions(pauseWriterThreshold: 200, resumeWriterThreshold: 100)); + connection.Transport = pipes.Transport; + var timeProvider = new FakeTimeProvider(); + using var messageBuffer = new MessageBuffer(connection, protocol, bufferLimit: 100_000, NullLogger.Instance, timeProvider); + + for (var i = 0; i < 2; i++) + { + await messageBuffer.WriteAsync(new InvocationMessage("t", [new byte[40]]), CancellationToken.None); + + var result = await pipes.Application.Input.ReadAsync(); + pipes.Application.Input.AdvanceTo(result.Buffer.End); + } + + DuplexPipe.UpdateConnectionPair( + ref pipes, + connection, + new PipeOptions(pauseWriterThreshold: 100, resumeWriterThreshold: 50)); + var resendTask = messageBuffer.ResendAsync(pipes.Transport.Output); + var writeTask = messageBuffer.WriteAsync(PingMessage.Instance, CancellationToken.None).AsTask(); + + Assert.False(resendTask.IsCompleted); + Assert.False(writeTask.IsCompleted); + + timeProvider.Advance(TimeSpan.FromSeconds(5) + TimeSpan.FromMilliseconds(1)); + + await resendTask.DefaultTimeout(); + await connection.Aborted.DefaultTimeout(); + await Assert.ThrowsAnyAsync(async () => await writeTask).DefaultTimeout(); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task ResendStopsWhenFlushIsCanceledOrCompleted(bool isCanceled) + { + var protocol = new JsonHubProtocol(); + var connection = new TestConnectionContext(); + var pipes = DuplexPipe.CreateConnectionPair(new PipeOptions(), new PipeOptions()); + connection.Transport = pipes.Transport; + using var messageBuffer = new MessageBuffer(connection, protocol, bufferLimit: 100_000, NullLogger.Instance); + + for (var i = 0; i < 3; i++) + { + await messageBuffer.WriteAsync(new InvocationMessage("t", [i]), CancellationToken.None); + + var result = await pipes.Application.Input.ReadAsync(); + pipes.Application.Input.AdvanceTo(result.Buffer.End); + } + + var reconnectPipe = new Pipe(); + var writer = new FlushResultPipeWriter( + reconnectPipe.Writer, + new FlushResult(isCanceled: isCanceled, isCompleted: !isCanceled)); + + await messageBuffer.ResendAsync(writer); + + Assert.Equal(1, writer.FlushCount); + Assert.False(connection.Aborted.IsCompleted); + } + + [Fact] + public async Task ResendBackpressureTimeoutResetsAfterProgress() + { + var protocol = new JsonHubProtocol(); + var connection = new TestConnectionContext(); + var pipes = DuplexPipe.CreateConnectionPair( + new PipeOptions(), + new PipeOptions(pauseWriterThreshold: 1_000, resumeWriterThreshold: 500)); + connection.Transport = pipes.Transport; + var timeProvider = new FakeTimeProvider(); + using var messageBuffer = new MessageBuffer(connection, protocol, bufferLimit: 100_000, NullLogger.Instance, timeProvider); + + for (var i = 0; i < 3; i++) + { + await messageBuffer.WriteAsync(new InvocationMessage("t", [new byte[100]]), CancellationToken.None); + + var result = await pipes.Application.Input.ReadAsync(); + pipes.Application.Input.AdvanceTo(result.Buffer.End); + } + + DuplexPipe.UpdateConnectionPair( + ref pipes, + connection, + new PipeOptions(pauseWriterThreshold: 100, resumeWriterThreshold: 50)); + var resendTask = messageBuffer.ResendAsync(pipes.Transport.Output); + + for (var i = 0; i < 3; i++) + { + var result = await pipes.Application.Input.ReadAsync().DefaultTimeout(); + Assert.False(result.Buffer.IsEmpty); + + timeProvider.Advance(TimeSpan.FromSeconds(4)); + Assert.False(resendTask.IsCompleted); + + pipes.Application.Input.AdvanceTo(result.Buffer.End); + } + + await resendTask.DefaultTimeout(); + await messageBuffer.WriteAsync(PingMessage.Instance, CancellationToken.None).AsTask().DefaultTimeout(); + } + [Fact] public async Task PipeBackpressureWriteMessageCanBeCanceled() { @@ -780,12 +913,107 @@ public async Task BufferedBackpressureWriteMessageCanBeCanceled() } } +internal sealed class BlockingFlushPipeWriter(PipeWriter inner) : PipeWriter +{ + private readonly TaskCompletionSource _flushStarted = new(TaskCreationOptions.RunContinuationsAsynchronously); + + public Task FlushStarted => _flushStarted.Task; + + public override void Advance(int bytes) + { + inner.Advance(bytes); + } + + public override void CancelPendingFlush() + { + inner.CancelPendingFlush(); + } + + public override void Complete(Exception exception = null) + { + inner.Complete(exception); + } + + public override ValueTask FlushAsync(CancellationToken cancellationToken = default) + { + _flushStarted.TrySetResult(); + return new(WaitForCancellationAsync(cancellationToken)); + } + + public override Memory GetMemory(int sizeHint = 0) + { + return inner.GetMemory(sizeHint); + } + + public override Span GetSpan(int sizeHint = 0) + { + return inner.GetSpan(sizeHint); + } + + private static async Task WaitForCancellationAsync(CancellationToken cancellationToken) + { + await Task.Delay(Timeout.InfiniteTimeSpan, cancellationToken); + return default; + } +} + +internal sealed class FlushResultPipeWriter(PipeWriter inner, FlushResult flushResult) : PipeWriter +{ + public int FlushCount { get; private set; } + + public override void Advance(int bytes) + { + inner.Advance(bytes); + } + + public override void CancelPendingFlush() + { + inner.CancelPendingFlush(); + } + + public override void Complete(Exception exception = null) + { + inner.Complete(exception); + } + + public override ValueTask FlushAsync(CancellationToken cancellationToken = default) + { + FlushCount++; + return new(flushResult); + } + + public override Memory GetMemory(int sizeHint = 0) + { + return inner.GetMemory(sizeHint); + } + + public override Span GetSpan(int sizeHint = 0) + { + return inner.GetSpan(sizeHint); + } + + public override ValueTask WriteAsync(ReadOnlyMemory source, CancellationToken cancellationToken = default) + { + FlushCount++; + return new(flushResult); + } +} + internal sealed class TestConnectionContext : ConnectionContext { + private readonly TaskCompletionSource _aborted = new(TaskCreationOptions.RunContinuationsAsynchronously); + + public Task Aborted => _aborted.Task; + public override string ConnectionId { get; set; } public override IFeatureCollection Features { get; } = new FeatureCollection(); public override IDictionary Items { get; set; } public override IDuplexPipe Transport { get; set; } + + public override void Abort() + { + _aborted.TrySetResult(); + } } internal sealed class DuplexPipe : IDuplexPipe From c93e4024e6a329f9983403f9ff7ca3c9b3eca0e0 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Tue, 20 Oct 2026 02:06:03 +0000 Subject: [PATCH 07/19] Update dependencies from build 337216 Updated Dependencies: Microsoft.NET.Runtime.WebAssembly.Sdk, Microsoft.NETCore.BrowserDebugHost.Transport, Microsoft.NET.Runtime.MonoAOTCompiler.Task, dotnet-ef, Microsoft.Bcl.AsyncInterfaces, Microsoft.Bcl.Cryptography, Microsoft.Bcl.TimeProvider, Microsoft.EntityFrameworkCore, Microsoft.EntityFrameworkCore.Design, Microsoft.EntityFrameworkCore.InMemory, Microsoft.EntityFrameworkCore.Relational, Microsoft.EntityFrameworkCore.Sqlite, Microsoft.EntityFrameworkCore.SqlServer, Microsoft.EntityFrameworkCore.Tools, Microsoft.Extensions.Caching.Abstractions, Microsoft.Extensions.Caching.Memory, Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Abstractions, Microsoft.Extensions.Configuration.Binder, Microsoft.Extensions.Configuration.CommandLine, Microsoft.Extensions.Configuration.EnvironmentVariables, Microsoft.Extensions.Configuration.FileExtensions, Microsoft.Extensions.Configuration.Ini, Microsoft.Extensions.Configuration.Json, Microsoft.Extensions.Configuration.UserSecrets, Microsoft.Extensions.Configuration.Xml, Microsoft.Extensions.DependencyInjection, Microsoft.Extensions.DependencyInjection.Abstractions, Microsoft.Extensions.DependencyModel, Microsoft.Extensions.Diagnostics, Microsoft.Extensions.Diagnostics.Abstractions, Microsoft.Extensions.FileProviders.Abstractions, Microsoft.Extensions.FileProviders.Composite, Microsoft.Extensions.FileProviders.Physical, Microsoft.Extensions.FileSystemGlobbing, Microsoft.Extensions.HostFactoryResolver.Sources, Microsoft.Extensions.Hosting, Microsoft.Extensions.Hosting.Abstractions, Microsoft.Extensions.Http, Microsoft.Extensions.Logging, Microsoft.Extensions.Logging.Abstractions, Microsoft.Extensions.Logging.Configuration, Microsoft.Extensions.Logging.Console, Microsoft.Extensions.Logging.Debug, Microsoft.Extensions.Logging.EventLog, Microsoft.Extensions.Logging.EventSource, Microsoft.Extensions.Logging.TraceSource, Microsoft.Extensions.Options, Microsoft.Extensions.Options.ConfigurationExtensions, Microsoft.Extensions.Options.DataAnnotations, Microsoft.Extensions.Primitives, Microsoft.Internal.Runtime.AspNetCore.Transport, Microsoft.NETCore.App.Ref, Microsoft.NETCore.Platforms, Microsoft.Web.Xdt, System.Collections.Immutable, System.Composition, System.Configuration.ConfigurationManager, System.Diagnostics.DiagnosticSource, System.Diagnostics.EventLog, System.Diagnostics.PerformanceCounter, System.DirectoryServices.Protocols, System.Formats.Asn1, System.Formats.Cbor, System.IO.Hashing, System.IO.Pipelines, System.Memory.Data, System.Net.Http.Json, System.Net.Http.WinHttpHandler, System.Net.ServerSentEvents, System.Numerics.Tensors, System.Reflection.Metadata, System.Resources.Extensions, System.Runtime.Caching, System.Security.Cryptography.Pkcs, System.Security.Cryptography.Xml, System.Security.Permissions, System.ServiceProcess.ServiceController, System.Text.Encodings.Web, System.Text.Json, System.Threading.AccessControl, System.Threading.Channels, System.Threading.RateLimiting (Version 12.0.0-alpha.1.26516.101 -> 12.0.0-alpha.1.26519.106) Microsoft.DotNet.Arcade.Sdk, Microsoft.DotNet.Build.Tasks.Archives, Microsoft.DotNet.Build.Tasks.Installers, Microsoft.DotNet.Build.Tasks.Templating, Microsoft.DotNet.Helix.JobMonitor, Microsoft.DotNet.Helix.Sdk, Microsoft.DotNet.RemoteExecutor, Microsoft.DotNet.SharedFramework.Sdk (Version 12.0.0-beta.26516.101 -> 12.0.0-beta.26519.106) NuGet.Frameworks, NuGet.Packaging, NuGet.Versioning (Version 8.1.0-rc.51701 -> 8.1.0-rc.52006) [[ commit created by automation ]] --- .config/dotnet-tools.json | 4 +- eng/Version.Details.props | 188 +++++++++---------- eng/Version.Details.xml | 378 +++++++++++++++++++------------------- global.json | 6 +- 4 files changed, 288 insertions(+), 288 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 3c60bb73491d..0873fa2a851e 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "dotnet-ef": { - "version": "12.0.0-alpha.1.26516.101", + "version": "12.0.0-alpha.1.26519.106", "commands": [ "dotnet-ef" ] @@ -27,7 +27,7 @@ ] }, "microsoft.dotnet.helix.jobmonitor": { - "version": "12.0.0-beta.26516.101", + "version": "12.0.0-beta.26519.106", "commands": [ "dotnet-helix-job-monitor" ] diff --git a/eng/Version.Details.props b/eng/Version.Details.props index acfa74d80e14..050c8d75468f 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -6,104 +6,104 @@ This file should be imported by eng/Versions.props - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 5.11.0-1.26420.103 5.11.0-1.26420.103 5.11.0-1.26420.103 5.11.0-1.26420.103 - 12.0.0-beta.26516.101 - 12.0.0-beta.26516.101 - 12.0.0-beta.26516.101 - 12.0.0-beta.26516.101 - 12.0.0-beta.26516.101 - 12.0.0-beta.26516.101 - 12.0.0-beta.26516.101 - 12.0.0-beta.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 8.1.0-rc.51701 - 8.1.0-rc.51701 - 8.1.0-rc.51701 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 - 12.0.0-alpha.1.26516.101 + 12.0.0-beta.26519.106 + 12.0.0-beta.26519.106 + 12.0.0-beta.26519.106 + 12.0.0-beta.26519.106 + 12.0.0-beta.26519.106 + 12.0.0-beta.26519.106 + 12.0.0-beta.26519.106 + 12.0.0-beta.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 8.1.0-rc.52006 + 8.1.0-rc.52006 + 8.1.0-rc.52006 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.106 10.10.1 10.10.1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 5e1f515e6d80..bad13d76618d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -8,333 +8,333 @@ See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md for instructions on using darc. --> - + - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b @@ -355,48 +355,48 @@ 1d599674e31ad86ca9e6e1dad7055b531e4d58e4 - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b https://github.com/dotnet/extensions @@ -456,17 +456,17 @@ https://github.com/dotnet/msbuild d1cce8d7cc03c23a4f1bad8e9240714fd9d199a3 - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b - + https://github.com/dotnet/dotnet - be06e8febe57db1ea30be9f0863133a892c01645 + 6a03f1dd6b109506102e265da3cb549381f5ed6b diff --git a/global.json b/global.json index 34f048c5e2ec..79b0a0f5cf99 100644 --- a/global.json +++ b/global.json @@ -22,9 +22,9 @@ "jdk": "latest" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "12.0.0-beta.26516.101", - "Microsoft.DotNet.Helix.Sdk": "12.0.0-beta.26516.101", - "Microsoft.DotNet.SharedFramework.Sdk": "12.0.0-beta.26516.101", + "Microsoft.DotNet.Arcade.Sdk": "12.0.0-beta.26519.106", + "Microsoft.DotNet.Helix.Sdk": "12.0.0-beta.26519.106", + "Microsoft.DotNet.SharedFramework.Sdk": "12.0.0-beta.26519.106", "Microsoft.Build.NoTargets": "3.7.134", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.WixToolset.Sdk": "6.0.3-dotnet.6" From bd45ff73c31a5409bb0ad39c1809233917f115b3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Wed, 21 Oct 2026 11:33:04 +0000 Subject: [PATCH 08/19] Update dependencies from build 337438 Updated Dependencies: Microsoft.NET.Runtime.WebAssembly.Sdk, Microsoft.NET.Runtime.MonoAOTCompiler.Task, dotnet-ef, Microsoft.Bcl.AsyncInterfaces, Microsoft.Bcl.Cryptography, Microsoft.Bcl.TimeProvider, Microsoft.EntityFrameworkCore, Microsoft.EntityFrameworkCore.Design, Microsoft.EntityFrameworkCore.InMemory, Microsoft.EntityFrameworkCore.Relational, Microsoft.EntityFrameworkCore.Sqlite, Microsoft.EntityFrameworkCore.SqlServer, Microsoft.EntityFrameworkCore.Tools, Microsoft.Extensions.Caching.Abstractions, Microsoft.Extensions.Caching.Memory, Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Abstractions, Microsoft.Extensions.Configuration.Binder, Microsoft.Extensions.Configuration.CommandLine, Microsoft.Extensions.Configuration.EnvironmentVariables, Microsoft.Extensions.Configuration.FileExtensions, Microsoft.Extensions.Configuration.Ini, Microsoft.Extensions.Configuration.Json, Microsoft.Extensions.Configuration.UserSecrets, Microsoft.Extensions.Configuration.Xml, Microsoft.Extensions.DependencyInjection, Microsoft.Extensions.DependencyInjection.Abstractions, Microsoft.Extensions.DependencyModel, Microsoft.Extensions.Diagnostics, Microsoft.Extensions.Diagnostics.Abstractions, Microsoft.Extensions.FileProviders.Abstractions, Microsoft.Extensions.FileProviders.Composite, Microsoft.Extensions.FileProviders.Physical, Microsoft.Extensions.FileSystemGlobbing, Microsoft.Extensions.HostFactoryResolver.Sources, Microsoft.Extensions.Hosting, Microsoft.Extensions.Hosting.Abstractions, Microsoft.Extensions.Http, Microsoft.Extensions.Logging, Microsoft.Extensions.Logging.Abstractions, Microsoft.Extensions.Logging.Configuration, Microsoft.Extensions.Logging.Console, Microsoft.Extensions.Logging.Debug, Microsoft.Extensions.Logging.EventLog, Microsoft.Extensions.Logging.EventSource, Microsoft.Extensions.Logging.TraceSource, Microsoft.Extensions.Options, Microsoft.Extensions.Options.ConfigurationExtensions, Microsoft.Extensions.Options.DataAnnotations, Microsoft.Extensions.Primitives, Microsoft.Internal.Runtime.AspNetCore.Transport, Microsoft.NETCore.App.Ref, Microsoft.NETCore.BrowserDebugHost.Transport, Microsoft.NETCore.Platforms, Microsoft.Web.Xdt, System.Collections.Immutable, System.Composition, System.Configuration.ConfigurationManager, System.Diagnostics.DiagnosticSource, System.Diagnostics.EventLog, System.Diagnostics.PerformanceCounter, System.DirectoryServices.Protocols, System.Formats.Asn1, System.Formats.Cbor, System.IO.Hashing, System.IO.Pipelines, System.Memory.Data, System.Net.Http.Json, System.Net.Http.WinHttpHandler, System.Net.ServerSentEvents, System.Numerics.Tensors, System.Reflection.Metadata, System.Resources.Extensions, System.Runtime.Caching, System.Security.Cryptography.Pkcs, System.Security.Cryptography.Xml, System.Security.Permissions, System.ServiceProcess.ServiceController, System.Text.Encodings.Web, System.Text.Json, System.Threading.AccessControl, System.Threading.Channels, System.Threading.RateLimiting (Version 12.0.0-alpha.1.26519.106 -> 12.0.0-alpha.1.26519.114) Microsoft.DotNet.Arcade.Sdk, Microsoft.DotNet.Build.Tasks.Archives, Microsoft.DotNet.Build.Tasks.Installers, Microsoft.DotNet.Build.Tasks.Templating, Microsoft.DotNet.Helix.JobMonitor, Microsoft.DotNet.Helix.Sdk, Microsoft.DotNet.RemoteExecutor, Microsoft.DotNet.SharedFramework.Sdk (Version 12.0.0-beta.26519.106 -> 12.0.0-beta.26519.114) NuGet.Frameworks, NuGet.Packaging, NuGet.Versioning (Version 8.1.0-rc.52006 -> 8.1.0-rc.52014) [[ commit created by automation ]] --- .config/dotnet-tools.json | 4 +- NuGet.config | 1 - eng/Version.Details.props | 188 +++++++++---------- eng/Version.Details.xml | 378 +++++++++++++++++++------------------- global.json | 6 +- 5 files changed, 288 insertions(+), 289 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 0873fa2a851e..c5a041d4cc91 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "dotnet-ef": { - "version": "12.0.0-alpha.1.26519.106", + "version": "12.0.0-alpha.1.26519.114", "commands": [ "dotnet-ef" ] @@ -27,7 +27,7 @@ ] }, "microsoft.dotnet.helix.jobmonitor": { - "version": "12.0.0-beta.26519.106", + "version": "12.0.0-beta.26519.114", "commands": [ "dotnet-helix-job-monitor" ] diff --git a/NuGet.config b/NuGet.config index df33f9d8020c..6bc4caeb4222 100644 --- a/NuGet.config +++ b/NuGet.config @@ -4,7 +4,6 @@ - diff --git a/eng/Version.Details.props b/eng/Version.Details.props index 5d1880147782..ddcba2c2fc68 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -6,104 +6,104 @@ This file should be imported by eng/Versions.props - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 5.11.0-1.26420.103 5.11.0-1.26420.103 5.11.0-1.26420.103 5.11.0-1.26420.103 - 12.0.0-beta.26519.106 - 12.0.0-beta.26519.106 - 12.0.0-beta.26519.106 - 12.0.0-beta.26519.106 - 12.0.0-beta.26519.106 - 12.0.0-beta.26519.106 - 12.0.0-beta.26519.106 - 12.0.0-beta.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 8.1.0-rc.52006 - 8.1.0-rc.52006 - 8.1.0-rc.52006 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 - 12.0.0-alpha.1.26519.106 + 12.0.0-beta.26519.114 + 12.0.0-beta.26519.114 + 12.0.0-beta.26519.114 + 12.0.0-beta.26519.114 + 12.0.0-beta.26519.114 + 12.0.0-beta.26519.114 + 12.0.0-beta.26519.114 + 12.0.0-beta.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 8.1.0-rc.52014 + 8.1.0-rc.52014 + 8.1.0-rc.52014 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26519.114 10.11.0 10.11.0 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 0ae4b9aeb289..1c96b2f3da1d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -8,333 +8,333 @@ See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md for instructions on using darc. --> - + - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd @@ -355,48 +355,48 @@ 1d599674e31ad86ca9e6e1dad7055b531e4d58e4 - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd https://github.com/dotnet/extensions @@ -456,17 +456,17 @@ https://github.com/dotnet/msbuild d1cce8d7cc03c23a4f1bad8e9240714fd9d199a3 - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd - + https://github.com/dotnet/dotnet - 6a03f1dd6b109506102e265da3cb549381f5ed6b + a69d27567bd8be379e504329c965b9ca3fdf53fd diff --git a/global.json b/global.json index 79b0a0f5cf99..bafc4abbb204 100644 --- a/global.json +++ b/global.json @@ -22,9 +22,9 @@ "jdk": "latest" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "12.0.0-beta.26519.106", - "Microsoft.DotNet.Helix.Sdk": "12.0.0-beta.26519.106", - "Microsoft.DotNet.SharedFramework.Sdk": "12.0.0-beta.26519.106", + "Microsoft.DotNet.Arcade.Sdk": "12.0.0-beta.26519.114", + "Microsoft.DotNet.Helix.Sdk": "12.0.0-beta.26519.114", + "Microsoft.DotNet.SharedFramework.Sdk": "12.0.0-beta.26519.114", "Microsoft.Build.NoTargets": "3.7.134", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.WixToolset.Sdk": "6.0.3-dotnet.6" From 08f96b0909f16d54ff6b032c7c3f41cdbcd23233 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Wed, 21 Oct 2026 20:03:05 +0000 Subject: [PATCH 09/19] Backflow from https://github.com/dotnet/dotnet / ee344f8 build 337683 Diff: https://github.com/dotnet/dotnet/compare/a69d27567bd8be379e504329c965b9ca3fdf53fd..ee344f85ef890dd92974e9b93d75906f1f8c39f3 From: https://github.com/dotnet/dotnet/commit/a69d27567bd8be379e504329c965b9ca3fdf53fd To: https://github.com/dotnet/dotnet/commit/ee344f85ef890dd92974e9b93d75906f1f8c39f3 [[ commit created by automation ]] --- Directory.Build.targets | 3 --- eng/tools/RepoTasks/RepoTasks.csproj | 17 ++++++++++++++++- ...etCore.Components.AI.SourceGenerators.csproj | 2 ++ ...NetCore.Components.Testing.Generators.csproj | 2 ++ ...pNetCore.Components.Testing.NativeAot.csproj | 2 ++ .../Microsoft.AspNetCore.App.Analyzers.csproj | 2 ++ .../Microsoft.AspNetCore.App.CodeFixes.csproj | 2 ++ ...osoft.AspNetCore.App.SourceGenerators.csproj | 2 ++ ...etCore.SignalR.Client.SourceGenerator.csproj | 2 ++ 9 files changed, 30 insertions(+), 4 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index 08b29341d23b..8c79a808c295 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -131,9 +131,6 @@ '$(Language)' == 'C#' AND '$(TargetFrameworkIdentifier)' != '.NETFramework' "> $(AspNetCoreMajorMinorVersion).0.0 - - 11.0.0.0 diff --git a/eng/tools/RepoTasks/RepoTasks.csproj b/eng/tools/RepoTasks/RepoTasks.csproj index f4093954405e..5fc522cd51cd 100644 --- a/eng/tools/RepoTasks/RepoTasks.csproj +++ b/eng/tools/RepoTasks/RepoTasks.csproj @@ -1,13 +1,26 @@ - + + + + + true + + + $(DefaultNetCoreTargetFramework) + $(BundledNETCoreAppTargetFramework) false true false false + false @@ -18,4 +31,6 @@ + + diff --git a/src/Components/AI/gen/Microsoft.AspNetCore.Components.AI.SourceGenerators.csproj b/src/Components/AI/gen/Microsoft.AspNetCore.Components.AI.SourceGenerators.csproj index 526cf54993ba..1ba66f97017b 100644 --- a/src/Components/AI/gen/Microsoft.AspNetCore.Components.AI.SourceGenerators.csproj +++ b/src/Components/AI/gen/Microsoft.AspNetCore.Components.AI.SourceGenerators.csproj @@ -1,6 +1,8 @@ + + false netstandard2.0 13.0 enable diff --git a/src/Components/Testing/gen/Microsoft.AspNetCore.Components.Testing.Generators.csproj b/src/Components/Testing/gen/Microsoft.AspNetCore.Components.Testing.Generators.csproj index 23d18bd434dd..0b0c58c06700 100644 --- a/src/Components/Testing/gen/Microsoft.AspNetCore.Components.Testing.Generators.csproj +++ b/src/Components/Testing/gen/Microsoft.AspNetCore.Components.Testing.Generators.csproj @@ -1,6 +1,8 @@ + + false netstandard2.0 true true diff --git a/src/Components/Testing/nativeaot/Microsoft.AspNetCore.Components.Testing.NativeAot.csproj b/src/Components/Testing/nativeaot/Microsoft.AspNetCore.Components.Testing.NativeAot.csproj index 60dcabd967ba..6b45015368b6 100644 --- a/src/Components/Testing/nativeaot/Microsoft.AspNetCore.Components.Testing.NativeAot.csproj +++ b/src/Components/Testing/nativeaot/Microsoft.AspNetCore.Components.Testing.NativeAot.csproj @@ -1,6 +1,8 @@ + + false netstandard2.0 enable true diff --git a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/Microsoft.AspNetCore.App.Analyzers.csproj b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/Microsoft.AspNetCore.App.Analyzers.csproj index 402e4b25cdab..3f595771c8ec 100644 --- a/src/Framework/AspNetCoreAnalyzers/src/Analyzers/Microsoft.AspNetCore.App.Analyzers.csproj +++ b/src/Framework/AspNetCoreAnalyzers/src/Analyzers/Microsoft.AspNetCore.App.Analyzers.csproj @@ -1,5 +1,7 @@ + + false CSharp Analyzers for ASP.NET Core. false false diff --git a/src/Framework/AspNetCoreAnalyzers/src/CodeFixes/Microsoft.AspNetCore.App.CodeFixes.csproj b/src/Framework/AspNetCoreAnalyzers/src/CodeFixes/Microsoft.AspNetCore.App.CodeFixes.csproj index af3609a542bf..673b2c79beb5 100644 --- a/src/Framework/AspNetCoreAnalyzers/src/CodeFixes/Microsoft.AspNetCore.App.CodeFixes.csproj +++ b/src/Framework/AspNetCoreAnalyzers/src/CodeFixes/Microsoft.AspNetCore.App.CodeFixes.csproj @@ -1,5 +1,7 @@ + + false CSharp CodeFixes for ASP.NET Core. false + false netstandard2.0 true false diff --git a/src/SignalR/clients/csharp/Client.SourceGenerator/src/Microsoft.AspNetCore.SignalR.Client.SourceGenerator.csproj b/src/SignalR/clients/csharp/Client.SourceGenerator/src/Microsoft.AspNetCore.SignalR.Client.SourceGenerator.csproj index 55de0443f17f..5f2eed5fa8bb 100644 --- a/src/SignalR/clients/csharp/Client.SourceGenerator/src/Microsoft.AspNetCore.SignalR.Client.SourceGenerator.csproj +++ b/src/SignalR/clients/csharp/Client.SourceGenerator/src/Microsoft.AspNetCore.SignalR.Client.SourceGenerator.csproj @@ -1,6 +1,8 @@ + + false netstandard2.0 false true From 96c0fdff3b918a8bc28c1994762c97c732c8ebd4 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" Date: Wed, 21 Oct 2026 20:03:07 +0000 Subject: [PATCH 10/19] Update dependencies from build 337683 Updated Dependencies: Microsoft.NET.Runtime.WebAssembly.Sdk, Microsoft.NET.Runtime.MonoAOTCompiler.Task, dotnet-ef, Microsoft.Bcl.AsyncInterfaces, Microsoft.Bcl.Cryptography, Microsoft.Bcl.TimeProvider, Microsoft.EntityFrameworkCore, Microsoft.EntityFrameworkCore.Design, Microsoft.EntityFrameworkCore.InMemory, Microsoft.EntityFrameworkCore.Relational, Microsoft.EntityFrameworkCore.Sqlite, Microsoft.EntityFrameworkCore.SqlServer, Microsoft.EntityFrameworkCore.Tools, Microsoft.Extensions.Caching.Abstractions, Microsoft.Extensions.Caching.Memory, Microsoft.Extensions.Configuration, Microsoft.Extensions.Configuration.Abstractions, Microsoft.Extensions.Configuration.Binder, Microsoft.Extensions.Configuration.CommandLine, Microsoft.Extensions.Configuration.EnvironmentVariables, Microsoft.Extensions.Configuration.FileExtensions, Microsoft.Extensions.Configuration.Ini, Microsoft.Extensions.Configuration.Json, Microsoft.Extensions.Configuration.UserSecrets, Microsoft.Extensions.Configuration.Xml, Microsoft.Extensions.DependencyInjection, Microsoft.Extensions.DependencyInjection.Abstractions, Microsoft.Extensions.DependencyModel, Microsoft.Extensions.Diagnostics, Microsoft.Extensions.Diagnostics.Abstractions, Microsoft.Extensions.FileProviders.Abstractions, Microsoft.Extensions.FileProviders.Composite, Microsoft.Extensions.FileProviders.Physical, Microsoft.Extensions.FileSystemGlobbing, Microsoft.Extensions.HostFactoryResolver.Sources, Microsoft.Extensions.Hosting, Microsoft.Extensions.Hosting.Abstractions, Microsoft.Extensions.Http, Microsoft.Extensions.Logging, Microsoft.Extensions.Logging.Abstractions, Microsoft.Extensions.Logging.Configuration, Microsoft.Extensions.Logging.Console, Microsoft.Extensions.Logging.Debug, Microsoft.Extensions.Logging.EventLog, Microsoft.Extensions.Logging.EventSource, Microsoft.Extensions.Logging.TraceSource, Microsoft.Extensions.Options, Microsoft.Extensions.Options.ConfigurationExtensions, Microsoft.Extensions.Options.DataAnnotations, Microsoft.Extensions.Primitives, Microsoft.Internal.Runtime.AspNetCore.Transport, Microsoft.NETCore.App.Ref, Microsoft.NETCore.BrowserDebugHost.Transport, Microsoft.NETCore.Platforms, Microsoft.Web.Xdt, System.Collections.Immutable, System.Composition, System.Configuration.ConfigurationManager, System.Diagnostics.DiagnosticSource, System.Diagnostics.EventLog, System.Diagnostics.PerformanceCounter, System.DirectoryServices.Protocols, System.Formats.Asn1, System.Formats.Cbor, System.IO.Hashing, System.IO.Pipelines, System.Memory.Data, System.Net.Http.Json, System.Net.Http.WinHttpHandler, System.Net.ServerSentEvents, System.Numerics.Tensors, System.Reflection.Metadata, System.Resources.Extensions, System.Runtime.Caching, System.Security.Cryptography.Pkcs, System.Security.Cryptography.Xml, System.Security.Permissions, System.ServiceProcess.ServiceController, System.Text.Encodings.Web, System.Text.Json, System.Threading.AccessControl, System.Threading.Channels, System.Threading.RateLimiting (Version 12.0.0-alpha.1.26519.114 -> 12.0.0-alpha.1.26521.103) Microsoft.DotNet.Arcade.Sdk, Microsoft.DotNet.Build.Tasks.Archives, Microsoft.DotNet.Build.Tasks.Installers, Microsoft.DotNet.Build.Tasks.Templating, Microsoft.DotNet.Helix.JobMonitor, Microsoft.DotNet.Helix.Sdk, Microsoft.DotNet.RemoteExecutor, Microsoft.DotNet.SharedFramework.Sdk (Version 12.0.0-beta.26519.114 -> 12.0.0-beta.26521.103) NuGet.Frameworks, NuGet.Packaging, NuGet.Versioning (Version 8.1.0-rc.52014 -> 8.1.0-rc.52203) [[ commit created by automation ]] --- .config/dotnet-tools.json | 4 +- eng/Version.Details.props | 188 +++++++++---------- eng/Version.Details.xml | 378 +++++++++++++++++++------------------- global.json | 6 +- 4 files changed, 288 insertions(+), 288 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index c5a041d4cc91..cfa6d258790e 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -9,7 +9,7 @@ ] }, "dotnet-ef": { - "version": "12.0.0-alpha.1.26519.114", + "version": "12.0.0-alpha.1.26521.103", "commands": [ "dotnet-ef" ] @@ -27,7 +27,7 @@ ] }, "microsoft.dotnet.helix.jobmonitor": { - "version": "12.0.0-beta.26519.114", + "version": "12.0.0-beta.26521.103", "commands": [ "dotnet-helix-job-monitor" ] diff --git a/eng/Version.Details.props b/eng/Version.Details.props index ddcba2c2fc68..18566f345daf 100644 --- a/eng/Version.Details.props +++ b/eng/Version.Details.props @@ -6,104 +6,104 @@ This file should be imported by eng/Versions.props - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 5.11.0-1.26420.103 5.11.0-1.26420.103 5.11.0-1.26420.103 5.11.0-1.26420.103 - 12.0.0-beta.26519.114 - 12.0.0-beta.26519.114 - 12.0.0-beta.26519.114 - 12.0.0-beta.26519.114 - 12.0.0-beta.26519.114 - 12.0.0-beta.26519.114 - 12.0.0-beta.26519.114 - 12.0.0-beta.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 8.1.0-rc.52014 - 8.1.0-rc.52014 - 8.1.0-rc.52014 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 - 12.0.0-alpha.1.26519.114 + 12.0.0-beta.26521.103 + 12.0.0-beta.26521.103 + 12.0.0-beta.26521.103 + 12.0.0-beta.26521.103 + 12.0.0-beta.26521.103 + 12.0.0-beta.26521.103 + 12.0.0-beta.26521.103 + 12.0.0-beta.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 8.1.0-rc.52203 + 8.1.0-rc.52203 + 8.1.0-rc.52203 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 + 12.0.0-alpha.1.26521.103 10.11.0 10.11.0 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1c96b2f3da1d..2e7aa993cb36 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -8,333 +8,333 @@ See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md for instructions on using darc. --> - + - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 @@ -355,48 +355,48 @@ 1d599674e31ad86ca9e6e1dad7055b531e4d58e4 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 https://github.com/dotnet/extensions @@ -456,17 +456,17 @@ https://github.com/dotnet/msbuild d1cce8d7cc03c23a4f1bad8e9240714fd9d199a3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 - + https://github.com/dotnet/dotnet - a69d27567bd8be379e504329c965b9ca3fdf53fd + ee344f85ef890dd92974e9b93d75906f1f8c39f3 diff --git a/global.json b/global.json index bafc4abbb204..8b940074013a 100644 --- a/global.json +++ b/global.json @@ -22,9 +22,9 @@ "jdk": "latest" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "12.0.0-beta.26519.114", - "Microsoft.DotNet.Helix.Sdk": "12.0.0-beta.26519.114", - "Microsoft.DotNet.SharedFramework.Sdk": "12.0.0-beta.26519.114", + "Microsoft.DotNet.Arcade.Sdk": "12.0.0-beta.26521.103", + "Microsoft.DotNet.Helix.Sdk": "12.0.0-beta.26521.103", + "Microsoft.DotNet.SharedFramework.Sdk": "12.0.0-beta.26521.103", "Microsoft.Build.NoTargets": "3.7.134", "Microsoft.Build.Traversal": "3.4.0", "Microsoft.WixToolset.Sdk": "6.0.3-dotnet.6" From 7058266abfccec113821d43e04fcb2a4310ee630 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 21 Oct 2026 14:04:42 -0700 Subject: [PATCH 11/19] Update bootstrap SDK to 12.0.100-alpha.1.26521.103 Use the SDK from the incoming VMR build so MSBuild task hosts and isolated package consumers use the .NET 12 runtime assembly identities. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index 8b940074013a..759d813194ef 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "12.0.100-alpha.1.26480.102", + "version": "12.0.100-alpha.1.26521.103", "paths": [ ".dotnet", "$host$" @@ -8,7 +8,7 @@ "errorMessage": "The .NET SDK could not be found, run ./restore.cmd or ./restore.sh first." }, "tools": { - "dotnet": "12.0.100-alpha.1.26480.102", + "dotnet": "12.0.100-alpha.1.26521.103", "runtimes": { "dotnet/x86": [ "$(MicrosoftInternalRuntimeAspNetCoreTransportVersion)" From e64576fb1d96fb86ce4a67051e2d895fc02ad362 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 21 Oct 2026 14:21:55 -0700 Subject: [PATCH 12/19] Remove redundant shared-framework package references Remove explicit DependencyInjection and Http package references from the Web SDK test apps. The shared framework already supplies both packages, and the updated SDK reports NU1510 for these redundant references. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Components/AI/testassets/DojoClient/DojoClient.csproj | 2 -- .../Platform/testassets/PlatformTestApp/PlatformTestApp.csproj | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/Components/AI/testassets/DojoClient/DojoClient.csproj b/src/Components/AI/testassets/DojoClient/DojoClient.csproj index 86b07fc428db..f24560636115 100644 --- a/src/Components/AI/testassets/DojoClient/DojoClient.csproj +++ b/src/Components/AI/testassets/DojoClient/DojoClient.csproj @@ -9,8 +9,6 @@ - - diff --git a/src/Components/Platform/testassets/PlatformTestApp/PlatformTestApp.csproj b/src/Components/Platform/testassets/PlatformTestApp/PlatformTestApp.csproj index be4607346d6c..6b1e8d91b8f3 100644 --- a/src/Components/Platform/testassets/PlatformTestApp/PlatformTestApp.csproj +++ b/src/Components/Platform/testassets/PlatformTestApp/PlatformTestApp.csproj @@ -8,8 +8,6 @@ - - From c3e7da42ead2bbf5d3f97d04d9ad0a6b259b39e2 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 21 Oct 2026 15:24:15 -0700 Subject: [PATCH 13/19] Make API Explorer logging test assembly versions dynamic Read expected versions from the loaded ApiExplorer and NewtonsoftJson assemblies instead of hard-coding version numbers. Preserve exact provider names, assembly names, complete ordinal message assertions, event name, and logger category. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Mvc/test/Mvc.FunctionalTests/ApiExplorerTest.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Mvc/test/Mvc.FunctionalTests/ApiExplorerTest.cs b/src/Mvc/test/Mvc.FunctionalTests/ApiExplorerTest.cs index 794c28ea94ac..635396bd4af3 100644 --- a/src/Mvc/test/Mvc.FunctionalTests/ApiExplorerTest.cs +++ b/src/Mvc/test/Mvc.FunctionalTests/ApiExplorerTest.cs @@ -1561,13 +1561,15 @@ public async Task ApiAction_ForActionWithVoidResponseType(string path, Type type public async Task ApiExplorer_LogsInvokedDescriptionProvidersOnStartup() { // Arrange & Act + var apiExplorerAssemblyVersion = typeof(DefaultApiDescriptionProvider).Assembly.GetName().Version; + var newtonsoftJsonAssemblyVersion = typeof(NewtonsoftJsonPatchInputFormatter).Assembly.GetName().Version; var response = await Client.GetAsync("http://localhost/ApiExplorerHttpMethod/All"); // Assert Assert.Contains(TestSink.Writes, w => w.EventId.Name?.Equals("ApiDescriptionProviderExecuting", StringComparison.Ordinal) == true); Assert.Contains(TestSink.Writes, w => w.LoggerName.Equals("Microsoft.AspNetCore.Mvc.ApiExplorer.ApiDescriptionGroupCollectionProvider", StringComparison.Ordinal)); - Assert.Contains(TestSink.Writes, w => w.Message.Equals("Executing API description provider 'DefaultApiDescriptionProvider' from assembly Microsoft.AspNetCore.Mvc.ApiExplorer v11.0.0.0.", StringComparison.Ordinal)); - Assert.Contains(TestSink.Writes, w => w.Message.Equals("Executing API description provider 'JsonPatchOperationsArrayProvider' from assembly Microsoft.AspNetCore.Mvc.NewtonsoftJson v42.42.42.42.", StringComparison.Ordinal)); + Assert.Contains(TestSink.Writes, w => w.Message.Equals($"Executing API description provider 'DefaultApiDescriptionProvider' from assembly Microsoft.AspNetCore.Mvc.ApiExplorer v{apiExplorerAssemblyVersion}.", StringComparison.Ordinal)); + Assert.Contains(TestSink.Writes, w => w.Message.Equals($"Executing API description provider 'JsonPatchOperationsArrayProvider' from assembly Microsoft.AspNetCore.Mvc.NewtonsoftJson v{newtonsoftJsonAssemblyVersion}.", StringComparison.Ordinal)); } [Fact] From 89ecabaffe589c1dfd810ab423375293cbc3d631 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 21 Oct 2026 11:58:43 -0700 Subject: [PATCH 14/19] Fix content root in endpoint redirect test fixture Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Endpoints/test/RazorComponentEndpointInvokerTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Endpoints/test/RazorComponentEndpointInvokerTest.cs b/src/Components/Endpoints/test/RazorComponentEndpointInvokerTest.cs index 9ece6f053116..52bb1d54ecc0 100644 --- a/src/Components/Endpoints/test/RazorComponentEndpointInvokerTest.cs +++ b/src/Components/Endpoints/test/RazorComponentEndpointInvokerTest.cs @@ -351,7 +351,7 @@ private class TestWebHostEnvironment : IWebHostEnvironment public IFileProvider WebRootFileProvider { get => new NullFileProvider(); set => throw new NotImplementedException(); } public string EnvironmentName { get => "Development"; set => throw new NotImplementedException(); } public string ApplicationName { get => "Test"; set => throw new NotImplementedException(); } - public string ContentRootPath { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + public string ContentRootPath { get; set; } = AppContext.BaseDirectory; public IFileProvider ContentRootFileProvider { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } } } From 876a69c2359c0cbbdd9451f160ac0e08d3a616c2 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 21 Oct 2026 11:58:43 -0700 Subject: [PATCH 15/19] Synchronize incomplete request body test before closing the client Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Servers/Kestrel/test/FunctionalTests/RequestTests.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Servers/Kestrel/test/FunctionalTests/RequestTests.cs b/src/Servers/Kestrel/test/FunctionalTests/RequestTests.cs index bdae9d88ccb8..036861ea0670 100644 --- a/src/Servers/Kestrel/test/FunctionalTests/RequestTests.cs +++ b/src/Servers/Kestrel/test/FunctionalTests/RequestTests.cs @@ -402,6 +402,7 @@ await connection.Receive( [Fact] public async Task IncompleteRequestBodyDoesNotLogAsApplicationError() { + var bodyReadStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var appErrorLogged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var badRequestLogged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); var connectionStoppedLogged = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -437,7 +438,9 @@ public async Task IncompleteRequestBodyDoesNotLogAsApplicationError() var buffer = new byte[1024]; // Attempt to read more of the body than will show up. - await context.Request.Body.ReadAsync(buffer, 0, buffer.Length); + var readTask = context.Request.Body.ReadAsync(buffer, 0, buffer.Length); + bodyReadStarted.TrySetResult(); + await readTask; }, new TestServiceContext(LoggerFactory)); using (var connection = server.CreateConnection()) @@ -450,6 +453,8 @@ await connection.Send( "Content-Length: 100", // Declare a larger body than will be sent "", ""); + + await bodyReadStarted.Task.DefaultTimeout(); } await connectionStoppedLogged.Task.DefaultTimeout(); From b78b77df8219d588d74919ea32148ce8849c4dea Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 21 Oct 2026 11:58:43 -0700 Subject: [PATCH 16/19] Wait for query string page navigation in routing test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Components/test/E2ETest/Tests/RoutingTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/test/E2ETest/Tests/RoutingTest.cs b/src/Components/test/E2ETest/Tests/RoutingTest.cs index bd12f3d60df9..0458b53bfb58 100644 --- a/src/Components/test/E2ETest/Tests/RoutingTest.cs +++ b/src/Components/test/E2ETest/Tests/RoutingTest.cs @@ -1595,7 +1595,7 @@ public virtual void CanNavigateToQueryStringPageWithNoQuery() var app = Browser.MountTestComponent(); app.FindElement(By.LinkText("With query parameters (none)")).Click(); - Assert.Equal("Hello Abc .", app.FindElement(By.Id("test-info")).Text); + Browser.Equal("Hello Abc .", () => app.FindElement(By.Id("test-info")).Text); Assert.Equal("0", app.FindElement(By.Id("value-QueryInt")).Text); Assert.Equal("0", app.FindElement(By.Id("value-nested-QueryInt")).Text); Assert.Equal(string.Empty, app.FindElement(By.Id("value-NullableDateTimeValue")).Text); From 0b14e71d1055590a78a0583d8688f90b5c8d50c5 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 21 Oct 2026 16:51:15 -0700 Subject: [PATCH 17/19] Isolate generated template restore from parent SDK Clear inherited MSBuildSDKsPath consistently so creation, restore, build, and publish resolve packs from the copied SDK instead of mixing installed pack layouts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/ProjectTemplates/README.md | 2 ++ src/ProjectTemplates/Shared/Project.cs | 23 +++++++++++++++---- .../Shared/TemplatePackageInstaller.cs | 3 ++- .../WebWorkerTemplateE2ETest.cs | 20 ++++++++++++---- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/ProjectTemplates/README.md b/src/ProjectTemplates/README.md index 13388e5953b0..88138bcfdcd8 100644 --- a/src/ProjectTemplates/README.md +++ b/src/ProjectTemplates/README.md @@ -17,6 +17,8 @@ The following contains a description of each sub-directory in the `ProjectTempla - `Templates.Blazor.Tests`: Contains the Blazor template tests. These are currently split out due to not being Helix ready yet. - `testassets`: Contains assets used by the tests, like a dotnet tools installer +Generated-project .NET CLI commands must clear inherited `MSBuildSDKsPath` so restore, build, and publish use the same copied SDK and pack layout. + ## Submitting pull requests You can submit changes for templates in this repo by submitting a pull request. If you make changes to any diff --git a/src/ProjectTemplates/Shared/Project.cs b/src/ProjectTemplates/Shared/Project.cs index 3e8fe4e4ad49..35a08bcd8443 100644 --- a/src/ProjectTemplates/Shared/Project.cs +++ b/src/ProjectTemplates/Shared/Project.cs @@ -135,7 +135,13 @@ internal async Task RunDotNetNewAsync( Directory.Delete(TemplateOutputDir, recursive: true); } - using var createExecution = ProcessEx.Run(Output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), argString, environmentVariables); + using var createExecution = ProcessEx.Run( + Output, + AppContext.BaseDirectory, + DotNetMuxer.MuxerPathOrDefault(), + argString, + environmentVariables, + envVarToRemove: _msBuildSdksPathEnvironmentVariable); await createExecution.Exited; var createResult = new ProcessResult(createExecution); @@ -149,7 +155,13 @@ internal async Task RunDotNetNewAsync( argString += $" {restoreArgs}"; } - using var restoreExecution = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), argString, environmentVariables); + using var restoreExecution = ProcessEx.Run( + Output, + TemplateOutputDir, + DotNetMuxer.MuxerPathOrDefault(), + argString, + environmentVariables, + envVarToRemove: _msBuildSdksPathEnvironmentVariable); await restoreExecution.Exited; var restoreResult = new ProcessResult(restoreExecution); @@ -366,7 +378,7 @@ internal async Task RunDotNetEfCreateMigrationAsync(string migrationName) command = "dotnet-ef"; } - using var result = ProcessEx.Run(Output, TemplateOutputDir, command, args); + using var result = ProcessEx.Run(Output, TemplateOutputDir, command, args, envVarToRemove: _msBuildSdksPathEnvironmentVariable); await result.Exited; var processResult = new ProcessResult(result); Assert.True(0 == processResult.ExitCode, ErrorMessages.GetFailedProcessMessage("run EF migrations", this, processResult)); @@ -386,7 +398,7 @@ internal async Task RunDotNetEfUpdateDatabaseAsync() command = "dotnet-ef"; } - using var result = ProcessEx.Run(Output, TemplateOutputDir, command, args); + using var result = ProcessEx.Run(Output, TemplateOutputDir, command, args, envVarToRemove: _msBuildSdksPathEnvironmentVariable); await result.Exited; var processResult = new ProcessResult(result); Assert.True(0 == processResult.ExitCode, ErrorMessages.GetFailedProcessMessage("update database", this, processResult)); @@ -585,7 +597,8 @@ internal async Task RunDotNetNewRawAsync(string arguments) DotNetMuxer.MuxerPathOrDefault(), arguments + $" --debug:disable-sdk-templates --debug:custom-hive \"{TemplatePackageInstaller.CustomHivePath}\"" + - $" -o {TemplateOutputDir}"); + $" -o {TemplateOutputDir}", + envVarToRemove: _msBuildSdksPathEnvironmentVariable); await result.Exited; Assert.True(result.ExitCode == 0, result.GetFormattedOutput()); } diff --git a/src/ProjectTemplates/Shared/TemplatePackageInstaller.cs b/src/ProjectTemplates/Shared/TemplatePackageInstaller.cs index 0b41dd588798..0a7f80bdb3e1 100644 --- a/src/ProjectTemplates/Shared/TemplatePackageInstaller.cs +++ b/src/ProjectTemplates/Shared/TemplatePackageInstaller.cs @@ -70,7 +70,8 @@ public static async Task RunDotNetNew(ITestOutputHelper output, strin DotNetMuxer.MuxerPathOrDefault(), //--debug:disable-sdk-templates means, don't include C:\Program Files\dotnet\templates, aka. what comes with SDK, so we don't need to uninstall //--debug:custom-hive means, don't install templates on CI/developer machine, instead create new temporary instance - $"new {arguments} --debug:disable-sdk-templates --debug:custom-hive \"{CustomHivePath}\""); + $"new {arguments} --debug:disable-sdk-templates --debug:custom-hive \"{CustomHivePath}\"", + envVarToRemove: "MSBuildSDKsPath"); await proc.Exited; diff --git a/src/ProjectTemplates/test/Templates.Blazor.Tests/WebWorkerTemplateE2ETest.cs b/src/ProjectTemplates/test/Templates.Blazor.Tests/WebWorkerTemplateE2ETest.cs index 59d74bd12b3c..38c978304a4c 100644 --- a/src/ProjectTemplates/test/Templates.Blazor.Tests/WebWorkerTemplateE2ETest.cs +++ b/src/ProjectTemplates/test/Templates.Blazor.Tests/WebWorkerTemplateE2ETest.cs @@ -146,7 +146,8 @@ public async ValueTask DisposeAsync() output, hostProject.TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), - "remove reference ../WorkerLib/WorkerLib.csproj"); + "remove reference ../WorkerLib/WorkerLib.csproj", + envVarToRemove: "MSBuildSDKsPath"); await result.Exited; if (Directory.Exists(workerLibDir)) @@ -162,13 +163,23 @@ private async Task CreateWebWorkerLibrary(string workerLibDir) var hiveArg = $"--debug:disable-sdk-templates --debug:custom-hive \"{TemplatePackageInstaller.CustomHivePath}\""; var args = $"new blazorwebworker {hiveArg} -n WorkerLib -o \"{workerLibDir}\""; - using var result = ProcessEx.Run(Output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), args); + using var result = ProcessEx.Run( + Output, + AppContext.BaseDirectory, + DotNetMuxer.MuxerPathOrDefault(), + args, + envVarToRemove: "MSBuildSDKsPath"); await result.Exited; Assert.True(result.ExitCode == 0, $"Failed to create blazorwebworker template: {result.Output}\n{result.Error}"); CopyWorkerMethods(workerLibDir); - using var restoreResult= ProcessEx.Run(Output, workerLibDir, DotNetMuxer.MuxerPathOrDefault(), "restore"); + using var restoreResult= ProcessEx.Run( + Output, + workerLibDir, + DotNetMuxer.MuxerPathOrDefault(), + "restore", + envVarToRemove: "MSBuildSDKsPath"); await restoreResult.Exited; Assert.True(restoreResult.ExitCode == 0, $"Failed to restore blazorwebworker library: {restoreResult.Output}\n{restoreResult.Error}"); } @@ -193,7 +204,8 @@ private async Task AddWorkerLibReferenceAsync(Project hostProject) Output, hostProject.TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), - "add reference ../WorkerLib/WorkerLib.csproj"); + "add reference ../WorkerLib/WorkerLib.csproj", + envVarToRemove: "MSBuildSDKsPath"); await result.Exited; Assert.True(result.ExitCode == 0, $"Failed to add WorkerLib reference: {result.Output}\n{result.Error}"); } From d6894301da5dd29f9c709f4144b1a6f8ee9f086d Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 21 Oct 2026 16:51:15 -0700 Subject: [PATCH 18/19] Verify propagation-data creation tags during sampling Observe initial request tags in the sampling callback after the runtime stopped retaining them for PropagationData. Preserve end-tag absence and unset activity status assertions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../test/HostingApplicationDiagnosticsTests.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs b/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs index b5614e97f749..0bc35f43765c 100644 --- a/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs +++ b/src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs @@ -1485,7 +1485,14 @@ public void ActivityListeners_PropagationDataSample_EndTagsNotAdded() using var listener = new ActivityListener { ShouldListenTo = activitySource => ReferenceEquals(activitySource, testSource), - Sample = (ref ActivityCreationOptions _) => ActivitySamplingResult.PropagationData, + Sample = (ref ActivityCreationOptions options) => + { + var tags = options.Tags.ToDictionary(); + Assert.Equal("GET", tags[HostingTelemetryHelpers.AttributeHttpRequestMethod]); + Assert.Equal("http", tags[HostingTelemetryHelpers.AttributeUrlScheme]); + Assert.Equal("/hello", tags[HostingTelemetryHelpers.AttributeUrlPath]); + return ActivitySamplingResult.PropagationData; + }, ActivityStopped = activity => stoppedActivity = activity }; @@ -1505,11 +1512,6 @@ public void ActivityListeners_PropagationDataSample_EndTagsNotAdded() var tags = stoppedActivity.TagObjects.ToDictionary(); - // Verify sampling tags are still present - Assert.True(tags.ContainsKey(HostingTelemetryHelpers.AttributeHttpRequestMethod)); - Assert.True(tags.ContainsKey(HostingTelemetryHelpers.AttributeUrlScheme)); - Assert.True(tags.ContainsKey(HostingTelemetryHelpers.AttributeUrlPath)); - // Verify end tags are NOT present since IsAllDataRequested is false Assert.False(tags.ContainsKey(HostingTelemetryHelpers.AttributeHttpResponseStatusCode)); Assert.False(tags.ContainsKey(HostingTelemetryHelpers.AttributeNetworkProtocolVersion)); From 6ebbcd12b9bb22c83fded638a0e472c2ae67d8f3 Mon Sep 17 00:00:00 2001 From: William Godbe Date: Wed, 21 Oct 2026 17:53:33 -0700 Subject: [PATCH 19/19] Isolate Kestrel certificate validation tests from TLS resumption Require full TLS handshakes in certificate callback, rejection, and validation-override tests so resumed sessions cannot skip the validation being tested. Preserve all existing assertions and production TLS defaults. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../HttpsConnectionMiddlewareTests.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpsConnectionMiddlewareTests.cs b/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpsConnectionMiddlewareTests.cs index 991b6e992223..81dafd94ca3b 100644 --- a/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpsConnectionMiddlewareTests.cs +++ b/src/Servers/Kestrel/test/InMemory.FunctionalTests/HttpsConnectionMiddlewareTests.cs @@ -1408,6 +1408,8 @@ void ConfigureListenOptions(ListenOptions listenOptions) { ServerCertificate = _x509Certificate2, ClientCertificateMode = mode, + // Resumed TLS sessions skip certificate validation callbacks. + OnAuthenticate = (_, sslOptions) => sslOptions.AllowTlsResume = false, ClientCertificateValidation = (certificate, chain, sslPolicyErrors) => { clientCertificateValidationCalled = true; @@ -1441,6 +1443,7 @@ void ConfigureListenOptions(ListenOptions listenOptions) { ServerCertificate = _x509Certificate2, ClientCertificateMode = mode, + OnAuthenticate = (_, sslOptions) => sslOptions.AllowTlsResume = false, ClientCertificateValidation = (certificate, chain, sslPolicyErrors) => false }); } @@ -1465,7 +1468,8 @@ void ConfigureListenOptions(ListenOptions listenOptions) listenOptions.UseHttps(new HttpsConnectionAdapterOptions { ServerCertificate = _x509Certificate2, - ClientCertificateMode = mode + ClientCertificateMode = mode, + OnAuthenticate = (_, sslOptions) => sslOptions.AllowTlsResume = false }); } @@ -1488,6 +1492,7 @@ void ConfigureListenOptions(ListenOptions listenOptions) { options.ServerCertificate = _x509Certificate2; options.ClientCertificateMode = ClientCertificateMode.RequireCertificate; + options.OnAuthenticate = (_, sslOptions) => sslOptions.AllowTlsResume = false; options.ClientCertificateValidation = (certificate, x509Chain, sslPolicyErrors) => false; options.AllowAnyClientCertificate(); });