diff --git a/.azure/pipelines/blazor-daily-tests.yml b/.azure/pipelines/blazor-daily-tests.yml
index c22f30db60dd..df3d335489d2 100644
--- a/.azure/pipelines/blazor-daily-tests.yml
+++ b/.azure/pipelines/blazor-daily-tests.yml
@@ -7,7 +7,6 @@
# We just need one Windows machine because all it does is trigger SauceLabs.
variables:
- ${{ if ne(variables['System.TeamProject'], 'public') }}:
- - group: DotNet-MSRC-Storage
- group: AzureDevOps-Artifact-Feeds-Pats
- name: SAUCE_CONNECT_DOWNLOAD_ON_INSTALL
value: true
diff --git a/.azure/pipelines/ci.yml b/.azure/pipelines/ci.yml
index 2b65d7e703b6..b72915d1d416 100644
--- a/.azure/pipelines/ci.yml
+++ b/.azure/pipelines/ci.yml
@@ -135,7 +135,7 @@ extends:
sdl:
sourceAnalysisPool:
name: NetCore1ESPool-Svc-Internal
- image: 1es-windows-2022-pt
+ image: 1es-windows-2022
os: windows
spotBugs:
enabled: false
diff --git a/.azure/pipelines/helix-matrix.yml b/.azure/pipelines/helix-matrix.yml
index b2c9c1a4cc06..33b1a3c483fa 100644
--- a/.azure/pipelines/helix-matrix.yml
+++ b/.azure/pipelines/helix-matrix.yml
@@ -12,7 +12,6 @@ schedules:
branches:
include:
- release/6.0
- - release/7.0
- release/8.0
always: false
diff --git a/.azure/pipelines/identitymodel-helix-matrix.yml b/.azure/pipelines/identitymodel-helix-matrix.yml
new file mode 100644
index 000000000000..55f0f8dd8063
--- /dev/null
+++ b/.azure/pipelines/identitymodel-helix-matrix.yml
@@ -0,0 +1,101 @@
+# We only want to run IdentityModel matrix on main
+pr: none
+trigger: none
+schedules:
+# Cron timezone is UTC.
+- cron: "0 */12 * * *"
+ branches:
+ include:
+ - release/8.0
+ always: true
+
+variables:
+- name: _UseHelixOpenQueues
+ value: false
+- group: DotNet-HelixApi-Access
+- template: /eng/common/templates-official/variables/pool-providers.yml@self
+
+resources:
+ repositories:
+ # Repo: 1ESPipelineTemplates/1ESPipelineTemplates
+ - repository: 1esPipelines
+ type: git
+ name: 1ESPipelineTemplates/1ESPipelineTemplates
+ ref: refs/tags/release
+
+extends:
+ template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines
+ parameters:
+ sdl:
+ sourceAnalysisPool:
+ name: NetCore1ESPool-Svc-Internal
+ image: 1es-windows-2022
+ os: windows
+ codeql:
+ compiled:
+ enabled: false
+ justificationForDisabling: 'This is a test-only pipeline. The same product code is already scanned in the main pipeline (aspnetcore-ci)'
+
+ stages:
+ - stage: build
+ displayName: Build
+ jobs:
+ - template: .azure/pipelines/jobs/default-build.yml@self
+ parameters:
+ jobName: IdentityModel_helix_matrix_x64
+ jobDisplayName: 'Tests: IdentityModel nightlies helix full matrix x64'
+ agentOs: Windows
+ timeoutInMinutes: 300
+ steps:
+ - task: NuGetAuthenticate@1
+ inputs:
+ forceReinstallCredentialProvider: true
+ - task: NuGetCommand@2
+ displayName: Install Microsoft.IdentityModel.Logging
+ inputs:
+ command: 'custom'
+ arguments: 'install Microsoft.IdentityModel.Logging
+ -Source https://pkgs.dev.azure.com/dnceng/internal/_packaging/identitymodel-nightlies/nuget/v3/index.json
+ -DependencyVersion Highest -OutputDirectory $(Build.StagingDirectory) -PreRelease'
+ - task: NuGetCommand@2
+ displayName: Install Microsoft.IdentityModel.Protocols.OpenIdConnect
+ inputs:
+ command: 'custom'
+ arguments: 'install Microsoft.IdentityModel.Protocols.OpenIdConnect
+ -Source https://pkgs.dev.azure.com/dnceng/internal/_packaging/identitymodel-nightlies/nuget/v3/index.json
+ -DependencyVersion Highest -OutputDirectory $(Build.StagingDirectory) -PreRelease'
+ - task: NuGetCommand@2
+ displayName: Install Microsoft.IdentityModel.Protocols.WsFederation
+ inputs:
+ command: 'custom'
+ arguments: 'install Microsoft.IdentityModel.Protocols.WsFederation
+ -Source https://pkgs.dev.azure.com/dnceng/internal/_packaging/identitymodel-nightlies/nuget/v3/index.json
+ -DependencyVersion Highest -OutputDirectory $(Build.StagingDirectory) -PreRelease'
+ - task: NuGetCommand@2
+ displayName: System.IdentityModel.Tokens.Jwt
+ inputs:
+ command: 'custom'
+ arguments: 'install System.IdentityModel.Tokens.Jwt
+ -Source https://pkgs.dev.azure.com/dnceng/internal/_packaging/identitymodel-nightlies/nuget/v3/index.json
+ -DependencyVersion Highest -OutputDirectory $(Build.StagingDirectory) -PreRelease'
+ - task: PowerShell@2
+ displayName: Add IdentityModel feel to NuGet.config
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/scripts/SetupIdentitySources.ps1
+ arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -IdentityModelPackageSource $(Build.StagingDirectory)
+ # Build the shared framework
+ - script: ./eng/build.cmd -ci -nobl -all -pack -arch x64
+ /p:CrossgenOutput=false /p:IsIdentityModelTestJob=true /p:ASPNETCORE_TEST_LOG_DIR=artifacts/log
+ displayName: Build shared fx
+ # -noBuildRepoTasks -noBuildNative -noBuild to avoid repeating work done in the previous step.
+ - script: .\eng\build.cmd -ci -nobl -all -noBuildRepoTasks -noBuildNative -noBuild -test
+ -projects eng\helix\helix.proj /p:IsHelixJob=true /p:RunTemplateTests=false
+ /p:CrossgenOutput=false /p:IsIdentityModelTestJob=true /p:ASPNETCORE_TEST_LOG_DIR=artifacts/log
+ displayName: Run build.cmd helix target
+ env:
+ HelixApiAccessToken: $(HelixApiAccessToken) # Needed for internal queues
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken) # We need to set this env var to publish helix results to Azure Dev Ops
+ artifacts:
+ - name: Helix_logs
+ path: artifacts/log/
+ publishOnError: true
\ No newline at end of file
diff --git a/.azure/pipelines/signalr-daily-tests.yml b/.azure/pipelines/signalr-daily-tests.yml
index 5bedd10fc3f4..ad33363fad91 100644
--- a/.azure/pipelines/signalr-daily-tests.yml
+++ b/.azure/pipelines/signalr-daily-tests.yml
@@ -6,7 +6,6 @@
variables:
- ${{ if ne(variables['System.TeamProject'], 'public') }}:
- - group: DotNet-MSRC-Storage
- group: AzureDevOps-Artifact-Feeds-Pats
- template: /eng/common/templates/variables/pool-providers.yml
diff --git a/Directory.Build.props b/Directory.Build.props
index 9ae6760c645e..d080a9e0fb8e 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -117,6 +117,8 @@
$(NoWarn.Replace('1591', ''))
$(NoWarn);0105
+
+ $(NoWarn);NU5104
$(WarningsNotAsErrors);CS1591
diff --git a/NuGet.config b/NuGet.config
index a67fb5e3b1f1..0049dc24f34d 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -6,10 +6,10 @@
-
+
-
+
@@ -30,10 +30,10 @@
-
+
-
+
diff --git a/eng/Baseline.Designer.props b/eng/Baseline.Designer.props
index 49210d5502a1..a89151e8a015 100644
--- a/eng/Baseline.Designer.props
+++ b/eng/Baseline.Designer.props
@@ -2,117 +2,117 @@
$(MSBuildAllProjects);$(MSBuildThisFileFullPath)
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
-
+
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
@@ -120,137 +120,137 @@
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
-
+
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
-
+
- 8.0.4
+ 8.0.5
-
-
+
+
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
-
-
+
+
- 8.0.4
+ 8.0.5
-
+
- 8.0.4
+ 8.0.5
-
+
- 8.0.4
+ 8.0.5
-
+
- 8.0.4
+ 8.0.5
-
-
+
+
- 8.0.4
+ 8.0.5
-
-
-
+
+
+
- 8.0.4
+ 8.0.5
-
-
+
+
- 8.0.4
+ 8.0.5
-
-
+
+
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
-
-
+
+
@@ -258,7 +258,7 @@
- 8.0.4
+ 8.0.5
@@ -267,133 +267,133 @@
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
-
-
+
+
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
-
+
- 8.0.4
+ 8.0.5
@@ -402,7 +402,7 @@
- 8.0.4
+ 8.0.5
@@ -410,71 +410,71 @@
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
-
-
+
+
- 8.0.4
+ 8.0.5
-
-
+
+
- 8.0.4
+ 8.0.5
@@ -490,27 +490,27 @@
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
-
+
- 8.0.4
+ 8.0.5
@@ -519,23 +519,23 @@
- 8.0.4
+ 8.0.5
-
+
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
@@ -544,54 +544,54 @@
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
-
-
+
+
-
-
+
+
-
-
+
+
- 8.0.4
+ 8.0.5
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
@@ -599,83 +599,83 @@
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
-
-
-
-
+
+
+
+
- 8.0.4
+ 8.0.5
@@ -684,64 +684,64 @@
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
-
+
- 8.0.4
+ 8.0.5
-
+
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
@@ -763,7 +763,7 @@
- 8.0.4
+ 8.0.5
@@ -785,7 +785,7 @@
- 8.0.4
+ 8.0.5
@@ -801,23 +801,23 @@
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
@@ -825,24 +825,24 @@
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
-
-
-
+
+
+
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
@@ -852,7 +852,7 @@
- 8.0.4
+ 8.0.5
@@ -861,73 +861,73 @@
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
-
+
-
+
-
+
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
@@ -956,11 +956,11 @@
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
@@ -978,18 +978,18 @@
- 8.0.4
+ 8.0.5
- 8.0.4
+ 8.0.5
-
+
- 8.0.4
+ 8.0.5
diff --git a/eng/Baseline.xml b/eng/Baseline.xml
index 110083387ae6..7d886afd31fc 100644
--- a/eng/Baseline.xml
+++ b/eng/Baseline.xml
@@ -4,110 +4,110 @@ This file contains a list of all the packages and their versions which were rele
Update this list when preparing for a new patch.
-->
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 8165a50d2627..66d02fcb8180 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -9,37 +9,37 @@
-->
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- f42a208554fed9bb37603c5ed4f02206b2b1b9fa
+ 0d1256be4658567c8a24b4c027bdbb3dbd6de656
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- f42a208554fed9bb37603c5ed4f02206b2b1b9fa
+ 0d1256be4658567c8a24b4c027bdbb3dbd6de656
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- f42a208554fed9bb37603c5ed4f02206b2b1b9fa
+ 0d1256be4658567c8a24b4c027bdbb3dbd6de656
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- f42a208554fed9bb37603c5ed4f02206b2b1b9fa
+ 0d1256be4658567c8a24b4c027bdbb3dbd6de656
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- f42a208554fed9bb37603c5ed4f02206b2b1b9fa
+ 0d1256be4658567c8a24b4c027bdbb3dbd6de656
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- f42a208554fed9bb37603c5ed4f02206b2b1b9fa
+ 0d1256be4658567c8a24b4c027bdbb3dbd6de656
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- f42a208554fed9bb37603c5ed4f02206b2b1b9fa
+ 0d1256be4658567c8a24b4c027bdbb3dbd6de656
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-efcore
- f42a208554fed9bb37603c5ed4f02206b2b1b9fa
+ 0d1256be4658567c8a24b4c027bdbb3dbd6de656
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -53,9 +53,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- bf5e279d9239bfef5bb1b8d6212f1b971c434606
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -65,9 +65,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 5535e31a712343a63f5d7d796cd874e563e5ac14
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -121,9 +121,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 087e15321bb712ef6fe8b0ba6f8bd12facf92629
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -185,13 +185,13 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 087e15321bb712ef6fe8b0ba6f8bd12facf92629
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
-
+
https://github.com/dotnet/source-build-externals
- 300e99190e6ae1983681694dbdd5f75f0c692081
+ 4f2151df120194f0268944f1b723c14820738fc8
@@ -223,9 +223,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 5535e31a712343a63f5d7d796cd874e563e5ac14
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -241,7 +241,7 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 087e15321bb712ef6fe8b0ba6f8bd12facf92629
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -255,9 +255,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9f4b1f5d664afdfc80e1508ab7ed099dff210fbd
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -271,21 +271,21 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 5535e31a712343a63f5d7d796cd874e563e5ac14
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 087e15321bb712ef6fe8b0ba6f8bd12facf92629
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 087e15321bb712ef6fe8b0ba6f8bd12facf92629
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 087e15321bb712ef6fe8b0ba6f8bd12facf92629
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -316,31 +316,31 @@
Win-x64 is used here because we have picked an arbitrary runtime identifier to flow the version of the latest NETCore.App runtime.
All Runtime.$rid packages should have the same version.
-->
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 087e15321bb712ef6fe8b0ba6f8bd12facf92629
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 087e15321bb712ef6fe8b0ba6f8bd12facf92629
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 087e15321bb712ef6fe8b0ba6f8bd12facf92629
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 087e15321bb712ef6fe8b0ba6f8bd12facf92629
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
https://github.com/dotnet/xdt
9a1c3e1b7f0c8763d4c96e593961a61a72679a7b
-
+
https://github.com/dotnet/source-build-reference-packages
- 79827eed138fd2575a8b24820b4f385ee4ffb6e6
+ 6ed73280a6d70f7e7ac39c86f2abe8c10983f0bb
@@ -368,34 +368,34 @@
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 087e15321bb712ef6fe8b0ba6f8bd12facf92629
+ 2aade6beb02ea367fd97c4070a4198802fe61c03
https://github.com/dotnet/winforms
abda8e3bfa78319363526b5a5f86863ec979940e
-
+
https://github.com/dotnet/arcade
- 188340e12c0a372b1681ad6a5e72c608021efdba
+ e6f70c7dd528f05cd28cec2a179d58c22e91d9ac
-
+
https://github.com/dotnet/arcade
- 188340e12c0a372b1681ad6a5e72c608021efdba
+ e6f70c7dd528f05cd28cec2a179d58c22e91d9ac
-
+
https://github.com/dotnet/arcade
- 188340e12c0a372b1681ad6a5e72c608021efdba
+ e6f70c7dd528f05cd28cec2a179d58c22e91d9ac
-
+
https://github.com/dotnet/arcade
- 188340e12c0a372b1681ad6a5e72c608021efdba
+ e6f70c7dd528f05cd28cec2a179d58c22e91d9ac
-
+
https://github.com/dotnet/arcade
- 188340e12c0a372b1681ad6a5e72c608021efdba
+ e6f70c7dd528f05cd28cec2a179d58c22e91d9ac
https://github.com/dotnet/extensions
diff --git a/eng/Versions.props b/eng/Versions.props
index 138a9144ab30..74cc2f6bc296 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -8,11 +8,12 @@
8
0
- 5
+ 7
- true
- 7.1.2
+ false
+ 7.1.2
+ *-*
@@ -65,20 +66,20 @@
-->
- 8.0.0
- 8.0.5
- 8.0.5
- 8.0.5
- 8.0.5
- 8.0.5
- 8.0.5-servicing.24216.15
+ 8.0.1
+ 8.0.7
+ 8.0.7
+ 8.0.7
+ 8.0.7
+ 8.0.7
+ 8.0.7-servicing.24313.11
8.0.0
8.0.0
8.0.0
- 8.0.1
+ 8.0.2
8.0.0
8.0.0
- 8.0.0
+ 8.0.1
8.0.0
8.0.0
8.0.0
@@ -92,7 +93,7 @@
8.0.0
8.0.0
8.0.0
- 8.0.5-servicing.24216.15
+ 8.0.7-servicing.24313.11
8.0.0
8.0.0
8.0.0
@@ -108,7 +109,7 @@
8.0.0
8.0.2
8.0.0
- 8.0.5-servicing.24216.15
+ 8.0.7-servicing.24313.11
8.0.0
8.0.1
8.0.0
@@ -116,7 +117,7 @@
8.0.0-rtm.23520.14
8.0.0
8.0.0
- 8.0.0
+ 8.0.1
8.0.0
8.0.0
8.0.0
@@ -124,13 +125,13 @@
8.0.0
8.0.0
8.0.0
- 8.0.3
+ 8.0.4
8.0.0
8.0.0
8.0.0
- 8.0.5-servicing.24216.15
+ 8.0.7-servicing.24313.11
- 8.0.5-servicing.24216.15
+ 8.0.7-servicing.24313.11
8.0.0
8.0.1
@@ -142,14 +143,14 @@
8.1.0-preview.23604.1
8.1.0-preview.23604.1
- 8.0.5
- 8.0.5
- 8.0.5
- 8.0.5
- 8.0.5
- 8.0.5
- 8.0.5
- 8.0.5
+ 8.0.7
+ 8.0.7
+ 8.0.7
+ 8.0.7
+ 8.0.7
+ 8.0.7
+ 8.0.7
+ 8.0.7
4.8.0-3.23518.7
4.8.0-3.23518.7
@@ -161,13 +162,13 @@
6.2.4
6.2.4
- 8.0.0-beta.24204.3
- 8.0.0-beta.24204.3
- 8.0.0-beta.24204.3
+ 8.0.0-beta.24266.3
+ 8.0.0-beta.24266.3
+ 8.0.0-beta.24266.3
- 8.0.0-alpha.1.24175.3
+ 8.0.0-alpha.1.24269.1
- 8.0.0-alpha.1.24163.3
+ 8.0.0-alpha.1.24257.2
2.0.0-beta-23228-03
diff --git a/eng/common/templates-official/job/source-index-stage1.yml b/eng/common/templates-official/job/source-index-stage1.yml
index f0513aee5b0d..43ee0c202fc7 100644
--- a/eng/common/templates-official/job/source-index-stage1.yml
+++ b/eng/common/templates-official/job/source-index-stage1.yml
@@ -1,6 +1,7 @@
parameters:
runAsPublic: false
- sourceIndexPackageVersion: 1.0.1-20230228.2
+ sourceIndexUploadPackageVersion: 2.0.0-20240502.12
+ sourceIndexProcessBinlogPackageVersion: 1.0.1-20240129.2
sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci"
preSteps: []
@@ -14,15 +15,15 @@ jobs:
dependsOn: ${{ parameters.dependsOn }}
condition: ${{ parameters.condition }}
variables:
- - name: SourceIndexPackageVersion
- value: ${{ parameters.sourceIndexPackageVersion }}
+ - name: SourceIndexUploadPackageVersion
+ value: ${{ parameters.sourceIndexUploadPackageVersion }}
+ - name: SourceIndexProcessBinlogPackageVersion
+ value: ${{ parameters.sourceIndexProcessBinlogPackageVersion }}
- name: SourceIndexPackageSource
value: ${{ parameters.sourceIndexPackageSource }}
- name: BinlogPath
value: ${{ parameters.binlogPath }}
- - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - group: source-dot-net stage1 variables
- - template: /eng/common/templates-official/variables/pool-providers.yml
+ - template: /eng/common/templates/variables/pool-providers.yml
${{ if ne(parameters.pool, '') }}:
pool: ${{ parameters.pool }}
@@ -33,24 +34,23 @@ jobs:
demands: ImageOverride -equals windows.vs2019.amd64.open
${{ if eq(variables['System.TeamProject'], 'internal') }}:
name: $(DncEngInternalBuildPool)
- image: windows.vs2022.amd64
- os: windows
+ demands: ImageOverride -equals windows.vs2019.amd64
steps:
- ${{ each preStep in parameters.preSteps }}:
- ${{ preStep }}
- task: UseDotNet@2
- displayName: Use .NET Core SDK 6
+ displayName: Use .NET 8 SDK
inputs:
packageType: sdk
- version: 6.0.x
+ version: 8.0.x
installationPath: $(Agent.TempDirectory)/dotnet
workingDirectory: $(Agent.TempDirectory)
- script: |
- $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
- $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
+ $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(sourceIndexProcessBinlogPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
+ $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(sourceIndexUploadPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
displayName: Download Tools
# Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk.
workingDirectory: $(Agent.TempDirectory)
@@ -62,7 +62,24 @@ jobs:
displayName: Process Binlog into indexable sln
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name)
- displayName: Upload stage1 artifacts to source index
- env:
- BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url)
+ - task: AzureCLI@2
+ displayName: Get stage 1 auth token
+ inputs:
+ azureSubscription: 'SourceDotNet Stage1 Publish'
+ addSpnToEnvironment: true
+ scriptType: 'ps'
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ echo "##vso[task.setvariable variable=ARM_CLIENT_ID]$env:servicePrincipalId"
+ echo "##vso[task.setvariable variable=ARM_ID_TOKEN]$env:idToken"
+ echo "##vso[task.setvariable variable=ARM_TENANT_ID]$env:tenantId"
+
+ - script: |
+ echo "Client ID: $(ARM_CLIENT_ID)"
+ echo "ID Token: $(ARM_ID_TOKEN)"
+ echo "Tenant ID: $(ARM_TENANT_ID)"
+ az login --service-principal -u $(ARM_CLIENT_ID) --tenant $(ARM_TENANT_ID) --allow-no-subscriptions --federated-token $(ARM_ID_TOKEN)
+ displayName: "Login to Azure"
+
+ - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) -s netsourceindexstage1 -b stage1
+ displayName: Upload stage1 artifacts to source index
\ No newline at end of file
diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml
index b98202aa02d8..43ee0c202fc7 100644
--- a/eng/common/templates/job/source-index-stage1.yml
+++ b/eng/common/templates/job/source-index-stage1.yml
@@ -1,6 +1,7 @@
parameters:
runAsPublic: false
- sourceIndexPackageVersion: 1.0.1-20230228.2
+ sourceIndexUploadPackageVersion: 2.0.0-20240502.12
+ sourceIndexProcessBinlogPackageVersion: 1.0.1-20240129.2
sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci"
preSteps: []
@@ -14,14 +15,14 @@ jobs:
dependsOn: ${{ parameters.dependsOn }}
condition: ${{ parameters.condition }}
variables:
- - name: SourceIndexPackageVersion
- value: ${{ parameters.sourceIndexPackageVersion }}
+ - name: SourceIndexUploadPackageVersion
+ value: ${{ parameters.sourceIndexUploadPackageVersion }}
+ - name: SourceIndexProcessBinlogPackageVersion
+ value: ${{ parameters.sourceIndexProcessBinlogPackageVersion }}
- name: SourceIndexPackageSource
value: ${{ parameters.sourceIndexPackageSource }}
- name: BinlogPath
value: ${{ parameters.binlogPath }}
- - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - group: source-dot-net stage1 variables
- template: /eng/common/templates/variables/pool-providers.yml
${{ if ne(parameters.pool, '') }}:
@@ -40,16 +41,16 @@ jobs:
- ${{ preStep }}
- task: UseDotNet@2
- displayName: Use .NET Core SDK 6
+ displayName: Use .NET 8 SDK
inputs:
packageType: sdk
- version: 6.0.x
+ version: 8.0.x
installationPath: $(Agent.TempDirectory)/dotnet
workingDirectory: $(Agent.TempDirectory)
- script: |
- $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
- $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
+ $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(sourceIndexProcessBinlogPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
+ $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(sourceIndexUploadPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
displayName: Download Tools
# Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk.
workingDirectory: $(Agent.TempDirectory)
@@ -61,7 +62,24 @@ jobs:
displayName: Process Binlog into indexable sln
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name)
- displayName: Upload stage1 artifacts to source index
- env:
- BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url)
+ - task: AzureCLI@2
+ displayName: Get stage 1 auth token
+ inputs:
+ azureSubscription: 'SourceDotNet Stage1 Publish'
+ addSpnToEnvironment: true
+ scriptType: 'ps'
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ echo "##vso[task.setvariable variable=ARM_CLIENT_ID]$env:servicePrincipalId"
+ echo "##vso[task.setvariable variable=ARM_ID_TOKEN]$env:idToken"
+ echo "##vso[task.setvariable variable=ARM_TENANT_ID]$env:tenantId"
+
+ - script: |
+ echo "Client ID: $(ARM_CLIENT_ID)"
+ echo "ID Token: $(ARM_ID_TOKEN)"
+ echo "Tenant ID: $(ARM_TENANT_ID)"
+ az login --service-principal -u $(ARM_CLIENT_ID) --tenant $(ARM_TENANT_ID) --allow-no-subscriptions --federated-token $(ARM_ID_TOKEN)
+ displayName: "Login to Azure"
+
+ - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name) -s netsourceindexstage1 -b stage1
+ displayName: Upload stage1 artifacts to source index
\ No newline at end of file
diff --git a/eng/helix/helix.proj b/eng/helix/helix.proj
index 73ed73a32068..99254551279f 100644
--- a/eng/helix/helix.proj
+++ b/eng/helix/helix.proj
@@ -21,7 +21,7 @@
-
+
diff --git a/eng/scripts/SetupIdentitySources.ps1 b/eng/scripts/SetupIdentitySources.ps1
new file mode 100644
index 000000000000..58a4e690d7b1
--- /dev/null
+++ b/eng/scripts/SetupIdentitySources.ps1
@@ -0,0 +1,46 @@
+[CmdletBinding()]
+param (
+ [Parameter(Mandatory = $true)][string]$ConfigFile,
+ [Parameter(Mandatory = $true)][string]$IdentityModelPackageSource
+)
+
+$ErrorActionPreference = "Stop"
+Set-StrictMode -Version 2.0
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+
+# Add source entry to PackageSources
+function AddPackageSource($sources, $SourceName, $SourceEndPoint) {
+ $packageSource = $sources.SelectSingleNode("add[@key='$SourceName']")
+
+ if ($packageSource -eq $null)
+ {
+ $packageSource = $doc.CreateElement("add")
+ $packageSource.SetAttribute("key", $SourceName)
+ $packageSource.SetAttribute("value", $SourceEndPoint)
+ $sources.AppendChild($packageSource) | Out-Null
+ }
+ else {
+ Write-Host "Package source $SourceName already present."
+ }
+}
+
+if (!(Test-Path $ConfigFile -PathType Leaf)) {
+ Write-PipelineTelemetryError -Category 'Build' -Message "eng/scripts/SetupIdentitySources.ps1 returned a non-zero exit code. Couldn't find the NuGet config file: $ConfigFile"
+ ExitWithExitCode 1
+}
+
+# Load NuGet.config
+$doc = New-Object System.Xml.XmlDocument
+$filename = (Get-Item $ConfigFile).FullName
+$doc.Load($filename)
+
+# Get reference to or create one if none exist already
+$sources = $doc.DocumentElement.SelectSingleNode("packageSources")
+if ($sources -eq $null) {
+ $sources = $doc.CreateElement("packageSources")
+ $doc.DocumentElement.AppendChild($sources) | Out-Null
+}
+
+AddPackageSource -Sources $sources -SourceName "identitymodel-nightlies" -SourceEndPoint $IdentityModelPackageSource
+
+$doc.Save($filename)
\ No newline at end of file
diff --git a/eng/targets/Helix.targets b/eng/targets/Helix.targets
index 35c116026c62..ee73eb8ac8a3 100644
--- a/eng/targets/Helix.targets
+++ b/eng/targets/Helix.targets
@@ -141,7 +141,7 @@
<_Temp Include="@(HelixAvailableTargetQueue)" />
-
+
diff --git a/global.json b/global.json
index 915af8cbaa3c..bfd92fee2223 100644
--- a/global.json
+++ b/global.json
@@ -1,9 +1,9 @@
{
"sdk": {
- "version": "8.0.104"
+ "version": "8.0.105"
},
"tools": {
- "dotnet": "8.0.104",
+ "dotnet": "8.0.105",
"runtimes": {
"dotnet/x86": [
"$(MicrosoftNETCoreBrowserDebugHostTransportVersion)"
@@ -27,7 +27,7 @@
},
"msbuild-sdks": {
"Yarn.MSBuild": "1.22.19",
- "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24204.3",
- "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24204.3"
+ "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24266.3",
+ "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24266.3"
}
}
diff --git a/src/Azure/AzureAppServices.HostingStartup/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup.csproj b/src/Azure/AzureAppServices.HostingStartup/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup.csproj
index dbc464028962..fe1c0f19275e 100644
--- a/src/Azure/AzureAppServices.HostingStartup/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup.csproj
+++ b/src/Azure/AzureAppServices.HostingStartup/src/Microsoft.AspNetCore.AzureAppServices.HostingStartup.csproj
@@ -13,6 +13,7 @@
+
diff --git a/src/Components/WebAssembly/DevServer/src/Microsoft.AspNetCore.Components.WebAssembly.DevServer.csproj b/src/Components/WebAssembly/DevServer/src/Microsoft.AspNetCore.Components.WebAssembly.DevServer.csproj
index 8267a699183b..ebd48678889a 100644
--- a/src/Components/WebAssembly/DevServer/src/Microsoft.AspNetCore.Components.WebAssembly.DevServer.csproj
+++ b/src/Components/WebAssembly/DevServer/src/Microsoft.AspNetCore.Components.WebAssembly.DevServer.csproj
@@ -21,6 +21,7 @@
+
diff --git a/src/Hosting/Hosting/src/Internal/HostingMetrics.cs b/src/Hosting/Hosting/src/Internal/HostingMetrics.cs
index 8d26f10f728f..bc84fb87dfe7 100644
--- a/src/Hosting/Hosting/src/Internal/HostingMetrics.cs
+++ b/src/Hosting/Hosting/src/Internal/HostingMetrics.cs
@@ -69,12 +69,8 @@ public void RequestEnd(string protocol, bool isHttps, string scheme, string meth
{
tags.Add("http.route", route);
}
- // This exception is only present if there is an unhandled exception.
- // An exception caught by ExceptionHandlerMiddleware and DeveloperExceptionMiddleware isn't thrown to here. Instead, those middleware add error.type to custom tags.
- if (exception != null)
- {
- tags.Add("error.type", exception.GetType().FullName);
- }
+
+ // Add before some built in tags so custom tags are prioritized when dealing with duplicates.
if (customTags != null)
{
for (var i = 0; i < customTags.Count; i++)
@@ -83,6 +79,15 @@ public void RequestEnd(string protocol, bool isHttps, string scheme, string meth
}
}
+ // This exception is only present if there is an unhandled exception.
+ // An exception caught by ExceptionHandlerMiddleware and DeveloperExceptionMiddleware isn't thrown to here. Instead, those middleware add error.type to custom tags.
+ if (exception != null)
+ {
+ // Exception tag could have been added by middleware. If an exception is later thrown in request pipeline
+ // then we don't want to add a duplicate tag here because that breaks some metrics systems.
+ tags.TryAddTag("error.type", exception.GetType().FullName);
+ }
+
var duration = Stopwatch.GetElapsedTime(startTimestamp, currentTimestamp);
_requestDuration.Record(duration.TotalSeconds, tags);
}
diff --git a/src/Hosting/Hosting/src/Microsoft.AspNetCore.Hosting.csproj b/src/Hosting/Hosting/src/Microsoft.AspNetCore.Hosting.csproj
index c898aed6af58..3caa14c4beb3 100644
--- a/src/Hosting/Hosting/src/Microsoft.AspNetCore.Hosting.csproj
+++ b/src/Hosting/Hosting/src/Microsoft.AspNetCore.Hosting.csproj
@@ -16,6 +16,7 @@
+
diff --git a/src/Installers/Windows/SharedFramework/Product.wxs b/src/Installers/Windows/SharedFramework/Product.wxs
index ae95ee10ae9c..30d8d6025817 100644
--- a/src/Installers/Windows/SharedFramework/Product.wxs
+++ b/src/Installers/Windows/SharedFramework/Product.wxs
@@ -60,6 +60,7 @@
+
@@ -73,6 +74,12 @@
+
+
+
+
+
+
@@ -110,5 +117,11 @@
+
+
+
+
+
+
diff --git a/src/Middleware/Diagnostics/src/DiagnosticsTelemetry.cs b/src/Middleware/Diagnostics/src/DiagnosticsTelemetry.cs
index aace88526805..36ab75c70ad2 100644
--- a/src/Middleware/Diagnostics/src/DiagnosticsTelemetry.cs
+++ b/src/Middleware/Diagnostics/src/DiagnosticsTelemetry.cs
@@ -15,7 +15,9 @@ public static void ReportUnhandledException(ILogger logger, HttpContext context,
if (context.Features.Get() is { } tagsFeature)
{
- tagsFeature.Tags.Add(new KeyValuePair("error.type", ex.GetType().FullName));
+ // Multiple exception middleware could be registered that have already added the tag.
+ // We don't want to add a duplicate tag here because that breaks some metrics systems.
+ tagsFeature.TryAddTag("error.type", ex.GetType().FullName);
}
}
}
diff --git a/src/Middleware/Diagnostics/src/Microsoft.AspNetCore.Diagnostics.csproj b/src/Middleware/Diagnostics/src/Microsoft.AspNetCore.Diagnostics.csproj
index 4657b64cbf7b..8671a3b03fb4 100644
--- a/src/Middleware/Diagnostics/src/Microsoft.AspNetCore.Diagnostics.csproj
+++ b/src/Middleware/Diagnostics/src/Microsoft.AspNetCore.Diagnostics.csproj
@@ -17,6 +17,7 @@
+
diff --git a/src/Middleware/Diagnostics/test/FunctionalTests/ExceptionHandlerSampleTest.cs b/src/Middleware/Diagnostics/test/FunctionalTests/ExceptionHandlerSampleTest.cs
index aea061e0c4c7..20a21449f879 100644
--- a/src/Middleware/Diagnostics/test/FunctionalTests/ExceptionHandlerSampleTest.cs
+++ b/src/Middleware/Diagnostics/test/FunctionalTests/ExceptionHandlerSampleTest.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.
using System.Net;
diff --git a/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerTest.cs b/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerTest.cs
index 7119b0bf7468..4ff8342e0957 100644
--- a/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerTest.cs
+++ b/src/Middleware/Diagnostics/test/UnitTests/ExceptionHandlerTest.cs
@@ -15,6 +15,7 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.Diagnostics.Metrics.Testing;
+using System.Net.Http;
namespace Microsoft.AspNetCore.Diagnostics;
@@ -965,4 +966,136 @@ public async Task UnhandledError_ExceptionNameTagAdded()
Assert.Equal("System.Exception", (string)m.Tags["error.type"]);
});
}
+
+ [Fact]
+ public async Task UnhandledError_MultipleHandlers_ExceptionNameTagAddedOnce()
+ {
+ // Arrange
+ var meterFactory = new TestMeterFactory();
+ using var instrumentCollector = new MetricCollector(meterFactory, "Microsoft.AspNetCore.Hosting", "http.server.request.duration");
+
+ using var host = new HostBuilder()
+ .ConfigureServices(s =>
+ {
+ s.AddSingleton(meterFactory);
+ })
+ .ConfigureWebHost(webHostBuilder =>
+ {
+ webHostBuilder
+ .UseTestServer()
+ .Configure(app =>
+ {
+ // Second error and handler
+ app.UseExceptionHandler(new ExceptionHandlerOptions()
+ {
+ ExceptionHandler = httpContext =>
+ {
+ httpContext.Response.StatusCode = StatusCodes.Status500InternalServerError;
+ return Task.CompletedTask;
+ }
+ });
+ app.Use(async (context, next) =>
+ {
+ await next();
+ throw new InvalidOperationException("Test exception2");
+ });
+
+ // First error and handler
+ app.UseExceptionHandler(new ExceptionHandlerOptions()
+ {
+ ExceptionHandler = httpContext =>
+ {
+ httpContext.Response.StatusCode = StatusCodes.Status404NotFound;
+ return Task.CompletedTask;
+ }
+ });
+ app.Run(context =>
+ {
+ throw new Exception("Test exception1");
+ });
+ });
+ }).Build();
+
+ await host.StartAsync();
+
+ var server = host.GetTestServer();
+
+ // Act
+ var response = await server.CreateClient().GetAsync("/path");
+ Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
+
+ await instrumentCollector.WaitForMeasurementsAsync(minCount: 1).DefaultTimeout();
+
+ // Assert
+ Assert.Collection(
+ instrumentCollector.GetMeasurementSnapshot(),
+ m =>
+ {
+ Assert.True(m.Value > 0);
+ Assert.Equal(500, (int)m.Tags["http.response.status_code"]);
+ Assert.Equal("System.Exception", (string)m.Tags["error.type"]);
+ });
+ }
+
+ [Fact]
+ public async Task UnhandledError_ErrorAfterHandler_ExceptionNameTagAddedOnce()
+ {
+ // Arrange
+ var meterFactory = new TestMeterFactory();
+ using var instrumentCollector = new MetricCollector(meterFactory, "Microsoft.AspNetCore.Hosting", "http.server.request.duration");
+
+ using var host = new HostBuilder()
+ .ConfigureServices(s =>
+ {
+ s.AddSingleton(meterFactory);
+ })
+ .ConfigureWebHost(webHostBuilder =>
+ {
+ webHostBuilder
+ .UseTestServer()
+ .Configure(app =>
+ {
+ // Second error
+ app.Use(async (context, next) =>
+ {
+ await next();
+
+ throw new InvalidOperationException("Test exception2");
+ });
+
+ // First error and handler
+ app.UseExceptionHandler(new ExceptionHandlerOptions()
+ {
+ ExceptionHandler = httpContext =>
+ {
+ httpContext.Response.StatusCode = StatusCodes.Status404NotFound;
+ return httpContext.Response.WriteAsync("Custom handler");
+ }
+ });
+ app.Run(context =>
+ {
+ throw new Exception("Test exception1");
+ });
+ });
+ }).Build();
+
+ await host.StartAsync();
+
+ var server = host.GetTestServer();
+
+ // Act
+ await Assert.ThrowsAsync(async () => await server.CreateClient().GetAsync("/path"));
+
+ await instrumentCollector.WaitForMeasurementsAsync(minCount: 1).DefaultTimeout();
+
+ // Assert
+ Assert.Collection(
+ instrumentCollector.GetMeasurementSnapshot(),
+ m =>
+ {
+ Assert.True(m.Value > 0);
+ Assert.Equal(404, (int)m.Tags["http.response.status_code"]);
+ Assert.Equal("System.Exception", (string)m.Tags["error.type"]);
+ });
+ }
}
diff --git a/src/Middleware/Diagnostics/test/testassets/ExceptionHandlerSample/ExceptionHandlerSample.csproj b/src/Middleware/Diagnostics/test/testassets/ExceptionHandlerSample/ExceptionHandlerSample.csproj
index 2faf636c4914..e2eaca2faeda 100644
--- a/src/Middleware/Diagnostics/test/testassets/ExceptionHandlerSample/ExceptionHandlerSample.csproj
+++ b/src/Middleware/Diagnostics/test/testassets/ExceptionHandlerSample/ExceptionHandlerSample.csproj
@@ -10,5 +10,6 @@
+
diff --git a/src/Middleware/Diagnostics/test/testassets/ExceptionHandlerSample/StartupWithWebSocket.cs b/src/Middleware/Diagnostics/test/testassets/ExceptionHandlerSample/StartupWithWebSocket.cs
new file mode 100644
index 000000000000..eb2fc7b4a956
--- /dev/null
+++ b/src/Middleware/Diagnostics/test/testassets/ExceptionHandlerSample/StartupWithWebSocket.cs
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.Text;
+using System.Text.Encodings.Web;
+using Microsoft.AspNetCore.Diagnostics;
+using Microsoft.AspNetCore.Http.Metadata;
+
+namespace ExceptionHandlerSample;
+
+// Note that this class isn't used in tests as TestServer doesn't have the right behavior to test web sockets
+// in the way we need. But leaving here so it can be used in Program.cs when starting the app manually.
+public class StartupWithWebSocket
+{
+ public void ConfigureServices(IServiceCollection services)
+ {
+ }
+
+ public void Configure(IApplicationBuilder app)
+ {
+ app.UseExceptionHandler(options => { }); // Exception handling middleware introduces duplicate tag
+ app.UseWebSockets();
+
+ app.Use(async (HttpContext context, Func next) =>
+ {
+ try
+ {
+ if (context.WebSockets.IsWebSocketRequest)
+ {
+ using var ws = await context.WebSockets.AcceptWebSocketAsync();
+ await ws.SendAsync(new ArraySegment(Encoding.UTF8.GetBytes("Hello")), System.Net.WebSockets.WebSocketMessageType.Text, true, context.RequestAborted);
+ await ws.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.NormalClosure, "done", context.RequestAborted);
+ throw new InvalidOperationException("Throw after websocket request completion to produce the bug");
+ }
+ else
+ {
+ await context.Response.WriteAsync($"Not a web socket request. PID: {Process.GetCurrentProcess().Id}");
+ }
+ }
+ catch (Exception ex)
+ {
+ _ = ex;
+ throw;
+ }
+ });
+ }
+}
+
diff --git a/src/ProjectTemplates/test/Templates.Blazor.Tests/Templates.Blazor.Tests.csproj b/src/ProjectTemplates/test/Templates.Blazor.Tests/Templates.Blazor.Tests.csproj
index 368459e98c90..1db85d5286fe 100644
--- a/src/ProjectTemplates/test/Templates.Blazor.Tests/Templates.Blazor.Tests.csproj
+++ b/src/ProjectTemplates/test/Templates.Blazor.Tests/Templates.Blazor.Tests.csproj
@@ -9,6 +9,7 @@
true
$(RunTemplateTests)
true
+ false
diff --git a/src/ProjectTemplates/test/Templates.Blazor.WebAssembly.Auth.Tests/Templates.Blazor.WebAssembly.Auth.Tests.csproj b/src/ProjectTemplates/test/Templates.Blazor.WebAssembly.Auth.Tests/Templates.Blazor.WebAssembly.Auth.Tests.csproj
index 3754aee3abd4..3d0831a1001a 100644
--- a/src/ProjectTemplates/test/Templates.Blazor.WebAssembly.Auth.Tests/Templates.Blazor.WebAssembly.Auth.Tests.csproj
+++ b/src/ProjectTemplates/test/Templates.Blazor.WebAssembly.Auth.Tests/Templates.Blazor.WebAssembly.Auth.Tests.csproj
@@ -9,6 +9,7 @@
true
true
+ false
diff --git a/src/ProjectTemplates/test/Templates.Blazor.WebAssembly.Tests/Templates.Blazor.WebAssembly.Tests.csproj b/src/ProjectTemplates/test/Templates.Blazor.WebAssembly.Tests/Templates.Blazor.WebAssembly.Tests.csproj
index 44348f90847a..b42866c3a78f 100644
--- a/src/ProjectTemplates/test/Templates.Blazor.WebAssembly.Tests/Templates.Blazor.WebAssembly.Tests.csproj
+++ b/src/ProjectTemplates/test/Templates.Blazor.WebAssembly.Tests/Templates.Blazor.WebAssembly.Tests.csproj
@@ -9,6 +9,7 @@
true
true
+ false
diff --git a/src/ProjectTemplates/test/Templates.Mvc.Tests/Templates.Mvc.Tests.csproj b/src/ProjectTemplates/test/Templates.Mvc.Tests/Templates.Mvc.Tests.csproj
index 880e1bb68d6b..152c0d7b0d07 100644
--- a/src/ProjectTemplates/test/Templates.Mvc.Tests/Templates.Mvc.Tests.csproj
+++ b/src/ProjectTemplates/test/Templates.Mvc.Tests/Templates.Mvc.Tests.csproj
@@ -9,6 +9,7 @@
true
true
+ false
diff --git a/src/ProjectTemplates/test/Templates.Tests/Templates.Tests.csproj b/src/ProjectTemplates/test/Templates.Tests/Templates.Tests.csproj
index d7c3c354d144..fb297bfae7c5 100644
--- a/src/ProjectTemplates/test/Templates.Tests/Templates.Tests.csproj
+++ b/src/ProjectTemplates/test/Templates.Tests/Templates.Tests.csproj
@@ -9,6 +9,7 @@
true
true
+ false
diff --git a/src/Security/Authentication/JwtBearer/src/JwtBearerConfigureOptions.cs b/src/Security/Authentication/JwtBearer/src/JwtBearerConfigureOptions.cs
index 812eb9287aa3..97568fde9751 100644
--- a/src/Security/Authentication/JwtBearer/src/JwtBearerConfigureOptions.cs
+++ b/src/Security/Authentication/JwtBearer/src/JwtBearerConfigureOptions.cs
@@ -40,12 +40,14 @@ public void Configure(string? name, JwtBearerOptions options)
return;
}
+ var validateIssuer = StringHelpers.ParseValueOrDefault(configSection[nameof(TokenValidationParameters.ValidateIssuer)], bool.Parse, options.TokenValidationParameters.ValidateIssuer);
var issuer = configSection[nameof(TokenValidationParameters.ValidIssuer)];
var issuers = configSection.GetSection(nameof(TokenValidationParameters.ValidIssuers)).GetChildren().Select(iss => iss.Value).ToList();
if (issuer is not null)
{
issuers.Add(issuer);
}
+ var validateAudience = StringHelpers.ParseValueOrDefault(configSection[nameof(TokenValidationParameters.ValidateAudience)], bool.Parse, options.TokenValidationParameters.ValidateAudience);
var audience = configSection[nameof(TokenValidationParameters.ValidAudience)];
var audiences = configSection.GetSection(nameof(TokenValidationParameters.ValidAudiences)).GetChildren().Select(aud => aud.Value).ToList();
if (audience is not null)
@@ -71,9 +73,9 @@ public void Configure(string? name, JwtBearerOptions options)
options.SaveToken = StringHelpers.ParseValueOrDefault(configSection[nameof(options.SaveToken)], bool.Parse, options.SaveToken);
options.TokenValidationParameters = new()
{
- ValidateIssuer = issuers.Count > 0,
+ ValidateIssuer = validateIssuer,
ValidIssuers = issuers,
- ValidateAudience = audiences.Count > 0,
+ ValidateAudience = validateAudience,
ValidAudiences = audiences,
ValidateIssuerSigningKey = true,
IssuerSigningKeys = GetIssuerSigningKeys(configSection, issuers),
diff --git a/src/Security/Authentication/test/JwtBearerTests_Handler.cs b/src/Security/Authentication/test/JwtBearerTests_Handler.cs
index 6d8260c2a39f..60001e54f3cd 100644
--- a/src/Security/Authentication/test/JwtBearerTests_Handler.cs
+++ b/src/Security/Authentication/test/JwtBearerTests_Handler.cs
@@ -31,17 +31,9 @@ public class JwtBearerTests_Handler : SharedAuthenticationTests false; }
protected override bool SupportsSignOut { get => false; }
- protected override void RegisterAuth(AuthenticationBuilder services, Action configure)
- {
- services.AddJwtBearer(o =>
- {
- ConfigureDefaults(o);
- configure.Invoke(o);
- });
- }
-
- private void ConfigureDefaults(JwtBearerOptions o)
+ protected override void RegisterAuth(AuthenticationBuilder services, Action configure = null)
{
+ services.AddJwtBearer(configure);
}
[Fact]
@@ -964,25 +956,19 @@ public async Task ExpirationAndIssuedWhenMinOrMaxValue()
[Fact]
public void CanReadJwtBearerOptionsFromConfig()
{
- var services = new ServiceCollection().AddLogging();
- var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
- {
- new KeyValuePair("Authentication:Schemes:Bearer:ValidIssuer", "dotnet-user-jwts"),
- new KeyValuePair("Authentication:Schemes:Bearer:ValidAudiences:0", "http://localhost:5000"),
- new KeyValuePair("Authentication:Schemes:Bearer:ValidAudiences:1", "https://localhost:5001"),
- new KeyValuePair("Authentication:Schemes:Bearer:BackchannelTimeout", "00:01:00"),
- new KeyValuePair("Authentication:Schemes:Bearer:RequireHttpsMetadata", "false"),
- new KeyValuePair("Authentication:Schemes:Bearer:SaveToken", "True"),
- }).Build();
+ var services = new ServiceCollection();
+ var config = new ConfigurationBuilder().AddInMemoryCollection([
+ new("Authentication:Schemes:Bearer:ValidIssuer", "dotnet-user-jwts"),
+ new("Authentication:Schemes:Bearer:ValidAudiences:0", "http://localhost:5000"),
+ new("Authentication:Schemes:Bearer:ValidAudiences:1", "https://localhost:5001"),
+ new("Authentication:Schemes:Bearer:BackchannelTimeout", "00:01:00"),
+ new("Authentication:Schemes:Bearer:RequireHttpsMetadata", "false"),
+ new("Authentication:Schemes:Bearer:SaveToken", "True"),
+ ]).Build();
services.AddSingleton(config);
// Act
- var builder = services.AddAuthentication(o =>
- {
- o.AddScheme("Bearer", "Bearer");
- });
- builder.AddJwtBearer("Bearer");
- RegisterAuth(builder, _ => { });
+ RegisterAuth(services.AddAuthentication());
var sp = services.BuildServiceProvider();
// Assert
@@ -992,35 +978,34 @@ public void CanReadJwtBearerOptionsFromConfig()
Assert.Equal(jwtBearerOptions.BackchannelTimeout, TimeSpan.FromSeconds(60));
Assert.False(jwtBearerOptions.RequireHttpsMetadata);
Assert.True(jwtBearerOptions.SaveToken);
- Assert.True(jwtBearerOptions.MapInboundClaims); // Assert default values are respected
+ // ValidateIssuerSigningKey should always be set to its non-default value of true if options are read from config.
+ Assert.True(jwtBearerOptions.TokenValidationParameters.ValidateIssuerSigningKey);
+ // Assert default values for other options are respected.
+ Assert.True(jwtBearerOptions.MapInboundClaims);
+ Assert.True(jwtBearerOptions.TokenValidationParameters.ValidateIssuer);
+ Assert.True(jwtBearerOptions.TokenValidationParameters.ValidateAudience);
}
[Fact]
public void CanReadMultipleIssuersFromConfig()
{
- var services = new ServiceCollection().AddLogging();
+ var services = new ServiceCollection();
var firstKey = "qPG6tDtfxFYZifHW3sEueQ==";
var secondKey = "6JPzXj6aOPdojlZdeLshaA==";
- var config = new ConfigurationBuilder().AddInMemoryCollection(new[]
- {
- new KeyValuePair("Authentication:Schemes:Bearer:ValidIssuers:0", "dotnet-user-jwts"),
- new KeyValuePair("Authentication:Schemes:Bearer:ValidIssuers:1", "dotnet-user-jwts-2"),
- new KeyValuePair("Authentication:Schemes:Bearer:SigningKeys:0:Issuer", "dotnet-user-jwts"),
- new KeyValuePair("Authentication:Schemes:Bearer:SigningKeys:0:Value", firstKey),
- new KeyValuePair("Authentication:Schemes:Bearer:SigningKeys:0:Length", "32"),
- new KeyValuePair("Authentication:Schemes:Bearer:SigningKeys:1:Issuer", "dotnet-user-jwts-2"),
- new KeyValuePair("Authentication:Schemes:Bearer:SigningKeys:1:Value", secondKey),
- new KeyValuePair("Authentication:Schemes:Bearer:SigningKeys:1:Length", "32"),
- }).Build();
+ var config = new ConfigurationBuilder().AddInMemoryCollection([
+ new("Authentication:Schemes:Bearer:ValidIssuers:0", "dotnet-user-jwts"),
+ new("Authentication:Schemes:Bearer:ValidIssuers:1", "dotnet-user-jwts-2"),
+ new("Authentication:Schemes:Bearer:SigningKeys:0:Issuer", "dotnet-user-jwts"),
+ new("Authentication:Schemes:Bearer:SigningKeys:0:Value", firstKey),
+ new("Authentication:Schemes:Bearer:SigningKeys:0:Length", "32"),
+ new("Authentication:Schemes:Bearer:SigningKeys:1:Issuer", "dotnet-user-jwts-2"),
+ new("Authentication:Schemes:Bearer:SigningKeys:1:Value", secondKey),
+ new("Authentication:Schemes:Bearer:SigningKeys:1:Length", "32"),
+ ]).Build();
services.AddSingleton(config);
// Act
- var builder = services.AddAuthentication(o =>
- {
- o.AddScheme("Bearer", "Bearer");
- });
- builder.AddJwtBearer("Bearer");
- RegisterAuth(builder, _ => { });
+ RegisterAuth(services.AddAuthentication());
var sp = services.BuildServiceProvider();
// Assert
@@ -1030,6 +1015,48 @@ public void CanReadMultipleIssuersFromConfig()
Assert.Equal(secondKey, Convert.ToBase64String(jwtBearerOptions.TokenValidationParameters.IssuerSigningKeys.OfType().LastOrDefault()?.Key));
}
+ [Fact]
+ public void IssuerAndAudienceValidationEnabledByDefaultWhenOptionsAreReadFromConfig()
+ {
+ var services = new ServiceCollection();
+ var config = new ConfigurationBuilder().AddInMemoryCollection([
+ new("Authentication:Schemes:Bearer:Authority", "https://localhost:5001"),
+ ]).Build();
+ services.AddSingleton(config);
+
+ // Act
+ RegisterAuth(services.AddAuthentication());
+ var sp = services.BuildServiceProvider();
+
+ // Assert
+ var jwtBearerOptions = sp.GetRequiredService>().Get(JwtBearerDefaults.AuthenticationScheme);
+ Assert.Equal("https://localhost:5001", jwtBearerOptions.Authority);
+ Assert.True(jwtBearerOptions.TokenValidationParameters.ValidateIssuer);
+ Assert.True(jwtBearerOptions.TokenValidationParameters.ValidateAudience);
+ }
+
+ [Fact]
+ public void IssuerAndAudienceValidationCanBeDisabledFromConfig()
+ {
+ var services = new ServiceCollection();
+ var config = new ConfigurationBuilder().AddInMemoryCollection([
+ new("Authentication:Schemes:Bearer:Authority", "https://localhost:5001"),
+ new("Authentication:Schemes:Bearer:ValidateIssuer", "false"),
+ new("Authentication:Schemes:Bearer:ValidateAudience", "false"),
+ ]).Build();
+ services.AddSingleton(config);
+
+ // Act
+ RegisterAuth(services.AddAuthentication());
+ var sp = services.BuildServiceProvider();
+
+ // Assert
+ var jwtBearerOptions = sp.GetRequiredService>().Get(JwtBearerDefaults.AuthenticationScheme);
+ Assert.Equal("https://localhost:5001", jwtBearerOptions.Authority);
+ Assert.False(jwtBearerOptions.TokenValidationParameters.ValidateIssuer);
+ Assert.False(jwtBearerOptions.TokenValidationParameters.ValidateAudience);
+ }
+
class InvalidTokenValidator : TokenHandler
{
public InvalidTokenValidator()
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp
index a1322eaabb32..fcd4205138c9 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp
+++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp
@@ -22,7 +22,8 @@ const PCWSTR HandlerResolver::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"
HandlerResolver::HandlerResolver(HMODULE hModule, const IHttpServer &pServer)
: m_hModule(hModule),
m_pServer(pServer),
- m_loadedApplicationHostingModel(HOSTING_UNKNOWN)
+ m_loadedApplicationHostingModel(HOSTING_UNKNOWN),
+ m_shutdownDelay()
{
m_disallowRotationOnConfigChange = false;
InitializeSRWLock(&m_requestHandlerLoadLock);
@@ -171,6 +172,7 @@ HandlerResolver::GetApplicationFactory(const IHttpApplication& pApplication, con
m_loadedApplicationHostingModel = options.QueryHostingModel();
m_loadedApplicationId = pApplication.GetApplicationId();
m_disallowRotationOnConfigChange = options.QueryDisallowRotationOnConfigChange();
+ m_shutdownDelay = options.QueryShutdownDelay();
RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, shadowCopyPath, options, pApplicationFactory, errorContext));
@@ -197,6 +199,11 @@ bool HandlerResolver::GetDisallowRotationOnConfigChange()
return m_disallowRotationOnConfigChange;
}
+std::chrono::milliseconds HandlerResolver::GetShutdownDelay() const
+{
+ return m_shutdownDelay;
+}
+
HRESULT
HandlerResolver::FindNativeAssemblyFromGlobalLocation(
const ShimOptions& pConfiguration,
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h
index a828773c20e1..54121f072cac 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h
+++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/HandlerResolver.h
@@ -19,6 +19,7 @@ class HandlerResolver
void ResetHostingModel();
APP_HOSTING_MODEL GetHostingModel();
bool GetDisallowRotationOnConfigChange();
+ std::chrono::milliseconds GetShutdownDelay() const;
private:
HRESULT LoadRequestHandlerAssembly(const IHttpApplication &pApplication, const std::filesystem::path& shadowCopyPath, const ShimOptions& pConfiguration, std::unique_ptr& pApplicationFactory, ErrorContext& errorContext);
@@ -40,6 +41,7 @@ class HandlerResolver
APP_HOSTING_MODEL m_loadedApplicationHostingModel;
HostFxr m_hHostFxrDll;
bool m_disallowRotationOnConfigChange;
+ std::chrono::milliseconds m_shutdownDelay;
static const PCWSTR s_pwzAspnetcoreInProcessRequestHandlerName;
static const PCWSTR s_pwzAspnetcoreOutOfProcessRequestHandlerName;
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp
index f85f5483a2c8..e538e3e8e9fa 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp
+++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.cpp
@@ -12,6 +12,8 @@
#define CS_ASPNETCORE_SHADOW_COPY_DIRECTORY L"shadowCopyDirectory"
#define CS_ASPNETCORE_CLEAN_SHADOW_DIRECTORY_CONTENT L"cleanShadowCopyDirectory"
#define CS_ASPNETCORE_DISALLOW_ROTATE_CONFIG L"disallowRotationOnConfigChange"
+#define CS_ASPNETCORE_SHUTDOWN_DELAY L"shutdownDelay"
+#define CS_ASPNETCORE_SHUTDOWN_DELAY_ENV L"ANCM_shutdownDelay"
ShimOptions::ShimOptions(const ConfigurationSource &configurationSource) :
m_hostingModel(HOSTING_UNKNOWN),
@@ -53,7 +55,7 @@ ShimOptions::ShimOptions(const ConfigurationSource &configurationSource) :
auto disallowRotationOnConfigChange = find_element(handlerSettings, CS_ASPNETCORE_DISALLOW_ROTATE_CONFIG).value_or(std::wstring());
m_fDisallowRotationOnConfigChange = equals_ignore_case(L"true", disallowRotationOnConfigChange);
-
+
m_strProcessPath = section->GetRequiredString(CS_ASPNETCORE_PROCESS_EXE_PATH);
m_strArguments = section->GetString(CS_ASPNETCORE_PROCESS_ARGUMENTS).value_or(CS_ASPNETCORE_PROCESS_ARGUMENTS_DEFAULT);
m_fStdoutLogEnabled = section->GetRequiredBool(CS_ASPNETCORE_STDOUT_LOG_ENABLED);
@@ -82,4 +84,38 @@ ShimOptions::ShimOptions(const ConfigurationSource &configurationSource) :
auto dotnetEnvironmentEnabled = equals_ignore_case(L"Development", dotnetEnvironment);
m_fShowDetailedErrors = detailedErrorsEnabled || aspnetCoreEnvironmentEnabled || dotnetEnvironmentEnabled;
+
+ // Specifies how long to delay (in milliseconds) after IIS tells us to stop before starting the application shutdown.
+ // See StartShutdown in globalmodule to see how it's used.
+ auto shutdownDelay = find_element(handlerSettings, CS_ASPNETCORE_SHUTDOWN_DELAY).value_or(std::wstring());
+ if (shutdownDelay.empty())
+ {
+ // Fallback to environment variable if process specific config wasn't set
+ shutdownDelay = Environment::GetEnvironmentVariableValue(CS_ASPNETCORE_SHUTDOWN_DELAY_ENV)
+ .value_or(environmentVariables[CS_ASPNETCORE_SHUTDOWN_DELAY_ENV]);
+ if (shutdownDelay.empty())
+ {
+ // Default if neither process specific config or environment variable aren't set
+ m_fShutdownDelay = std::chrono::seconds(0);
+ }
+ else
+ {
+ SetShutdownDelay(shutdownDelay);
+ }
+ }
+ else
+ {
+ SetShutdownDelay(shutdownDelay);
+ }
+}
+
+void ShimOptions::SetShutdownDelay(const std::wstring& shutdownDelay)
+{
+ auto millsecondsValue = std::stoi(shutdownDelay);
+ if (millsecondsValue < 0)
+ {
+ throw ConfigurationLoadException(format(
+ L"'shutdownDelay' in web.config or '%s' environment variable is less than 0.", CS_ASPNETCORE_SHUTDOWN_DELAY_ENV));
+ }
+ m_fShutdownDelay = std::chrono::milliseconds(millsecondsValue);
}
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.h
index 5b3cf72d692b..4e13190be6dd 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.h
+++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/ShimOptions.h
@@ -89,6 +89,12 @@ class ShimOptions: NonCopyable
return m_fDisallowRotationOnConfigChange;
}
+ std::chrono::milliseconds
+ QueryShutdownDelay() const noexcept
+ {
+ return m_fShutdownDelay;
+ }
+
ShimOptions(const ConfigurationSource &configurationSource);
private:
@@ -104,4 +110,7 @@ class ShimOptions: NonCopyable
bool m_fCleanShadowCopyDirectory;
bool m_fDisallowRotationOnConfigChange;
std::wstring m_strShadowCopyingDirectory;
+ std::chrono::milliseconds m_fShutdownDelay;
+
+ void SetShutdownDelay(const std::wstring& shutdownDelay);
};
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp
index 1da43e14343a..48855946d29a 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp
+++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationmanager.cpp
@@ -143,22 +143,26 @@ APPLICATION_MANAGER::RecycleApplicationFromManager(
}
}
- // If we receive a request at this point.
- // OutOfProcess: we will create a new application with new configuration
- // InProcess: the request would have to be rejected, as we are about to call g_HttpServer->RecycleProcess
- // on the worker process
-
if (!applicationsToRecycle.empty())
{
for (auto& application : applicationsToRecycle)
{
try
{
- application->ShutDownApplication(/* fServerInitiated */ false);
+ if (UseLegacyShutdown())
+ {
+ application->ShutDownApplication(/* fServerInitiated */ false);
+ }
+ else
+ {
+ // Recycle the process to trigger OnGlobalStopListening
+ // which will shutdown the server and stop listening for new requests for this app
+ m_pHttpServer.RecycleProcess(L"AspNetCore InProcess Recycle Process on Demand");
+ }
}
catch (...)
{
- LOG_ERRORF(L"Failed to stop application '%ls'", application->QueryApplicationInfoKey().c_str());
+ LOG_ERRORF(L"Failed to recycle application '%ls'", application->QueryApplicationInfoKey().c_str());
OBSERVE_CAUGHT_EXCEPTION()
// Failed to recycle an application. Log an event
@@ -176,28 +180,31 @@ APPLICATION_MANAGER::RecycleApplicationFromManager(
}
}
- // Remove apps after calling shutdown on each of them
- // This is exclusive to in-process, as the shutdown of an in-process app recycles
- // the entire worker process.
- if (m_handlerResolver.GetHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
+ if (UseLegacyShutdown())
{
- SRWExclusiveLock lock(m_srwLock);
- const std::wstring configurationPath = pszApplicationId;
-
- auto itr = m_pApplicationInfoHash.begin();
- while (itr != m_pApplicationInfoHash.end())
+ // Remove apps after calling shutdown on each of them
+ // This is exclusive to in-process, as the shutdown of an in-process app recycles
+ // the entire worker process.
+ if (m_handlerResolver.GetHostingModel() == APP_HOSTING_MODEL::HOSTING_IN_PROCESS)
{
- if (itr->second != nullptr && itr->second->ConfigurationPathApplies(configurationPath)
- && std::find(applicationsToRecycle.begin(), applicationsToRecycle.end(), itr->second) != applicationsToRecycle.end())
- {
- itr = m_pApplicationInfoHash.erase(itr);
- }
- else
+ SRWExclusiveLock lock(m_srwLock);
+ const std::wstring configurationPath = pszApplicationId;
+
+ auto itr = m_pApplicationInfoHash.begin();
+ while (itr != m_pApplicationInfoHash.end())
{
- ++itr;
+ if (itr->second != nullptr && itr->second->ConfigurationPathApplies(configurationPath)
+ && std::find(applicationsToRecycle.begin(), applicationsToRecycle.end(), itr->second) != applicationsToRecycle.end())
+ {
+ itr = m_pApplicationInfoHash.erase(itr);
+ }
+ else
+ {
+ ++itr;
+ }
}
- }
- } // Release Exclusive m_srwLock
+ } // Release Exclusive m_srwLock
+ }
}
CATCH_RETURN()
@@ -211,14 +218,19 @@ APPLICATION_MANAGER::RecycleApplicationFromManager(
VOID
APPLICATION_MANAGER::ShutDown()
{
+ // During shutdown we lock until we delete the application
+ SRWExclusiveLock lock(m_srwLock);
+
// We are guaranteed to only have one outstanding OnGlobalStopListening event at a time
// However, it is possible to receive multiple OnGlobalStopListening events
// Protect against this by checking if we already shut down.
+ if (g_fInShutdown)
+ {
+ return;
+ }
+
g_fInShutdown = TRUE;
g_fInAppOfflineShutdown = true;
-
- // During shutdown we lock until we delete the application
- SRWExclusiveLock lock(m_srwLock);
for (auto & [str, applicationInfo] : m_pApplicationInfoHash)
{
applicationInfo->ShutDownApplication(/* fServerInitiated */ true);
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationmanager.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationmanager.h
index 2f9f8b84ce5c..efc466dc7ca9 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationmanager.h
+++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/applicationmanager.h
@@ -47,6 +47,16 @@ class APPLICATION_MANAGER
return !m_handlerResolver.GetDisallowRotationOnConfigChange();
}
+ std::chrono::milliseconds GetShutdownDelay() const
+ {
+ return m_handlerResolver.GetShutdownDelay();
+ }
+
+ bool UseLegacyShutdown() const
+ {
+ return m_handlerResolver.GetShutdownDelay() == std::chrono::milliseconds::zero();
+ }
+
private:
std::unordered_map> m_pApplicationInfoHash;
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp
index 1fde8723bd77..4d55e36b80d9 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp
+++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/dllmain.cpp
@@ -125,13 +125,14 @@ HRESULT
moduleFactory.release(),
RQ_EXECUTE_REQUEST_HANDLER,
0));
-;
+
auto pGlobalModule = std::make_unique(std::move(applicationManager));
RETURN_IF_FAILED(pModuleInfo->SetGlobalNotifications(
- pGlobalModule.release(),
- GL_CONFIGURATION_CHANGE | // Configuration change triggers IIS application stop
- GL_STOP_LISTENING)); // worker process stop or recycle
+ pGlobalModule.release(),
+ GL_CONFIGURATION_CHANGE | // Configuration change triggers IIS application stop
+ GL_STOP_LISTENING | // worker process will stop listening for http requests
+ GL_APPLICATION_STOP)); // app pool recycle or stop
return S_OK;
}
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/globalmodule.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/globalmodule.cpp
index 94668ed8a34e..9e69d586cb80 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/globalmodule.cpp
+++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/globalmodule.cpp
@@ -6,7 +6,7 @@
extern BOOL g_fInShutdown;
ASPNET_CORE_GLOBAL_MODULE::ASPNET_CORE_GLOBAL_MODULE(std::shared_ptr pApplicationManager) noexcept
- :m_pApplicationManager(std::move(pApplicationManager))
+ : m_pApplicationManager(std::move(pApplicationManager))
{
}
@@ -16,26 +16,52 @@ ASPNET_CORE_GLOBAL_MODULE::ASPNET_CORE_GLOBAL_MODULE(std::shared_ptrShutDown();
- m_pApplicationManager = nullptr;
+ StartShutdown();
// Return processing to the pipeline.
return GL_NOTIFICATION_CONTINUE;
}
+GLOBAL_NOTIFICATION_STATUS
+ASPNET_CORE_GLOBAL_MODULE::OnGlobalApplicationStop(
+ IN IHttpApplicationStopProvider* pProvider
+)
+{
+ UNREFERENCED_PARAMETER(pProvider);
+
+ // If we're already cleaned up just return.
+ // If user has opted out of the new shutdown behavior ignore this call as we never registered for it before
+ if (!m_pApplicationManager || m_pApplicationManager->UseLegacyShutdown())
+ {
+ return GL_NOTIFICATION_CONTINUE;
+ }
+
+ LOG_INFO(L"ASPNET_CORE_GLOBAL_MODULE::OnGlobalApplicationStop");
+
+ if (!g_fInShutdown && !m_shutdown.joinable())
+ {
+ // Apps with preload + always running that don't receive a request before recycle/shutdown will never call OnGlobalStopListening
+ // IISExpress can also close without calling OnGlobalStopListening which is where we usually would trigger shutdown
+ // so we should make sure to shutdown the server in those cases
+ StartShutdown();
+ }
+
+ return GL_NOTIFICATION_CONTINUE;
+}
+
//
// Is called when configuration changed
// Recycled the corresponding core app if its configuration changed
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/globalmodule.h b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/globalmodule.h
index 80f047e08d74..3bcb30c0b2e8 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/globalmodule.h
+++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/globalmodule.h
@@ -4,6 +4,9 @@
#pragma once
#include "applicationmanager.h"
+#include
+
+extern BOOL g_fInShutdown;
class ASPNET_CORE_GLOBAL_MODULE : NonCopyable, public CGlobalModule
{
@@ -19,6 +22,12 @@ class ASPNET_CORE_GLOBAL_MODULE : NonCopyable, public CGlobalModule
VOID Terminate() override
{
LOG_INFO(L"ASPNET_CORE_GLOBAL_MODULE::Terminate");
+
+ if (m_shutdown.joinable())
+ {
+ m_shutdown.join();
+ }
+
// Remove the class from memory.
delete this;
}
@@ -33,6 +42,48 @@ class ASPNET_CORE_GLOBAL_MODULE : NonCopyable, public CGlobalModule
_In_ IGlobalConfigurationChangeProvider * pProvider
) override;
+ GLOBAL_NOTIFICATION_STATUS
+ OnGlobalApplicationStop(
+ IN IHttpApplicationStopProvider* pProvider
+ ) override;
+
private:
std::shared_ptr m_pApplicationManager;
+ std::thread m_shutdown;
+
+ void StartShutdown()
+ {
+ // Shutdown has already been started/finished
+ if (m_shutdown.joinable() || g_fInShutdown)
+ {
+ return;
+ }
+
+ // If delay is zero we can go back to the old behavior of calling shutdown inline
+ // this is primarily so that we have a way for users to revert the new behavior if there are issues with it
+ if (m_pApplicationManager->UseLegacyShutdown())
+ {
+ LOG_INFO(L"Shutdown starting.");
+ m_pApplicationManager->ShutDown();
+ m_pApplicationManager = nullptr;
+ }
+ else
+ {
+ // Run shutdown on a background thread. It seems like IIS keeps giving us requests if OnGlobalStopListening is still running
+ // which will result in 503s from applicationmanager since we're shutting down and don't want to process new requests.
+ // But if we return ASAP from OnGlobalStopListening, by not shutting down inline and with a small delay to reduce races,
+ // IIS will actually stop giving us new requests and queue them instead for processing by the new app process.
+ m_shutdown = std::thread([this]()
+ {
+ auto delay = m_pApplicationManager->GetShutdownDelay();
+ LOG_INFOF(L"Shutdown starting in %d ms.", delay.count());
+ // Delay so that any incoming requests while we're returning from OnGlobalStopListening are allowed to be processed
+ std::this_thread::sleep_for(delay);
+
+ LOG_INFO(L"Shutdown starting.");
+ m_pApplicationManager->ShutDown();
+ m_pApplicationManager = nullptr;
+ });
+ }
+ }
};
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/proxymodule.cpp b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/proxymodule.cpp
index 162c0fea907b..99dd210b3dd1 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/proxymodule.cpp
+++ b/src/Servers/IIS/AspNetCoreModuleV2/AspNetCore/proxymodule.cpp
@@ -93,6 +93,7 @@ ASPNET_CORE_PROXY_MODULE::OnExecuteRequestHandler(
{
if (g_fInShutdown)
{
+ LOG_WARN(L"Received a request during shutdown. Will return a 503 response.");
FINISHED(HRESULT_FROM_WIN32(ERROR_SERVER_SHUTDOWN_IN_PROGRESS));
}
diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessApplicationBase.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessApplicationBase.cpp
index b876d6dc2656..5282792f1e6f 100644
--- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessApplicationBase.cpp
+++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/InProcessApplicationBase.cpp
@@ -17,38 +17,40 @@ InProcessApplicationBase::StopInternal(bool fServerInitiated)
{
AppOfflineTrackingApplication::StopInternal(fServerInitiated);
- // Stop was initiated by server no need to do anything, server would stop on it's own
- if (fServerInitiated)
+ // Ignore fServerInitiated for IISExpress
+ // Recycle doesn't do anything in IISExpress, we need to explicitly shutdown
+ if (m_pHttpServer.IsCommandLineLaunch())
{
+ // Send WM_QUIT to the main window to initiate graceful shutdown
+ EnumWindows([](HWND hwnd, LPARAM) -> BOOL
+ {
+ DWORD processId;
+
+ if (GetWindowThreadProcessId(hwnd, &processId) &&
+ processId == GetCurrentProcessId() &&
+ GetConsoleWindow() != hwnd)
+ {
+ PostMessage(hwnd, WM_QUIT, 0, 0);
+ return false;
+ }
+
+ return true;
+ }, 0);
+
return;
}
- if (!m_pHttpServer.IsCommandLineLaunch())
+ // Stop was initiated by server no need to do anything, server would stop on its own
+ if (fServerInitiated)
{
- // IIS scenario.
- // We don't actually handle any shutdown logic here.
- // Instead, we notify IIS that the process needs to be recycled, which will call
- // ApplicationManager->Shutdown(). This will call shutdown on the application.
- LOG_INFO(L"AspNetCore InProcess Recycle Process on Demand");
- m_pHttpServer.RecycleProcess(L"AspNetCore InProcess Recycle Process on Demand");
+ return;
}
- else
- {
- // Send WM_QUIT to the main window to initiate graceful shutdown
- EnumWindows([](HWND hwnd, LPARAM) -> BOOL
- {
- DWORD processId;
- if (GetWindowThreadProcessId(hwnd, &processId) &&
- processId == GetCurrentProcessId() &&
- GetConsoleWindow() != hwnd)
- {
- PostMessage(hwnd, WM_QUIT, 0, 0);
- return false;
- }
-
- return true;
- }, 0);
- }
+ // IIS scenario.
+ // We don't actually handle any shutdown logic here.
+ // Instead, we notify IIS that the process needs to be recycled, which will call
+ // ApplicationManager->Shutdown(). This will call shutdown on the application.
+ LOG_INFO(L"AspNetCore InProcess Recycle Process on Demand");
+ m_pHttpServer.RecycleProcess(L"AspNetCore InProcess Recycle Process on Demand");
}
diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/EventLogHelpers.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/EventLogHelpers.cs
index 857c87721bb1..9e08448d969b 100644
--- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/EventLogHelpers.cs
+++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/EventLogHelpers.cs
@@ -79,7 +79,7 @@ private static string FormatEntries(IEnumerable entries)
return string.Join(",", entries.Select(e => e.Message));
}
- private static IEnumerable GetEntries(IISDeploymentResult deploymentResult)
+ internal static IEnumerable GetEntries(IISDeploymentResult deploymentResult)
{
var eventLog = new EventLog("Application");
@@ -162,9 +162,16 @@ public static string InProcessFailedToStart(IISDeploymentResult deploymentResult
}
}
- public static string InProcessShutdown()
+ public static string ShutdownMessage(IISDeploymentResult deploymentResult)
{
- return "Application 'MACHINE/WEBROOT/APPHOST/.*?' has shutdown.";
+ if (deploymentResult.DeploymentParameters.HostingModel == HostingModel.InProcess)
+ {
+ return "Application 'MACHINE/WEBROOT/APPHOST/.*?' has shutdown.";
+ }
+ else
+ {
+ return "Application '/LM/W3SVC/1/ROOT' with physical root '.*?' shut down process with Id '.*?' listening on port '.*?'";
+ }
}
public static string ShutdownFileChange(IISDeploymentResult deploymentResult)
diff --git a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/Helpers.cs b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/Helpers.cs
index 0b8c5bbeff58..74f499ce488e 100644
--- a/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/Helpers.cs
+++ b/src/Servers/IIS/IIS/test/Common.FunctionalTests/Infrastructure/Helpers.cs
@@ -8,6 +8,7 @@
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.Extensions.Logging;
+using Microsoft.Web.Administration;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests;
@@ -179,6 +180,15 @@ public static async Task AssertRecycledAsync(this IISDeploymentResult deployment
}
}
+ // Don't use with IISExpress, recycle isn't a valid operation
+ public static void Recycle(string appPoolName)
+ {
+ using var serverManager = new ServerManager();
+ var appPool = serverManager.ApplicationPools.FirstOrDefault(ap => ap.Name == appPoolName);
+ Assert.NotNull(appPool);
+ appPool.Recycle();
+ }
+
public static IEnumerable