From cd54b4ea8415f6bbb40f6215902bb3dbfa3813d3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 09:42:14 +0200 Subject: [PATCH 01/13] [main] Source code updates from dotnet/diagnostics (#1623) Co-authored-by: dotnet-maestro[bot] --- src/diagnostics/eng/Version.Details.xml | 4 +++ src/diagnostics/eng/Versions.props | 1 + .../RemoteExecutorHelper.cs | 3 +++ .../dotnet-dsrouter/ADBTcpRouterFactory.cs | 27 ++++++++++++++++--- .../src/Tools/dotnet-dsrouter/Program.cs | 2 +- .../dotnet-dsrouter/dotnet-dsrouter.csproj | 1 + src/source-manifest.json | 4 +-- 7 files changed, 36 insertions(+), 6 deletions(-) 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/source-manifest.json b/src/source-manifest.json index 1718ac38ccb..5355e1c4f14 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -49,10 +49,10 @@ "commitSha": "d65eb5b36511b6422cbad6e2e140a86831a004d2" }, { - "barId": 276200, + "barId": 276595, "path": "fsharp", "remoteUri": "https://github.com/dotnet/fsharp", - "commitSha": "a69caee31bd0c35ebd11ba4ccfa4c6297a42cd69" + "commitSha": "7dd51e626b3787b69d3933a33cf2ce23fc36c576" }, { "barId": 276397, From b3ebae43bcb98f5955c3e7e668f88612574cf259 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 09:42:35 +0200 Subject: [PATCH 03/13] [main] Source code updates from dotnet/aspnetcore (#1629) Co-authored-by: dotnet-maestro[bot] --- src/aspnetcore/.editorconfig | 6 - .../workflows/browsertesting-issue-body.md | 5 +- src/aspnetcore/eng/Dependencies.props | 2 - src/aspnetcore/eng/Version.Details.xml | 366 +++++---- src/aspnetcore/eng/Versions.props | 175 +++-- src/aspnetcore/global.json | 6 +- ...t.AspNetCore.Components.WebAssembly.csproj | 2 - .../Internal/Json/MessageTypeInfoResolver.cs | 44 +- .../ConverterTests/JsonConverterReadTests.cs | 20 + .../ConverterTests/JsonConverterWriteTests.cs | 20 + .../ProtobutMessages/WrappersMessage.cs | 731 ++++++++++++++++++ .../src/Metadata/ApiEndpointMetadata.cs | 20 + .../src/Metadata/IApiEndpointMetadata.cs | 12 + ...rosoft.AspNetCore.Http.Abstractions.csproj | 2 +- .../src/PublicAPI.Unshipped.txt | 1 + .../RequestDelegateGenerator.cs | 7 +- .../RequestDelegateGeneratorSources.cs | 38 +- .../StaticRouteHandlerModel.Emitter.cs | 11 +- .../src/RequestDelegateFactory.cs | 28 +- .../test/RequestDelegateFactoryTests.cs | 27 +- ...ntsWithAndWithoutDiagnostics.generated.txt | 16 + ...ion_BindAsync_NullableReturn.generated.txt | 16 + ...MapAction_BindAsync_Snapshot.generated.txt | 16 + ...Param_ComplexReturn_Snapshot.generated.txt | 16 + ...Header_ComplexTypeArrayParam.generated.txt | 17 + ...der_NullableStringArrayParam.generated.txt | 17 + ...licitHeader_StringArrayParam.generated.txt | 17 + ...tQuery_ComplexTypeArrayParam.generated.txt | 17 + ...Query_IntArrayParam_Optional.generated.txt | 17 + ...ram_Optional_QueryNotPresent.generated.txt | 17 + ...llableIntArrayParam_Optional.generated.txt | 17 + ...ram_Optional_QueryNotPresent.generated.txt | 17 + ...ery_NullableStringArrayParam.generated.txt | 17 + ...plicitQuery_StringArrayParam.generated.txt | 17 + ...ry_StringArrayParam_Optional.generated.txt | 17 + ...ram_Optional_QueryNotPresent.generated.txt | 17 + ...eParam_SimpleReturn_Snapshot.generated.txt | 16 + ...Source_SimpleReturn_Snapshot.generated.txt | 16 + ...tQuery_ComplexTypeArrayParam.generated.txt | 17 + ...Query_IntArrayParam_Optional.generated.txt | 17 + ...ram_Optional_QueryNotPresent.generated.txt | 17 + ...llableIntArrayParam_Optional.generated.txt | 17 + ...ram_Optional_QueryNotPresent.generated.txt | 17 + ...ery_NullableStringArrayParam.generated.txt | 18 + ...gArrayParam_EmptyQueryValues.generated.txt | 18 + ...ngArrayParam_QueryNotPresent.generated.txt | 18 + ...plicitQuery_StringArrayParam.generated.txt | 18 + ...ry_StringArrayParam_Optional.generated.txt | 18 + ...ram_Optional_QueryNotPresent.generated.txt | 18 + ...ce_HandlesBothJsonAndService.generated.txt | 17 + ...pecialTypeParam_StringReturn.generated.txt | 16 + ...ipleStringParam_StringReturn.generated.txt | 16 + ...aram_StringReturn_WithFilter.generated.txt | 16 + ...n_ReturnsString_Has_Metadata.generated.txt | 16 + ...ion_ReturnsTodo_Has_Metadata.generated.txt | 17 + ...omplexTypeParam_StringReturn.generated.txt | 16 + ...SingleEnumParam_StringReturn.generated.txt | 16 + ...ngValueProvided_StringReturn.generated.txt | 16 + ...MetadataEmitter_Has_Metadata.generated.txt | 17 + ...AndBody_ShouldUseQueryString.generated.txt | 17 + ...AndBody_ShouldUseQueryString.generated.txt | 17 + ...String_AndBody_ShouldUseBody.generated.txt | 17 + ...String_AndBody_ShouldUseBody.generated.txt | 17 + ...String_AndBody_ShouldUseBody.generated.txt | 17 + ...hArrayQueryString_ShouldFail.generated.txt | 18 + ...pAction_NoParam_StringReturn.generated.txt | 16 + ...tion_WithParams_StringReturn.generated.txt | 16 + ...ateValidateGeneratedFormCode.generated.txt | 18 +- ...InterceptorsFromSameLocation.generated.txt | 16 + ...terceptorsFromDifferentFiles.generated.txt | 16 + .../VerifyAsParametersBaseline.generated.txt | 19 + .../RequestDelegateCreationTests.Metadata.cs | 22 +- .../src/Http/Http.Results/src/Accepted.cs | 1 + .../Http/Http.Results/src/AcceptedAtRoute.cs | 1 + .../Http.Results/src/AcceptedAtRouteOfT.cs | 1 + .../src/Http/Http.Results/src/AcceptedOfT.cs | 1 + .../src/Http/Http.Results/src/BadRequest.cs | 1 + .../Http/Http.Results/src/BadRequestOfT.cs | 1 + .../src/Http/Http.Results/src/Conflict.cs | 1 + .../src/Http/Http.Results/src/ConflictOfT.cs | 1 + .../src/Http/Http.Results/src/Created.cs | 1 + .../Http/Http.Results/src/CreatedAtRoute.cs | 1 + .../Http.Results/src/CreatedAtRouteOfT.cs | 1 + .../src/Http/Http.Results/src/CreatedOfT.cs | 1 + .../src/InternalServerErrorOfT.cs | 1 + .../Http.Results/src/JsonHttpResultOfT.cs | 12 +- .../src/Http/Http.Results/src/NoContent.cs | 1 + .../src/Http/Http.Results/src/NotFoundOfT.cs | 1 + .../src/Http/Http.Results/src/Ok.cs | 1 + .../src/Http/Http.Results/src/OkOfT.cs | 1 + .../Http.Results/src/ProblemHttpResult.cs | 14 +- .../src/ServerSentEventsResult.cs | 1 + .../Http.Results/src/UnprocessableEntity.cs | 1 + .../src/UnprocessableEntityOfT.cs | 1 + .../Http.Results/src/ValidationProblem.cs | 1 + .../test/AcceptedAtRouteOfTResultTests.cs | 2 + .../test/AcceptedAtRouteResultTests.cs | 2 + .../test/AcceptedOfTResultTests.cs | 2 + .../Http.Results/test/AcceptedResultTests.cs | 2 + .../test/BadRequestOfTResultTests.cs | 2 + .../test/BadRequestResultTests.cs | 2 + .../test/ConflictOfTResultTests.cs | 2 + .../Http.Results/test/ConflictResultTests.cs | 2 + .../test/CreatedAtRouteOfTResultTests.cs | 2 + .../test/CreatedAtRouteResultTests.cs | 2 + .../test/CreatedOfTResultTests.cs | 2 + .../Http.Results/test/CreatedResultTests.cs | 2 + .../test/InternalServerErrorOfTResultTests.cs | 2 + .../Http/Http.Results/test/JsonResultTests.cs | 23 + .../Http.Results/test/NoContentResultTests.cs | 3 + .../test/NotFoundOfTResultTests.cs | 2 + .../Http.Results/test/OkOfTResultTests.cs | 2 + .../Http/Http.Results/test/OkResultTests.cs | 2 + .../test/UnprocessableEntityOfTResultTests.cs | 2 + .../test/UnprocessableEntityResultTests.cs | 2 + .../EndpointMetadataApiDescriptionProvider.cs | 24 +- .../Mvc.Core/src/ApiControllerAttribute.cs | 3 +- .../DefaultApplicationModelProviderTest.cs | 6 +- .../Cookies/src/CookieAuthenticationEvents.cs | 11 +- .../Authentication/test/CookieTests.cs | 51 +- .../src/AuthorizationServiceExtensions.cs | 16 +- .../Core/src/DefaultAuthorizationService.cs | 8 +- .../Core/src/IAuthorizationService.cs | 9 +- .../Http3/QPack/H3StaticTable.Http3.cs | 15 - ...onnectionEndpointRouteBuilderExtensions.cs | 9 + src/source-manifest.json | 4 +- 126 files changed, 2268 insertions(+), 402 deletions(-) create mode 100644 src/aspnetcore/src/Grpc/JsonTranscoding/test/Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests/TestObjects/ProtobutMessages/WrappersMessage.cs create mode 100644 src/aspnetcore/src/Http/Http.Abstractions/src/Metadata/ApiEndpointMetadata.cs create mode 100644 src/aspnetcore/src/Http/Http.Abstractions/src/Metadata/IApiEndpointMetadata.cs 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 GetSetMethod(FieldDescriptor field) + private static Action GetSetMethod(FieldDescriptor field, FieldDescriptor? wrapperTypeValueField) { Debug.Assert(!field.IsRepeated && !field.IsMap, "Collections shouldn't have a setter."); @@ -135,19 +157,27 @@ private JsonPropertyInfo CreatePropertyInfo(JsonTypeInfo typeInfo, string name, throw new InvalidOperationException($"Multiple values specified for oneof {field.RealContainingOneof.Name}."); } - SetFieldValue(field, (IMessage)o, v); + SetFieldValue(field, wrapperTypeValueField, (IMessage)o, v); }; } return (o, v) => { - SetFieldValue(field, (IMessage)o, v); + SetFieldValue(field, wrapperTypeValueField, (IMessage)o, v); }; - static void SetFieldValue(FieldDescriptor field, IMessage m, object? v) + static void SetFieldValue(FieldDescriptor field, FieldDescriptor? wrapperTypeValueField, IMessage m, object? v) { if (v != null) { + // This field exposes a wrapper type. Need to create a wrapper instance and set the value on it. + if (wrapperTypeValueField != null && v is not IMessage) + { + var wrapper = (IMessage)Activator.CreateInstance(field.MessageType.ClrType)!; + wrapperTypeValueField.Accessor.SetValue(wrapper, v); + v = wrapper; + } + field.Accessor.SetValue(m, v); } else diff --git a/src/aspnetcore/src/Grpc/JsonTranscoding/test/Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests/ConverterTests/JsonConverterReadTests.cs b/src/aspnetcore/src/Grpc/JsonTranscoding/test/Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests/ConverterTests/JsonConverterReadTests.cs index 519f4022121..95c51908ba3 100644 --- a/src/aspnetcore/src/Grpc/JsonTranscoding/test/Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests/ConverterTests/JsonConverterReadTests.cs +++ b/src/aspnetcore/src/Grpc/JsonTranscoding/test/Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests/ConverterTests/JsonConverterReadTests.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal; using Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.Json; using Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests.Infrastructure; +using Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests.TestObjects.ProtobufMessages; using Transcoding; using Xunit.Abstractions; @@ -531,6 +532,25 @@ public void NullableWrappers() AssertReadJson(json); } + [Fact] + public void NullableWrappers_Type() + { + var json = @"{ + ""stringValue"": ""A string"", + ""int32Value"": 1, + ""int64Value"": ""2"", + ""floatValue"": 1.2, + ""doubleValue"": 1.1, + ""boolValue"": true, + ""uint32Value"": 3, + ""uint64Value"": ""4"", + ""bytesValue"": ""SGVsbG8gd29ybGQ="" +}"; + + var result = AssertReadJson(json, serializeOld: false); + Assert.Equal("A string", result.StringValue.Value); + } + [Fact] public void NullValue_Default_Null() { diff --git a/src/aspnetcore/src/Grpc/JsonTranscoding/test/Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests/ConverterTests/JsonConverterWriteTests.cs b/src/aspnetcore/src/Grpc/JsonTranscoding/test/Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests/ConverterTests/JsonConverterWriteTests.cs index 32d1df26d8e..7dfe0c38095 100644 --- a/src/aspnetcore/src/Grpc/JsonTranscoding/test/Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests/ConverterTests/JsonConverterWriteTests.cs +++ b/src/aspnetcore/src/Grpc/JsonTranscoding/test/Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests/ConverterTests/JsonConverterWriteTests.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal; using Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.Json; using Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests.Infrastructure; +using Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests.TestObjects.ProtobufMessages; using Transcoding; using Xunit.Abstractions; using Type = System.Type; @@ -201,6 +202,25 @@ public void NullableWrappers() AssertWrittenJson(wrappers); } + [Fact] + public void NullableWrappers_Types() + { + var wrappers = new WrappersMessage + { + BoolValue = new BoolValue { Value = true }, + BytesValue = new BytesValue { Value = ByteString.CopyFrom(Encoding.UTF8.GetBytes("Hello world")) }, + DoubleValue = new DoubleValue { Value = 1.1 }, + FloatValue = new FloatValue { Value = 1.2f }, + Int32Value = new Int32Value { Value = 1 }, + Int64Value = new Int64Value { Value = 2L }, + StringValue = new StringValue { Value = "A string" }, + Uint32Value = new UInt32Value { Value = 3U }, + Uint64Value = new UInt64Value { Value = 4UL } + }; + + AssertWrittenJson(wrappers); + } + [Fact] public void NullableWrapper_Root_Int32() { diff --git a/src/aspnetcore/src/Grpc/JsonTranscoding/test/Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests/TestObjects/ProtobutMessages/WrappersMessage.cs b/src/aspnetcore/src/Grpc/JsonTranscoding/test/Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests/TestObjects/ProtobutMessages/WrappersMessage.cs new file mode 100644 index 00000000000..d1ae86daa8c --- /dev/null +++ b/src/aspnetcore/src/Grpc/JsonTranscoding/test/Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests/TestObjects/ProtobutMessages/WrappersMessage.cs @@ -0,0 +1,731 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: Protos/extra.proto +// +#pragma warning disable 1591, 0612, 3021, 8981 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +namespace Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests.TestObjects.ProtobufMessages +{ + + /// Holder for reflection information generated from Protos/extra.proto + public static partial class ExtraReflection + { + + #region Descriptor + /// File descriptor for Protos/extra.proto + public static pbr::FileDescriptor Descriptor + { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static ExtraReflection() + { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "ChJQcm90b3MvZXh0cmEucHJvdG8SBHRlc3QaHkdvb2dsZS9wcm90b2J1Zi93", + "cmFwcGVycy5wcm90bxocR29vZ2xlL2FwaS9hbm5vdGF0aW9ucy5wcm90byLZ", + "AwoPV3JhcHBlcnNNZXNzYWdlEjIKDHN0cmluZ192YWx1ZRgBIAEoCzIcLmdv", + "b2dsZS5wcm90b2J1Zi5TdHJpbmdWYWx1ZRIwCgtpbnQzMl92YWx1ZRgCIAEo", + "CzIbLmdvb2dsZS5wcm90b2J1Zi5JbnQzMlZhbHVlEjAKC2ludDY0X3ZhbHVl", + "GAMgASgLMhsuZ29vZ2xlLnByb3RvYnVmLkludDY0VmFsdWUSMAoLZmxvYXRf", + "dmFsdWUYBCABKAsyGy5nb29nbGUucHJvdG9idWYuRmxvYXRWYWx1ZRIyCgxk", + "b3VibGVfdmFsdWUYBSABKAsyHC5nb29nbGUucHJvdG9idWYuRG91YmxlVmFs", + "dWUSLgoKYm9vbF92YWx1ZRgGIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5Cb29s", + "VmFsdWUSMgoMdWludDMyX3ZhbHVlGAcgASgLMhwuZ29vZ2xlLnByb3RvYnVm", + "LlVJbnQzMlZhbHVlEjIKDHVpbnQ2NF92YWx1ZRgIIAEoCzIcLmdvb2dsZS5w", + "cm90b2J1Zi5VSW50NjRWYWx1ZRIwCgtieXRlc192YWx1ZRgJIAEoCzIbLmdv", + "b2dsZS5wcm90b2J1Zi5CeXRlc1ZhbHVlQk+qAkxNaWNyb3NvZnQuQXNwTmV0", + "Q29yZS5HcnBjLkpzb25UcmFuc2NvZGluZy5UZXN0cy5UZXN0T2JqZWN0cy5Q", + "cm90b2J1dE1lc3NhZ2VzYgZwcm90bzM=")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.WrappersReflection.Descriptor, global::Google.Api.AnnotationsReflection.Descriptor, }, + new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests.TestObjects.ProtobufMessages.WrappersMessage), global::Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests.TestObjects.ProtobufMessages.WrappersMessage.Parser, new[]{ "StringValue", "Int32Value", "Int64Value", "FloatValue", "DoubleValue", "BoolValue", "Uint32Value", "Uint64Value", "BytesValue" }, null, null, null, null) + })); + } + #endregion + + } + #region Messages + [global::System.Diagnostics.DebuggerDisplayAttribute("{ToString(),nq}")] + public sealed partial class WrappersMessage : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage +#endif + { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new WrappersMessage()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor + { + get { return global::Microsoft.AspNetCore.Grpc.JsonTranscoding.Tests.TestObjects.ProtobufMessages.ExtraReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor + { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public WrappersMessage() + { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public WrappersMessage(WrappersMessage other) : this() + { + stringValue_ = other.stringValue_ != null ? other.stringValue_.Clone() : null; + int32Value_ = other.int32Value_ != null ? other.int32Value_.Clone() : null; + int64Value_ = other.int64Value_ != null ? other.int64Value_.Clone() : null; + floatValue_ = other.floatValue_ != null ? other.floatValue_.Clone() : null; + doubleValue_ = other.doubleValue_ != null ? other.doubleValue_.Clone() : null; + boolValue_ = other.boolValue_ != null ? other.boolValue_.Clone() : null; + uint32Value_ = other.uint32Value_ != null ? other.uint32Value_.Clone() : null; + uint64Value_ = other.uint64Value_ != null ? other.uint64Value_.Clone() : null; + bytesValue_ = other.bytesValue_ != null ? other.bytesValue_.Clone() : null; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public WrappersMessage Clone() + { + return new WrappersMessage(this); + } + + /// Field number for the "string_value" field. + public const int StringValueFieldNumber = 1; + private global::Google.Protobuf.WellKnownTypes.StringValue stringValue_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Protobuf.WellKnownTypes.StringValue StringValue + { + get { return stringValue_; } + set + { + stringValue_ = value; + } + } + + /// Field number for the "int32_value" field. + public const int Int32ValueFieldNumber = 2; + private global::Google.Protobuf.WellKnownTypes.Int32Value int32Value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Protobuf.WellKnownTypes.Int32Value Int32Value + { + get { return int32Value_; } + set + { + int32Value_ = value; + } + } + + /// Field number for the "int64_value" field. + public const int Int64ValueFieldNumber = 3; + private global::Google.Protobuf.WellKnownTypes.Int64Value int64Value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Protobuf.WellKnownTypes.Int64Value Int64Value + { + get { return int64Value_; } + set + { + int64Value_ = value; + } + } + + /// Field number for the "float_value" field. + public const int FloatValueFieldNumber = 4; + private global::Google.Protobuf.WellKnownTypes.FloatValue floatValue_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Protobuf.WellKnownTypes.FloatValue FloatValue + { + get { return floatValue_; } + set + { + floatValue_ = value; + } + } + + /// Field number for the "double_value" field. + public const int DoubleValueFieldNumber = 5; + private global::Google.Protobuf.WellKnownTypes.DoubleValue doubleValue_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Protobuf.WellKnownTypes.DoubleValue DoubleValue + { + get { return doubleValue_; } + set + { + doubleValue_ = value; + } + } + + /// Field number for the "bool_value" field. + public const int BoolValueFieldNumber = 6; + private global::Google.Protobuf.WellKnownTypes.BoolValue boolValue_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Protobuf.WellKnownTypes.BoolValue BoolValue + { + get { return boolValue_; } + set + { + boolValue_ = value; + } + } + + /// Field number for the "uint32_value" field. + public const int Uint32ValueFieldNumber = 7; + private global::Google.Protobuf.WellKnownTypes.UInt32Value uint32Value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Protobuf.WellKnownTypes.UInt32Value Uint32Value + { + get { return uint32Value_; } + set + { + uint32Value_ = value; + } + } + + /// Field number for the "uint64_value" field. + public const int Uint64ValueFieldNumber = 8; + private global::Google.Protobuf.WellKnownTypes.UInt64Value uint64Value_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Protobuf.WellKnownTypes.UInt64Value Uint64Value + { + get { return uint64Value_; } + set + { + uint64Value_ = value; + } + } + + /// Field number for the "bytes_value" field. + public const int BytesValueFieldNumber = 9; + private global::Google.Protobuf.WellKnownTypes.BytesValue bytesValue_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Google.Protobuf.WellKnownTypes.BytesValue BytesValue + { + get { return bytesValue_; } + set + { + bytesValue_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) + { + return Equals(other as WrappersMessage); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(WrappersMessage other) + { + if (ReferenceEquals(other, null)) + { + return false; + } + if (ReferenceEquals(other, this)) + { + return true; + } + if (!object.Equals(StringValue, other.StringValue)) return false; + if (!object.Equals(Int32Value, other.Int32Value)) return false; + if (!object.Equals(Int64Value, other.Int64Value)) return false; + if (!object.Equals(FloatValue, other.FloatValue)) return false; + if (!object.Equals(DoubleValue, other.DoubleValue)) return false; + if (!object.Equals(BoolValue, other.BoolValue)) return false; + if (!object.Equals(Uint32Value, other.Uint32Value)) return false; + if (!object.Equals(Uint64Value, other.Uint64Value)) return false; + if (!object.Equals(BytesValue, other.BytesValue)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() + { + int hash = 1; + if (stringValue_ != null) hash ^= StringValue.GetHashCode(); + if (int32Value_ != null) hash ^= Int32Value.GetHashCode(); + if (int64Value_ != null) hash ^= Int64Value.GetHashCode(); + if (floatValue_ != null) hash ^= FloatValue.GetHashCode(); + if (doubleValue_ != null) hash ^= DoubleValue.GetHashCode(); + if (boolValue_ != null) hash ^= BoolValue.GetHashCode(); + if (uint32Value_ != null) hash ^= Uint32Value.GetHashCode(); + if (uint64Value_ != null) hash ^= Uint64Value.GetHashCode(); + if (bytesValue_ != null) hash ^= BytesValue.GetHashCode(); + if (_unknownFields != null) + { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() + { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); +#else + if (stringValue_ != null) { + output.WriteRawTag(10); + output.WriteMessage(StringValue); + } + if (int32Value_ != null) { + output.WriteRawTag(18); + output.WriteMessage(Int32Value); + } + if (int64Value_ != null) { + output.WriteRawTag(26); + output.WriteMessage(Int64Value); + } + if (floatValue_ != null) { + output.WriteRawTag(34); + output.WriteMessage(FloatValue); + } + if (doubleValue_ != null) { + output.WriteRawTag(42); + output.WriteMessage(DoubleValue); + } + if (boolValue_ != null) { + output.WriteRawTag(50); + output.WriteMessage(BoolValue); + } + if (uint32Value_ != null) { + output.WriteRawTag(58); + output.WriteMessage(Uint32Value); + } + if (uint64Value_ != null) { + output.WriteRawTag(66); + output.WriteMessage(Uint64Value); + } + if (bytesValue_ != null) { + output.WriteRawTag(74); + output.WriteMessage(BytesValue); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } +#endif + } + +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) + { + if (stringValue_ != null) + { + output.WriteRawTag(10); + output.WriteMessage(StringValue); + } + if (int32Value_ != null) + { + output.WriteRawTag(18); + output.WriteMessage(Int32Value); + } + if (int64Value_ != null) + { + output.WriteRawTag(26); + output.WriteMessage(Int64Value); + } + if (floatValue_ != null) + { + output.WriteRawTag(34); + output.WriteMessage(FloatValue); + } + if (doubleValue_ != null) + { + output.WriteRawTag(42); + output.WriteMessage(DoubleValue); + } + if (boolValue_ != null) + { + output.WriteRawTag(50); + output.WriteMessage(BoolValue); + } + if (uint32Value_ != null) + { + output.WriteRawTag(58); + output.WriteMessage(Uint32Value); + } + if (uint64Value_ != null) + { + output.WriteRawTag(66); + output.WriteMessage(Uint64Value); + } + if (bytesValue_ != null) + { + output.WriteRawTag(74); + output.WriteMessage(BytesValue); + } + if (_unknownFields != null) + { + _unknownFields.WriteTo(ref output); + } + } +#endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() + { + int size = 0; + if (stringValue_ != null) + { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(StringValue); + } + if (int32Value_ != null) + { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Int32Value); + } + if (int64Value_ != null) + { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Int64Value); + } + if (floatValue_ != null) + { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(FloatValue); + } + if (doubleValue_ != null) + { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(DoubleValue); + } + if (boolValue_ != null) + { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(BoolValue); + } + if (uint32Value_ != null) + { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Uint32Value); + } + if (uint64Value_ != null) + { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(Uint64Value); + } + if (bytesValue_ != null) + { + size += 1 + pb::CodedOutputStream.ComputeMessageSize(BytesValue); + } + if (_unknownFields != null) + { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(WrappersMessage other) + { + if (other == null) + { + return; + } + if (other.stringValue_ != null) + { + if (stringValue_ == null) + { + StringValue = new global::Google.Protobuf.WellKnownTypes.StringValue(); + } + StringValue.MergeFrom(other.StringValue); + } + if (other.int32Value_ != null) + { + if (int32Value_ == null) + { + Int32Value = new global::Google.Protobuf.WellKnownTypes.Int32Value(); + } + Int32Value.MergeFrom(other.Int32Value); + } + if (other.int64Value_ != null) + { + if (int64Value_ == null) + { + Int64Value = new global::Google.Protobuf.WellKnownTypes.Int64Value(); + } + Int64Value.MergeFrom(other.Int64Value); + } + if (other.floatValue_ != null) + { + if (floatValue_ == null) + { + FloatValue = new global::Google.Protobuf.WellKnownTypes.FloatValue(); + } + FloatValue.MergeFrom(other.FloatValue); + } + if (other.doubleValue_ != null) + { + if (doubleValue_ == null) + { + DoubleValue = new global::Google.Protobuf.WellKnownTypes.DoubleValue(); + } + DoubleValue.MergeFrom(other.DoubleValue); + } + if (other.boolValue_ != null) + { + if (boolValue_ == null) + { + BoolValue = new global::Google.Protobuf.WellKnownTypes.BoolValue(); + } + BoolValue.MergeFrom(other.BoolValue); + } + if (other.uint32Value_ != null) + { + if (uint32Value_ == null) + { + Uint32Value = new global::Google.Protobuf.WellKnownTypes.UInt32Value(); + } + Uint32Value.MergeFrom(other.Uint32Value); + } + if (other.uint64Value_ != null) + { + if (uint64Value_ == null) + { + Uint64Value = new global::Google.Protobuf.WellKnownTypes.UInt64Value(); + } + Uint64Value.MergeFrom(other.Uint64Value); + } + if (other.bytesValue_ != null) + { + if (bytesValue_ == null) + { + BytesValue = new global::Google.Protobuf.WellKnownTypes.BytesValue(); + } + BytesValue.MergeFrom(other.BytesValue); + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) + { +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); +#else + uint tag; + while ((tag = input.ReadTag()) != 0) { + if ((tag & 7) == 4) { + // Abort on any end group tag. + return; + } + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 10: { + if (stringValue_ == null) { + StringValue = new global::Google.Protobuf.WellKnownTypes.StringValue(); + } + input.ReadMessage(StringValue); + break; + } + case 18: { + if (int32Value_ == null) { + Int32Value = new global::Google.Protobuf.WellKnownTypes.Int32Value(); + } + input.ReadMessage(Int32Value); + break; + } + case 26: { + if (int64Value_ == null) { + Int64Value = new global::Google.Protobuf.WellKnownTypes.Int64Value(); + } + input.ReadMessage(Int64Value); + break; + } + case 34: { + if (floatValue_ == null) { + FloatValue = new global::Google.Protobuf.WellKnownTypes.FloatValue(); + } + input.ReadMessage(FloatValue); + break; + } + case 42: { + if (doubleValue_ == null) { + DoubleValue = new global::Google.Protobuf.WellKnownTypes.DoubleValue(); + } + input.ReadMessage(DoubleValue); + break; + } + case 50: { + if (boolValue_ == null) { + BoolValue = new global::Google.Protobuf.WellKnownTypes.BoolValue(); + } + input.ReadMessage(BoolValue); + break; + } + case 58: { + if (uint32Value_ == null) { + Uint32Value = new global::Google.Protobuf.WellKnownTypes.UInt32Value(); + } + input.ReadMessage(Uint32Value); + break; + } + case 66: { + if (uint64Value_ == null) { + Uint64Value = new global::Google.Protobuf.WellKnownTypes.UInt64Value(); + } + input.ReadMessage(Uint64Value); + break; + } + case 74: { + if (bytesValue_ == null) { + BytesValue = new global::Google.Protobuf.WellKnownTypes.BytesValue(); + } + input.ReadMessage(BytesValue); + break; + } + } + } +#endif + } + +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) + { + uint tag; + while ((tag = input.ReadTag()) != 0) + { + if ((tag & 7) == 4) + { + // Abort on any end group tag. + return; + } + switch (tag) + { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 10: + { + if (stringValue_ == null) + { + StringValue = new global::Google.Protobuf.WellKnownTypes.StringValue(); + } + input.ReadMessage(StringValue); + break; + } + case 18: + { + if (int32Value_ == null) + { + Int32Value = new global::Google.Protobuf.WellKnownTypes.Int32Value(); + } + input.ReadMessage(Int32Value); + break; + } + case 26: + { + if (int64Value_ == null) + { + Int64Value = new global::Google.Protobuf.WellKnownTypes.Int64Value(); + } + input.ReadMessage(Int64Value); + break; + } + case 34: + { + if (floatValue_ == null) + { + FloatValue = new global::Google.Protobuf.WellKnownTypes.FloatValue(); + } + input.ReadMessage(FloatValue); + break; + } + case 42: + { + if (doubleValue_ == null) + { + DoubleValue = new global::Google.Protobuf.WellKnownTypes.DoubleValue(); + } + input.ReadMessage(DoubleValue); + break; + } + case 50: + { + if (boolValue_ == null) + { + BoolValue = new global::Google.Protobuf.WellKnownTypes.BoolValue(); + } + input.ReadMessage(BoolValue); + break; + } + case 58: + { + if (uint32Value_ == null) + { + Uint32Value = new global::Google.Protobuf.WellKnownTypes.UInt32Value(); + } + input.ReadMessage(Uint32Value); + break; + } + case 66: + { + if (uint64Value_ == null) + { + Uint64Value = new global::Google.Protobuf.WellKnownTypes.UInt64Value(); + } + input.ReadMessage(Uint64Value); + break; + } + case 74: + { + if (bytesValue_ == null) + { + BytesValue = new global::Google.Protobuf.WellKnownTypes.BytesValue(); + } + input.ReadMessage(BytesValue); + break; + } + } + } + } +#endif + + } + + #endregion + +} + +#endregion Designer generated code diff --git a/src/aspnetcore/src/Http/Http.Abstractions/src/Metadata/ApiEndpointMetadata.cs b/src/aspnetcore/src/Http/Http.Abstractions/src/Metadata/ApiEndpointMetadata.cs new file mode 100644 index 00000000000..815bf2c834c --- /dev/null +++ b/src/aspnetcore/src/Http/Http.Abstractions/src/Metadata/ApiEndpointMetadata.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. + +namespace Microsoft.AspNetCore.Http.Metadata; + +/// +/// Metadata that indicates the endpoint is intended for API clients. +/// When present, authentication handlers should prefer returning status codes over browser redirects. +/// +internal sealed class ApiEndpointMetadata : IApiEndpointMetadata +{ + /// + /// Singleton instance of . + /// + public static readonly ApiEndpointMetadata Instance = new(); + + private ApiEndpointMetadata() + { + } +} diff --git a/src/aspnetcore/src/Http/Http.Abstractions/src/Metadata/IApiEndpointMetadata.cs b/src/aspnetcore/src/Http/Http.Abstractions/src/Metadata/IApiEndpointMetadata.cs new file mode 100644 index 00000000000..cadaafcae1a --- /dev/null +++ b/src/aspnetcore/src/Http/Http.Abstractions/src/Metadata/IApiEndpointMetadata.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Microsoft.AspNetCore.Http.Metadata; + +/// +/// Metadata that indicates the endpoint is an API intended for programmatic access rather than direct browser navigation. +/// When present, authentication handlers should prefer returning status codes over browser redirects. +/// +public interface IApiEndpointMetadata +{ +} diff --git a/src/aspnetcore/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj b/src/aspnetcore/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj index d383efa6a20..37e17a0f0f4 100644 --- a/src/aspnetcore/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj +++ b/src/aspnetcore/src/Http/Http.Abstractions/src/Microsoft.AspNetCore.Http.Abstractions.csproj @@ -35,7 +35,6 @@ Microsoft.AspNetCore.Http.HttpResponse - @@ -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/source-manifest.json b/src/source-manifest.json index 5355e1c4f14..3869bdb0bcf 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -7,10 +7,10 @@ "commitSha": "2586309f3f8553152e2d1d54612e9199975f9cd4" }, { - "barId": 276473, + "barId": 276610, "path": "aspnetcore", "remoteUri": "https://github.com/dotnet/aspnetcore", - "commitSha": "c56ce2f92858158819569e11d4131c09fd847764" + "commitSha": "bf1f642be9fe230fed38e10561d4aa9ed5859b8f" }, { "barId": 276375, From 761a1653d30957e7c26c235d05b7fb8dae3a0455 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 09:42:43 +0200 Subject: [PATCH 04/13] [main] Source code updates from dotnet/xdt (#1631) Co-authored-by: dotnet-maestro[bot] --- src/source-manifest.json | 4 ++-- src/xdt/eng/Version.Details.props | 1 + src/xdt/eng/Version.Details.xml | 6 +++--- src/xdt/eng/common/tools.ps1 | 2 +- src/xdt/global.json | 6 +++--- 5 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 src/xdt/eng/Version.Details.props diff --git a/src/source-manifest.json b/src/source-manifest.json index 3869bdb0bcf..e22790e96d0 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -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/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" } } From 7dce45792cea55a150f386f0e62660efdaf71bb7 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 09:42:52 +0200 Subject: [PATCH 05/13] [main] Update dependencies from dotnet/arcade-services (#1621) Co-authored-by: dotnet-maestro[bot] --- .config/dotnet-tools.json | 2 +- eng/Version.Details.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 From 36ddc8359f32114ebce7e3a8a03636887b7058f6 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 09:43:11 +0200 Subject: [PATCH 06/13] [main] Source code updates from dotnet/msbuild (#1624) Co-authored-by: dotnet-maestro[bot] --- ...ting-and-Debugging-on-.Net-Core-MSBuild.md | 23 +++- src/msbuild/eng/BootStrapMsBuild.targets | 12 -- src/msbuild/eng/Version.Details.xml | 8 +- src/msbuild/eng/Versions.props | 4 +- .../eng/cibuild_bootstrapped_msbuild.ps1 | 2 + .../eng/cibuild_bootstrapped_msbuild.sh | 3 + src/msbuild/eng/restore-toolset.ps1 | 91 +++++++++++++++ src/msbuild/eng/restore-toolset.sh | 26 +++++ src/msbuild/global.json | 4 +- .../BackEnd/MockSdkResolverService.cs | 6 +- .../ProjectCache/ProjectCacheTests.cs | 24 ++-- .../NodeProviderOutOfProcBase.cs | 110 +++++++----------- .../SerializationContractInitializer.cs | 1 + .../HostedSdkResolverServiceBase.cs | 6 + .../SdkResolution/ISdkResolverService.cs | 5 + .../OutOfProcNodeSdkResolverService.cs | 10 ++ .../SdkResolution/SdkResolverService.cs | 3 + .../SdkResolverServiceException.cs | 26 +++++ .../src/Build/BackEnd/Node/OutOfProcNode.cs | 15 ++- src/msbuild/src/Build/Evaluation/Evaluator.cs | 11 +- src/msbuild/src/Build/Microsoft.Build.csproj | 1 + .../src/Framework/MSBuildEventSource.cs | 18 +++ .../src/Shared/NodeEndpointOutOfProcBase.cs | 5 +- src/source-manifest.json | 4 +- 24 files changed, 311 insertions(+), 107 deletions(-) create mode 100644 src/msbuild/eng/restore-toolset.ps1 create mode 100644 src/msbuild/eng/restore-toolset.sh create mode 100644 src/msbuild/src/Build/BackEnd/Components/SdkResolution/SdkResolverServiceException.cs 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 - + - + 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" From ebdc08ef978c083cfd61eb9f73e8831a7d0b9057 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 09:43:37 +0200 Subject: [PATCH 08/13] [main] Source code updates from microsoft/vstest (#1630) Co-authored-by: dotnet-maestro[bot] --- src/source-manifest.json | 4 ++-- src/vstest/eng/Version.Details.props | 1 + src/vstest/eng/Version.Details.xml | 10 +++++----- src/vstest/eng/Versions.props | 2 +- src/vstest/eng/common/tools.ps1 | 2 +- src/vstest/global.json | 6 +++--- .../Helpers/DotnetHostHelper.cs | 15 +++++++++++++++ 7 files changed, 28 insertions(+), 12 deletions(-) create mode 100644 src/vstest/eng/Version.Details.props diff --git a/src/source-manifest.json b/src/source-manifest.json index 910737d250b..1738f02b178 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -127,10 +127,10 @@ "commitSha": "fabe4020161ba6c194289c9c963121c948f1f9ea" }, { - "barId": 275610, + "barId": 276591, "path": "vstest", "remoteUri": "https://github.com/microsoft/vstest", - "commitSha": "f97214fe5fd493b90959165c6db77f878bcb60bd" + "commitSha": "dbcd471883202088496ab81d3ec2d3f3be0981b5" }, { "barId": 276382, 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 { From 201027938cddfb937605b8fe97eeafa1533c1c39 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 09:43:53 +0200 Subject: [PATCH 09/13] [main] Source code updates from dotnet/efcore (#1628) Co-authored-by: dotnet-maestro[bot] --- src/efcore/.gitignore | 3 + src/efcore/eng/Versions.props | 4 +- ...ingExpressionVisitor.StructuralEquality.cs | 2 +- .../Query/SqlExpressions/SelectExpression.cs | 194 +++++++++++++----- ...yableMethodTranslatingExpressionVisitor.cs | 24 ++- ...ingExpressionVisitor.ExpressionVisitors.cs | 18 +- ...nExpandingExpressionVisitor.Expressions.cs | 23 ++- .../NavigationExpandingExpressionVisitor.cs | 23 ++- .../OwnedNavigationsCollectionCosmosTest.cs | 32 +++ .../OwnedNavigationsProjectionCosmosTest.cs | 2 - ...OwnedNavigationsSetOperationsCosmosTest.cs | 66 ++++++ .../InMemoryComplianceTest.cs | 6 +- ...ComplexJsonCollectionRelationalTestBase.cs | 16 ++ ...plexJsonSetOperationsRelationalTestBase.cs | 43 ++++ ...NavigationsCollectionRelationalTestBase.cs | 14 ++ ...igationsSetOperationsRelationalTestBase.cs | 29 +++ .../OwnedJsonCollectionRelationalTestBase.cs | 14 ++ ...wnedJsonSetOperationsRelationalTestBase.cs | 7 + ...NavigationsCollectionRelationalTestBase.cs | 14 ++ ...igationsSetOperationsRelationalTestBase.cs | 40 ++++ .../ComplexPropertiesCollectionTestBase.cs | 2 - .../ComplexPropertiesSetOperationsTestBase.cs | 19 ++ .../NavigationsSetOperationsTestBase.cs | 10 + .../OwnedNavigationsCollectionTestBase.cs | 16 ++ .../OwnedNavigationsSetOperationsTestBase.cs | 10 + .../RelationshipsCollectionTestBase.cs | 33 +++ .../Query/Relationships/RelationshipsData.cs | 40 +++- .../RelationshipsSetOperationsTestBase.cs | 53 +++++ .../ComplexJsonCollectionSqlServerTest.cs | 81 ++++++++ .../ComplexJsonSetOperationsSqlServerTest.cs | 101 +++++++++ .../NavigationsCollectionSqlServerTest.cs | 71 +++++++ .../NavigationsSetOperationsSqlServerTest.cs | 116 +++++++++++ .../OwnedJsonCollectionSqlServerTest.cs | 97 +++++++++ ...OwnedNavigationsCollectionSqlServerTest.cs | 99 +++++++++ ...edNavigationsSetOperationsSqlServerTest.cs | 126 ++++++++++++ .../ComplexJsonSetOperationsSqliteTest.cs | 10 + .../NavigationsSetOperationsSqliteTest.cs | 9 + .../OwnedJsonCollectionSqliteTest.cs | 12 ++ .../OwnedNavigationsCollectionSqliteTest.cs | 12 ++ ...OwnedNavigationsSetOperationsSqliteTest.cs | 14 ++ src/source-manifest.json | 4 +- 41 files changed, 1429 insertions(+), 80 deletions(-) create mode 100644 src/efcore/test/EFCore.Cosmos.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsSetOperationsCosmosTest.cs create mode 100644 src/efcore/test/EFCore.Relational.Specification.Tests/Query/Relationships/ComplexJson/ComplexJsonSetOperationsRelationalTestBase.cs create mode 100644 src/efcore/test/EFCore.Relational.Specification.Tests/Query/Relationships/Navigations/NavigationsSetOperationsRelationalTestBase.cs create mode 100644 src/efcore/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedJson/OwnedJsonSetOperationsRelationalTestBase.cs create mode 100644 src/efcore/test/EFCore.Relational.Specification.Tests/Query/Relationships/OwnedNavigations/OwnedNavigationsSetOperationsRelationalTestBase.cs create mode 100644 src/efcore/test/EFCore.Specification.Tests/Query/Relationships/ComplexProperties/ComplexPropertiesSetOperationsTestBase.cs create mode 100644 src/efcore/test/EFCore.Specification.Tests/Query/Relationships/Navigations/NavigationsSetOperationsTestBase.cs create mode 100644 src/efcore/test/EFCore.Specification.Tests/Query/Relationships/OwnedNavigations/OwnedNavigationsSetOperationsTestBase.cs create mode 100644 src/efcore/test/EFCore.Specification.Tests/Query/Relationships/RelationshipsSetOperationsTestBase.cs create mode 100644 src/efcore/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/ComplexJson/ComplexJsonSetOperationsSqlServerTest.cs create mode 100644 src/efcore/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/Navigations/NavigationsSetOperationsSqlServerTest.cs create mode 100644 src/efcore/test/EFCore.SqlServer.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsSetOperationsSqlServerTest.cs create mode 100644 src/efcore/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/ComplexJson/ComplexJsonSetOperationsSqliteTest.cs create mode 100644 src/efcore/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/Navigations/NavigationsSetOperationsSqliteTest.cs create mode 100644 src/efcore/test/EFCore.Sqlite.FunctionalTests/Query/Relationships/OwnedNavigations/OwnedNavigationsSetOperationsSqliteTest.cs diff --git a/src/efcore/.gitignore b/src/efcore/.gitignore index 345de448057..69367c59bdc 100644 --- a/src/efcore/.gitignore +++ b/src/efcore/.gitignore @@ -301,6 +301,9 @@ paket-files/ .idea/ *.sln.iml +# Visual Studio Code +.vscode/ + # CodeRush personal settings .cr/personal diff --git a/src/efcore/eng/Versions.props b/src/efcore/eng/Versions.props index fa4c79320c3..1b0a4fc84bd 100644 --- a/src/efcore/eng/Versions.props +++ b/src/efcore/eng/Versions.props @@ -1,8 +1,8 @@ 10.0.0 - preview - 7 + rc + 1 False true 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/source-manifest.json b/src/source-manifest.json index d8140d91e62..b3afeb0916b 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -1,10 +1,10 @@ { "repositories": [ { - "barId": 276435, + "barId": 276631, "path": "arcade", "remoteUri": "https://github.com/dotnet/arcade", - "commitSha": "2586309f3f8553152e2d1d54612e9199975f9cd4" + "commitSha": "0fbc9e8711fa91e68c2bf3db376fb83b46f4ac35" }, { "barId": 276610, From 910ba8c7204481004fa36c9aae584be7a68e2f4d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 08:46:58 +0000 Subject: [PATCH 11/13] [main] Source code updates from dotnet/command-line-api (#1614) [main] Source code updates from dotnet/command-line-api --- src/command-line-api/eng/Versions.props | 5 ++- ...ommandLine_api_is_not_changed.approved.txt | 1 + .../HelpOptionTests.cs | 25 ++++++++++++ .../src/System.CommandLine/Help/HelpAction.cs | 38 ++++++++++++++++++- src/source-manifest.json | 4 +- 5 files changed, 68 insertions(+), 5 deletions(-) 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/source-manifest.json b/src/source-manifest.json index b3afeb0916b..f98113162a2 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -19,10 +19,10 @@ "commitSha": "2478ada175a4089ab1310960d2590810e9adc4f9" }, { - "barId": 275338, + "barId": 276587, "path": "command-line-api", "remoteUri": "https://github.com/dotnet/command-line-api", - "commitSha": "dbc3781d3398b69cd9ffe24f60a7b77110bdadbf" + "commitSha": "00d2b3bb1c6b31037cf2c72443b7042a58fd536d" }, { "barId": 276378, From 00380ade7d89de26abb116c09456915330d3f7ab Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 09:18:53 +0000 Subject: [PATCH 12/13] [main] Source code updates from dotnet/sdk (#1582) [main] Source code updates from dotnet/sdk - Add Version.Details.xml entry for System.Diagnostics.DiagnosticSource - Only reference System.Diagnostics.DiagnosticSource in netframework --- .../.github/workflows/copilot-setup-steps.yml | 1 + src/sdk/CODEOWNERS | 16 +- src/sdk/Directory.Packages.props | 1 + .../documentation/general/dotnet-run-file.md | 2 + src/sdk/eng/Version.Details.xml | 12 +- src/sdk/eng/Versions.props | 9 +- .../Microsoft.DotNet.Cli.Utils/Activities.cs | 20 +++ .../ForwardingAppImplementation.cs | 6 +- .../MSBuildForwardingAppWithoutLogging.cs | 8 +- .../Microsoft.DotNet.Cli.Utils.csproj | 4 + .../Commands/MSBuild/MSBuildForwardingApp.cs | 2 +- .../Run/VirtualProjectBuildingCommand.cs | 138 +++++++++++------- src/sdk/src/Cli/dotnet/Telemetry/Telemetry.cs | 120 ++++++++++----- .../Telemetry/TelemetryCommonProperties.cs | 5 +- .../Tasks/ComputeDotnetBaseImageAndTag.cs | 1 - .../FrameworkPackages.net5.0.cs | 2 +- .../FrameworkPackages.net6.0.cs | 2 +- .../FrameworkPackages.netcoreapp2.1.cs | 10 +- .../FrameworkPackages.netcoreapp3.0.cs | 2 +- .../FrameworkPackages.netcoreapp3.1.cs | 2 +- .../FrameworkPackages.netstandard2.0.cs | 2 +- .../FrameworkPackages.netstandard2.1.cs | 8 +- .../Convert/DotnetProjectConvertTests.cs | 96 ++++++++---- .../CommandTests/Run/RunFileTests.cs | 40 +++-- src/source-manifest.json | 4 +- 25 files changed, 333 insertions(+), 180 deletions(-) create mode 100644 src/sdk/src/Cli/Microsoft.DotNet.Cli.Utils/Activities.cs diff --git a/src/sdk/.github/workflows/copilot-setup-steps.yml b/src/sdk/.github/workflows/copilot-setup-steps.yml index a47f9b027ad..604513c0414 100644 --- a/src/sdk/.github/workflows/copilot-setup-steps.yml +++ b/src/sdk/.github/workflows/copilot-setup-steps.yml @@ -25,6 +25,7 @@ jobs: steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Do an initial build to ensure all dependencies are restored + continue-on-error: true run: | ./build.sh - name: Put repo-local dotnet install on PATH diff --git a/src/sdk/CODEOWNERS b/src/sdk/CODEOWNERS index c69655b8bee..25ce375c375 100644 --- a/src/sdk/CODEOWNERS +++ b/src/sdk/CODEOWNERS @@ -34,12 +34,16 @@ /test/dotnet-format.UnitTests @arunchndr # Area-NuGet -/src/Cli/dotnet/commands/dotnet-add/dotnet-add-package @dotnet/nuget-team -/test/dotnet-add-package.Tests @dotnet/nuget-team -/src/Cli/dotnet/commands/dotnet-nuget @dotnet/nuget-team -/test/dotnet-nuget.UnitTests @dotnet/nuget-team -/src/Cli/dotnet/commands/dotnet-list/dotnet-list-package @dotnet/nuget-team -/test/dotnet-list-package.Tests @dotnet/nuget-team +/src/Cli/dotnet/Commands/NuGet @dotnet/nuget-team +/src/Cli/dotnet/Commands/Pack @dotnet/nuget-team +/src/Cli/dotnet/Commands/Package @dotnet/nuget-team +/src/Cli/dotnet/Commands/Restore @dotnet/nuget-team +/test/Microsoft.NET.Restore.Tests @dotnet/nuget-team +/test/Microsoft.NET.Pack.Tests @dotnet/nuget-team +/test/dotnet.Tests/CommandTests/NuGet @dotnet/nuget-team +/test/dotnet.Tests/CommandTests/Pack @dotnet/nuget-team +/test/dotnet.Tests/CommandTests/Package @dotnet/nuget-team +/test/dotnet.Tests/CommandTests/Restore @dotnet/nuget-team # Area-FSharp /src/Cli/dotnet/commands/dotnet-fsi @dotnet/fsharp diff --git a/src/sdk/Directory.Packages.props b/src/sdk/Directory.Packages.props index 104dedfd9ea..abe2e9e23b4 100644 --- a/src/sdk/Directory.Packages.props +++ b/src/sdk/Directory.Packages.props @@ -108,6 +108,7 @@ + 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)} + """); + } + } - - """); + // 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 f98113162a2..10ccc6637cf 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -97,10 +97,10 @@ "commitSha": "086c9380ad71ac75c8af5d5091d3ad339fc842e1" }, { - "barId": 276134, + "barId": 276276, "path": "sdk", "remoteUri": "https://github.com/dotnet/sdk", - "commitSha": "2f666ecda03b5b6c669b9728e9f35315af6edf96" + "commitSha": "049672a7df90f87cfead427665edc37c37c22ed1" }, { "barId": 276385, From 2dfd0aa278fc5a46c7f5e881584d0895aaac68fc Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jul 2025 11:54:10 +0000 Subject: [PATCH 13/13] [main] Source code updates from dotnet/command-line-api (#1632) [main] Source code updates from dotnet/command-line-api --- src/command-line-api/eng/Version.Details.props | 1 + src/source-manifest.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 src/command-line-api/eng/Version.Details.props 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/source-manifest.json b/src/source-manifest.json index 10ccc6637cf..93508d62c58 100644 --- a/src/source-manifest.json +++ b/src/source-manifest.json @@ -19,10 +19,10 @@ "commitSha": "2478ada175a4089ab1310960d2590810e9adc4f9" }, { - "barId": 276587, + "barId": 276722, "path": "command-line-api", "remoteUri": "https://github.com/dotnet/command-line-api", - "commitSha": "00d2b3bb1c6b31037cf2c72443b7042a58fd536d" + "commitSha": "3a3e014313d2c1bddc01b4333886783a7492c652" }, { "barId": 276378,