diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 968d655e3e6..0d7cd4c7f03 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"microsoft.dotnet.darc": {
- "version": "1.1.0-beta.25367.1",
+ "version": "1.1.0-beta.25374.1",
"commands": [
"darc"
]
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index eee49d9b303..5d3f77c3cfe 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -10,9 +10,9 @@
https://github.com/dotnet/dotnet
67889d9d2f21a890ac29bcd175c0d1937a401781
-
+
https://github.com/dotnet/arcade-services
- 448a29d2d2e4e27303f728202602708ed45838f5
+ e5296d002b0c674b8cc023e06fe3b0a3d9392273
diff --git a/src/arcade/eng/common/core-templates/jobs/jobs.yml b/src/arcade/eng/common/core-templates/jobs/jobs.yml
index bf35b78faa6..2f992b2c6ec 100644
--- a/src/arcade/eng/common/core-templates/jobs/jobs.yml
+++ b/src/arcade/eng/common/core-templates/jobs/jobs.yml
@@ -83,7 +83,6 @@ jobs:
- template: /eng/common/core-templates/jobs/source-build.yml
parameters:
is1ESPipeline: ${{ parameters.is1ESPipeline }}
- allCompletedJobId: Source_Build_Complete
${{ each parameter in parameters.sourceBuildParameters }}:
${{ parameter.key }}: ${{ parameter.value }}
@@ -108,8 +107,6 @@ jobs:
- ${{ if eq(parameters.publishBuildAssetsDependsOn, '') }}:
- ${{ each job in parameters.jobs }}:
- ${{ job.job }}
- - ${{ if eq(parameters.enableSourceBuild, true) }}:
- - Source_Build_Complete
runAsPublic: ${{ parameters.runAsPublic }}
publishAssetsImmediately: ${{ or(parameters.publishAssetsImmediately, parameters.isAssetlessBuild) }}
diff --git a/src/arcade/eng/common/core-templates/jobs/source-build.yml b/src/arcade/eng/common/core-templates/jobs/source-build.yml
index df24c948ba1..d92860cba20 100644
--- a/src/arcade/eng/common/core-templates/jobs/source-build.yml
+++ b/src/arcade/eng/common/core-templates/jobs/source-build.yml
@@ -2,12 +2,6 @@ parameters:
# This template adds arcade-powered source-build to CI. A job is created for each platform, as
# well as an optional server job that completes when all platform jobs complete.
- # The name of the "join" job for all source-build platforms. If set to empty string, the job is
- # not included. Existing repo pipelines can use this job depend on all source-build jobs
- # completing without maintaining a separate list of every single job ID: just depend on this one
- # server job. By default, not included. Recommended name if used: 'Source_Build_Complete'.
- allCompletedJobId: ''
-
# See /eng/common/core-templates/job/source-build.yml
jobNamePrefix: 'Source_Build'
@@ -31,16 +25,6 @@ parameters:
jobs:
-- ${{ if ne(parameters.allCompletedJobId, '') }}:
- - job: ${{ parameters.allCompletedJobId }}
- displayName: Source-Build Complete
- pool: server
- dependsOn:
- - ${{ each platform in parameters.platforms }}:
- - ${{ parameters.jobNamePrefix }}_${{ platform.name }}
- - ${{ if eq(length(parameters.platforms), 0) }}:
- - ${{ parameters.jobNamePrefix }}_${{ parameters.defaultManagedPlatform.name }}
-
- ${{ each platform in parameters.platforms }}:
- template: /eng/common/core-templates/job/source-build.yml
parameters:
diff --git a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Microsoft.Testing.Platform/Microsoft.Testing.Platform.targets b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Microsoft.Testing.Platform/Microsoft.Testing.Platform.targets
index 36a79347618..9ffc61e4992 100644
--- a/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Microsoft.Testing.Platform/Microsoft.Testing.Platform.targets
+++ b/src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Microsoft.Testing.Platform/Microsoft.Testing.Platform.targets
@@ -6,13 +6,15 @@
<_TestEnvironment>%(TestToRun.EnvironmentDisplay)
<_TestAssembly>%(TestToRun.Identity)
<_TestRunner>%(TestToRun.RunCommand)
+ <_RunArguments>%(TestToRun.RunArguments)
<_TestRuntime>%(TestToRun.TestRuntime)
<_TestTimeout>%(TestToRun.TestTimeout)
- <_TestRunnerAdditionalArguments>$(TestToRun.RunArguments) %(TestToRun.TestRunnerAdditionalArguments)
+ <_TestRunnerAdditionalArguments>%(TestToRun.TestRunnerAdditionalArguments)
+ <_TestRunnerAdditionalArguments>$(_RunArguments) $(_TestRunnerAdditionalArguments)
<_TestResultDirectory>$([System.IO.Path]::GetDirectoryName('%(TestToRun.ResultsTrxPath)'))
<_TestResultTrxFileName>$([System.IO.Path]::GetFileName('%(TestToRun.ResultsTrxPath)'))
- <_TestRunnerArgs>"$(_TestRunner)" $(_TestRunnerAdditionalArguments) --no-progress --report-trx --report-trx-filename "$(_TestResultTrxFileName)" --results-directory "$(_TestResultDirectory)"
+ <_TestRunnerArgs>$(_TestRunnerAdditionalArguments) --no-progress --report-trx --report-trx-filename "$(_TestResultTrxFileName)" --results-directory "$(_TestResultDirectory)"
diff --git a/src/arcade/src/Microsoft.DotNet.Build.Tasks.Feed/src/PublishBuildToMaestro.cs b/src/arcade/src/Microsoft.DotNet.Build.Tasks.Feed/src/PublishBuildToMaestro.cs
index 96578508bb7..a33f4ab1037 100644
--- a/src/arcade/src/Microsoft.DotNet.Build.Tasks.Feed/src/PublishBuildToMaestro.cs
+++ b/src/arcade/src/Microsoft.DotNet.Build.Tasks.Feed/src/PublishBuildToMaestro.cs
@@ -546,8 +546,32 @@ private void LookupForMatchingGitHubRepository(BuildIdentity buildIdentity)
client.BaseAddress = new Uri($"https://api.{gitHubHost}");
client.DefaultRequestHeaders.Add("User-Agent", "PushToBarTask");
- HttpResponseMessage response =
- client.GetAsync($"/repos/{repoIdentity}/commits/{buildIdentity.Commit}").Result;
+ string url = $"/repos/{repoIdentity}/commits/{buildIdentity.Commit}";
+ HttpResponseMessage response = client.GetAsync(url).Result;
+
+ const int MaxRetries = 5;
+ for (int retry = 1; retry <= MaxRetries && response.StatusCode == System.Net.HttpStatusCode.TooManyRequests; retry++)
+ {
+ TimeSpan timeSpan;
+ if (response.Headers.RetryAfter?.Delta != null)
+ {
+ timeSpan = response.Headers.RetryAfter.Delta.Value;
+ }
+ else if (response.Headers.RetryAfter?.Date != null)
+ {
+ timeSpan = response.Headers.RetryAfter.Date.Value - DateTimeOffset.UtcNow;
+ }
+ else
+ {
+ const int defaultRetryAfterSeconds = 10;
+ timeSpan = TimeSpan.FromSeconds(defaultRetryAfterSeconds);
+ }
+
+ Log.LogMessage(MessageImportance.High,
+ $"API rate limit exceeded, retrying in {timeSpan.TotalSeconds} seconds. Retry attempt: {retry}");
+ Thread.Sleep(timeSpan);
+ response = client.GetAsync(url).Result;
+ }
if (response.IsSuccessStatusCode)
{
diff --git a/src/aspnetcore/.editorconfig b/src/aspnetcore/.editorconfig
index 45ead881a43..bff8c6c606a 100644
--- a/src/aspnetcore/.editorconfig
+++ b/src/aspnetcore/.editorconfig
@@ -464,12 +464,6 @@ dotnet_diagnostic.IDE0161.severity = silent
# IDE0005: Remove unused usings. Ignore for shared src files since imports for those depend on the projects in which they are included.
dotnet_diagnostic.IDE0005.severity = silent
-[{**/microsoft.dotnet.hotreload.agent*/**.cs}]
-# IDE0005: Remove unused usings. Ignore for shared src files coming from nuget package.
-dotnet_diagnostic.IDE0005.severity = silent
-# IDE0073: A source file is missing a required header. Ignore for shared src files coming from nuget package.
-dotnet_diagnostic.IDE0073.severity = silent
-
# Verify settings
[*.{received,verified}.{txt,xml,json}]
diff --git a/src/aspnetcore/.github/workflows/browsertesting-issue-body.md b/src/aspnetcore/.github/workflows/browsertesting-issue-body.md
index eb3780f32a8..6555c38eb7d 100644
--- a/src/aspnetcore/.github/workflows/browsertesting-issue-body.md
+++ b/src/aspnetcore/.github/workflows/browsertesting-issue-body.md
@@ -18,4 +18,7 @@ To update the Selenium and Playwright versions, these files need to be updated:
## Actions
Please, open the PR against `main` branch and include changes to the files listed above.
-Also mention @dotnet/aspnet-build in the opened Pull Request - this will be a responsible engineer for changes validation.
+
+Also:
+- mention @dotnet/aspnet-build in the opened Pull Request - this will be a responsible engineer for changes validation.
+- add the `build-ops` label to the opened Pull Request
diff --git a/src/aspnetcore/eng/Dependencies.props b/src/aspnetcore/eng/Dependencies.props
index 564d8e2c461..d41269c9613 100644
--- a/src/aspnetcore/eng/Dependencies.props
+++ b/src/aspnetcore/eng/Dependencies.props
@@ -25,8 +25,6 @@ and are generated based on the last package release.
-
-
diff --git a/src/aspnetcore/eng/Version.Details.xml b/src/aspnetcore/eng/Version.Details.xml
index 646a3fd7ce3..a96281cad42 100644
--- a/src/aspnetcore/eng/Version.Details.xml
+++ b/src/aspnetcore/eng/Version.Details.xml
@@ -8,341 +8,333 @@
See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md for instructions on using darc.
-->
-
+
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
-
-
- https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
-
-
- https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
@@ -366,37 +358,37 @@
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
https://github.com/dotnet/extensions
diff --git a/src/aspnetcore/eng/Versions.props b/src/aspnetcore/eng/Versions.props
index ab3af5beb2e..fc762f1006d 100644
--- a/src/aspnetcore/eng/Versions.props
+++ b/src/aspnetcore/eng/Versions.props
@@ -67,104 +67,101 @@
-->
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
9.8.0-preview.1.25369.1
9.8.0-preview.1.25369.1
9.8.0-preview.1.25369.1
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
-
- 10.0.100-preview.7.25372.103
- 10.0.100-preview.7.25372.103
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
- 10.0.0-beta.25372.103
- 10.0.0-beta.25372.103
- 10.0.0-beta.25372.103
- 10.0.0-beta.25372.103
+ 10.0.0-beta.25373.104
+ 10.0.0-beta.25373.104
+ 10.0.0-beta.25373.104
+ 10.0.0-beta.25373.104
- 3.2.0-preview.25372.103
+ 3.2.0-preview.25373.104
1.0.0-prerelease.25364.1
1.0.0-prerelease.25364.1
diff --git a/src/aspnetcore/global.json b/src/aspnetcore/global.json
index 3afb76cdfac..10a1e748cf1 100644
--- a/src/aspnetcore/global.json
+++ b/src/aspnetcore/global.json
@@ -27,9 +27,9 @@
"jdk": "latest"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25372.103",
- "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25372.103",
- "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25372.103",
+ "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25373.104",
+ "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25373.104",
+ "Microsoft.DotNet.SharedFramework.Sdk": "10.0.0-beta.25373.104",
"Microsoft.Build.NoTargets": "3.7.0",
"Microsoft.Build.Traversal": "3.4.0"
}
diff --git a/src/aspnetcore/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj b/src/aspnetcore/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
index 957925b0327..f0418fd1035 100644
--- a/src/aspnetcore/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
+++ b/src/aspnetcore/src/Components/WebAssembly/WebAssembly/src/Microsoft.AspNetCore.Components.WebAssembly.csproj
@@ -21,8 +21,6 @@
-
-
diff --git a/src/aspnetcore/src/Grpc/JsonTranscoding/src/Microsoft.AspNetCore.Grpc.JsonTranscoding/Internal/Json/MessageTypeInfoResolver.cs b/src/aspnetcore/src/Grpc/JsonTranscoding/src/Microsoft.AspNetCore.Grpc.JsonTranscoding/Internal/Json/MessageTypeInfoResolver.cs
index 66e249194e0..12d188d19df 100644
--- a/src/aspnetcore/src/Grpc/JsonTranscoding/src/Microsoft.AspNetCore.Grpc.JsonTranscoding/Internal/Json/MessageTypeInfoResolver.cs
+++ b/src/aspnetcore/src/Grpc/JsonTranscoding/src/Microsoft.AspNetCore.Grpc.JsonTranscoding/Internal/Json/MessageTypeInfoResolver.cs
@@ -1,7 +1,6 @@
// 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;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
@@ -94,6 +93,23 @@ private JsonPropertyInfo CreatePropertyInfo(JsonTypeInfo typeInfo, string name,
JsonConverterHelper.GetFieldType(field),
name);
+ // A property with a wrapper type is usually the underlying type on the DTO.
+ // For example, a field of type google.protobuf.StringValue will have a property of type string.
+ // However, the wrapper type is exposed if someone manually creates a DTO with it, or there is a problem
+ // detecting wrapper type in code generation. For example, https://github.com/protocolbuffers/protobuf/issues/22744
+ FieldDescriptor? wrapperTypeValueField = null;
+ if (field.FieldType == FieldType.Message && ServiceDescriptorHelpers.IsWrapperType(field.MessageType))
+ {
+ var property = field.ContainingType.ClrType.GetProperty(field.PropertyName);
+
+ // Check if the property type is the same as the field type. This means the property is StringValue, et al,
+ // and additional conversion is required.
+ if (property != null && property.PropertyType == field.MessageType.ClrType)
+ {
+ wrapperTypeValueField = field.MessageType.FindFieldByName("value");
+ }
+ }
+
propertyInfo.ShouldSerialize = (o, v) =>
{
// Properties that don't have this flag set are only used to deserialize incoming JSON.
@@ -105,7 +121,13 @@ private JsonPropertyInfo CreatePropertyInfo(JsonTypeInfo typeInfo, string name,
};
propertyInfo.Get = (o) =>
{
- return field.Accessor.GetValue((IMessage)o);
+ var value = field.Accessor.GetValue((IMessage)o);
+ if (wrapperTypeValueField != null && value is IMessage wrapperMessage)
+ {
+ return wrapperTypeValueField.Accessor.GetValue(wrapperMessage);
+ }
+
+ return value;
};
if (field.IsMap || field.IsRepeated)
@@ -115,13 +137,13 @@ private JsonPropertyInfo CreatePropertyInfo(JsonTypeInfo typeInfo, string name,
}
else
{
- propertyInfo.Set = GetSetMethod(field);
+ propertyInfo.Set = GetSetMethod(field, wrapperTypeValueField);
}
return propertyInfo;
}
- private static Action
-
@@ -61,5 +60,6 @@ Microsoft.AspNetCore.Http.HttpResponse
+
diff --git a/src/aspnetcore/src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt b/src/aspnetcore/src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt
index 3a2461306d5..2944a853cdf 100644
--- a/src/aspnetcore/src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt
+++ b/src/aspnetcore/src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt
@@ -1,4 +1,5 @@
#nullable enable
+Microsoft.AspNetCore.Http.Metadata.IApiEndpointMetadata
Microsoft.AspNetCore.Http.Metadata.IDisableValidationMetadata
Microsoft.AspNetCore.Http.ProducesResponseTypeMetadata.Description.get -> string?
Microsoft.AspNetCore.Http.ProducesResponseTypeMetadata.Description.set -> void
diff --git a/src/aspnetcore/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGenerator.cs b/src/aspnetcore/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGenerator.cs
index f4e2ad0e8e3..f5e2abacaaf 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGenerator.cs
+++ b/src/aspnetcore/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGenerator.cs
@@ -248,7 +248,12 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
if (hasFormBody)
{
- codeWriter.WriteLine(RequestDelegateGeneratorSources.AntiforgeryMetadataType);
+ codeWriter.WriteLine(RequestDelegateGeneratorSources.AntiforgeryMetadataClass);
+ }
+
+ if (hasJsonBody || hasResponseMetadata)
+ {
+ codeWriter.WriteLine(RequestDelegateGeneratorSources.ApiEndpointMetadataClass);
}
if (hasFormBody || hasJsonBody || hasResponseMetadata)
diff --git a/src/aspnetcore/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGeneratorSources.cs b/src/aspnetcore/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGeneratorSources.cs
index d7c7a480446..b626db27412 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGeneratorSources.cs
+++ b/src/aspnetcore/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGeneratorSources.cs
@@ -479,19 +479,39 @@ internal ParameterBindingMetadata(
}
""";
- public static string AntiforgeryMetadataType = """
-file sealed class AntiforgeryMetadata : IAntiforgeryMetadata
-{
- public static readonly IAntiforgeryMetadata ValidationRequired = new AntiforgeryMetadata(true);
-
- public AntiforgeryMetadata(bool requiresValidation)
+ public static string AntiforgeryMetadataClass = """
+ file sealed class AntiforgeryMetadata : IAntiforgeryMetadata
{
- RequiresValidation = requiresValidation;
+ public static readonly IAntiforgeryMetadata ValidationRequired = new AntiforgeryMetadata(true);
+
+ public AntiforgeryMetadata(bool requiresValidation)
+ {
+ RequiresValidation = requiresValidation;
+ }
+
+ public bool RequiresValidation { get; }
}
+""";
- public bool RequiresValidation { get; }
-}
+ public static string ApiEndpointMetadataClass = """
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
""";
+
public static string GetGeneratedRouteBuilderExtensionsSource(string endpoints, string helperMethods, string helperTypes, ImmutableHashSet verbs) => $$"""
{{SourceHeader}}
diff --git a/src/aspnetcore/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs b/src/aspnetcore/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs
index 83790d44eb3..97fe2dc990f 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs
+++ b/src/aspnetcore/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs
@@ -205,7 +205,7 @@ private static void EmitBuiltinResponseTypeMetadata(this Endpoint endpoint, Code
return;
}
- if (!endpoint.Response.IsAwaitable && (response.HasNoResponse || response.IsIResult))
+ if (response.HasNoResponse || response.IsIResult)
{
return;
}
@@ -215,13 +215,10 @@ private static void EmitBuiltinResponseTypeMetadata(this Endpoint endpoint, Code
{
codeWriter.WriteLine($"options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(string), contentTypes: GeneratedMetadataConstants.PlaintextContentType));");
}
- else if (response.IsAwaitable && response.ResponseType == null)
- {
- codeWriter.WriteLine($"options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(void), contentTypes: GeneratedMetadataConstants.PlaintextContentType));");
- }
else if (response.ResponseType is { } responseType)
{
codeWriter.WriteLine($$"""options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof({{responseType.ToDisplayString(EmitterConstants.DisplayFormatWithoutNullability)}}), contentTypes: GeneratedMetadataConstants.JsonContentType));""");
+ codeWriter.WriteLine("ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);");
}
}
@@ -339,13 +336,15 @@ public static void EmitJsonAcceptsMetadata(this Endpoint endpoint, CodeWriter co
codeWriter.WriteLine("if (!serviceProviderIsService.IsService(type))");
codeWriter.StartBlock();
codeWriter.WriteLine("options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));");
+ codeWriter.WriteLine("options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);");
codeWriter.WriteLine("break;");
codeWriter.EndBlock();
codeWriter.EndBlock();
}
else
{
- codeWriter.WriteLine($"options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(contentTypes: GeneratedMetadataConstants.JsonContentType));");
+ codeWriter.WriteLine("options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(contentTypes: GeneratedMetadataConstants.JsonContentType));");
+ codeWriter.WriteLine("options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);");
}
}
diff --git a/src/aspnetcore/src/Http/Http.Extensions/src/RequestDelegateFactory.cs b/src/aspnetcore/src/Http/Http.Extensions/src/RequestDelegateFactory.cs
index 19965ef1fc3..aaebe417980 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/src/RequestDelegateFactory.cs
+++ b/src/aspnetcore/src/Http/Http.Extensions/src/RequestDelegateFactory.cs
@@ -401,7 +401,14 @@ private static Expression[] CreateArgumentsAndInferMetadata(MethodInfo methodInf
InferAntiforgeryMetadata(factoryContext);
}
- PopulateBuiltInResponseTypeMetadata(methodInfo.ReturnType, factoryContext.EndpointBuilder);
+ // If this endpoint expects a JSON request body, we assume its an API endpoint not intended for browser navigation.
+ // When present, authentication handlers should prefer returning status codes over browser redirects.
+ if (factoryContext.JsonRequestBodyParameter is not null)
+ {
+ factoryContext.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
+ }
+
+ PopulateBuiltInResponseTypeMetadata(methodInfo.ReturnType, factoryContext);
// Add metadata provided by the delegate return type and parameter types next, this will be more specific than inferred metadata from above
EndpointMetadataPopulator.PopulateMetadata(methodInfo, factoryContext.EndpointBuilder, factoryContext.Parameters);
@@ -1023,37 +1030,40 @@ private static Expression CreateParamCheckingResponseWritingMethodCall(Type retu
return Expression.Block(localVariables, checkParamAndCallMethod);
}
- private static void PopulateBuiltInResponseTypeMetadata(Type returnType, EndpointBuilder builder)
+ private static void PopulateBuiltInResponseTypeMetadata(Type returnType, RequestDelegateFactoryContext factoryContext)
{
if (returnType.IsByRefLike)
{
throw GetUnsupportedReturnTypeException(returnType);
}
- var isAwaitable = false;
if (CoercedAwaitableInfo.IsTypeAwaitable(returnType, out var coercedAwaitableInfo))
{
returnType = coercedAwaitableInfo.AwaitableInfo.ResultType;
- isAwaitable = true;
}
// Skip void returns and IResults. IResults might implement IEndpointMetadataProvider but otherwise we don't know what it might do.
- if (!isAwaitable && (returnType == typeof(void) || typeof(IResult).IsAssignableFrom(returnType)))
+ if (returnType == typeof(void) || typeof(IResult).IsAssignableFrom(returnType))
{
return;
}
+ var builder = factoryContext.EndpointBuilder;
+
if (returnType == typeof(string))
{
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(type: typeof(string), statusCode: 200, PlaintextContentType));
}
- else if (returnType == typeof(void))
- {
- builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(returnType, statusCode: 200, PlaintextContentType));
- }
else
{
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(returnType, statusCode: 200, DefaultAcceptsAndProducesContentType));
+
+ if (factoryContext.JsonRequestBodyParameter is null)
+ {
+ // Since this endpoint responds with JSON, we assume its an API endpoint not intended for browser navigation,
+ // but we don't want to bother adding this metadata twice if we've already inferred it based on the expected JSON request body.
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
+ }
}
}
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs
index 083da9bd7ae..7cee04fb8a0 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateFactoryTests.cs
@@ -2533,7 +2533,7 @@ public void Create_AddJsonResponseType_AsMetadata()
var @delegate = () => new object();
var result = RequestDelegateFactory.Create(@delegate);
- var responseMetadata = Assert.IsAssignableFrom(Assert.Single(result.EndpointMetadata));
+ var responseMetadata = Assert.Single(result.EndpointMetadata.OfType());
Assert.Equal("application/json", Assert.Single(responseMetadata.ContentTypes));
Assert.Equal(typeof(object), responseMetadata.Type);
@@ -2545,7 +2545,7 @@ public void Create_AddPlaintextResponseType_AsMetadata()
var @delegate = () => "Hello";
var result = RequestDelegateFactory.Create(@delegate);
- var responseMetadata = Assert.IsAssignableFrom(Assert.Single(result.EndpointMetadata));
+ var responseMetadata = Assert.Single(result.EndpointMetadata.OfType());
Assert.Equal("text/plain", Assert.Single(responseMetadata.ContentTypes));
Assert.Equal(typeof(string), responseMetadata.Type);
@@ -2683,6 +2683,7 @@ public void Create_CombinesDefaultMetadata_AndMetadataFromReturnTypesImplementin
// Assert
Assert.Contains(result.EndpointMetadata, m => m is CustomEndpointMetadata { Source: MetadataSource.Caller });
+ Assert.DoesNotContain(result.EndpointMetadata, m => m is IProducesResponseTypeMetadata);
// Expecting '1' because only initial metadata will be in the metadata list when this metadata item is added
Assert.Contains(result.EndpointMetadata, m => m is MetadataCountMetadata { Count: 1 });
}
@@ -2705,9 +2706,9 @@ public void Create_CombinesDefaultMetadata_AndMetadataFromTaskWrappedReturnTypes
// Assert
Assert.Contains(result.EndpointMetadata, m => m is CustomEndpointMetadata { Source: MetadataSource.Caller });
- Assert.Contains(result.EndpointMetadata, m => m is ProducesResponseTypeMetadata { Type: { } type } && type == typeof(CountsDefaultEndpointMetadataResult));
- // Expecting the custom metadata and the implicit metadata associated with a Task-based return type to be inserted
- Assert.Contains(result.EndpointMetadata, m => m is MetadataCountMetadata { Count: 2 });
+ Assert.DoesNotContain(result.EndpointMetadata, m => m is IProducesResponseTypeMetadata);
+ // Expecting '1' because only initial metadata will be in the metadata list when this metadata item is added
+ Assert.Contains(result.EndpointMetadata, m => m is MetadataCountMetadata { Count: 1 });
}
[Fact]
@@ -2728,9 +2729,9 @@ public void Create_CombinesDefaultMetadata_AndMetadataFromValueTaskWrappedReturn
// Assert
Assert.Contains(result.EndpointMetadata, m => m is CustomEndpointMetadata { Source: MetadataSource.Caller });
- Assert.Contains(result.EndpointMetadata, m => m is ProducesResponseTypeMetadata { Type: { } type } && type == typeof(CountsDefaultEndpointMetadataResult));
- // Expecting the custom metadata nad hte implicit metadata associated with a Task-based return type to be inserted
- Assert.Contains(result.EndpointMetadata, m => m is MetadataCountMetadata { Count: 2 });
+ Assert.DoesNotContain(result.EndpointMetadata, m => m is IProducesResponseTypeMetadata);
+ // Expecting '1' because only initial metadata will be in the metadata list when this metadata item is added
+ Assert.Contains(result.EndpointMetadata, m => m is MetadataCountMetadata { Count: 1 });
}
[Fact]
@@ -2751,9 +2752,9 @@ public void Create_CombinesDefaultMetadata_AndMetadataFromFSharpAsyncWrappedRetu
// Assert
Assert.Contains(result.EndpointMetadata, m => m is CustomEndpointMetadata { Source: MetadataSource.Caller });
- Assert.Contains(result.EndpointMetadata, m => m is IProducesResponseTypeMetadata { Type: { } type } && type == typeof(CountsDefaultEndpointMetadataResult));
+ Assert.DoesNotContain(result.EndpointMetadata, m => m is IProducesResponseTypeMetadata);
// Expecting '1' because only initial metadata will be in the metadata list when this metadata item is added
- Assert.Contains(result.EndpointMetadata, m => m is MetadataCountMetadata { Count: 2 });
+ Assert.Contains(result.EndpointMetadata, m => m is MetadataCountMetadata { Count: 1 });
}
[Fact]
@@ -2824,14 +2825,16 @@ public void Create_CombinesAllMetadata_InCorrectOrder()
m => Assert.True(m is AcceptsMetadata am && am.RequestType == typeof(AddsCustomParameterMetadata)),
// Inferred ParameterBinding metadata
m => Assert.True(m is IParameterBindingMetadata { Name: "param1" }),
- // Inferred ProducesResopnseTypeMetadata from RDF for complex type
+ // Inferred IApiEndpointMetadata from RDF for complex request and response type
+ m => Assert.True(m is IApiEndpointMetadata),
+ // Inferred ProducesResponseTypeMetadata from RDF for complex type
m => Assert.Equal(typeof(CountsDefaultEndpointMetadataPoco), ((IProducesResponseTypeMetadata)m).Type),
// Metadata provided by parameters implementing IEndpointParameterMetadataProvider
m => Assert.True(m is ParameterNameMetadata { Name: "param1" }),
// Metadata provided by parameters implementing IEndpointMetadataProvider
m => Assert.True(m is CustomEndpointMetadata { Source: MetadataSource.Parameter }),
// Metadata provided by return type implementing IEndpointMetadataProvider
- m => Assert.True(m is MetadataCountMetadata { Count: 6 }));
+ m => Assert.True(m is MetadataCountMetadata { Count: 7 }));
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/HandlesEndpointsWithAndWithoutDiagnostics.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/HandlesEndpointsWithAndWithoutDiagnostics.generated.txt
index ae38db99890..18cf2ce8010 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/HandlesEndpointsWithAndWithoutDiagnostics.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/HandlesEndpointsWithAndWithoutDiagnostics.generated.txt
@@ -225,6 +225,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_BindAsync_NullableReturn.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_BindAsync_NullableReturn.generated.txt
index ddfeaf60467..04b1dc6c3bb 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_BindAsync_NullableReturn.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_BindAsync_NullableReturn.generated.txt
@@ -363,6 +363,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_BindAsync_Snapshot.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_BindAsync_Snapshot.generated.txt
index ab79dddfdc1..6c1240e6b8f 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_BindAsync_Snapshot.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_BindAsync_Snapshot.generated.txt
@@ -2225,6 +2225,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitBodyParam_ComplexReturn_Snapshot.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitBodyParam_ComplexReturn_Snapshot.generated.txt
index 28e8316f4a7..830c81d1309 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitBodyParam_ComplexReturn_Snapshot.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitBodyParam_ComplexReturn_Snapshot.generated.txt
@@ -412,6 +412,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitHeader_ComplexTypeArrayParam.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitHeader_ComplexTypeArrayParam.generated.txt
index 3a8e7fe8928..bd0ceac2524 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitHeader_ComplexTypeArrayParam.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitHeader_ComplexTypeArrayParam.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: true, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -259,6 +260,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitHeader_NullableStringArrayParam.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitHeader_NullableStringArrayParam.generated.txt
index 6365d1485f4..e2c866e2c2b 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitHeader_NullableStringArrayParam.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitHeader_NullableStringArrayParam.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -231,6 +232,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitHeader_StringArrayParam.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitHeader_StringArrayParam.generated.txt
index 66c4504e000..b2fc71b9158 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitHeader_StringArrayParam.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitHeader_StringArrayParam.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -231,6 +232,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_ComplexTypeArrayParam.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_ComplexTypeArrayParam.generated.txt
index 860627ce40b..9aee726d205 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_ComplexTypeArrayParam.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_ComplexTypeArrayParam.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: true, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -259,6 +260,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_IntArrayParam_Optional.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_IntArrayParam_Optional.generated.txt
index f09d01273f7..01d6808eaf6 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_IntArrayParam_Optional.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_IntArrayParam_Optional.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: true, hasBindAsync: false, isOptional: true));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32[]), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -259,6 +260,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_IntArrayParam_Optional_QueryNotPresent.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_IntArrayParam_Optional_QueryNotPresent.generated.txt
index f09d01273f7..01d6808eaf6 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_IntArrayParam_Optional_QueryNotPresent.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_IntArrayParam_Optional_QueryNotPresent.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: true, hasBindAsync: false, isOptional: true));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32[]), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -259,6 +260,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_NullableIntArrayParam_Optional.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_NullableIntArrayParam_Optional.generated.txt
index 9075d188acd..40a1b29bb12 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_NullableIntArrayParam_Optional.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_NullableIntArrayParam_Optional.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: true, hasBindAsync: false, isOptional: true));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32?[]), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -259,6 +260,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_NullableIntArrayParam_Optional_QueryNotPresent.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_NullableIntArrayParam_Optional_QueryNotPresent.generated.txt
index 9075d188acd..40a1b29bb12 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_NullableIntArrayParam_Optional_QueryNotPresent.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_NullableIntArrayParam_Optional_QueryNotPresent.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: true, hasBindAsync: false, isOptional: true));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32?[]), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -259,6 +260,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_NullableStringArrayParam.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_NullableStringArrayParam.generated.txt
index 1d755d1dc5a..9bebb6eea5e 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_NullableStringArrayParam.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_NullableStringArrayParam.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -230,6 +231,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_StringArrayParam.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_StringArrayParam.generated.txt
index e9d7ec91cc4..7931fdc136d 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_StringArrayParam.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_StringArrayParam.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -230,6 +231,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_StringArrayParam_Optional.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_StringArrayParam_Optional.generated.txt
index 3e4918ffd63..757eb5f81f8 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_StringArrayParam_Optional.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_StringArrayParam_Optional.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: true));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.String[]), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -230,6 +231,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_StringArrayParam_Optional_QueryNotPresent.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_StringArrayParam_Optional_QueryNotPresent.generated.txt
index 3e4918ffd63..757eb5f81f8 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_StringArrayParam_Optional_QueryNotPresent.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitQuery_StringArrayParam_Optional_QueryNotPresent.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: true));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.String[]), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -230,6 +231,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitServiceParam_SimpleReturn_Snapshot.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitServiceParam_SimpleReturn_Snapshot.generated.txt
index a82fa6fb9ba..2e18c631a26 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitServiceParam_SimpleReturn_Snapshot.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitServiceParam_SimpleReturn_Snapshot.generated.txt
@@ -439,6 +439,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitSource_SimpleReturn_Snapshot.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitSource_SimpleReturn_Snapshot.generated.txt
index 794413cb79a..3663350edf7 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitSource_SimpleReturn_Snapshot.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ExplicitSource_SimpleReturn_Snapshot.generated.txt
@@ -606,6 +606,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_ComplexTypeArrayParam.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_ComplexTypeArrayParam.generated.txt
index 948327f881b..07e79ab2982 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_ComplexTypeArrayParam.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_ComplexTypeArrayParam.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: true, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -266,6 +267,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_IntArrayParam_Optional.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_IntArrayParam_Optional.generated.txt
index 682208c08c8..e51b39e6f80 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_IntArrayParam_Optional.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_IntArrayParam_Optional.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: true, hasBindAsync: false, isOptional: true));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32[]), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -266,6 +267,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_IntArrayParam_Optional_QueryNotPresent.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_IntArrayParam_Optional_QueryNotPresent.generated.txt
index 682208c08c8..e51b39e6f80 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_IntArrayParam_Optional_QueryNotPresent.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_IntArrayParam_Optional_QueryNotPresent.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: true, hasBindAsync: false, isOptional: true));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32[]), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -266,6 +267,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableIntArrayParam_Optional.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableIntArrayParam_Optional.generated.txt
index 82e1993b1b4..2e4b0d343e0 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableIntArrayParam_Optional.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableIntArrayParam_Optional.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: true, hasBindAsync: false, isOptional: true));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32?[]), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -266,6 +267,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableIntArrayParam_Optional_QueryNotPresent.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableIntArrayParam_Optional_QueryNotPresent.generated.txt
index 82e1993b1b4..2e4b0d343e0 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableIntArrayParam_Optional_QueryNotPresent.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableIntArrayParam_Optional_QueryNotPresent.generated.txt
@@ -72,6 +72,7 @@ namespace Microsoft.AspNetCore.Http.Generated
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: true, hasBindAsync: false, isOptional: true));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32?[]), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -266,6 +267,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableStringArrayParam.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableStringArrayParam.generated.txt
index af6f3f0d1c1..85750166999 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableStringArrayParam.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableStringArrayParam.generated.txt
@@ -81,12 +81,14 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -327,6 +329,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableStringArrayParam_EmptyQueryValues.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableStringArrayParam_EmptyQueryValues.generated.txt
index af6f3f0d1c1..85750166999 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableStringArrayParam_EmptyQueryValues.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableStringArrayParam_EmptyQueryValues.generated.txt
@@ -81,12 +81,14 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -327,6 +329,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableStringArrayParam_QueryNotPresent.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableStringArrayParam_QueryNotPresent.generated.txt
index af6f3f0d1c1..85750166999 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableStringArrayParam_QueryNotPresent.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_NullableStringArrayParam_QueryNotPresent.generated.txt
@@ -81,12 +81,14 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -327,6 +329,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_StringArrayParam.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_StringArrayParam.generated.txt
index 3d2c9a68231..9c1fe26e590 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_StringArrayParam.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_StringArrayParam.generated.txt
@@ -81,12 +81,14 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -327,6 +329,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_StringArrayParam_Optional.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_StringArrayParam_Optional.generated.txt
index 5e6adff6d90..65ddf710920 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_StringArrayParam_Optional.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_StringArrayParam_Optional.generated.txt
@@ -81,12 +81,14 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: true));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.String[]), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -327,6 +329,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_StringArrayParam_Optional_QueryNotPresent.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_StringArrayParam_Optional_QueryNotPresent.generated.txt
index 5e6adff6d90..65ddf710920 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_StringArrayParam_Optional_QueryNotPresent.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ImplicitQuery_StringArrayParam_Optional_QueryNotPresent.generated.txt
@@ -81,12 +81,14 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: true));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.String[]), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -327,6 +329,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_JsonBodyOrService_HandlesBothJsonAndService.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_JsonBodyOrService_HandlesBothJsonAndService.generated.txt
index 9a7acd7eb45..bc9c6a59d73 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_JsonBodyOrService_HandlesBothJsonAndService.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_JsonBodyOrService_HandlesBothJsonAndService.generated.txt
@@ -82,6 +82,7 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
@@ -345,6 +346,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_MultipleSpecialTypeParam_StringReturn.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_MultipleSpecialTypeParam_StringReturn.generated.txt
index 8ac1c767314..560f0ec1f94 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_MultipleSpecialTypeParam_StringReturn.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_MultipleSpecialTypeParam_StringReturn.generated.txt
@@ -234,6 +234,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_MultipleStringParam_StringReturn.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_MultipleStringParam_StringReturn.generated.txt
index 139a5739a23..0c26ae02146 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_MultipleStringParam_StringReturn.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_MultipleStringParam_StringReturn.generated.txt
@@ -267,6 +267,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_NoParam_StringReturn_WithFilter.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_NoParam_StringReturn_WithFilter.generated.txt
index ae38db99890..18cf2ce8010 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_NoParam_StringReturn_WithFilter.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_NoParam_StringReturn_WithFilter.generated.txt
@@ -225,6 +225,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ReturnsString_Has_Metadata.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ReturnsString_Has_Metadata.generated.txt
index ae38db99890..18cf2ce8010 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ReturnsString_Has_Metadata.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ReturnsString_Has_Metadata.generated.txt
@@ -225,6 +225,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ReturnsTodo_Has_Metadata.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ReturnsTodo_Has_Metadata.generated.txt
index f1a99f9eb04..808d55a9698 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ReturnsTodo_Has_Metadata.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_ReturnsTodo_Has_Metadata.generated.txt
@@ -70,6 +70,7 @@ namespace Microsoft.AspNetCore.Http.Generated
Debug.Assert(options.EndpointBuilder != null, "EndpointBuilder not found.");
options.EndpointBuilder.Metadata.Add(new System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.RequestDelegateGenerator, Version=42.42.42.42, Culture=neutral, PublicKeyToken=adb9793829ddae60", "42.42.42.42"));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::Microsoft.AspNetCore.Http.Generators.Tests.Todo), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -218,6 +219,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_SingleComplexTypeParam_StringReturn.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_SingleComplexTypeParam_StringReturn.generated.txt
index dd910316c8f..50993013154 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_SingleComplexTypeParam_StringReturn.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_SingleComplexTypeParam_StringReturn.generated.txt
@@ -266,6 +266,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_SingleEnumParam_StringReturn.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_SingleEnumParam_StringReturn.generated.txt
index e37a0fa0f25..b1b71f8eecd 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_SingleEnumParam_StringReturn.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_SingleEnumParam_StringReturn.generated.txt
@@ -266,6 +266,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_SingleNullableStringParam_WithEmptyQueryStringValueProvided_StringReturn.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_SingleNullableStringParam_WithEmptyQueryStringValueProvided_StringReturn.generated.txt
index 773c77bc8d2..b56621cb8c5 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_SingleNullableStringParam_WithEmptyQueryStringValueProvided_StringReturn.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_SingleNullableStringParam_WithEmptyQueryStringValueProvided_StringReturn.generated.txt
@@ -238,6 +238,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_TakesCustomMetadataEmitter_Has_Metadata.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_TakesCustomMetadataEmitter_Has_Metadata.generated.txt
index 839b8eaa937..72e03e06b74 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_TakesCustomMetadataEmitter_Has_Metadata.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapAction_TakesCustomMetadataEmitter_Has_Metadata.generated.txt
@@ -81,6 +81,7 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
@@ -333,6 +334,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_Get_WithArrayQueryString_AndBody_ShouldUseQueryString.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_Get_WithArrayQueryString_AndBody_ShouldUseQueryString.generated.txt
index 0daff798796..7409065d2ce 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_Get_WithArrayQueryString_AndBody_ShouldUseQueryString.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_Get_WithArrayQueryString_AndBody_ShouldUseQueryString.generated.txt
@@ -81,6 +81,7 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
@@ -334,6 +335,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_PostAndGet_WithArrayQueryString_AndBody_ShouldUseQueryString.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_PostAndGet_WithArrayQueryString_AndBody_ShouldUseQueryString.generated.txt
index 0daff798796..7409065d2ce 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_PostAndGet_WithArrayQueryString_AndBody_ShouldUseQueryString.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_PostAndGet_WithArrayQueryString_AndBody_ShouldUseQueryString.generated.txt
@@ -81,6 +81,7 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
@@ -334,6 +335,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_PostAndPut_WithArrayQueryString_AndBody_ShouldUseBody.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_PostAndPut_WithArrayQueryString_AndBody_ShouldUseBody.generated.txt
index 0daff798796..7409065d2ce 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_PostAndPut_WithArrayQueryString_AndBody_ShouldUseBody.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_PostAndPut_WithArrayQueryString_AndBody_ShouldUseBody.generated.txt
@@ -81,6 +81,7 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
@@ -334,6 +335,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_Post_WithArrayQueryString_AndBody_ShouldUseBody.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_Post_WithArrayQueryString_AndBody_ShouldUseBody.generated.txt
index 0daff798796..7409065d2ce 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_Post_WithArrayQueryString_AndBody_ShouldUseBody.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapMethods_Post_WithArrayQueryString_AndBody_ShouldUseBody.generated.txt
@@ -81,6 +81,7 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
@@ -334,6 +335,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapPost_WithArrayQueryString_AndBody_ShouldUseBody.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapPost_WithArrayQueryString_AndBody_ShouldUseBody.generated.txt
index 8a2bc539262..3fb5a66501a 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapPost_WithArrayQueryString_AndBody_ShouldUseBody.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapPost_WithArrayQueryString_AndBody_ShouldUseBody.generated.txt
@@ -81,6 +81,7 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
@@ -334,6 +335,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapPost_WithArrayQueryString_ShouldFail.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapPost_WithArrayQueryString_ShouldFail.generated.txt
index 379c78383b4..f34ec56593e 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapPost_WithArrayQueryString_ShouldFail.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/MapPost_WithArrayQueryString_ShouldFail.generated.txt
@@ -81,12 +81,14 @@ namespace Microsoft.AspNetCore.Http.Generated
if (!serviceProviderIsService.IsService(type))
{
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(type: type, isOptional: isOptional, contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
break;
}
}
var parameters = methodInfo.GetParameters();
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("p", parameters[0], hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(global::System.Int32), contentTypes: GeneratedMetadataConstants.JsonContentType));
+ ApiEndpointMetadata.AddApiEndpointMetadataIfMissing(options.EndpointBuilder);
return new RequestDelegateMetadataResult { EndpointMetadata = options.EndpointBuilder.Metadata.AsReadOnly() };
};
RequestDelegateFactoryFunc createRequestDelegate = (del, options, inferredMetadataResult) =>
@@ -327,6 +329,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/Multiple_MapAction_NoParam_StringReturn.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/Multiple_MapAction_NoParam_StringReturn.generated.txt
index 79567d9d3a0..bf51a39927f 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/Multiple_MapAction_NoParam_StringReturn.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/Multiple_MapAction_NoParam_StringReturn.generated.txt
@@ -414,6 +414,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/Multiple_MapAction_WithParams_StringReturn.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/Multiple_MapAction_WithParams_StringReturn.generated.txt
index 38e13d3e6d5..ffb90a91f7f 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/Multiple_MapAction_WithParams_StringReturn.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/Multiple_MapAction_WithParams_StringReturn.generated.txt
@@ -428,6 +428,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/RequestDelegateValidateGeneratedFormCode.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/RequestDelegateValidateGeneratedFormCode.generated.txt
index 905324b900e..8119c31870e 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/RequestDelegateValidateGeneratedFormCode.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/RequestDelegateValidateGeneratedFormCode.generated.txt
@@ -373,17 +373,17 @@ namespace Microsoft.AspNetCore.Http.Generated
}
-file sealed class AntiforgeryMetadata : IAntiforgeryMetadata
-{
- public static readonly IAntiforgeryMetadata ValidationRequired = new AntiforgeryMetadata(true);
-
- public AntiforgeryMetadata(bool requiresValidation)
+ file sealed class AntiforgeryMetadata : IAntiforgeryMetadata
{
- RequiresValidation = requiresValidation;
- }
+ public static readonly IAntiforgeryMetadata ValidationRequired = new AntiforgeryMetadata(true);
- public bool RequiresValidation { get; }
-}
+ public AntiforgeryMetadata(bool requiresValidation)
+ {
+ RequiresValidation = requiresValidation;
+ }
+
+ public bool RequiresValidation { get; }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/SupportsDifferentInterceptorsFromSameLocation.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/SupportsDifferentInterceptorsFromSameLocation.generated.txt
index 5316ad22d59..fea0e359a92 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/SupportsDifferentInterceptorsFromSameLocation.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/SupportsDifferentInterceptorsFromSameLocation.generated.txt
@@ -388,6 +388,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/SupportsSameInterceptorsFromDifferentFiles.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/SupportsSameInterceptorsFromDifferentFiles.generated.txt
index aad88a30d27..cafc9280c93 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/SupportsSameInterceptorsFromDifferentFiles.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/SupportsSameInterceptorsFromDifferentFiles.generated.txt
@@ -257,6 +257,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/VerifyAsParametersBaseline.generated.txt b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/VerifyAsParametersBaseline.generated.txt
index 30b4541a6f4..489a8b16b73 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/VerifyAsParametersBaseline.generated.txt
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/Baselines/VerifyAsParametersBaseline.generated.txt
@@ -446,6 +446,7 @@ namespace Microsoft.AspNetCore.Http.Generated
Debug.Assert(options.EndpointBuilder != null, "EndpointBuilder not found.");
options.EndpointBuilder.Metadata.Add(new System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.RequestDelegateGenerator, Version=42.42.42.42, Culture=neutral, PublicKeyToken=adb9793829ddae60", "42.42.42.42"));
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("HttpContext", new PropertyAsParameterInfo(false, typeof(Microsoft.AspNetCore.Http.Generators.Tests.ParametersListWithImplicitFromBody)!.GetProperty("HttpContext")!, typeof(Microsoft.AspNetCore.Http.Generators.Tests.ParametersListWithImplicitFromBody).GetConstructor(new[] { typeof(Microsoft.AspNetCore.Http.HttpContext), typeof(Microsoft.AspNetCore.Http.Generators.Tests.TodoStruct) })?.GetParameters()[0]), hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("Todo", new PropertyAsParameterInfo(false, typeof(Microsoft.AspNetCore.Http.Generators.Tests.ParametersListWithImplicitFromBody)!.GetProperty("Todo")!, typeof(Microsoft.AspNetCore.Http.Generators.Tests.ParametersListWithImplicitFromBody).GetConstructor(new[] { typeof(Microsoft.AspNetCore.Http.HttpContext), typeof(Microsoft.AspNetCore.Http.Generators.Tests.TodoStruct) })?.GetParameters()[1]), hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(string), contentTypes: GeneratedMetadataConstants.PlaintextContentType));
@@ -567,6 +568,7 @@ namespace Microsoft.AspNetCore.Http.Generated
Debug.Assert(options.EndpointBuilder != null, "EndpointBuilder not found.");
options.EndpointBuilder.Metadata.Add(new System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.RequestDelegateGenerator, Version=42.42.42.42, Culture=neutral, PublicKeyToken=adb9793829ddae60", "42.42.42.42"));
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("HttpContext", new PropertyAsParameterInfo(false, typeof(Microsoft.AspNetCore.Http.Generators.Tests.ParametersListWithMetadataType)!.GetProperty("HttpContext")!, typeof(Microsoft.AspNetCore.Http.Generators.Tests.ParametersListWithMetadataType).GetConstructor(new[] { typeof(Microsoft.AspNetCore.Http.HttpContext), typeof(Microsoft.AspNetCore.Http.Generators.Tests.AddsCustomParameterMetadataAsProperty) })?.GetParameters()[0]), hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("Value", new PropertyAsParameterInfo(false, typeof(Microsoft.AspNetCore.Http.Generators.Tests.ParametersListWithMetadataType)!.GetProperty("Value")!, typeof(Microsoft.AspNetCore.Http.Generators.Tests.ParametersListWithMetadataType).GetConstructor(new[] { typeof(Microsoft.AspNetCore.Http.HttpContext), typeof(Microsoft.AspNetCore.Http.Generators.Tests.AddsCustomParameterMetadataAsProperty) })?.GetParameters()[1]), hasTryParse: false, hasBindAsync: false, isOptional: false));
var parameterInfos = methodInfo.GetParameters();
@@ -683,6 +685,7 @@ namespace Microsoft.AspNetCore.Http.Generated
Debug.Assert(options.EndpointBuilder != null, "EndpointBuilder not found.");
options.EndpointBuilder.Metadata.Add(new System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.RequestDelegateGenerator, Version=42.42.42.42, Culture=neutral, PublicKeyToken=adb9793829ddae60", "42.42.42.42"));
options.EndpointBuilder.Metadata.Add(new AcceptsMetadata(contentTypes: GeneratedMetadataConstants.JsonContentType));
+ options.EndpointBuilder.Metadata.Add(ApiEndpointMetadata.Instance);
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("Todo", new PropertyAsParameterInfo(false, typeof(Microsoft.AspNetCore.Http.Generators.Tests.ParameterRecordStructWithJsonBodyOrService)!.GetProperty("Todo")!), hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ParameterBindingMetadata("Service", new PropertyAsParameterInfo(false, typeof(Microsoft.AspNetCore.Http.Generators.Tests.ParameterRecordStructWithJsonBodyOrService)!.GetProperty("Service")!), hasTryParse: false, hasBindAsync: false, isOptional: false));
options.EndpointBuilder.Metadata.Add(new ProducesResponseTypeMetadata(statusCode: StatusCodes.Status200OK, type: typeof(string), contentTypes: GeneratedMetadataConstants.PlaintextContentType));
@@ -966,6 +969,22 @@ namespace Microsoft.AspNetCore.Http.Generated
}
+ file sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static readonly ApiEndpointMetadata Instance = new();
+
+ private ApiEndpointMetadata()
+ {
+ }
+
+ public static void AddApiEndpointMetadataIfMissing(EndpointBuilder builder)
+ {
+ if (!builder.Metadata.Any(m => m is IApiEndpointMetadata))
+ {
+ builder.Metadata.Add(Instance);
+ }
+ }
+ }
%GENERATEDCODEATTRIBUTE%
file static class GeneratedMetadataConstants
{
diff --git a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/RequestDelegateCreationTests.Metadata.cs b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/RequestDelegateCreationTests.Metadata.cs
index 68f0af00465..1f3412e5439 100644
--- a/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/RequestDelegateCreationTests.Metadata.cs
+++ b/src/aspnetcore/src/Http/Http.Extensions/test/RequestDelegateGenerator/RequestDelegateCreationTests.Metadata.cs
@@ -83,17 +83,14 @@ public async Task MapAction_ReturnsTaskOfString_Has_Metadata()
}
[Fact]
- public async Task MapAction_ReturnsTask_ProducesInferredMetadata()
+ public async Task MapAction_ReturnsTask_ProducesNoInferredProducesResponseTypeMetadata()
{
var (_, compilation) = await RunGeneratorAsync("""
app.MapGet("/", Task () => Task.CompletedTask);
""");
var endpoint = GetEndpointFromCompilation(compilation);
- var metadata = endpoint.Metadata.OfType().Single();
- Assert.Equal(200, metadata.StatusCode);
- Assert.Equal("text/plain", metadata.ContentTypes.Single());
- Assert.Equal(typeof(void), metadata.Type);
+ Assert.Empty(endpoint.Metadata.OfType());
}
[Fact]
@@ -111,17 +108,14 @@ public async Task MapAction_ReturnsValueTaskOfString_Has_Metadata()
}
[Fact]
- public async Task MapAction_ReturnsValueTask_ProducesInferredMetadata()
+ public async Task MapAction_ReturnsValueTask_ProducesNoInferredProducesResponseTypeMetadata()
{
var (_, compilation) = await RunGeneratorAsync("""
app.MapGet("/", ValueTask () => ValueTask.CompletedTask);
""");
var endpoint = GetEndpointFromCompilation(compilation);
- var metadata = endpoint.Metadata.OfType().Single();
- Assert.Equal(200, metadata.StatusCode);
- Assert.Equal("text/plain", metadata.ContentTypes.Single());
- Assert.Equal(typeof(void), metadata.Type);
+ Assert.Empty(endpoint.Metadata.OfType());
}
[Fact]
@@ -512,6 +506,11 @@ public async Task InferMetadata_ThenCreate_CombinesAllMetadata_InCorrectOrder()
// Act
var endpoint = GetEndpointFromCompilation(compilation);
+ // IApiEndpointMetadata is tricky to order consistently because it depends on whether AddsCustomParameterMetadata is registered
+ // as a service at runtime. However, the order of IApiEndpointMetadata is not significant since there's no way to override it
+ // other than removing it.
+ Assert.Single(endpoint.Metadata, m => m is IApiEndpointMetadata);
+
// Assert
// NOTE: Depending on whether we are running under RDG or RDG, there are some generated types which
// don't have equivalents in the opposite. The two examples here are NullableContextAttribute which
@@ -525,7 +524,8 @@ m is not MethodInfo &&
m is not HttpMethodMetadata &&
m is not Attribute1 &&
m is not Attribute2 &&
- m is not IRouteDiagnosticsMetadata);
+ m is not IRouteDiagnosticsMetadata &&
+ m is not IApiEndpointMetadata);
Assert.Collection(filteredMetadata,
// Inferred AcceptsMetadata from RDF for complex type
diff --git a/src/aspnetcore/src/Http/Http.Results/src/Accepted.cs b/src/aspnetcore/src/Http/Http.Results/src/Accepted.cs
index 5dbc56987c4..d71fe9072c7 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/Accepted.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/Accepted.cs
@@ -82,5 +82,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status202Accepted, typeof(void)));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/AcceptedAtRoute.cs b/src/aspnetcore/src/Http/Http.Results/src/AcceptedAtRoute.cs
index 7472559549d..900ee507d9c 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/AcceptedAtRoute.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/AcceptedAtRoute.cs
@@ -109,5 +109,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status202Accepted, typeof(void)));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs b/src/aspnetcore/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs
index e9467dbe1e5..b8e4304a723 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/AcceptedAtRouteOfT.cs
@@ -123,5 +123,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status202Accepted, ContentTypeConstants.ApplicationJsonContentTypes));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/AcceptedOfT.cs b/src/aspnetcore/src/Http/Http.Results/src/AcceptedOfT.cs
index 6777d3549d5..346070714b4 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/AcceptedOfT.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/AcceptedOfT.cs
@@ -101,5 +101,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status202Accepted, ContentTypeConstants.ApplicationJsonContentTypes));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/BadRequest.cs b/src/aspnetcore/src/Http/Http.Results/src/BadRequest.cs
index 9eef74aa41c..0356afedc2c 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/BadRequest.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/BadRequest.cs
@@ -52,5 +52,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status400BadRequest, typeof(void)));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/BadRequestOfT.cs b/src/aspnetcore/src/Http/Http.Results/src/BadRequestOfT.cs
index 4b932786eb3..b8fa51423d7 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/BadRequestOfT.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/BadRequestOfT.cs
@@ -66,5 +66,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status400BadRequest, ContentTypeConstants.ApplicationJsonContentTypes));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/Conflict.cs b/src/aspnetcore/src/Http/Http.Results/src/Conflict.cs
index da162ed5d20..f0067ba4aea 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/Conflict.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/Conflict.cs
@@ -52,5 +52,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status409Conflict, typeof(void)));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/ConflictOfT.cs b/src/aspnetcore/src/Http/Http.Results/src/ConflictOfT.cs
index bbfb3c6a503..dda54d9dd5c 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/ConflictOfT.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/ConflictOfT.cs
@@ -66,5 +66,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status409Conflict, ContentTypeConstants.ApplicationJsonContentTypes));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/Created.cs b/src/aspnetcore/src/Http/Http.Results/src/Created.cs
index 7766d91a6f4..1959556280c 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/Created.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/Created.cs
@@ -82,5 +82,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status201Created, typeof(void)));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/CreatedAtRoute.cs b/src/aspnetcore/src/Http/Http.Results/src/CreatedAtRoute.cs
index 2fb70fa23b1..2ff79596ba3 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/CreatedAtRoute.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/CreatedAtRoute.cs
@@ -109,5 +109,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status201Created, typeof(void)));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/CreatedAtRouteOfT.cs b/src/aspnetcore/src/Http/Http.Results/src/CreatedAtRouteOfT.cs
index d13d6154413..a2868afdc0a 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/CreatedAtRouteOfT.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/CreatedAtRouteOfT.cs
@@ -126,5 +126,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status201Created, ContentTypeConstants.ApplicationJsonContentTypes));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/CreatedOfT.cs b/src/aspnetcore/src/Http/Http.Results/src/CreatedOfT.cs
index 58d0638b218..a12e52b9f69 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/CreatedOfT.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/CreatedOfT.cs
@@ -100,5 +100,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status201Created, ContentTypeConstants.ApplicationJsonContentTypes));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/InternalServerErrorOfT.cs b/src/aspnetcore/src/Http/Http.Results/src/InternalServerErrorOfT.cs
index 36ec9fed951..c726debf67c 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/InternalServerErrorOfT.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/InternalServerErrorOfT.cs
@@ -66,5 +66,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status500InternalServerError, ContentTypeConstants.ApplicationJsonContentTypes));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/JsonHttpResultOfT.cs b/src/aspnetcore/src/Http/Http.Results/src/JsonHttpResultOfT.cs
index 4841e675ecf..fea230609a2 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/JsonHttpResultOfT.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/JsonHttpResultOfT.cs
@@ -2,8 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -13,7 +16,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults;
///
/// An action result which formats the given object as JSON.
///
-public sealed partial class JsonHttpResult : IResult, IStatusCodeHttpResult, IValueHttpResult, IValueHttpResult, IContentTypeHttpResult
+public sealed partial class JsonHttpResult : IResult, IEndpointMetadataProvider, IStatusCodeHttpResult, IValueHttpResult, IValueHttpResult, IContentTypeHttpResult
{
///
/// Initializes a new instance of the class with the values.
@@ -117,7 +120,7 @@ public Task ExecuteAsync(HttpContext httpContext)
typedJsonTypeInfo,
contentType: ContentType);
}
-
+
return httpContext.Response.WriteAsJsonAsync(
Value,
JsonTypeInfo,
@@ -131,4 +134,9 @@ public Task ExecuteAsync(HttpContext httpContext)
ContentType,
JsonSerializerOptions);
}
+
+ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, EndpointBuilder builder)
+ {
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
+ }
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/NoContent.cs b/src/aspnetcore/src/Http/Http.Results/src/NoContent.cs
index 987a06fc4ee..35ffb3c5670 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/NoContent.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/NoContent.cs
@@ -52,5 +52,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status204NoContent, typeof(void)));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/NotFoundOfT.cs b/src/aspnetcore/src/Http/Http.Results/src/NotFoundOfT.cs
index ad9c3a1032e..d37a4ee9707 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/NotFoundOfT.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/NotFoundOfT.cs
@@ -65,5 +65,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status404NotFound, ContentTypeConstants.ApplicationJsonContentTypes));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/Ok.cs b/src/aspnetcore/src/Http/Http.Results/src/Ok.cs
index 0db060d4e6d..837a0fa7513 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/Ok.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/Ok.cs
@@ -51,5 +51,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status200OK, typeof(void)));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/OkOfT.cs b/src/aspnetcore/src/Http/Http.Results/src/OkOfT.cs
index 108674fdc2a..7f19598effe 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/OkOfT.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/OkOfT.cs
@@ -65,5 +65,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status200OK, ContentTypeConstants.ApplicationJsonContentTypes));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/ProblemHttpResult.cs b/src/aspnetcore/src/Http/Http.Results/src/ProblemHttpResult.cs
index 4fe63c4277c..8ac29336f05 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/ProblemHttpResult.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/ProblemHttpResult.cs
@@ -4,6 +4,9 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using System.Reflection;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http.Metadata;
namespace Microsoft.AspNetCore.Http.HttpResults;
@@ -11,7 +14,7 @@ namespace Microsoft.AspNetCore.Http.HttpResults;
/// An that on execution will write Problem Details
/// HTTP API responses based on
///
-public sealed class ProblemHttpResult : IResult, IStatusCodeHttpResult, IContentTypeHttpResult, IValueHttpResult, IValueHttpResult
+public sealed class ProblemHttpResult : IResult, IEndpointMetadataProvider, IStatusCodeHttpResult, IContentTypeHttpResult, IValueHttpResult, IValueHttpResult
{
///
/// Creates a new instance with
@@ -69,4 +72,13 @@ await HttpResultsHelper.WriteResultAsJsonAsync(
ContentType);
}
}
+
+ ///
+ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, EndpointBuilder builder)
+ {
+ ArgumentNullException.ThrowIfNull(method);
+ ArgumentNullException.ThrowIfNull(builder);
+
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
+ }
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/ServerSentEventsResult.cs b/src/aspnetcore/src/Http/Http.Results/src/ServerSentEventsResult.cs
index 448b2076daa..a7951acd155 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/ServerSentEventsResult.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/ServerSentEventsResult.cs
@@ -105,5 +105,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status200OK, typeof(SseItem), contentTypes: ["text/event-stream"]));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/UnprocessableEntity.cs b/src/aspnetcore/src/Http/Http.Results/src/UnprocessableEntity.cs
index eef96dc9f51..49d3982720b 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/UnprocessableEntity.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/UnprocessableEntity.cs
@@ -52,5 +52,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(new ProducesResponseTypeMetadata(StatusCodes.Status422UnprocessableEntity, typeof(void)));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/UnprocessableEntityOfT.cs b/src/aspnetcore/src/Http/Http.Results/src/UnprocessableEntityOfT.cs
index 475a0bc3ad2..2d1ee494a27 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/UnprocessableEntityOfT.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/UnprocessableEntityOfT.cs
@@ -66,5 +66,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(TValue), StatusCodes.Status422UnprocessableEntity, ContentTypeConstants.ApplicationJsonContentTypes));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/src/ValidationProblem.cs b/src/aspnetcore/src/Http/Http.Results/src/ValidationProblem.cs
index ba738cfbcf3..c4a539c9cd5 100644
--- a/src/aspnetcore/src/Http/Http.Results/src/ValidationProblem.cs
+++ b/src/aspnetcore/src/Http/Http.Results/src/ValidationProblem.cs
@@ -77,5 +77,6 @@ static void IEndpointMetadataProvider.PopulateMetadata(MethodInfo method, Endpoi
ArgumentNullException.ThrowIfNull(builder);
builder.Metadata.Add(ProducesResponseTypeMetadata.CreateUnvalidated(typeof(HttpValidationProblemDetails), StatusCodes.Status400BadRequest, ContentTypeConstants.ProblemDetailsContentTypes));
+ builder.Metadata.Add(ApiEndpointMetadata.Instance);
}
}
diff --git a/src/aspnetcore/src/Http/Http.Results/test/AcceptedAtRouteOfTResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/AcceptedAtRouteOfTResultTests.cs
index 47b1569390d..1d53452fa65 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/AcceptedAtRouteOfTResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/AcceptedAtRouteOfTResultTests.cs
@@ -134,6 +134,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
Assert.Equal(StatusCodes.Status202Accepted, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type);
Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json");
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs
index 8f29f5a5134..15a93310e80 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/AcceptedAtRouteResultTests.cs
@@ -87,6 +87,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
var producesResponseTypeMetadata = builder.Metadata.OfType().Last();
Assert.Equal(StatusCodes.Status202Accepted, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(void), producesResponseTypeMetadata.Type);
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/AcceptedOfTResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/AcceptedOfTResultTests.cs
index 853a57d4704..2ee6e03193d 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/AcceptedOfTResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/AcceptedOfTResultTests.cs
@@ -75,6 +75,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
Assert.Equal(StatusCodes.Status202Accepted, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type);
Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json");
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/AcceptedResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/AcceptedResultTests.cs
index 7511b05fa24..171b4511217 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/AcceptedResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/AcceptedResultTests.cs
@@ -44,6 +44,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
var producesResponseTypeMetadata = builder.Metadata.OfType().Last();
Assert.Equal(StatusCodes.Status202Accepted, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(void), producesResponseTypeMetadata.Type);
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/BadRequestOfTResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/BadRequestOfTResultTests.cs
index 58e1e452e39..c930db6ea80 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/BadRequestOfTResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/BadRequestOfTResultTests.cs
@@ -118,6 +118,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
Assert.Equal(StatusCodes.Status400BadRequest, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type);
Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json");
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/BadRequestResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/BadRequestResultTests.cs
index e8f3a444de0..cca2a4d139e 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/BadRequestResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/BadRequestResultTests.cs
@@ -57,6 +57,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
var producesResponseTypeMetadata = builder.Metadata.OfType().Last();
Assert.Equal(StatusCodes.Status400BadRequest, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(void), producesResponseTypeMetadata.Type);
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/ConflictOfTResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/ConflictOfTResultTests.cs
index 5e757e3b191..be4e43d441d 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/ConflictOfTResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/ConflictOfTResultTests.cs
@@ -96,6 +96,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
Assert.Equal(StatusCodes.Status409Conflict, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type);
Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json");
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/ConflictResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/ConflictResultTests.cs
index 88f64740aae..2f639948eac 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/ConflictResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/ConflictResultTests.cs
@@ -58,6 +58,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
var producesResponseTypeMetadata = builder.Metadata.OfType().Last();
Assert.Equal(StatusCodes.Status409Conflict, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(void), producesResponseTypeMetadata.Type);
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/CreatedAtRouteOfTResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/CreatedAtRouteOfTResultTests.cs
index dec5f3ceafb..a55f7dd6ef9 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/CreatedAtRouteOfTResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/CreatedAtRouteOfTResultTests.cs
@@ -104,6 +104,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
Assert.Equal(StatusCodes.Status201Created, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type);
Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json");
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs
index e91822afc79..5a36fdcce05 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/CreatedAtRouteResultTests.cs
@@ -85,6 +85,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
var producesResponseTypeMetadata = builder.Metadata.OfType().Last();
Assert.Equal(StatusCodes.Status201Created, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(void), producesResponseTypeMetadata.Type);
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/CreatedOfTResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/CreatedOfTResultTests.cs
index 9e5f0637058..b4b5747745a 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/CreatedOfTResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/CreatedOfTResultTests.cs
@@ -110,6 +110,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
Assert.Equal(StatusCodes.Status201Created, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type);
Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json");
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/CreatedResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/CreatedResultTests.cs
index 21b678d3930..af1c8a1179b 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/CreatedResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/CreatedResultTests.cs
@@ -75,6 +75,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
var producesResponseTypeMetadata = builder.Metadata.OfType().Last();
Assert.Equal(StatusCodes.Status201Created, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(void), producesResponseTypeMetadata.Type);
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/InternalServerErrorOfTResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/InternalServerErrorOfTResultTests.cs
index d063b4e66a1..1ee5bd75105 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/InternalServerErrorOfTResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/InternalServerErrorOfTResultTests.cs
@@ -118,6 +118,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
Assert.Equal(StatusCodes.Status500InternalServerError, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type);
Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json");
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/JsonResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/JsonResultTests.cs
index 1c2d6d7fb22..52d76c0a03c 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/JsonResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/JsonResultTests.cs
@@ -1,11 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.Unicode;
+using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http.Json;
+using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.Routing;
+using Microsoft.AspNetCore.Routing.Patterns;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
@@ -310,6 +315,24 @@ public void JsonResult_Implements_IValueHttpResultOfT_Correctly()
Assert.Equal(value, result.Value);
}
+ [Fact]
+ public void PopulateMetadata_AddsNonBrowserEndpointMetadata()
+ {
+ // Arrange
+ JsonHttpResult MyApi() { throw new NotImplementedException(); }
+ var metadata = new List();
+ var builder = new RouteEndpointBuilder(requestDelegate: null, RoutePatternFactory.Parse("/"), order: 0);
+
+ // Act
+ PopulateMetadata>(((Delegate)MyApi).GetMethodInfo(), builder);
+
+ // Assert
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
+ }
+
+ private static void PopulateMetadata(MethodInfo method, EndpointBuilder builder)
+ where TResult : IEndpointMetadataProvider => TResult.PopulateMetadata(method, builder);
+
private static IServiceProvider CreateServices()
{
var services = new ServiceCollection();
diff --git a/src/aspnetcore/src/Http/Http.Results/test/NoContentResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/NoContentResultTests.cs
index 31a7c8cbc6a..fc1cae4a95a 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/NoContentResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/NoContentResultTests.cs
@@ -54,6 +54,9 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
var producesResponseTypeMetadata = builder.Metadata.OfType().Last();
Assert.Equal(StatusCodes.Status204NoContent, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(void), producesResponseTypeMetadata.Type);
+
+ // Assert ApiEndpointMetadata is added
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/NotFoundOfTResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/NotFoundOfTResultTests.cs
index 0aa82fdd431..ec15a5c8a7e 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/NotFoundOfTResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/NotFoundOfTResultTests.cs
@@ -78,6 +78,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
Assert.Equal(StatusCodes.Status404NotFound, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type);
Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json");
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/OkOfTResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/OkOfTResultTests.cs
index 99ce735caa2..85693056570 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/OkOfTResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/OkOfTResultTests.cs
@@ -95,6 +95,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
Assert.Equal(StatusCodes.Status200OK, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type);
Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json");
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/OkResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/OkResultTests.cs
index fe5db61ff5d..98cac07cbb6 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/OkResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/OkResultTests.cs
@@ -56,6 +56,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
var producesResponseTypeMetadata = builder.Metadata.OfType().Last();
Assert.Equal(StatusCodes.Status200OK, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(void), producesResponseTypeMetadata.Type);
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/UnprocessableEntityOfTResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/UnprocessableEntityOfTResultTests.cs
index 6ec306cbcaf..8c8161f9955 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/UnprocessableEntityOfTResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/UnprocessableEntityOfTResultTests.cs
@@ -95,6 +95,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
Assert.Equal(StatusCodes.Status422UnprocessableEntity, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(Todo), producesResponseTypeMetadata.Type);
Assert.Single(producesResponseTypeMetadata.ContentTypes, "application/json");
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Http/Http.Results/test/UnprocessableEntityResultTests.cs b/src/aspnetcore/src/Http/Http.Results/test/UnprocessableEntityResultTests.cs
index 36edb8923ab..7931b226c06 100644
--- a/src/aspnetcore/src/Http/Http.Results/test/UnprocessableEntityResultTests.cs
+++ b/src/aspnetcore/src/Http/Http.Results/test/UnprocessableEntityResultTests.cs
@@ -57,6 +57,8 @@ public void PopulateMetadata_AddsResponseTypeMetadata()
var producesResponseTypeMetadata = builder.Metadata.OfType().Last();
Assert.Equal(StatusCodes.Status422UnprocessableEntity, producesResponseTypeMetadata.StatusCode);
Assert.Equal(typeof(void), producesResponseTypeMetadata.Type);
+
+ Assert.Contains(builder.Metadata, m => m is IApiEndpointMetadata);
}
[Fact]
diff --git a/src/aspnetcore/src/Mvc/Mvc.ApiExplorer/src/EndpointMetadataApiDescriptionProvider.cs b/src/aspnetcore/src/Mvc/Mvc.ApiExplorer/src/EndpointMetadataApiDescriptionProvider.cs
index 89d45efc5e1..2f25045d378 100644
--- a/src/aspnetcore/src/Mvc/Mvc.ApiExplorer/src/EndpointMetadataApiDescriptionProvider.cs
+++ b/src/aspnetcore/src/Mvc/Mvc.ApiExplorer/src/EndpointMetadataApiDescriptionProvider.cs
@@ -332,10 +332,9 @@ private static void AddSupportedResponseTypes(
var defaultErrorType = errorMetadata?.Type ?? typeof(void);
var contentTypes = new MediaTypeCollection();
- // If the return type is an IResult or an awaitable IResult, then we should treat it as a void return type
- // since we can't infer anything without additional metadata.
- if (typeof(IResult).IsAssignableFrom(responseType) ||
- producesResponseMetadata.Any(metadata => typeof(IResult).IsAssignableFrom(metadata.Type)))
+ // If the return type is an IResult or wrapped in a Task or ValueTask, then we should treat it as a void return type
+ // since we can't infer anything without additional metadata or requiring unreferenced code.
+ if (IsTaskOrValueTask(responseType) || typeof(IResult).IsAssignableFrom(responseType))
{
responseType = typeof(void);
}
@@ -427,6 +426,23 @@ static bool TypesAreCompatible(Type? apiResponseType, Type? metadataType)
return apiResponseType == metadataType ||
metadataType?.IsAssignableFrom(apiResponseType) == true;
}
+
+ static bool IsTaskOrValueTask(Type returnType)
+ {
+ // If this method did not need to be trim-safe, we would use CoercedAwaitableInfo.IsTypeAwaitable, but we cannot.
+ if (returnType.IsAssignableFrom(typeof(Task)) || returnType.IsAssignableFrom(typeof(ValueTask)))
+ {
+ return true;
+ }
+
+ if (returnType.FullName is null)
+ {
+ return false;
+ }
+
+ return returnType.FullName.StartsWith("System.Threading.Tasks.Task`1[", StringComparison.Ordinal) ||
+ returnType.FullName.StartsWith("System.Threading.Tasks.ValueTask`1[", StringComparison.Ordinal);
+ }
}
private static ApiResponseType CreateDefaultApiResponseType(Type responseType)
diff --git a/src/aspnetcore/src/Mvc/Mvc.Core/src/ApiControllerAttribute.cs b/src/aspnetcore/src/Mvc/Mvc.Core/src/ApiControllerAttribute.cs
index a1b95b3ee82..f7179b0b447 100644
--- a/src/aspnetcore/src/Mvc/Mvc.Core/src/ApiControllerAttribute.cs
+++ b/src/aspnetcore/src/Mvc/Mvc.Core/src/ApiControllerAttribute.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.Mvc.Infrastructure;
namespace Microsoft.AspNetCore.Mvc;
@@ -17,6 +18,6 @@ namespace Microsoft.AspNetCore.Mvc;
///
///
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
-public class ApiControllerAttribute : ControllerAttribute, IApiBehaviorMetadata
+public class ApiControllerAttribute : ControllerAttribute, IApiBehaviorMetadata, IApiEndpointMetadata
{
}
diff --git a/src/aspnetcore/src/Mvc/Mvc.Core/test/ApplicationModels/DefaultApplicationModelProviderTest.cs b/src/aspnetcore/src/Mvc/Mvc.Core/test/ApplicationModels/DefaultApplicationModelProviderTest.cs
index 19aea8a971b..c8c6368fe7e 100644
--- a/src/aspnetcore/src/Mvc/Mvc.Core/test/ApplicationModels/DefaultApplicationModelProviderTest.cs
+++ b/src/aspnetcore/src/Mvc/Mvc.Core/test/ApplicationModels/DefaultApplicationModelProviderTest.cs
@@ -3,6 +3,7 @@
using System.Reflection;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
@@ -1277,8 +1278,9 @@ public void AddReturnTypeMetadata_ExtractsMetadataFromReturnType()
// Assert
Assert.NotNull(selector.EndpointMetadata);
- Assert.Single(selector.EndpointMetadata);
- Assert.IsType(selector.EndpointMetadata.Single());
+ Assert.Equal(2, selector.EndpointMetadata.Count);
+ Assert.Single(selector.EndpointMetadata.OfType());
+ Assert.Single(selector.EndpointMetadata.OfType());
Assert.Equal(200, ((ProducesResponseTypeMetadata)selector.EndpointMetadata[0]).StatusCode);
}
diff --git a/src/aspnetcore/src/Security/Authentication/Cookies/src/CookieAuthenticationEvents.cs b/src/aspnetcore/src/Security/Authentication/Cookies/src/CookieAuthenticationEvents.cs
index be47982a28d..994d999aaf5 100644
--- a/src/aspnetcore/src/Security/Authentication/Cookies/src/CookieAuthenticationEvents.cs
+++ b/src/aspnetcore/src/Security/Authentication/Cookies/src/CookieAuthenticationEvents.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.Net.Http.Headers;
namespace Microsoft.AspNetCore.Authentication.Cookies;
@@ -41,7 +42,7 @@ public class CookieAuthenticationEvents
///
public Func, Task> OnRedirectToLogin { get; set; } = context =>
{
- if (IsAjaxRequest(context.Request))
+ if (IsAjaxRequest(context.Request) || IsApiEndpoint(context.HttpContext))
{
context.Response.Headers.Location = context.RedirectUri;
context.Response.StatusCode = 401;
@@ -58,7 +59,7 @@ public class CookieAuthenticationEvents
///
public Func, Task> OnRedirectToAccessDenied { get; set; } = context =>
{
- if (IsAjaxRequest(context.Request))
+ if (IsAjaxRequest(context.Request) || IsApiEndpoint(context.HttpContext))
{
context.Response.Headers.Location = context.RedirectUri;
context.Response.StatusCode = 403;
@@ -108,6 +109,12 @@ private static bool IsAjaxRequest(HttpRequest request)
string.Equals(request.Headers.XRequestedWith, "XMLHttpRequest", StringComparison.Ordinal);
}
+ private static bool IsApiEndpoint(HttpContext context)
+ {
+ var endpoint = context.GetEndpoint();
+ return endpoint?.Metadata.GetMetadata() is not null;
+ }
+
///
/// Invoked to validate the principal.
///
diff --git a/src/aspnetcore/src/Security/Authentication/test/CookieTests.cs b/src/aspnetcore/src/Security/Authentication/test/CookieTests.cs
index cb65ba5a6ba..3dc0d638b8c 100644
--- a/src/aspnetcore/src/Security/Authentication/test/CookieTests.cs
+++ b/src/aspnetcore/src/Security/Authentication/test/CookieTests.cs
@@ -11,6 +11,7 @@
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.TestHost;
using Microsoft.AspNetCore.InternalTesting;
using Microsoft.Extensions.DependencyInjection;
@@ -96,6 +97,30 @@ public async Task AjaxChallengeRedirectTurnsInto200WithLocationHeader()
Assert.StartsWith("http://example.com/Account/Login", responded.Single());
}
+ [Fact]
+ public async Task ApiEndpointChallengeReturns401WithLocationHeader()
+ {
+ using var host = await CreateHost(s => { });
+ using var server = host.GetTestServer();
+ var transaction = await SendAsync(server, "http://example.com/api/challenge");
+ Assert.Equal(HttpStatusCode.Unauthorized, transaction.Response.StatusCode);
+ var responded = transaction.Response.Headers.GetValues("Location");
+ Assert.Single(responded);
+ Assert.StartsWith("http://example.com/Account/Login", responded.Single());
+ }
+
+ [Fact]
+ public async Task ApiEndpointForbidReturns403WithLocationHeader()
+ {
+ using var host = await CreateHost(s => { });
+ using var server = host.GetTestServer();
+ var transaction = await SendAsync(server, "http://example.com/api/forbid");
+ Assert.Equal(HttpStatusCode.Forbidden, transaction.Response.StatusCode);
+ var responded = transaction.Response.Headers.GetValues("Location");
+ Assert.Single(responded);
+ Assert.StartsWith("http://example.com/Account/AccessDenied", responded.Single());
+ }
+
[Fact]
public async Task ProtectedCustomRequestShouldRedirectToCustomRedirectUri()
{
@@ -1879,8 +1904,28 @@ private static async Task CreateHostWithServices(Action
+ {
+ var apiRouteGroup = endpoints.MapGroup("/api").WithMetadata(new TestApiEndpointMetadata());
+ // Add endpoints with IApiEndpointMetadata
+ apiRouteGroup.MapGet("/challenge", async context =>
+ {
+ await context.ChallengeAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+ });
+
+ apiRouteGroup.MapGet("/forbid", async context =>
+ {
+ await context.ForbidAsync(CookieAuthenticationDefaults.AuthenticationScheme);
+ });
+ });
})
- .ConfigureServices(configureServices))
+ .ConfigureServices(services =>
+ {
+ services.AddRoutingCore();
+ configureServices(services);
+ }))
.Build();
await host.StartAsync();
@@ -1949,4 +1994,8 @@ private class Transaction
public string ResponseText { get; set; }
public XElement ResponseElement { get; set; }
}
+
+ private class TestApiEndpointMetadata : IApiEndpointMetadata
+ {
+ }
}
diff --git a/src/aspnetcore/src/Security/Authorization/Core/src/AuthorizationServiceExtensions.cs b/src/aspnetcore/src/Security/Authorization/Core/src/AuthorizationServiceExtensions.cs
index 324d613cf8f..47d381136f2 100644
--- a/src/aspnetcore/src/Security/Authorization/Core/src/AuthorizationServiceExtensions.cs
+++ b/src/aspnetcore/src/Security/Authorization/Core/src/AuthorizationServiceExtensions.cs
@@ -21,8 +21,8 @@ public static class AuthorizationServiceExtensions
/// The resource to evaluate the policy against.
/// The requirement to evaluate the policy against.
///
- /// A flag indicating whether requirement evaluation has succeeded or failed.
- /// This value is true when the user fulfills the policy, otherwise false.
+ /// A that contains an indicating whether requirement evaluation has succeeded or failed.
+ /// The result's property is true when the user fulfills the policy; otherwise false.
///
public static Task AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, object? resource, IAuthorizationRequirement requirement)
{
@@ -40,8 +40,8 @@ public static Task AuthorizeAsync(this IAuthorizationServic
/// The resource to evaluate the policy against.
/// The policy to evaluate.
///
- /// A flag indicating whether policy evaluation has succeeded or failed.
- /// This value is true when the user fulfills the policy, otherwise false.
+ /// A that contains an indicating whether policy evaluation has succeeded or failed.
+ /// The result's property is true when the user fulfills the policy; otherwise false.
///
public static Task AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, object? resource, AuthorizationPolicy policy)
{
@@ -58,8 +58,8 @@ public static Task AuthorizeAsync(this IAuthorizationServic
/// The user to evaluate the policy against.
/// The policy to evaluate.
///
- /// A flag indicating whether policy evaluation has succeeded or failed.
- /// This value is true when the user fulfills the policy, otherwise false.
+ /// A that contains an indicating whether policy evaluation has succeeded or failed.
+ /// The result's property is true when the user fulfills the policy; otherwise false.
///
public static Task AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, AuthorizationPolicy policy)
{
@@ -76,8 +76,8 @@ public static Task AuthorizeAsync(this IAuthorizationServic
/// The user to evaluate the policy against.
/// The name of the policy to evaluate.
///
- /// A flag indicating whether policy evaluation has succeeded or failed.
- /// This value is true when the user fulfills the policy, otherwise false.
+ /// A that contains an indicating whether policy evaluation has succeeded or failed.
+ /// The result's property is true when the user fulfills the policy; otherwise false.
///
public static Task AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, string policyName)
{
diff --git a/src/aspnetcore/src/Security/Authorization/Core/src/DefaultAuthorizationService.cs b/src/aspnetcore/src/Security/Authorization/Core/src/DefaultAuthorizationService.cs
index 1a947463448..0a1b4c37b38 100644
--- a/src/aspnetcore/src/Security/Authorization/Core/src/DefaultAuthorizationService.cs
+++ b/src/aspnetcore/src/Security/Authorization/Core/src/DefaultAuthorizationService.cs
@@ -56,8 +56,8 @@ public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider,
/// The resource to evaluate the requirements against.
/// The requirements to evaluate.
///
- /// A flag indicating whether authorization has succeeded.
- /// This value is true when the user fulfills the policy, otherwise false.
+ /// A that contains an indicating whether authorization has succeeded.
+ /// The result's property is true when the user fulfills the policy; otherwise false.
///
public virtual async Task AuthorizeAsync(ClaimsPrincipal user, object? resource, IEnumerable requirements)
{
@@ -93,8 +93,8 @@ public virtual async Task AuthorizeAsync(ClaimsPrincipal us
/// The resource the policy should be checked with.
/// The name of the policy to check against a specific context.
///
- /// A flag indicating whether authorization has succeeded.
- /// This value is true when the user fulfills the policy otherwise false.
+ /// A that contains an indicating whether authorization has succeeded.
+ /// The result's property is true when the user fulfills the policy; otherwise false.
///
public virtual async Task AuthorizeAsync(ClaimsPrincipal user, object? resource, string policyName)
{
diff --git a/src/aspnetcore/src/Security/Authorization/Core/src/IAuthorizationService.cs b/src/aspnetcore/src/Security/Authorization/Core/src/IAuthorizationService.cs
index 64ac3b5cd51..5c612869d4d 100644
--- a/src/aspnetcore/src/Security/Authorization/Core/src/IAuthorizationService.cs
+++ b/src/aspnetcore/src/Security/Authorization/Core/src/IAuthorizationService.cs
@@ -22,8 +22,8 @@ public interface IAuthorizationService
///
/// The requirements to evaluate.
///
- /// A flag indicating whether authorization has succeeded.
- /// This value is true when the user fulfills the policy; otherwise false.
+ /// A that contains an indicating whether authorization has succeeded.
+ /// The result's property is true when the user fulfills the policy; otherwise false.
///
///
/// Resource is an optional parameter and may be null. Please ensure that you check it is not
@@ -41,9 +41,8 @@ public interface IAuthorizationService
///
/// The name of the policy to check against a specific context.
///
- /// A flag indicating whether authorization has succeeded.
- /// Returns a flag indicating whether the user, and optional resource has fulfilled the policy.
- /// true when the policy has been fulfilled; otherwise false.
+ /// A that contains an indicating whether authorization has succeeded.
+ /// The result's property is true when the policy has been fulfilled; otherwise false.
///
///
/// Resource is an optional parameter and may be null. Please ensure that you check it is not
diff --git a/src/aspnetcore/src/Shared/runtime/Http3/QPack/H3StaticTable.Http3.cs b/src/aspnetcore/src/Shared/runtime/Http3/QPack/H3StaticTable.Http3.cs
index aa157ab41b6..aee248efc78 100644
--- a/src/aspnetcore/src/Shared/runtime/Http3/QPack/H3StaticTable.Http3.cs
+++ b/src/aspnetcore/src/Shared/runtime/Http3/QPack/H3StaticTable.Http3.cs
@@ -1,24 +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.Collections.Generic;
using System.Text;
namespace System.Net.Http.QPack
{
internal static partial class H3StaticTable
{
- private static readonly Dictionary s_methodIndex = new Dictionary
- {
- // TODO connect is internal to system.net.http
- [HttpMethod.Delete] = 16,
- [HttpMethod.Get] = 17,
- [HttpMethod.Head] = 18,
- [HttpMethod.Options] = 19,
- [HttpMethod.Post] = 20,
- [HttpMethod.Put] = 21,
- };
-
public static bool TryGetStatusIndex(int status, out int index)
{
index = status switch
@@ -45,9 +33,6 @@ public static bool TryGetStatusIndex(int status, out int index)
public static int Count => s_staticTable.Length;
- // TODO: just use Dictionary directly to avoid interface dispatch.
- public static IReadOnlyDictionary MethodIndex => s_methodIndex;
-
public static ref readonly HeaderField Get(int index) => ref s_staticTable[index];
private static readonly HeaderField[] s_staticTable = new HeaderField[]
diff --git a/src/aspnetcore/src/SignalR/common/Http.Connections/src/ConnectionEndpointRouteBuilderExtensions.cs b/src/aspnetcore/src/SignalR/common/Http.Connections/src/ConnectionEndpointRouteBuilderExtensions.cs
index 8ed01395df6..f1aad8649e8 100644
--- a/src/aspnetcore/src/SignalR/common/Http.Connections/src/ConnectionEndpointRouteBuilderExtensions.cs
+++ b/src/aspnetcore/src/SignalR/common/Http.Connections/src/ConnectionEndpointRouteBuilderExtensions.cs
@@ -5,6 +5,7 @@
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Http.Connections;
using Microsoft.AspNetCore.Http.Connections.Internal;
+using Microsoft.AspNetCore.Http.Metadata;
using Microsoft.AspNetCore.Http.Timeouts;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
@@ -125,6 +126,9 @@ public static ConnectionEndpointRouteBuilder MapConnections(this IEndpointRouteB
{
e.Metadata.Add(data);
}
+
+ // Add IApiEndpointMetadata to indicate this is a non-browser endpoint (SignalR)
+ e.Metadata.Add(ApiEndpointMetadata.Instance);
});
return new ConnectionEndpointRouteBuilder(compositeConventionBuilder);
@@ -155,4 +159,9 @@ public void Finally(Action finalConvention)
}
}
}
+
+ private sealed class ApiEndpointMetadata : IApiEndpointMetadata
+ {
+ public static ApiEndpointMetadata Instance { get; } = new();
+ }
}
diff --git a/src/command-line-api/eng/Version.Details.props b/src/command-line-api/eng/Version.Details.props
new file mode 100644
index 00000000000..aa1fc141196
--- /dev/null
+++ b/src/command-line-api/eng/Version.Details.props
@@ -0,0 +1 @@
+
diff --git a/src/command-line-api/eng/Versions.props b/src/command-line-api/eng/Versions.props
index 62f4f4068b7..0d98696bb25 100644
--- a/src/command-line-api/eng/Versions.props
+++ b/src/command-line-api/eng/Versions.props
@@ -2,6 +2,9 @@
2.0.0
- beta7
+ rc
+ 1
+
+
diff --git a/src/command-line-api/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt b/src/command-line-api/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt
index 80214bd154c..cfac3fae653 100644
--- a/src/command-line-api/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt
+++ b/src/command-line-api/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt
@@ -178,6 +178,7 @@ System.CommandLine.Completions
System.CommandLine.Help
public class HelpAction : System.CommandLine.Invocation.SynchronousCommandLineAction
.ctor()
+ public System.Int32 MaxWidth { get; set; }
public System.Int32 Invoke(System.CommandLine.ParseResult parseResult)
public class HelpOption : System.CommandLine.Option
.ctor()
diff --git a/src/command-line-api/src/System.CommandLine.Tests/HelpOptionTests.cs b/src/command-line-api/src/System.CommandLine.Tests/HelpOptionTests.cs
index cfd85d795a2..27552bf8ace 100644
--- a/src/command-line-api/src/System.CommandLine.Tests/HelpOptionTests.cs
+++ b/src/command-line-api/src/System.CommandLine.Tests/HelpOptionTests.cs
@@ -230,6 +230,31 @@ public void The_users_can_print_help_output_of_a_subcommand()
output.ToString().Should().NotContain(RootDescription);
}
+ [Fact]
+ public void The_users_can_set_max_width()
+ {
+ string firstPart = new('a', count: 50);
+ string secondPart = new('b', count: 50);
+ string description = firstPart + secondPart;
+
+ RootCommand rootCommand = new(description);
+ rootCommand.Options.Clear();
+ rootCommand.Options.Add(new HelpOption()
+ {
+ Action = new HelpAction()
+ {
+ MaxWidth = 2 /* each line starts with two spaces */ + description.Length / 2
+ }
+ });
+ StringWriter output = new ();
+
+ rootCommand.Parse("--help").Invoke(new() { Output = output });
+
+ output.ToString().Should().NotContain(description);
+ output.ToString().Should().Contain($" {firstPart}{Environment.NewLine}");
+ output.ToString().Should().Contain($" {secondPart}{Environment.NewLine}");
+ }
+
private sealed class CustomizedHelpAction : SynchronousCommandLineAction
{
internal const string CustomUsageText = "This is custom command usage example.";
diff --git a/src/command-line-api/src/System.CommandLine/Help/HelpAction.cs b/src/command-line-api/src/System.CommandLine/Help/HelpAction.cs
index c04a8db53af..8b6460631a6 100644
--- a/src/command-line-api/src/System.CommandLine/Help/HelpAction.cs
+++ b/src/command-line-api/src/System.CommandLine/Help/HelpAction.cs
@@ -8,13 +8,47 @@ namespace System.CommandLine.Help
public sealed class HelpAction : SynchronousCommandLineAction
{
private HelpBuilder? _builder;
+ private int _maxWidth = -1;
+
+ ///
+ /// The maximum width in characters after which help output is wrapped.
+ ///
+ /// It defaults to .
+ public int MaxWidth
+ {
+ get
+ {
+ if (_maxWidth < 0)
+ {
+ try
+ {
+ _maxWidth = Console.IsOutputRedirected ? int.MaxValue : Console.WindowWidth;
+ }
+ catch (Exception)
+ {
+ _maxWidth = int.MaxValue;
+ }
+ }
+
+ return _maxWidth;
+ }
+ set
+ {
+ if (value <= 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(value));
+ }
+
+ _maxWidth = value;
+ }
+ }
///
/// Specifies an to be used to format help output when help is requested.
///
internal HelpBuilder Builder
{
- get => _builder ??= new HelpBuilder(Console.IsOutputRedirected ? int.MaxValue : Console.WindowWidth);
+ get => _builder ??= new HelpBuilder(MaxWidth);
set => _builder = value ?? throw new ArgumentNullException(nameof(value));
}
@@ -32,4 +66,4 @@ public override int Invoke(ParseResult parseResult)
return 0;
}
}
-}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/diagnostics/eng/Version.Details.xml b/src/diagnostics/eng/Version.Details.xml
index 260c35a22a7..24dddd69c8e 100644
--- a/src/diagnostics/eng/Version.Details.xml
+++ b/src/diagnostics/eng/Version.Details.xml
@@ -9,6 +9,10 @@
https://github.com/microsoft/clrmd
d724947392626b66e39b525998a8817447d50380
+
+ https://github.com/dotnet/android
+ bf304cf475308547a2a1a342bb9f2e6825cc33cd
+
diff --git a/src/diagnostics/eng/Versions.props b/src/diagnostics/eng/Versions.props
index 8e96ea5ed8c..e01e55b9a45 100644
--- a/src/diagnostics/eng/Versions.props
+++ b/src/diagnostics/eng/Versions.props
@@ -72,6 +72,7 @@
10.0.26100.1
13.0.1
10.0.622304
+ 1.0.105-preview.225
diff --git a/src/msbuild/documentation/wiki/Building-Testing-and-Debugging-on-.Net-Core-MSBuild.md b/src/msbuild/documentation/wiki/Building-Testing-and-Debugging-on-.Net-Core-MSBuild.md
index bb95bf7dcc7..fd3c5ca1717 100644
--- a/src/msbuild/documentation/wiki/Building-Testing-and-Debugging-on-.Net-Core-MSBuild.md
+++ b/src/msbuild/documentation/wiki/Building-Testing-and-Debugging-on-.Net-Core-MSBuild.md
@@ -44,8 +44,25 @@ Set the environment variable `MSBUILDDEBUGONSTART` to `2`, then attach a debugge
## Using the repository binaries to perform builds
-To build projects using the MSBuild binaries from the repository, you first need to execute the build command (`build.cmd`). This generates a bootstrap directory that emulates either a Visual Studio environment (full framework version) in the `net472` folder or a .NET Core environment in the `core` folder.
+## Run tests from the command line
-Next, navigate to the `core` folder and run the dotnet executable from this location using the following syntax: `artifacts/bin/bootstrap/core/dotnet.exe `. Replace `` with any valid dotnet command (such as `build`, `restore`, `test`, etc.) and `` with the path to your project file.
+```shell
+build.cmd # to have a full build first
+.\artifacts\msbuild-build-env.bat
+cd test\YOURTEST.Tests # cd to the test folder that contains the test csproj file
+dotnet test --filter "FullyQualifiedName~TESTNAME" # run individual test
+```
-See other debugging options [here](./Building-Testing-and-Debugging-on-Full-Framework-MSBuild.md#Debugging-MSBuild).
+## Run tests in Visual Studio
+
+Use developer command prompt for Visual Studio or put devenv on you PATH
+
+```shell
+build.cmd # to have a full build first
+.\artifacts\msbuild-build-env.bat
+devenv MSBuild.sln
+```
+
+Note again that in Visual studio "Use previews of the .NET SDK (requires restart)" must be checked. See the above comment for how to enable this.
+
+See other debugging options [here](./Building-Testing-and-Debugging-on-Full-Framework-MSBuild.md#Debugging-MSBuild).
\ No newline at end of file
diff --git a/src/msbuild/eng/BootStrapMsBuild.targets b/src/msbuild/eng/BootStrapMsBuild.targets
index f8163ff1d89..2466f17e7dd 100644
--- a/src/msbuild/eng/BootStrapMsBuild.targets
+++ b/src/msbuild/eng/BootStrapMsBuild.targets
@@ -251,18 +251,6 @@
-
-
-
- $([System.IO.File]::ReadAllText('$(InstallDir)\global.json'))
- $([System.Text.RegularExpressions.Regex]::Replace($(GlobalJsonContent), ',?\s*"paths":\s*\[[^\]]*\]', ''))
-
-
-
-
diff --git a/src/msbuild/eng/Version.Details.xml b/src/msbuild/eng/Version.Details.xml
index 4fa10a7f1ee..ea1db739dcd 100644
--- a/src/msbuild/eng/Version.Details.xml
+++ b/src/msbuild/eng/Version.Details.xml
@@ -112,9 +112,9 @@
-
+
https://github.com/dotnet/arcade
- 4e526204e83e615efe8eb5743be7fbccfa4e492a
+ d777c20040bdc2e52b372fa98dcb84141ed692d3
https://github.com/nuget/nuget.client
@@ -124,9 +124,9 @@
https://github.com/dotnet/roslyn
a8d4395106dcc0d720dd7d1a838661a0ca7cf939
-
+
https://github.com/dotnet/arcade
- 4e526204e83e615efe8eb5743be7fbccfa4e492a
+ d777c20040bdc2e52b372fa98dcb84141ed692d3
diff --git a/src/msbuild/eng/Versions.props b/src/msbuild/eng/Versions.props
index 687a6db67e5..478551f3d14 100644
--- a/src/msbuild/eng/Versions.props
+++ b/src/msbuild/eng/Versions.props
@@ -79,7 +79,7 @@
$([System.Text.RegularExpressions.Regex]::Match($([System.IO.File]::ReadAllText('$(MSBuildThisFileDirectory)..\global.json')), '"dotnet": "([^"]*)"').Groups.get_Item(1))
- 10.0.0-beta.25358.3
+ 10.0.0-beta.25367.5
6.15.0-preview.1.86
5.0.0-2.25369.9
@@ -92,7 +92,7 @@
5.0.0-1.25277.114
- 10.0.100-preview.6.25315.102
+ 10.0.100-preview.7.25322.101
diff --git a/src/sdk/documentation/general/dotnet-run-file.md b/src/sdk/documentation/general/dotnet-run-file.md
index 0c75aa0910d..2a06c445a56 100644
--- a/src/sdk/documentation/general/dotnet-run-file.md
+++ b/src/sdk/documentation/general/dotnet-run-file.md
@@ -45,6 +45,8 @@ Additionally, the implicit project file has the following customizations:
string? directoryPath = AppContext.GetData("EntryPointFileDirectoryPath") as string;
```
+ - `FileBasedProgram` property is set to `true` and can be used by SDK targets to detect file-based apps.
+
## Grow up
When file-based programs reach an inflection point where build customizations in a project file are needed,
diff --git a/src/sdk/eng/Version.Details.xml b/src/sdk/eng/Version.Details.xml
index 9f754a26ef5..43ef9807098 100644
--- a/src/sdk/eng/Version.Details.xml
+++ b/src/sdk/eng/Version.Details.xml
@@ -499,6 +499,10 @@
https://github.com/dotnet/dotnet
f451e5d3036a4f140a989e0a7f3f1ae432420e71
+
+ https://github.com/dotnet/dotnet
+ f451e5d3036a4f140a989e0a7f3f1ae432420e71
+
https://github.com/dotnet/dotnet
f451e5d3036a4f140a989e0a7f3f1ae432420e71
@@ -561,13 +565,13 @@
https://github.com/dotnet/arcade-services
448a29d2d2e4e27303f728202602708ed45838f5
-
+
https://github.com/microsoft/testfx
- 639e5cd9730d9642d93c2828b1e4686a164e040c
+ 4a8fcdaacd6ff086be895fc4aaf9e5c7d49e9f24
-
+
https://github.com/microsoft/testfx
- 639e5cd9730d9642d93c2828b1e4686a164e040c
+ 4a8fcdaacd6ff086be895fc4aaf9e5c7d49e9f24
https://github.com/dotnet/dotnet
diff --git a/src/sdk/eng/Versions.props b/src/sdk/eng/Versions.props
index 64c4292a183..bf12684fe36 100644
--- a/src/sdk/eng/Versions.props
+++ b/src/sdk/eng/Versions.props
@@ -30,7 +30,7 @@
true
true
- 1.8.0-preview.25369.5
+ 1.8.0-preview.25371.5
30
@@ -39,8 +39,8 @@
36
20
- 16
- 5
+ 17
+ 6
<_NET70ILLinkPackVersion>7.0.100-1.23211.1
@@ -119,6 +119,7 @@
10.0.0-preview.7.25359.101
10.0.0-preview.7.25359.101
10.0.0-preview.7.25359.101
+ 10.0.0-preview.7.25359.101
10.0.0-preview.7.25359.101
10.0.0-preview.7.25359.101
10.0.0-preview.7.25359.101
@@ -311,7 +312,7 @@
8.0.2
8.0.0
4.18.4
- 3.10.0-preview.25369.5
+ 3.10.0-preview.25371.5
1.3.2
8.0.0-beta.23607.1
0.14.0
diff --git a/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/Activities.cs b/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/Activities.cs
new file mode 100644
index 00000000000..9f466557243
--- /dev/null
+++ b/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/Activities.cs
@@ -0,0 +1,20 @@
+// 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;
+
+namespace Microsoft.DotNet.Cli.Utils;
+
+///
+/// Contains helpers for working with Activities in the .NET CLI.
+///
+public static class Activities
+{
+
+ ///
+ /// The main entrypoint for creating Activities in the .NET CLI.
+ /// All activities created in the CLI should use this , to allow
+ /// consumers to easily filter and trace CLI activities.
+ ///
+ public static ActivitySource Source { get; } = new("dotnet-cli", Product.Version);
+}
diff --git a/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/ForwardingAppImplementation.cs b/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/ForwardingAppImplementation.cs
index f6acb60ea0a..1b2058d1774 100644
--- a/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/ForwardingAppImplementation.cs
+++ b/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/ForwardingAppImplementation.cs
@@ -19,7 +19,7 @@ internal class ForwardingAppImplementation
private readonly string? _depsFile;
private readonly string? _runtimeConfig;
private readonly string? _additionalProbingPath;
- private Dictionary _environmentVariables;
+ private Dictionary _environmentVariables;
private readonly string[] _allArgs;
@@ -29,7 +29,7 @@ public ForwardingAppImplementation(
string? depsFile = null,
string? runtimeConfig = null,
string? additionalProbingPath = null,
- Dictionary? environmentVariables = null)
+ Dictionary? environmentVariables = null)
{
_forwardApplicationPath = forwardApplicationPath;
_argsToForward = argsToForward;
@@ -86,7 +86,7 @@ public ProcessStartInfo GetProcessStartInfo()
return processInfo;
}
- public ForwardingAppImplementation WithEnvironmentVariable(string name, string value)
+ public ForwardingAppImplementation WithEnvironmentVariable(string name, string? value)
{
_environmentVariables.Add(name, value);
diff --git a/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs b/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs
index 2e95365623a..64e6fea0ccf 100644
--- a/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs
+++ b/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs
@@ -39,7 +39,7 @@ public static string MSBuildVersion
// True if, given current state of the class, MSBuild would be executed in its own process.
public bool ExecuteMSBuildOutOfProc => _forwardingApp != null;
- private readonly Dictionary _msbuildRequiredEnvironmentVariables = GetMSBuildRequiredEnvironmentVariables();
+ private readonly Dictionary _msbuildRequiredEnvironmentVariables = GetMSBuildRequiredEnvironmentVariables();
private readonly List _msbuildRequiredParameters = [ "-maxcpucount", "--verbosity:m" ];
@@ -112,7 +112,7 @@ private static string EmitProperty(KeyValuePair property, string
: $"--{label}:{property.Key}={property.Value}";
}
- public void EnvironmentVariable(string name, string value)
+ public void EnvironmentVariable(string name, string? value)
{
if (_forwardingApp != null)
{
@@ -153,7 +153,7 @@ public int ExecuteInProc(string[] arguments)
Dictionary savedEnvironmentVariables = [];
try
{
- foreach (KeyValuePair kvp in _msbuildRequiredEnvironmentVariables)
+ foreach (KeyValuePair kvp in _msbuildRequiredEnvironmentVariables)
{
savedEnvironmentVariables[kvp.Key] = Environment.GetEnvironmentVariable(kvp.Key);
Environment.SetEnvironmentVariable(kvp.Key, kvp.Value);
@@ -218,7 +218,7 @@ private static string GetDotnetPath()
return new Muxer().MuxerPath;
}
- internal static Dictionary GetMSBuildRequiredEnvironmentVariables()
+ internal static Dictionary GetMSBuildRequiredEnvironmentVariables()
{
return new()
{
diff --git a/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj b/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj
index 97bfea50c79..b64200efdad 100644
--- a/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj
+++ b/src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj
@@ -57,5 +57,9 @@
+
+
+
+
diff --git a/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs b/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs
index f3ef9d93a44..67c2a47f105 100644
--- a/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs
+++ b/src/sdk/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs
@@ -59,7 +59,7 @@ public MSBuildForwardingApp(MSBuildArgs msBuildArgs, string? msbuildPath = null,
public IEnumerable MSBuildArguments { get { return _forwardingAppWithoutLogging.GetAllArguments(); } }
- public void EnvironmentVariable(string name, string value)
+ public void EnvironmentVariable(string name, string? value)
{
_forwardingAppWithoutLogging.EnvironmentVariable(name, value);
}
diff --git a/src/sdk/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs b/src/sdk/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs
index 93738284837..5386123d7cb 100644
--- a/src/sdk/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs
+++ b/src/sdk/src/Cli/dotnet/Commands/Run/VirtualProjectBuildingCommand.cs
@@ -63,6 +63,18 @@ internal sealed class VirtualProjectBuildingCommand : CommandBase
"MSBuild.rsp",
];
+ ///
+ /// Kept in sync with the default dotnet new console project file (enforced by DotnetProjectAddTests.SameAsTemplate).
+ ///
+ private static readonly FrozenDictionary s_defaultProperties = FrozenDictionary.Create(StringComparer.OrdinalIgnoreCase,
+ [
+ new("OutputType", "Exe"),
+ new("TargetFramework", "net10.0"),
+ new("ImplicitUsings", "enable"),
+ new("Nullable", "enable"),
+ new("PublishAot", "true"),
+ ]);
+
internal static readonly string TargetOverrides = """
-
""");
+
+ if (firstSdkVersion is null)
+ {
+ writer.WriteLine($"""
+
+ """);
+ }
+ else
+ {
+ writer.WriteLine($"""
+
+ """);
+ }
}
else
{
+ string slashDelimited = firstSdkVersion is null
+ ? firstSdkName
+ : $"{firstSdkName}/{firstSdkVersion}";
writer.WriteLine($"""
-
+
""");
}
@@ -697,34 +732,33 @@ public static void WriteProjectFile(
writer.WriteLine();
}
- // Kept in sync with the default `dotnet new console` project file (enforced by `DotnetProjectAddTests.SameAsTemplate`).
- writer.WriteLine($"""
-
- Exe
- net10.0
- enable
- enable
- true
-
- """);
-
- if (isVirtualProject)
+ // Write default and custom properties.
{
writer.WriteLine("""
-
- false
-
""");
- }
- if (propertyDirectives.Any())
- {
- writer.WriteLine("""
+ // First write the default properties except those specified by the user.
+ var customPropertyNames = propertyDirectives.Select(d => d.Name).ToHashSet(StringComparer.OrdinalIgnoreCase);
+ foreach (var (name, value) in s_defaultProperties)
+ {
+ if (!customPropertyNames.Contains(name))
+ {
+ writer.WriteLine($"""
+ <{name}>{EscapeValue(value)}{name}>
+ """);
+ }
+ }
-
- """);
+ // Write virtual-only properties.
+ if (isVirtualProject)
+ {
+ writer.WriteLine("""
+ false
+ """);
+ }
+ // Write custom properties.
foreach (var property in propertyDirectives)
{
writer.WriteLine($"""
@@ -734,24 +768,23 @@ public static void WriteProjectFile(
processedDirectives++;
}
- writer.WriteLine(" ");
- }
+ // Write virtual-only properties which cannot be overridden.
+ if (isVirtualProject)
+ {
+ writer.WriteLine("""
+ $(Features);FileBasedProgram
+ """);
+ }
- if (isVirtualProject)
- {
- // After `#:property` directives so they don't override this.
writer.WriteLine("""
-
-
- $(Features);FileBasedProgram
+
""");
}
if (packageDirectives.Any())
{
writer.WriteLine("""
-
""");
@@ -773,13 +806,15 @@ public static void WriteProjectFile(
processedDirectives++;
}
- writer.WriteLine(" ");
+ writer.WriteLine("""
+
+
+ """);
}
if (projectDirectives.Any())
{
writer.WriteLine("""
-
""");
@@ -792,7 +827,10 @@ public static void WriteProjectFile(
processedDirectives++;
}
- writer.WriteLine(" ");
+ writer.WriteLine("""
+
+
+ """);
}
Debug.Assert(processedDirectives + directives.OfType().Count() == directives.Length);
@@ -802,7 +840,6 @@ public static void WriteProjectFile(
Debug.Assert(targetFilePath is not null);
writer.WriteLine($"""
-
@@ -813,12 +850,12 @@ public static void WriteProjectFile(
{
var targetDirectory = Path.GetDirectoryName(targetFilePath) ?? "";
writer.WriteLine($"""
-
-
-
-
+
+
+
+
- """);
+ """);
}
foreach (var sdk in sdkDirectives)
@@ -828,18 +865,20 @@ public static void WriteProjectFile(
if (!sdkDirectives.Any())
{
- Debug.Assert(sdkValue == "Microsoft.NET.Sdk");
+ Debug.Assert(firstSdkName == "Microsoft.NET.Sdk" && firstSdkVersion == null);
writer.WriteLine("""
""");
}
- writer.WriteLine();
- writer.WriteLine(TargetOverrides);
+ writer.WriteLine($"""
+
+ {TargetOverrides}
+
+ """);
}
writer.WriteLine("""
-
""");
@@ -1188,11 +1227,6 @@ private Sdk() { }
Version = sdkVersion,
};
}
-
- public string ToSlashDelimitedString()
- {
- return Version is null ? Name : $"{Name}/{Version}";
- }
}
///
diff --git a/src/sdk/src/Cli/dotnet/Telemetry/Telemetry.cs b/src/sdk/src/Cli/dotnet/Telemetry/Telemetry.cs
index 28851da921b..ba190b16950 100644
--- a/src/sdk/src/Cli/dotnet/Telemetry/Telemetry.cs
+++ b/src/sdk/src/Cli/dotnet/Telemetry/Telemetry.cs
@@ -1,8 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-#nullable disable
-
+using System.Collections.Frozen;
using System.Diagnostics;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;
@@ -14,13 +13,13 @@ namespace Microsoft.DotNet.Cli.Telemetry;
public class Telemetry : ITelemetry
{
- internal static string CurrentSessionId = null;
+ internal static string? CurrentSessionId = null;
internal static bool DisabledForTests = false;
private readonly int _senderCount;
- private TelemetryClient _client = null;
- private Dictionary _commonProperties = null;
- private Dictionary _commonMeasurements = null;
- private Task _trackEventTask = null;
+ private TelemetryClient? _client = null;
+ private FrozenDictionary? _commonProperties = null;
+ private FrozenDictionary? _commonMeasurements = null;
+ private Task? _trackEventTask = null;
private const string ConnectionString = "InstrumentationKey=74cc1c9e-3e6e-4d05-b3fc-dde9101d0254";
@@ -28,13 +27,13 @@ public class Telemetry : ITelemetry
public Telemetry() : this(null) { }
- public Telemetry(IFirstTimeUseNoticeSentinel sentinel) : this(sentinel, null) { }
+ public Telemetry(IFirstTimeUseNoticeSentinel? sentinel) : this(sentinel, null) { }
public Telemetry(
- IFirstTimeUseNoticeSentinel sentinel,
- string sessionId,
+ IFirstTimeUseNoticeSentinel? sentinel,
+ string? sessionId,
bool blockThreadInitialization = false,
- IEnvironmentProvider environmentProvider = null,
+ IEnvironmentProvider? environmentProvider = null,
int senderCount = 3)
{
@@ -78,7 +77,7 @@ internal static void EnableForTests()
DisabledForTests = false;
}
- private static bool PermissionExists(IFirstTimeUseNoticeSentinel sentinel)
+ private static bool PermissionExists(IFirstTimeUseNoticeSentinel? sentinel)
{
if (sentinel == null)
{
@@ -97,9 +96,17 @@ public void TrackEvent(string eventName, IDictionary properties,
}
//continue the task in different threads
- _trackEventTask = _trackEventTask.ContinueWith(
- x => TrackEventTask(eventName, properties, measurements)
- );
+ if (_trackEventTask == null)
+ {
+ _trackEventTask = Task.Run(() => TrackEventTask(eventName, properties, measurements));
+ return;
+ }
+ else
+ {
+ _trackEventTask = _trackEventTask.ContinueWith(
+ x => TrackEventTask(eventName, properties, measurements)
+ );
+ }
}
public void Flush()
@@ -148,7 +155,7 @@ private void InitializeTelemetry()
_client.Context.Device.OperatingSystem = CLIRuntimeEnvironment.OperatingSystem;
_commonProperties = new TelemetryCommonProperties().GetTelemetryCommonProperties();
- _commonMeasurements = [];
+ _commonMeasurements = FrozenDictionary.Empty;
}
catch (Exception e)
{
@@ -170,12 +177,14 @@ private void TrackEventTask(
try
{
- Dictionary eventProperties = GetEventProperties(properties);
- Dictionary eventMeasurements = GetEventMeasures(measurements);
+ var eventProperties = GetEventProperties(properties);
+ var eventMeasurements = GetEventMeasures(measurements);
+ eventProperties ??= new Dictionary();
eventProperties.Add("event id", Guid.NewGuid().ToString());
_client.TrackEvent(PrependProducerNamespace(eventName), eventProperties, eventMeasurements);
+ Activity.Current?.AddEvent(CreateActivityEvent(eventName, eventProperties, eventMeasurements));
}
catch (Exception e)
{
@@ -183,35 +192,72 @@ private void TrackEventTask(
}
}
- private static string PrependProducerNamespace(string eventName)
+ private static ActivityEvent CreateActivityEvent(
+ string eventName,
+ IDictionary? properties,
+ IDictionary? measurements)
{
- return "dotnet/cli/" + eventName;
+ var tags = MakeTags(properties, measurements);
+ return new ActivityEvent(
+ PrependProducerNamespace(eventName),
+ tags: tags);
}
- private Dictionary GetEventMeasures(IDictionary measurements)
+ private static ActivityTagsCollection? MakeTags(
+ IDictionary? properties,
+ IDictionary? measurements)
{
- Dictionary eventMeasurements = new(_commonMeasurements);
- if (measurements != null)
+ if (properties == null && measurements == null)
{
- foreach (KeyValuePair measurement in measurements)
- {
- eventMeasurements[measurement.Key] = measurement.Value;
- }
+ return null;
+ }
+ else if (properties != null && measurements == null)
+ {
+ return [.. properties.Select(p => new KeyValuePair(p.Key, p.Value))];
+ }
+ else if (properties == null && measurements != null)
+ {
+ return [.. measurements.Select(m => new KeyValuePair(m.Key, m.Value.ToString()))];
}
- return eventMeasurements;
+ else return [ .. properties!.Select(p => new KeyValuePair(p.Key, p.Value)),
+ .. measurements!.Select(m => new KeyValuePair(m.Key, m.Value.ToString())) ];
}
- private Dictionary GetEventProperties(IDictionary properties)
+ private static string PrependProducerNamespace(string eventName) => $"dotnet/cli/{eventName}";
+
+ private IDictionary? GetEventMeasures(IDictionary? measurements)
{
- var eventProperties = new Dictionary(_commonProperties);
- if (properties != null)
+ return (measurements, _commonMeasurements) switch
{
- foreach (KeyValuePair property in properties)
- {
- eventProperties[property.Key] = property.Value;
- }
- }
+ (null, null) => null,
+ (null, not null) => _commonMeasurements == FrozenDictionary.Empty ? null : new Dictionary(_commonMeasurements),
+ (not null, null) => measurements,
+ (not null, not null) => Combine(_commonMeasurements, measurements),
+ };
+ }
- return eventProperties;
+ private IDictionary? GetEventProperties(IDictionary? properties)
+ {
+ return (properties, _commonProperties) switch
+ {
+ (null, null) => null,
+ (null, not null) => _commonProperties == FrozenDictionary.Empty ? null : new Dictionary(_commonProperties),
+ (not null, null) => properties,
+ (not null, not null) => Combine(_commonProperties, properties),
+ };
}
+
+ static IDictionary Combine(IDictionary common, IDictionary specific) where TKey : notnull
+ {
+ IDictionary eventMeasurements = new Dictionary(capacity: common.Count + specific.Count);
+ foreach (KeyValuePair measurement in common)
+ {
+ eventMeasurements[measurement.Key] = measurement.Value;
+ }
+ foreach (KeyValuePair measurement in specific)
+ {
+ eventMeasurements[measurement.Key] = measurement.Value;
+ }
+ return eventMeasurements;
+ }
}
diff --git a/src/sdk/src/Cli/dotnet/Telemetry/TelemetryCommonProperties.cs b/src/sdk/src/Cli/dotnet/Telemetry/TelemetryCommonProperties.cs
index 88b2c215210..9f58d488a12 100644
--- a/src/sdk/src/Cli/dotnet/Telemetry/TelemetryCommonProperties.cs
+++ b/src/sdk/src/Cli/dotnet/Telemetry/TelemetryCommonProperties.cs
@@ -3,6 +3,7 @@
#nullable disable
+using System.Collections.Frozen;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Configurer;
using RuntimeEnvironment = Microsoft.DotNet.Cli.Utils.RuntimeEnvironment;
@@ -52,7 +53,7 @@ internal class TelemetryCommonProperties(
private const string MachineIdCacheKey = "MachineId";
private const string IsDockerContainerCacheKey = "IsDockerContainer";
- public Dictionary GetTelemetryCommonProperties()
+ public FrozenDictionary GetTelemetryCommonProperties()
{
return new Dictionary
{
@@ -82,7 +83,7 @@ public Dictionary GetTelemetryCommonProperties()
{ProductType, ExternalTelemetryProperties.GetProductType()},
{LibcRelease, ExternalTelemetryProperties.GetLibcRelease()},
{LibcVersion, ExternalTelemetryProperties.GetLibcVersion()}
- };
+ }.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase);
}
private string GetMachineId()
diff --git a/src/sdk/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs b/src/sdk/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs
index b51640e9405..92cd3f5a5c8 100644
--- a/src/sdk/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs
+++ b/src/sdk/src/Containers/Microsoft.NET.Build.Containers/Tasks/ComputeDotnetBaseImageAndTag.cs
@@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics.CodeAnalysis;
-using System.Security.Cryptography;
using Microsoft.Build.Framework;
using NuGet.Versioning;
#if NETFRAMEWORK
diff --git a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.net5.0.cs b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.net5.0.cs
index 3c5fdd54512..6c829725385 100644
--- a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.net5.0.cs
+++ b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.net5.0.cs
@@ -20,7 +20,7 @@ internal static class NETCoreApp50
{ "System.Formats.Asn1", "5.0.0" },
{ "System.IO.FileSystem.AccessControl", "5.0.0" },
{ "System.Net.Http.Json", "5.0.0" },
- { "System.Reflection.DispatchProxy", "4.7.1" },
+ { "System.Reflection.DispatchProxy", "4.8.2" },
{ "System.Reflection.Metadata", "5.0.0" },
{ "System.Runtime.CompilerServices.Unsafe", "5.0.0" },
{ "System.Security.AccessControl", "5.0.0" },
diff --git a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.net6.0.cs b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.net6.0.cs
index 4c54ccc4c26..4fa9e725ca6 100644
--- a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.net6.0.cs
+++ b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.net6.0.cs
@@ -18,7 +18,7 @@ internal static class NETCoreApp60
{ "System.Formats.Asn1", "6.0.0" },
{ "System.Net.Http.Json", "6.0.0" },
{ "System.Reflection.Metadata", "6.0.0" },
- { "System.Runtime.CompilerServices.Unsafe", "6.0.0" },
+ { "System.Runtime.CompilerServices.Unsafe", "6.1.2" },
{ "System.Security.AccessControl", "6.0.0" },
{ "System.Text.Encoding.CodePages", "6.0.0" },
{ "System.Text.Encodings.Web", "6.0.0" },
diff --git a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netcoreapp2.1.cs b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netcoreapp2.1.cs
index 8de6482b456..9d5f293f924 100644
--- a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netcoreapp2.1.cs
+++ b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netcoreapp2.1.cs
@@ -17,14 +17,14 @@ internal static class NETCoreApp21
{ "Microsoft.NETCore.App", "2.1.0" },
{ "Microsoft.VisualBasic", "10.3.0" },
{ "Microsoft.Win32.Registry", "4.5.0" },
- { "System.Buffers", "4.5.0" },
+ { "System.Buffers", "4.6.1" },
{ "System.Collections.Immutable", "1.5.0" },
{ "System.ComponentModel.Annotations", "4.5.0" },
{ "System.Diagnostics.DiagnosticSource", "4.5.0" },
{ "System.IO.FileSystem.AccessControl", "4.5.0" },
{ "System.IO.Pipes.AccessControl", "4.5.0" },
- { "System.Memory", "4.5.5" },
- { "System.Numerics.Vectors", "4.5.0" },
+ { "System.Memory", "4.6.3" },
+ { "System.Numerics.Vectors", "4.6.1" },
{ "System.Reflection.DispatchProxy", "4.5.0" },
{ "System.Reflection.Metadata", "1.6.0" },
{ "System.Security.AccessControl", "4.5.0" },
@@ -32,8 +32,8 @@ internal static class NETCoreApp21
{ "System.Security.Cryptography.OpenSsl", "4.5.0" },
{ "System.Security.Principal.Windows", "4.5.0" },
{ "System.Threading.Tasks.Dataflow", "4.9.0" },
- { "System.Threading.Tasks.Extensions", "4.5.4" },
- { "System.ValueTuple", "4.5.0" },
+ { "System.Threading.Tasks.Extensions", "4.6.3" },
+ { "System.ValueTuple", "4.6.1" },
};
internal static void Register() => FrameworkPackages.Register(Instance);
diff --git a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netcoreapp3.0.cs b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netcoreapp3.0.cs
index d28e3f83c1f..f7619c05773 100644
--- a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netcoreapp3.0.cs
+++ b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netcoreapp3.0.cs
@@ -15,7 +15,7 @@ internal static class NETCoreApp30
{
{ "Microsoft.CSharp", "4.6.0" },
{ "Microsoft.Win32.Registry", "4.6.0" },
- { "System.Buffers", "4.5.1" },
+ { "System.Buffers", "4.6.1" },
{ "System.Collections.Immutable", "1.6.0" },
{ "System.ComponentModel.Annotations", "4.6.0" },
{ "System.Data.DataSetExtensions", "4.5.0" },
diff --git a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netcoreapp3.1.cs b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netcoreapp3.1.cs
index 38e20c6df52..719389380bc 100644
--- a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netcoreapp3.1.cs
+++ b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netcoreapp3.1.cs
@@ -19,7 +19,7 @@ internal static class NETCoreApp31
{ "System.ComponentModel.Annotations", "4.7.0" },
{ "System.Diagnostics.DiagnosticSource", "4.7.0" },
{ "System.IO.FileSystem.AccessControl", "4.7.0" },
- { "System.Reflection.DispatchProxy", "4.7.0" },
+ { "System.Reflection.DispatchProxy", "4.8.2" },
{ "System.Reflection.Metadata", "1.8.0" },
{ "System.Runtime.CompilerServices.Unsafe", "4.7.1" },
{ "System.Runtime.WindowsRuntime", "4.7.0" },
diff --git a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netstandard2.0.cs b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netstandard2.0.cs
index f9ab0f22bd5..12907371a50 100644
--- a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netstandard2.0.cs
+++ b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netstandard2.0.cs
@@ -98,7 +98,7 @@ internal static class NETStandard20
{ "System.Threading.Thread", "4.3.0" },
{ "System.Threading.ThreadPool", "4.3.0" },
{ "System.Threading.Timer", "4.3.0" },
- { "System.ValueTuple", "4.4.0" },
+ { "System.ValueTuple", "4.6.1" },
{ "System.Xml.ReaderWriter", "4.3.1" },
{ "System.Xml.XDocument", "4.0.11" },
{ "System.Xml.XmlDocument", "4.3.0" },
diff --git a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netstandard2.1.cs b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netstandard2.1.cs
index b746ac664a6..bb4c3474f2d 100644
--- a/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netstandard2.1.cs
+++ b/src/sdk/src/Tasks/Microsoft.NET.Build.Tasks/FrameworkPackages/FrameworkPackages.netstandard2.1.cs
@@ -13,7 +13,7 @@ internal static class NETStandard21
{
internal static FrameworkPackages Instance { get; } = new(NetStandard21, FrameworkNames.NetStandardLibrary, NETStandard20.Instance)
{
- { "System.Buffers", "4.5.1" },
+ { "System.Buffers", "4.6.1" },
{ "System.Collections.Concurrent", "4.3.0" },
{ "System.Collections.Immutable", "1.4.0" },
{ "System.ComponentModel", "4.3.0" },
@@ -22,10 +22,10 @@ internal static class NETStandard21
{ "System.Diagnostics.Contracts", "4.3.0" },
{ "System.Dynamic.Runtime", "4.3.0" },
{ "System.Linq.Queryable", "4.3.0" },
- { "System.Memory", "4.5.5" },
+ { "System.Memory", "4.6.3" },
{ "System.Net.Requests", "4.3.0" },
{ "System.Net.WebHeaderCollection", "4.3.0" },
- { "System.Numerics.Vectors", "4.5.0" },
+ { "System.Numerics.Vectors", "4.6.1" },
{ "System.ObjectModel", "4.3.0" },
{ "System.Private.DataContractSerialization", "4.3.0" },
{ "System.Reflection.DispatchProxy", "4.5.1" },
@@ -42,7 +42,7 @@ internal static class NETStandard21
{ "System.Security.Principal", "4.3.0" },
{ "System.Security.Principal.Windows", "4.4.0" },
{ "System.Threading", "4.3.0" },
- { "System.Threading.Tasks.Extensions", "4.5.4" },
+ { "System.Threading.Tasks.Extensions", "4.6.3" },
{ "System.Threading.Tasks.Parallel", "4.3.0" },
{ "System.Xml.XDocument", "4.3.0" },
{ "System.Xml.XmlSerializer", "4.3.0" },
diff --git a/src/sdk/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs b/src/sdk/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs
index e07855c873e..082f5c5ecd2 100644
--- a/src/sdk/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs
+++ b/src/sdk/test/dotnet.Tests/CommandTests/Project/Convert/DotnetProjectConvertTests.cs
@@ -642,26 +642,22 @@ public void Directives()
#!/program
#:sdk Microsoft.NET.Sdk
#:sdk Aspire.Hosting.Sdk@9.1.0
- #:property TargetFramework=net11.0
+ #:property TargetFramework=net472
#:package System.CommandLine@2.0.0-beta4.22272.1
#:property LangVersion=preview
Console.WriteLine();
""",
- expectedProject: $"""
+ expectedProject: """
Exe
- {ToolsetInfo.CurrentTargetFramework}
enable
enable
true
-
-
-
- net11.0
+ net472
preview
@@ -677,6 +673,44 @@ public void Directives()
""");
}
+ ///
+ /// There should be only one PropertyGroup element when the default properties are overridden.
+ ///
+ [Fact]
+ public void Directives_AllDefaultOverridden()
+ {
+ VerifyConversion(
+ inputCSharp: """
+ #!/program
+ #:sdk Microsoft.NET.Web.Sdk
+ #:property OutputType=Exe
+ #:property TargetFramework=net472
+ #:property Nullable=disable
+ #:property PublishAot=false
+ #:property Custom=1
+ #:property ImplicitUsings=disable
+ Console.WriteLine();
+ """,
+ expectedProject: """
+
+
+
+ Exe
+ net472
+ disable
+ false
+ 1
+ disable
+
+
+
+
+ """,
+ expectedCSharp: """
+ Console.WriteLine();
+ """);
+ }
+
[Fact]
public void Directives_Variable()
{
@@ -694,9 +728,6 @@ public void Directives_Variable()
enable
enable
true
-
-
-
MyValue
@@ -772,9 +803,6 @@ public void Directives_Separators()
enable
enable
true
-
-
-
One=a/b
Two/a=b
@@ -884,9 +912,6 @@ public void Directives_Escaping()
enable
enable
true
-
-
-
<test">
@@ -921,9 +946,6 @@ public void Directives_Whitespace()
enable
enable
true
-
-
-
Value
"My package with spaces"
@@ -968,9 +990,6 @@ public void Directives_AfterToken()
enable
enable
true
-
-
-
1
2
@@ -1017,9 +1036,6 @@ public void Directives_AfterIf()
enable
enable
true
-
-
-
1
2
@@ -1063,9 +1079,6 @@ public void Directives_Comments()
enable
enable
true
-
-
-
1
2
@@ -1156,6 +1169,33 @@ public void Directives_Duplicate()
]);
}
+ [Fact] // https://github.com/dotnet/sdk/issues/49797
+ public void Directives_VersionedSdkFirst()
+ {
+ VerifyConversion(
+ inputCSharp: """
+ #:sdk Microsoft.NET.Sdk@9.0.0
+ Console.WriteLine();
+ """,
+ expectedProject: $"""
+
+
+
+ Exe
+ {ToolsetInfo.CurrentTargetFramework}
+ enable
+ enable
+ true
+
+
+
+
+ """,
+ expectedCSharp: """
+ Console.WriteLine();
+ """);
+ }
+
private static void Convert(string inputCSharp, out string actualProject, out string? actualCSharp, bool force, string? filePath)
{
var sourceFile = new SourceFile(filePath ?? "/app/Program.cs", SourceText.From(inputCSharp, Encoding.UTF8));
diff --git a/src/sdk/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs b/src/sdk/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs
index ad76071ae24..012a920081e 100644
--- a/src/sdk/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs
+++ b/src/sdk/test/dotnet.Tests/CommandTests/Run/RunFileTests.cs
@@ -1565,6 +1565,21 @@ public void SdkReference()
.Should().Pass();
}
+ [Fact] // https://github.com/dotnet/sdk/issues/49797
+ public void SdkReference_VersionedSdkFirst()
+ {
+ var testInstance = _testAssetsManager.CreateTestDirectory();
+ File.WriteAllText(Path.Join(testInstance.Path, "Program.cs"), """
+ #:sdk Microsoft.NET.Sdk@9.0.0
+ Console.WriteLine();
+ """);
+
+ new DotnetCommand(Log, "build", "Program.cs")
+ .WithWorkingDirectory(testInstance.Path)
+ .Execute()
+ .Should().Pass();
+ }
+
[Theory]
[InlineData("../Lib/Lib.csproj")]
[InlineData("../Lib")]
@@ -1856,6 +1871,7 @@ public void Api()
false
/artifacts
artifacts/$(MSBuildProjectName)
+ true
@@ -1868,22 +1884,12 @@ public void Api()
Exe
- {ToolsetInfo.CurrentTargetFramework}
enable
enable
true
-
-
-
false
-
-
-
net11.0
preview
-
-
-
$(Features);FileBasedProgram
@@ -1935,6 +1941,7 @@ public void Api_Diagnostic_01()
false
/artifacts
artifacts/$(MSBuildProjectName)
+ true
@@ -1950,13 +1957,7 @@ public void Api_Diagnostic_01()
enable
enable
true
-
-
-
false
-
-
-
$(Features);FileBasedProgram
@@ -2007,6 +2008,7 @@ public void Api_Diagnostic_02()
false
/artifacts
artifacts/$(MSBuildProjectName)
+ true
@@ -2022,13 +2024,7 @@ public void Api_Diagnostic_02()
enable
enable
true
-
-
-
false
-
-
-
$(Features);FileBasedProgram
diff --git a/src/source-manifest.json b/src/source-manifest.json
index d23758f02d4..93508d62c58 100644
--- a/src/source-manifest.json
+++ b/src/source-manifest.json
@@ -1,16 +1,16 @@
{
"repositories": [
{
- "barId": 276435,
+ "barId": 276631,
"path": "arcade",
"remoteUri": "https://github.com/dotnet/arcade",
- "commitSha": "2586309f3f8553152e2d1d54612e9199975f9cd4"
+ "commitSha": "0fbc9e8711fa91e68c2bf3db376fb83b46f4ac35"
},
{
- "barId": 276473,
+ "barId": 276610,
"path": "aspnetcore",
"remoteUri": "https://github.com/dotnet/aspnetcore",
- "commitSha": "c56ce2f92858158819569e11d4131c09fd847764"
+ "commitSha": "bf1f642be9fe230fed38e10561d4aa9ed5859b8f"
},
{
"barId": 276375,
@@ -19,10 +19,10 @@
"commitSha": "2478ada175a4089ab1310960d2590810e9adc4f9"
},
{
- "barId": 275338,
+ "barId": 276722,
"path": "command-line-api",
"remoteUri": "https://github.com/dotnet/command-line-api",
- "commitSha": "dbc3781d3398b69cd9ffe24f60a7b77110bdadbf"
+ "commitSha": "3a3e014313d2c1bddc01b4333886783a7492c652"
},
{
"barId": 276378,
@@ -31,16 +31,16 @@
"commitSha": "0fe2f4d151b9412a87be13caac8ba1bfaba0d148"
},
{
- "barId": 276140,
+ "barId": 276672,
"path": "diagnostics",
"remoteUri": "https://github.com/dotnet/diagnostics",
- "commitSha": "790647464027d129ad72b901d25ecaba8474e9c6"
+ "commitSha": "d7d850097b755b343851f9c5b93325aacb8323aa"
},
{
- "barId": 276441,
+ "barId": 276679,
"path": "efcore",
"remoteUri": "https://github.com/dotnet/efcore",
- "commitSha": "4ff0eb02aba1c4e9e1fd59c62441168a5a8fc5e0"
+ "commitSha": "cb3e343b2ca25dbf34f9b6d9f2544cdae73f7481"
},
{
"barId": 276379,
@@ -49,16 +49,16 @@
"commitSha": "d65eb5b36511b6422cbad6e2e140a86831a004d2"
},
{
- "barId": 276200,
+ "barId": 276595,
"path": "fsharp",
"remoteUri": "https://github.com/dotnet/fsharp",
- "commitSha": "a69caee31bd0c35ebd11ba4ccfa4c6297a42cd69"
+ "commitSha": "7dd51e626b3787b69d3933a33cf2ce23fc36c576"
},
{
- "barId": 276397,
+ "barId": 276630,
"path": "msbuild",
"remoteUri": "https://github.com/dotnet/msbuild",
- "commitSha": "41f5988ea12bf1eb2dfbbeafc410410737b18e3c"
+ "commitSha": "1f60126fb517e342dd563e50bb3cb52f8109f837"
},
{
"barId": 271771,
@@ -97,10 +97,10 @@
"commitSha": "086c9380ad71ac75c8af5d5091d3ad339fc842e1"
},
{
- "barId": 276134,
+ "barId": 276276,
"path": "sdk",
"remoteUri": "https://github.com/dotnet/sdk",
- "commitSha": "2f666ecda03b5b6c669b9728e9f35315af6edf96"
+ "commitSha": "049672a7df90f87cfead427665edc37c37c22ed1"
},
{
"barId": 276385,
@@ -127,10 +127,10 @@
"commitSha": "fabe4020161ba6c194289c9c963121c948f1f9ea"
},
{
- "barId": 275610,
+ "barId": 276591,
"path": "vstest",
"remoteUri": "https://github.com/microsoft/vstest",
- "commitSha": "f97214fe5fd493b90959165c6db77f878bcb60bd"
+ "commitSha": "dbcd471883202088496ab81d3ec2d3f3be0981b5"
},
{
"barId": 276382,
@@ -139,10 +139,10 @@
"commitSha": "41346681fafc7b7ab31239a77aba00d7c3e71be5"
},
{
- "barId": 276392,
+ "barId": 276486,
"path": "winforms",
"remoteUri": "https://github.com/dotnet/winforms",
- "commitSha": "37effbf08c5f46603cd0aefb26538de521338a9c"
+ "commitSha": "91ebb7421e6248f425c79169c448246150bd4c39"
},
{
"barId": 275831,
@@ -151,10 +151,10 @@
"commitSha": "390c57065309a5b4ec1075894f5fcecab472aa62"
},
{
- "barId": 274010,
+ "barId": 276515,
"path": "xdt",
"remoteUri": "https://github.com/dotnet/xdt",
- "commitSha": "d1231b22ac3ba77f8a7e506b10d922f6f7ace210"
+ "commitSha": "3ae5c14d94509e8ffed62d10685ca4a4159754df"
}
],
"submodules": [
diff --git a/src/vstest/eng/Version.Details.props b/src/vstest/eng/Version.Details.props
new file mode 100644
index 00000000000..aa1fc141196
--- /dev/null
+++ b/src/vstest/eng/Version.Details.props
@@ -0,0 +1 @@
+
diff --git a/src/vstest/eng/Version.Details.xml b/src/vstest/eng/Version.Details.xml
index 185bd6fa6ec..d3105b28292 100644
--- a/src/vstest/eng/Version.Details.xml
+++ b/src/vstest/eng/Version.Details.xml
@@ -1,14 +1,14 @@
-
+
https://dev.azure.com/devdiv/DevDiv/_git/vs-code-coverage
b3c8a0e7de26919a4efd2a347133522dca5b8ee6
-
+
https://github.com/dotnet/dotnet
- 9bcfe617e4f615d6931e2eec47767c3f15116d1d
+ d13c858f5792ca573c322dcaf2cf7ea814fa5f31
@@ -27,9 +27,9 @@
-
+
https://github.com/dotnet/arcade
- 4e526204e83e615efe8eb5743be7fbccfa4e492a
+ d777c20040bdc2e52b372fa98dcb84141ed692d3
https://github.com/dotnet/symreader-converter
diff --git a/src/vstest/eng/Versions.props b/src/vstest/eng/Versions.props
index 2e998b96142..9c4e64e698c 100644
--- a/src/vstest/eng/Versions.props
+++ b/src/vstest/eng/Versions.props
@@ -48,7 +48,7 @@
3.3.4
3.3.4
17.7.0
- 0.2.631904
+ 0.2.0-preview.25366.103
6.0.2
6.0.0
18.0.0-beta.25364.2
diff --git a/src/vstest/eng/common/tools.ps1 b/src/vstest/eng/common/tools.ps1
index 40f0aa86128..996a5f9c872 100644
--- a/src/vstest/eng/common/tools.ps1
+++ b/src/vstest/eng/common/tools.ps1
@@ -414,7 +414,7 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements =
# Locate Visual Studio installation or download x-copy msbuild.
$vsInfo = LocateVisualStudio $vsRequirements
- if ($vsInfo -ne $null) {
+ if ($vsInfo -ne $null -and $env:ForceUseXCopyMSBuild -eq $null) {
# Ensure vsInstallDir has a trailing slash
$vsInstallDir = Join-Path $vsInfo.installationPath "\"
$vsMajorVersion = $vsInfo.installationVersion.Split('.')[0]
diff --git a/src/vstest/global.json b/src/vstest/global.json
index ed7ad0de933..cf8590564e4 100644
--- a/src/vstest/global.json
+++ b/src/vstest/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "10.0.100-preview.6.25315.102",
+ "version": "10.0.100-preview.7.25322.101",
"rollForward": "minor",
"allowPrerelease": false,
"architecture": "x64"
@@ -30,9 +30,9 @@
"version": "17.8.0"
},
"vswhere": "2.2.7",
- "dotnet": "10.0.100-preview.6.25315.102"
+ "dotnet": "10.0.100-preview.7.25322.101"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25358.3"
+ "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25367.5"
}
}
diff --git a/src/vstest/src/Microsoft.TestPlatform.CoreUtilities/Helpers/DotnetHostHelper.cs b/src/vstest/src/Microsoft.TestPlatform.CoreUtilities/Helpers/DotnetHostHelper.cs
index d71c2f24d55..d9bc7043f46 100644
--- a/src/vstest/src/Microsoft.TestPlatform.CoreUtilities/Helpers/DotnetHostHelper.cs
+++ b/src/vstest/src/Microsoft.TestPlatform.CoreUtilities/Helpers/DotnetHostHelper.cs
@@ -23,6 +23,13 @@ public class DotnetHostHelper : IDotnetHostHelper
{
public const string MONOEXENAME = "mono";
+ // Mach-O magic numbers from https://en.wikipedia.org/wiki/Mach-O
+ private const uint MachOMagic32BigEndian = 0xfeedface; // 32-bit big-endian
+ private const uint MachOMagic64BigEndian = 0xfeedfacf; // 64-bit big-endian
+ private const uint MachOMagic32LittleEndian = 0xcefaedfe; // 32-bit little-endian
+ private const uint MachOMagic64LittleEndian = 0xcffaedfe; // 64-bit little-endian
+ private const uint MachOMagicFatBigEndian = 0xcafebabe; // Multi-architecture big-endian
+
private readonly IFileHelper _fileHelper;
private readonly IEnvironment _environment;
private readonly IWindowsRegistryHelper _windowsRegistryHelper;
@@ -414,6 +421,14 @@ public bool TryGetDotnetPathByArchitecture(
ReadExactly(headerReader, cpuInfoBytes, 0, cpuInfoBytes.Length);
var magic = BitConverter.ToUInt32(magicBytes, 0);
+
+ // Validate magic bytes to ensure this is a valid Mach-O binary
+ if (magic is not (MachOMagic32BigEndian or MachOMagic64BigEndian or MachOMagic32LittleEndian or MachOMagic64LittleEndian or MachOMagicFatBigEndian))
+ {
+ EqtTrace.Error($"DotnetHostHelper.GetMuxerArchitectureByMachoOnMac: Invalid Mach-O magic bytes: 0x{magic:X8}");
+ return null;
+ }
+
var cpuInfo = BitConverter.ToUInt32(cpuInfoBytes, 0);
PlatformArchitecture? architecture = (MacOsCpuType)cpuInfo switch
{
diff --git a/src/winforms/docs/dataobject-serialization.md b/src/winforms/docs/dataobject-serialization.md
new file mode 100644
index 00000000000..0e5949ad673
--- /dev/null
+++ b/src/winforms/docs/dataobject-serialization.md
@@ -0,0 +1,180 @@
+# WinForms Clipboard/DataObject updates for .NET 10
+
+The **.NET 10** cycle introduces major updates to the clipboard and drag‑and‑drop stack in **System.Windows.Forms**. These changes were driven by the **removal of `BinaryFormatter`** from the runtime, which previously handled serialization of custom types for OLE data transfer. The new APIs provide explicit type‑safe methods and use **JSON** instead of binary serialization, while still allowing an opt‑in fallback to `BinaryFormatter` for legacy applications.
+
+## Background
+
+`BinaryFormatter` was used when a custom type was placed on the clipboard for a user defined data format or in a drag‑and‑drop operation. The `BinaryFormatter` is insecure and has been removed from the base runtime. WinForms has introduced new, safer APIs and deprecated older APIs. WinForms also now makes you explicitly enable clipboard and drag drop scenarios for `BinaryFormatter` so you don't get unexpected usage if you need to enable it for other scenarios.
+
+### Best Practices
+
+- Avoid enabling the `BinaryFormatter` for clipboard and drag and drop scenarios if at all possible.
+- Use the safe built-in types (listed below) and `SetData` APIs.
+- For custom types, use the new `SetDataAsJson()` APIs or serialize manually as `string` or `byte[]` data.
+- **Always** use `TryGetData()` to get data (not `GetData()`).
+- Read legacy data using the `NrbfDecoder`.
+
+### Safe built‑in types
+
+Without `BinaryFormatter`, WinForms can still transfer certain intrinsic types using a built‑in manual serializer in the `BinaryFormatter` data format, **NRBF** ([.NET Remoting Binary Format](https://learn.microsoft.com/openspecs/windows_protocols/ms-nrbf/75b9fe09-be15-475f-85b8-ae7b7558cfe5)). Supported types include:
+
+- **Primitive types**: `bool`, `byte`, `char`, `decimal`, `double`, `short`, `int`, `long`, `sbyte`, `ushort`, `uint`, `ulong`, `float`, `string`, `TimeSpan` and `DateTime`.
+- **Arrays or `List`** of these primitive types.
+- **System.Drawing types**: `Bitmap`, `PointF`, `RectangleF`, `Point`, `Rectangle`, `SizeF`, `Size`, and `Color`.
+
+When data is one of these types, WinForms transfers it without the user needing to implement any special logic. For custom types with [`DataFormats`](https://learn.microsoft.com/dotnet/api/system.windows.forms.dataformats) that aren't predefined, you should use JSON or your own serialization using raw string or byte data.
+
+## New APIs in .NET 10
+
+### `TryGetData` – constrained deserialization of data
+
+Several overloads of `TryGetData` exist on **`Clipboard`**, **`DataObject`**, **`ITypedDataObject`**, **`DataObjectExtensions`** and the VB **`ClipboardProxy`**. These methods:
+
+- Attempt to retrieve data in a given format and deserialize it to the requested type `T`.
+- Return a boolean indicating success instead of throwing.
+- When enabling `BinaryFormatter`, requires a **`resolver`** callback to restrict deserialization to known types.
+
+Example using the **simplest overload** (no resolver). This will **never** fall back to `BinaryFormatter`; it only succeeds if the data was serialized with `SetDataAsJson`, one of the built‑in safe NRBF types (see above), _or_ if the data was set in-process without the `copy` flag (not the default):
+
+```csharp
+// Reading a Person previously stored with SetDataAsJson
+if (Clipboard.TryGetData("MyApp.Person", out Person? person))
+{
+ Console.WriteLine($"Person: {person.Name} is {person.Age}");
+}
+else
+{
+ Console.WriteLine("No person data on clipboard or type mismatch");
+}
+```
+
+A resolver overload can be used when you need to support legacy binary formats and have fully enabled the `BinaryFormatter`. See the "Enabling Full BinaryFormatter Support" below for details.
+
+### `SetDataAsJson` – write custom types without BinaryFormatter
+
+`SetDataAsJson` is a new overload on the **`Clipboard`**, **`DataObject`** and **VB `ClipboardProxy`** classes. It serializes *simple* `T` types to JSON using **`System.Text.Json`**. For example:
+
+```csharp
+public record Person(string Name, int Age);
+
+// Serialize to JSON and put on the clipboard
+Person person = new("Alisha", 34);
+Clipboard.SetDataAsJson(person);
+```
+Internally `DataObject.SetDataAsJson` writes the JSON to the underlying OLE data stream in the NRBF format in a way that it can be safely extracted without using the `BinaryFormatter`.
+
+
+### `ITypedDataObject` interface – enabling typed data retrieval
+
+Custom data objects used with drag & drop should implement the **`ITypedDataObject`** interface. This interface declares the typed `TryGetData` overloads. Implementing it signals to WinForms that your data object is capable of deserializing data into specific types; if it is not implemented, calls to the typed APIs throw `NotSupportedException`. The `DataObject` class already implements `ITypedDataObject`.
+
+### Summary of new API signatures
+
+| API (class) | Description | Remarks |
+|---|---|---|
+| `DataObject.SetDataAsJson(string format, T data)` and `DataObject.SetDataAsJson(T data)` | Serialize an object to JSON and store it under the specified format (or the type’s full name). | Uses `System.Text.Json`. |
+| `Clipboard.SetDataAsJson(string format, T data)` | Clears the clipboard and stores JSON data in a new `DataObject`. | Equivalent VB method: `ClipboardProxy.SetDataAsJson(Of T)`. |
+| `DataObject.TryGetData(string format, Func resolver, bool autoConvert, out T data)` | Attempts to read data and deserialize it; `resolver` controls allowed types when falling back to binary deserialization; `autoConvert` indicates whether OLE conversion should be attempted. | Returns `true` when successful; does not throw. |
+| `DataObject.TryGetData(string format, bool autoConvert, out T data)` | Same as above without a resolver; does not fall back to binary serialization. | |
+| `DataObject.TryGetData(string format, out T data)` | Uses default `autoConvert=true`; no resolver. | |
+| `DataObject.TryGetData(out T data)` | Infers the format from the full name of `T`. | |
+| `Clipboard.TryGetData` overloads | Static methods that obtain the current clipboard data and delegate to the corresponding `DataObject` overloads. | Overloads include versions with and without resolver and autoConvert. |
+| `ITypedDataObject` | Interface declaring typed `TryGetData` methods. | Implement on custom data objects used for drag & drop. |
+| `DataObjectExtensions.TryGetData` | Extension methods on `IDataObject` that call through to `ITypedDataObject`; throws when the underlying object does not implement `ITypedDataObject`. | Enables typed retrieval without explicitly casting. |
+| `ClipboardProxy` (VB) new methods | Exposes `SetDataAsJson(Of T)`, `TryGetData(Of T)` and `TryGetData(Of T)(resolver)` in Visual Basic’s `My.Computer.Clipboard`. | VB apps can use typed clipboard APIs without referencing the `System.Windows.Forms` namespace directly. |
+
+## Enabling full `BinaryFormatter` support (not recommended)
+
+Although the default behaviour removes `BinaryFormatter`, a full fallback is still available **for legacy applications**. To enable it you must do **all** of the following:
+
+1. **Reference the `System.Runtime.Serialization.Formatters` package**: Add a PackageReference to your project file:
+
+ ```xml
+
+
+
+ ```
+
+ This compatibility package is unsupported and dangerous; use it only as a last resort.
+
+2. **Set the runtime switch to enable unsafe serialization**: In your project file, set the property `EnableUnsafeBinaryFormatterSerialization` to `true`. Without this switch, calls to binary serialization throw.
+
+ ```xml
+
+ true
+
+ ```
+
+3. **Set the WinForms‑specific switch**: WinForms adds an app‑context switch `Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization`. Without this switch, WinForms will not fall back to `BinaryFormatter` even if the general serialization switch is enabled. Set this flag in your `runtimeconfig.json` file:
+
+ ```json
+ {
+ "configProperties": {
+ "Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization": true
+ }
+ }
+ ```
+
+4. **Use the resolver overload to control which types are allowed**: Even with `BinaryFormatter` enabled, you must specify a resolver when calling `TryGetData` so you only deserialize known safe types. The existing, deprecated, `GetData` APIs will continue to work, but provide no additional constraints. A sample type resolver follows:
+
+ ```csharp
+ static Type MyExactMatchResolver(TypeName typeName)
+ {
+ (Type type, TypeName typeName)[] allowedTypes =
+ [
+ (typeof(MyClass1), TypeName.Parse(typeof(MyClass1).AssemblyQualifiedName)),
+ (typeof(MyClass2), TypeName.Parse(typeof(MyClass2).AssemblyQualifiedName))
+ ];
+
+ foreach (var (type, name) in allowedTypes)
+ {
+ // Check the type name
+ if (name.FullName != typeName.FullName)
+ {
+ continue;
+ }
+
+ // You should also consider checking the `.AssemblyName` here as well.
+ return type;
+ }
+
+ // Always throw to prevent the BinaryFormatter from implicitly loading assemblies.
+ throw new NotSupportedException($"Can't resolve {typeName.AssemblyQualifiedName}");
+ }
+ ```
+
+Only after completing **all of the first three steps** above will WinForms behave as in older versions and automatically use `BinaryFormatter` for unknown types.
+
+## Compatibility
+
+### Predefined formats and primitive types
+
+Types already defined in [`DataFormats`](https://learn.microsoft.com/dotnet/api/system.windows.forms.dataformats) and the primitive types described in the beginning of the document just work. This ensures compatibility with existing applications and common data exchange scenarios.
+
+### Reading JSON down‑level
+
+Even though `SetDataAsJson` is only available in .NET 10, you can round‑trip JSON data across processes and frameworks by storing the JSON yourself (as UTF-8 `byte[]` or `string`) if you're able to change all of the consumer code.
+
+### Reading legacy NRBF / binary data in .NET 10
+
+While .NET 10 removes `BinaryFormatter` by default, WinForms still includes safe support for the types mentioned above and provides mechanisms to read legacy binary payloads **without referencing `BinaryFormatter`**. The simplest way to read NRBF data is to use the `NrbfDecoder` `SerializationRecord`:
+
+```csharp
+if (dataObject.TryGetData("LegacyFormat", out SerializationRecord? record))
+{
+ // Process the serialization record
+}
+```
+
+You can also retrieve raw data as a `MemoryStream` for custom processing.
+
+## Links
+
+- [BinaryFormatter migration guide](https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-migration-guide/)
+- [Windows Forms migration guide for BinaryFormatter](https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-migration-guide/winforms-applications)
+- [Windows Forms and Windows Presentation Foundation BinaryFormatter OLE guidance](https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-migration-guide)
+- [System.Text.Json documentation](https://learn.microsoft.com/dotnet/standard/serialization/system-text-json/overview)
+- [.NET Core runtime configuration settings](https://learn.microsoft.com/dotnet/core/runtime-config/)
+- [Windows Forms Clipboard class](https://learn.microsoft.com/dotnet/api/system.windows.forms.clipboard)
+- [DataObject class](https://learn.microsoft.com/dotnet/api/system.windows.forms.dataobject)
+- [NRBF format specification](https://learn.microsoft.com/openspecs/windows_protocols/ms-nrbf/75b9fe09-be15-475f-85b8-ae7b7558cfe5)
diff --git a/src/winforms/eng/Version.Details.xml b/src/winforms/eng/Version.Details.xml
index f21b39e19a5..4d38acee9d3 100644
--- a/src/winforms/eng/Version.Details.xml
+++ b/src/winforms/eng/Version.Details.xml
@@ -6,106 +6,106 @@ Note: if the Uri is a new place, you will need to add a subscription from that p
And you can check these with "darc get-dependencies target-repo "winforms"
-->
-
+
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
-
+
https://github.com/dotnet/dotnet
- 96ac952a7886b565e83acc4c9cef656954ed0686
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
diff --git a/src/winforms/eng/Versions.props b/src/winforms/eng/Versions.props
index c6fc87f81b0..ff59a99cad4 100644
--- a/src/winforms/eng/Versions.props
+++ b/src/winforms/eng/Versions.props
@@ -10,30 +10,30 @@
$(MajorVersion).$(MinorVersion).$(PatchVersion)
false
release
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
5.0.0-preview.7.20320.5
- 10.0.0-preview.7.25372.103
+ 10.0.0-preview.7.25373.104
6.1.0-preview.1.24511.1
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
10.0.0-preview.5.25227.101
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
- 10.0.0-preview.7.25372.103
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
+ 10.0.0-preview.7.25373.104
@@ -46,9 +46,9 @@
- 10.0.0-beta.25372.103
- 10.0.0-beta.25372.103
- 10.0.0-beta.25372.103
+ 10.0.0-beta.25373.104
+ 10.0.0-beta.25373.104
+ 10.0.0-beta.25373.104
17.4.0-preview-20220707-01
diff --git a/src/winforms/global.json b/src/winforms/global.json
index b750c94ca3f..fc48a85d607 100644
--- a/src/winforms/global.json
+++ b/src/winforms/global.json
@@ -21,11 +21,11 @@
}
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25372.103",
- "Microsoft.DotNet.CMake.Sdk": "10.0.0-beta.25372.103",
- "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25372.103",
+ "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25373.104",
+ "Microsoft.DotNet.CMake.Sdk": "10.0.0-beta.25373.104",
+ "Microsoft.DotNet.Helix.Sdk": "10.0.0-beta.25373.104",
"FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0",
- "Microsoft.NET.Sdk.IL": "10.0.0-preview.7.25372.103"
+ "Microsoft.NET.Sdk.IL": "10.0.0-preview.7.25373.104"
},
"native-tools": {
"cmake": "latest"
diff --git a/src/xdt/eng/Version.Details.props b/src/xdt/eng/Version.Details.props
new file mode 100644
index 00000000000..aa1fc141196
--- /dev/null
+++ b/src/xdt/eng/Version.Details.props
@@ -0,0 +1 @@
+
diff --git a/src/xdt/eng/Version.Details.xml b/src/xdt/eng/Version.Details.xml
index 7561781d66a..57c2d2a8e99 100644
--- a/src/xdt/eng/Version.Details.xml
+++ b/src/xdt/eng/Version.Details.xml
@@ -1,10 +1,10 @@
-
+
-
+
https://github.com/dotnet/dotnet
- eaa19c281d34580a8168cff9ce1e7337da8bfe4f
+ c0e325f90fb79db0da6be5128dc292f2aabb264f
diff --git a/src/xdt/eng/common/tools.ps1 b/src/xdt/eng/common/tools.ps1
index 40f0aa86128..996a5f9c872 100644
--- a/src/xdt/eng/common/tools.ps1
+++ b/src/xdt/eng/common/tools.ps1
@@ -414,7 +414,7 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements =
# Locate Visual Studio installation or download x-copy msbuild.
$vsInfo = LocateVisualStudio $vsRequirements
- if ($vsInfo -ne $null) {
+ if ($vsInfo -ne $null -and $env:ForceUseXCopyMSBuild -eq $null) {
# Ensure vsInstallDir has a trailing slash
$vsInstallDir = Join-Path $vsInfo.installationPath "\"
$vsMajorVersion = $vsInfo.installationVersion.Split('.')[0]
diff --git a/src/xdt/global.json b/src/xdt/global.json
index eefa97f0ae0..a2eb44059c7 100644
--- a/src/xdt/global.json
+++ b/src/xdt/global.json
@@ -1,12 +1,12 @@
{
"tools": {
- "dotnet": "10.0.100-preview.6.25315.102"
+ "dotnet": "10.0.100-preview.7.25322.101"
},
"sdk": {
- "version": "10.0.100-preview.6.25315.102",
+ "version": "10.0.100-preview.7.25322.101",
"allowPrerelease": true
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25351.106"
+ "Microsoft.DotNet.Arcade.Sdk": "10.0.0-beta.25373.104"
}
}