From 9192d0309151d17b48c01f141e2c3ba797798866 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Tue, 18 Feb 2025 22:25:08 -0800 Subject: [PATCH 1/2] Add set up for validations generator --- AspNetCore.sln | 116 ++-- .../SupportFiles/Directory.Build.targets | 2 +- .../src/Microsoft.AspNetCore.App.Ref.sfxproj | 2 +- .../DiagnosticDescriptors.cs | 0 .../GeneratorSteps.cs | 0 ...tCore.Http.RequestDelegateGenerator.csproj | 0 .../RequestDelegateGenerator.cs | 0 .../RequestDelegateGeneratorSources.cs | 0 .../RequestDelegateGeneratorSuppressor.cs | 0 .../Resources.resx | 0 .../Emitters/DiagnosticEmitter.cs | 0 .../Emitters/EmitterConstants.cs | 0 .../Emitters/EmitterContext.cs | 0 .../Emitters/EmitterExtensions.cs | 0 .../Emitters/EndpointEmitter.cs | 0 .../EndpointJsonPreparationEmitter.cs | 0 .../Emitters/EndpointParameterEmitter.cs | 0 .../StaticRouteHandlerModel/Endpoint.cs | 0 .../EndpointDelegateComparer.cs | 0 .../EndpointHttpMethodComparer.cs | 0 .../EndpointParameter.cs | 0 .../EndpointParameterSource.cs | 0 .../EndpointResponse.cs | 0 .../InvocationOperationExtensions.cs | 0 .../Model/ConstructorParameter.cs | 0 .../Model/EndpointParameterExtensions.cs | 0 .../Model/ParameterLookupKey.cs | 0 .../StaticRouteHandlerModel.Emitter.cs | 0 ...spNetCore.Http.ValidationsGenerator.csproj | 33 ++ .../ValidationsGenerator.cs | 14 + ...ft.AspNetCore.Http.Extensions.Tests.csproj | 8 +- .../ValidationsGenerator.Parameters.cs | 44 ++ .../ValidationsGeneratorTestBase.cs | 534 ++++++++++++++++++ ...orTests.CanValidateParameters.verified.txt | 1 + ...oft.AspNetCore.Http.Microbenchmarks.csproj | 2 +- src/Http/HttpAbstractions.slnf | 5 +- .../MinimalSample/MinimalSample.csproj | 2 +- .../src/Microsoft.AspNetCore.Identity.csproj | 2 +- src/Identity/Identity.slnf | 4 +- src/Mvc/Mvc.slnf | 4 +- src/OpenApi/sample/Sample.csproj | 2 +- .../src/Microsoft.AspNetCore.OpenApi.csproj | 2 +- 42 files changed, 687 insertions(+), 90 deletions(-) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/DiagnosticDescriptors.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/GeneratorSteps.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/RequestDelegateGenerator.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/RequestDelegateGeneratorSources.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/RequestDelegateGeneratorSuppressor.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/Resources.resx (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/Emitters/DiagnosticEmitter.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/Emitters/EmitterConstants.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/Emitters/EmitterContext.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/Emitters/EmitterExtensions.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/Emitters/EndpointEmitter.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/Emitters/EndpointJsonPreparationEmitter.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/Endpoint.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/EndpointDelegateComparer.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/EndpointHttpMethodComparer.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/EndpointParameter.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/EndpointParameterSource.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/EndpointResponse.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/InvocationOperationExtensions.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/Model/ConstructorParameter.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/Model/EndpointParameterExtensions.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/Model/ParameterLookupKey.cs (100%) rename src/Http/Http.Extensions/gen/{ => Microsoft.AspNetCore.Http.RequestDelegateGenerator}/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs (100%) create mode 100644 src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/Microsoft.AspNetCore.Http.ValidationsGenerator.csproj create mode 100644 src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/ValidationsGenerator.cs create mode 100644 src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGenerator.Parameters.cs create mode 100644 src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGeneratorTestBase.cs create mode 100644 src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidateParameters.verified.txt diff --git a/AspNetCore.sln b/AspNetCore.sln index 52fe9c9b652c..09105a846cb0 100644 --- a/AspNetCore.sln +++ b/AspNetCore.sln @@ -537,8 +537,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Tests" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.FunctionalTests", "src\DefaultBuilder\test\Microsoft.AspNetCore.FunctionalTests\Microsoft.AspNetCore.FunctionalTests.csproj", "{D708256C-4A68-4B15-AAE5-6EFA41223A70}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Grpc", "Grpc", "{8DAC59BE-CB96-4F04-909C-56C22E7665EB}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{E763DA15-8F4E-446C-99B8-309053C75598}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InteropTests", "src\Grpc\Interop\test\InteropTests\InteropTests.csproj", "{3ADC50B9-2EBB-422A-8424-F9FC67841CA1}" @@ -1598,46 +1596,24 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IIS.ShadowCopy.Tests", "src\Servers\IIS\IIS\test\IIS.ShadowCopy.Tests\IIS.ShadowCopy.Tests.csproj", "{93D3CC76-9FA9-4198-B49D-54BA918105EE}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SDK-Analyzers", "SDK-Analyzers", "{6C06163A-80E9-49C1-817C-B391852BA563}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Components", "Components", "{CC45FA2D-128B-485D-BA6D-DFD9735CB3C3}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.SdkAnalyzers", "src\Tools\SDK-Analyzers\Components\src\Microsoft.AspNetCore.Components.SdkAnalyzers.csproj", "{825BCF97-67A9-4834-B3A8-C3DC97A90E41}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.SdkAnalyzers.Tests", "src\Tools\SDK-Analyzers\Components\test\Microsoft.AspNetCore.Components.SdkAnalyzers.Tests.csproj", "{DC349A25-0DBF-4468-99E1-B95C22D3A7EF}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OutputCaching", "OutputCaching", "{AA5ABFBC-177C-421E-B743-005E0FD1248B}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OutputCaching", "src\Middleware\OutputCaching\src\Microsoft.AspNetCore.OutputCaching.csproj", "{5D5A3B60-A014-447C-9126-B1FA6C821C8D}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{B5AC1D8B-9D43-4261-AE0F-6B7574656F2C}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OutputCachingSample", "src\Middleware\OutputCaching\samples\OutputCachingSample\OutputCachingSample.csproj", "{C3FFA4E4-0E7E-4866-A15F-034245BFD800}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RequestDecompression", "RequestDecompression", "{5465F96F-33D5-454E-9C40-494E58AEEE5D}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.RequestDecompression.Tests", "src\Middleware\RequestDecompression\test\Microsoft.AspNetCore.RequestDecompression.Tests.csproj", "{97996D39-7722-4AFC-A41A-AD61CA7A413D}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RequestDecompressionSample", "src\Middleware\RequestDecompression\sample\RequestDecompressionSample.csproj", "{37144E52-611B-40E8-807C-2821F5A814CB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.RequestDecompression", "src\Middleware\RequestDecompression\src\Microsoft.AspNetCore.RequestDecompression.csproj", "{559FE354-7E08-4310-B4F3-AE30F34DEED5}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LinkabilityChecker", "LinkabilityChecker", "{94F95276-7CDF-44A8-B159-D09702EF6794}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinkabilityChecker", "src\Tools\LinkabilityChecker\LinkabilityChecker.csproj", "{EA7D844B-C180-41C7-9D55-273AD88BF71F}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interop", "Interop", "{7A331A1C-E2C4-4E37-B0A0-B5AA10661229}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "JsonTranscoding", "JsonTranscoding", "{DD076DDA-7956-4361-A7D4-2B8025AB3DFD}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "perf", "perf", "{5CDB8ABC-9DD0-4A9F-8948-EED5FFE89F67}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{151E6F9E-107B-4DDC-A2B1-95115801FD14}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{B43BE3EB-9846-4484-88D8-05165202A0FC}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "testassets", "testassets", "{9A8AE587-A3DB-4211-8354-430C4CCBEB9B}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTestsWebsite", "src\Grpc\JsonTranscoding\test\testassets\IntegrationTestsWebsite\IntegrationTestsWebsite.csproj", "{2E28881D-A188-47AF-800A-B5877AD8C288}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sandbox", "src\Grpc\JsonTranscoding\test\testassets\Sandbox\Sandbox.csproj", "{A53696E8-6065-41BA-84FB-E89E0DACFF6C}" @@ -1656,16 +1632,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Grpc.M EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IIS.LongTests", "src\Servers\IIS\IIS\test\IIS.LongTests\IIS.LongTests.csproj", "{B7DAA48B-8E5E-4A5D-9FEB-E6D49AE76A04}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildAfterTargetingPack", "BuildAfterTargetingPack", "{489020F2-80D9-4468-A5D3-07E785837A5D}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BuildAfterTargetingPack", "src\BuildAfterTargetingPack\BuildAfterTargetingPack.csproj", "{8FED7E65-A7DD-4F13-8980-BF03E77B6C85}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OutputCaching.Tests", "src\Middleware\OutputCaching\test\Microsoft.AspNetCore.OutputCaching.Tests.csproj", "{046F43BC-BEE4-48B7-8C09-ED0A1054A2D7}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ResultsOfTGenerator", "src\Http\Http.Results\tools\ResultsOfTGenerator\ResultsOfTGenerator.csproj", "{9716D0D0-2251-44DD-8596-67D253EEF41C}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OpenApi", "OpenApi", "{2299CCD8-8F9C-4F2B-A633-9BF4DA81022B}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OpenApi", "src\OpenApi\src\Microsoft.AspNetCore.OpenApi.csproj", "{EFC8EA45-572D-4D8D-A597-9045A2D8EC40}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.RateLimiting", "src\Middleware\RateLimiting\src\Microsoft.AspNetCore.RateLimiting.csproj", "{8EE73488-2B92-42BD-96C9-0DD65405C828}" @@ -1676,14 +1648,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelixTestRunner", "eng\tool EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Html.Abstractions.Tests", "src\Html.Abstractions\test\Microsoft.AspNetCore.Html.Abstractions.Tests.csproj", "{487EF7BE-5009-4C70-B79E-45519BDD9603}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RateLimiting", "RateLimiting", "{1D865E78-7A66-4CA9-92EE-2B350E45281F}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.RequestDecompression.Microbenchmarks", "src\Middleware\RequestDecompression\perf\Microbenchmarks\Microsoft.AspNetCore.RequestDecompression.Microbenchmarks.csproj", "{3309FA1E-4E95-49E9-BE2A-827D01FD63C0}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-user-jwts", "src\Tools\dotnet-user-jwts\src\dotnet-user-jwts.csproj", "{B34CB502-0286-4939-B25F-45998528A802}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dotnet-user-jwts", "dotnet-user-jwts", "{AB4B9E75-719C-4589-B852-20FBFD727730}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MinimalJwtBearerSample", "src\Security\Authentication\JwtBearer\samples\MinimalJwtBearerSample\MinimalJwtBearerSample.csproj", "{7F079E92-32D5-4257-B95B-CFFB0D49C160}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-user-jwts.Tests", "src\Tools\dotnet-user-jwts\test\dotnet-user-jwts.Tests.csproj", "{89896261-C5DD-4901-BCA7-7A5F718BC008}" @@ -1702,8 +1670,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "stress", "stress", "{A59464 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.CustomElements", "src\Components\CustomElements\src\Microsoft.AspNetCore.Components.CustomElements.csproj", "{76C3E22D-092B-4E8A-81F0-DCF071BFF4CD}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CustomElements", "CustomElements", "{0BB58FB6-8B66-4C6D-BA8A-DF3AFAF9AB8F}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Templates.Blazor.WebAssembly.Tests", "src\ProjectTemplates\test\Templates.Blazor.WebAssembly.Tests\Templates.Blazor.WebAssembly.Tests.csproj", "{7CA0A9AF-9088-471C-B0B6-EBF43F21D3B9}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RateLimitingSample", "src\Middleware\RateLimiting\samples\RateLimitingSample\RateLimitingSample.csproj", "{91C3C03E-EA56-4ABA-9E73-A3DA4C2833D9}" @@ -1716,42 +1682,28 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebTransportInteractiveSamp EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Templates.Blazor.WebAssembly.Auth.Tests", "src\ProjectTemplates\test\Templates.Blazor.WebAssembly.Auth.Tests\Templates.Blazor.WebAssembly.Auth.Tests.csproj", "{3A6FD623-F7F3-404B-8A39-CAFB40CA6A08}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{890B5210-48EF-488F-93A2-F13BCB07C780}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebAppSample", "src\Framework\AspNetCoreAnalyzers\samples\WebAppSample\WebAppSample.csproj", "{A8E2AB77-8F57-47C2-A961-2F316793CAFF}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F43CC5EA-6032-4A11-A9B2-6D48CB5EB082}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "perf", "perf", "{74377D3E-E0C6-41A4-89ED-11A9C00142A9}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.HttpSys.Microbenchmarks", "src\Servers\HttpSys\perf\Microbenchmarks\Microsoft.AspNetCore.Server.HttpSys.Microbenchmarks.csproj", "{3C7C65BF-0C13-418E-90BD-EC9C3CD282CB}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Transport.NamedPipes", "Transport.NamedPipes", "{F057512B-55BF-4A8B-A027-A0505F8BA10C}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes", "src\Servers\Kestrel\Transport.NamedPipes\src\Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes.csproj", "{10173568-A65E-44E5-8C6F-4AA49D0577A1}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes.Tests", "src\Servers\Kestrel\Transport.NamedPipes\test\Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes.Tests.csproj", "{97C7D2A4-87E5-4A4A-A170-D736427D5C21}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Http.RequestDelegateGenerator", "src\Http\Http.Extensions\gen\Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj", "{4730F56D-24EF-4BB2-AA75-862E31205F3A}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "QuickGrid", "QuickGrid", "{C406D9E0-1585-43F9-AA8F-D468AF84A996}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.QuickGrid", "src\Components\QuickGrid\Microsoft.AspNetCore.Components.QuickGrid\src\Microsoft.AspNetCore.Components.QuickGrid.csproj", "{7757E360-40F5-4C90-9D7F-E6B0E62BA9E2}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter", "src\Components\QuickGrid\Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter\src\Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter.csproj", "{F0BF2260-5AE2-4248-81DE-AC5B9FC6A931}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazingPizza.Server", "src\Components\benchmarkapps\BlazingPizza.Server\BlazingPizza.Server.csproj", "{A05652B3-953E-4915-9D7F-0E361D988815}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Endpoints", "Endpoints", "{7BAEB9BF-28F4-4DFD-9A04-E5193683C261}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Endpoints", "src\Components\Endpoints\src\Microsoft.AspNetCore.Components.Endpoints.csproj", "{AE4D272D-6F13-42C8-9404-C149188AFA33}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Components.Endpoints.Tests", "src\Components\Endpoints\test\Microsoft.AspNetCore.Components.Endpoints.Tests.csproj", "{5D438258-CB19-4282-814F-974ABBC71411}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorUnitedApp", "src\Components\Samples\BlazorUnitedApp\BlazorUnitedApp.csproj", "{F5AE525F-F435-40F9-A567-4D5EC3B50D6E}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BearerToken", "BearerToken", "{56291265-B7BF-4756-92AB-FC30F09381D1}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Authentication.BearerToken", "src\Security\Authentication\BearerToken\src\Microsoft.AspNetCore.Authentication.BearerToken.csproj", "{66FA1041-5556-43A0-9CA3-F9937F085F6E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IdentitySample.ApiEndpoints", "src\Identity\samples\IdentitySample.ApiEndpoints\IdentitySample.ApiEndpoints.csproj", "{37FC77EA-AC44-4D08-B002-8EFF415C424A}" @@ -1780,18 +1732,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Components.WasmRemoteAuthen EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample", "src\OpenApi\sample\Sample.csproj", "{6DEC24A8-A166-432F-8E3B-58FFCDA92F52}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MicroBenchmarks", "MicroBenchmarks", "{6469F11E-8CEE-4292-820B-324DFFC88EBC}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Caching.MicroBenchmarks", "src\Caching\perf\MicroBenchmarks\Microsoft.Extensions.Caching.MicroBenchmarks\Microsoft.Extensions.Caching.MicroBenchmarks.csproj", "{8D2CC6ED-5105-4F52-8757-C21F4DE78589}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "perf", "perf", "{9DC6B242-457B-4767-A84B-C3D23B76C642}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.OpenApi.Microbenchmarks", "src\OpenApi\perf\Microbenchmarks\Microsoft.AspNetCore.OpenApi.Microbenchmarks.csproj", "{D53F0EF7-0CDC-49B4-AA2D-229901B0A734}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KeyManagementSimulator", "src\DataProtection\samples\KeyManagementSimulator\KeyManagementSimulator.csproj", "{5B5F86CC-3598-463C-9F9B-F78FBB6642F4}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "StaticAssets", "StaticAssets", "{274100A5-5B2D-4EA2-AC42-A62257FC6BDC}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.StaticAssets", "src\StaticAssets\src\Microsoft.AspNetCore.StaticAssets.csproj", "{4D8DE54A-4F32-4881-B07B-DDC79619E573}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.StaticAssets.Tests", "src\StaticAssets\test\Microsoft.AspNetCore.StaticAssets.Tests.csproj", "{9536C284-65B4-4884-BB50-06D629095C3E}" @@ -1802,14 +1748,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GetDocumentSample", "src\To EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorUnitedApp.Client", "src\Components\Samples\BlazorUnitedApp.Client\BlazorUnitedApp.Client.csproj", "{757CBDE0-5D0A-4FD8-99F3-6C20BDDD4E63}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{B32FF7A7-9CB3-4DCD-AE97-3B2594DB9DAC}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.OpenApi.Tests", "src\OpenApi\test\Microsoft.AspNetCore.OpenApi.Tests\Microsoft.AspNetCore.OpenApi.Tests.csproj", "{B9BBC1A8-7F58-4F43-94C3-5F3CB125CEF7}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.App.SourceGenerators", "src\Framework\AspNetCoreAnalyzers\src\SourceGenerators\Microsoft.AspNetCore.App.SourceGenerators.csproj", "{C3928C15-1836-46DB-A09D-9EFBCCA33E08}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Assets", "Assets", "{2B858B82-5F0B-4A24-B3C0-5E99149F70D6}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.App.Internal.Assets", "src\Assets\Microsoft.AspNetCore.App.Internal.Assets.csproj", "{2AAE7819-BC3E-48F4-9CFA-5DD4CD5FFD62}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OpenApi", "OpenApi", "{96EC4DD3-028E-6E27-5B14-08C21B07CE89}" @@ -1824,6 +1766,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.OpenAp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.OpenApi.Build.Tests", "src\OpenApi\test\Microsoft.AspNetCore.OpenApi.Build.Tests\Microsoft.AspNetCore.OpenApi.Build.Tests.csproj", "{10F96346-4215-4642-B837-0B5B08AC27AE}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{01A75167-DF5A-AF38-8700-C3FBB2C2CFF5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Http.RequestDelegateGenerator", "src\Http\Http.Extensions\gen\Microsoft.AspNetCore.Http.RequestDelegateGenerator\Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj", "{E6D564C0-4CA5-411C-BF40-9802AF7900CB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Http.ValidationsGenerator", "src\Http\Http.Extensions\gen\Microsoft.AspNetCore.Http.ValidationsGenerator\Microsoft.AspNetCore.Http.ValidationsGenerator.csproj", "{7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -10459,22 +10407,6 @@ Global {97C7D2A4-87E5-4A4A-A170-D736427D5C21}.Release|x64.Build.0 = Release|Any CPU {97C7D2A4-87E5-4A4A-A170-D736427D5C21}.Release|x86.ActiveCfg = Release|Any CPU {97C7D2A4-87E5-4A4A-A170-D736427D5C21}.Release|x86.Build.0 = Release|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Debug|arm64.ActiveCfg = Debug|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Debug|arm64.Build.0 = Debug|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Debug|x64.ActiveCfg = Debug|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Debug|x64.Build.0 = Debug|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Debug|x86.ActiveCfg = Debug|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Debug|x86.Build.0 = Debug|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Release|Any CPU.Build.0 = Release|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Release|arm64.ActiveCfg = Release|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Release|arm64.Build.0 = Release|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Release|x64.ActiveCfg = Release|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Release|x64.Build.0 = Release|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Release|x86.ActiveCfg = Release|Any CPU - {4730F56D-24EF-4BB2-AA75-862E31205F3A}.Release|x86.Build.0 = Release|Any CPU {7757E360-40F5-4C90-9D7F-E6B0E62BA9E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7757E360-40F5-4C90-9D7F-E6B0E62BA9E2}.Debug|Any CPU.Build.0 = Debug|Any CPU {7757E360-40F5-4C90-9D7F-E6B0E62BA9E2}.Debug|arm64.ActiveCfg = Debug|Any CPU @@ -11019,6 +10951,38 @@ Global {10F96346-4215-4642-B837-0B5B08AC27AE}.Release|x64.Build.0 = Release|Any CPU {10F96346-4215-4642-B837-0B5B08AC27AE}.Release|x86.ActiveCfg = Release|Any CPU {10F96346-4215-4642-B837-0B5B08AC27AE}.Release|x86.Build.0 = Release|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Debug|arm64.ActiveCfg = Debug|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Debug|arm64.Build.0 = Debug|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Debug|x64.ActiveCfg = Debug|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Debug|x64.Build.0 = Debug|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Debug|x86.ActiveCfg = Debug|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Debug|x86.Build.0 = Debug|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Release|Any CPU.Build.0 = Release|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Release|arm64.ActiveCfg = Release|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Release|arm64.Build.0 = Release|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Release|x64.ActiveCfg = Release|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Release|x64.Build.0 = Release|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Release|x86.ActiveCfg = Release|Any CPU + {E6D564C0-4CA5-411C-BF40-9802AF7900CB}.Release|x86.Build.0 = Release|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Debug|arm64.ActiveCfg = Debug|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Debug|arm64.Build.0 = Debug|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Debug|x64.ActiveCfg = Debug|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Debug|x64.Build.0 = Debug|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Debug|x86.ActiveCfg = Debug|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Debug|x86.Build.0 = Debug|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Release|Any CPU.Build.0 = Release|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Release|arm64.ActiveCfg = Release|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Release|arm64.Build.0 = Release|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Release|x64.ActiveCfg = Release|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Release|x64.Build.0 = Release|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Release|x86.ActiveCfg = Release|Any CPU + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -11281,7 +11245,6 @@ Global {BCD032DD-D088-4F72-B80F-48D0EA845F87} = {881FE4C3-1553-4CA1-B430-DDD37B3493AB} {58955E85-0D55-45FF-97EE-BDD096522954} = {BCD032DD-D088-4F72-B80F-48D0EA845F87} {D708256C-4A68-4B15-AAE5-6EFA41223A70} = {BCD032DD-D088-4F72-B80F-48D0EA845F87} - {8DAC59BE-CB96-4F04-909C-56C22E7665EB} = {017429CC-C5FB-48B4-9C46-034E29EE2F06} {E763DA15-8F4E-446C-99B8-309053C75598} = {7A331A1C-E2C4-4E37-B0A0-B5AA10661229} {3ADC50B9-2EBB-422A-8424-F9FC67841CA1} = {E763DA15-8F4E-446C-99B8-309053C75598} {05A169C7-4F20-4516-B10A-B13C5649D346} = {017429CC-C5FB-48B4-9C46-034E29EE2F06} @@ -11811,6 +11774,9 @@ Global {4C4590E4-54F5-3693-9633-60A8DCA89385} = {96EC4DD3-028E-6E27-5B14-08C21B07CE89} {51BE4B37-D772-4BFA-8DAE-CF18730BEB89} = {4C4590E4-54F5-3693-9633-60A8DCA89385} {10F96346-4215-4642-B837-0B5B08AC27AE} = {4C4590E4-54F5-3693-9633-60A8DCA89385} + {01A75167-DF5A-AF38-8700-C3FBB2C2CFF5} = {225AEDCF-7162-4A86-AC74-06B84660B379} + {E6D564C0-4CA5-411C-BF40-9802AF7900CB} = {01A75167-DF5A-AF38-8700-C3FBB2C2CFF5} + {7899F5DD-AA7C-4561-BAC4-E2EC78B7D157} = {01A75167-DF5A-AF38-8700-C3FBB2C2CFF5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F} diff --git a/eng/testing/linker/SupportFiles/Directory.Build.targets b/eng/testing/linker/SupportFiles/Directory.Build.targets index eb82d94bec27..765082e447ac 100644 --- a/eng/testing/linker/SupportFiles/Directory.Build.targets +++ b/eng/testing/linker/SupportFiles/Directory.Build.targets @@ -76,7 +76,7 @@ - + diff --git a/src/Framework/App.Ref/src/Microsoft.AspNetCore.App.Ref.sfxproj b/src/Framework/App.Ref/src/Microsoft.AspNetCore.App.Ref.sfxproj index 9ef72c5f84e5..c0d8ce0f8962 100644 --- a/src/Framework/App.Ref/src/Microsoft.AspNetCore.App.Ref.sfxproj +++ b/src/Framework/App.Ref/src/Microsoft.AspNetCore.App.Ref.sfxproj @@ -72,7 +72,7 @@ OutputItemType="AspNetCoreAnalyzer" ReferenceOutputAssembly="false" /> - diff --git a/src/Http/Http.Extensions/gen/DiagnosticDescriptors.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/DiagnosticDescriptors.cs similarity index 100% rename from src/Http/Http.Extensions/gen/DiagnosticDescriptors.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/DiagnosticDescriptors.cs diff --git a/src/Http/Http.Extensions/gen/GeneratorSteps.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/GeneratorSteps.cs similarity index 100% rename from src/Http/Http.Extensions/gen/GeneratorSteps.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/GeneratorSteps.cs diff --git a/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj similarity index 100% rename from src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj diff --git a/src/Http/Http.Extensions/gen/RequestDelegateGenerator.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGenerator.cs similarity index 100% rename from src/Http/Http.Extensions/gen/RequestDelegateGenerator.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGenerator.cs diff --git a/src/Http/Http.Extensions/gen/RequestDelegateGeneratorSources.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGeneratorSources.cs similarity index 100% rename from src/Http/Http.Extensions/gen/RequestDelegateGeneratorSources.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGeneratorSources.cs diff --git a/src/Http/Http.Extensions/gen/RequestDelegateGeneratorSuppressor.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGeneratorSuppressor.cs similarity index 100% rename from src/Http/Http.Extensions/gen/RequestDelegateGeneratorSuppressor.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/RequestDelegateGeneratorSuppressor.cs diff --git a/src/Http/Http.Extensions/gen/Resources.resx b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/Resources.resx similarity index 100% rename from src/Http/Http.Extensions/gen/Resources.resx rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/Resources.resx diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/DiagnosticEmitter.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/DiagnosticEmitter.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/DiagnosticEmitter.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/DiagnosticEmitter.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EmitterConstants.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/EmitterConstants.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EmitterConstants.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/EmitterConstants.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EmitterContext.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/EmitterContext.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EmitterContext.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/EmitterContext.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EmitterExtensions.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/EmitterExtensions.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EmitterExtensions.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/EmitterExtensions.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointEmitter.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/EndpointEmitter.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointEmitter.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/EndpointEmitter.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointJsonPreparationEmitter.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/EndpointJsonPreparationEmitter.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointJsonPreparationEmitter.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/EndpointJsonPreparationEmitter.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Endpoint.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Endpoint.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Endpoint.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Endpoint.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointDelegateComparer.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/EndpointDelegateComparer.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointDelegateComparer.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/EndpointDelegateComparer.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointHttpMethodComparer.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/EndpointHttpMethodComparer.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointHttpMethodComparer.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/EndpointHttpMethodComparer.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointParameter.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/EndpointParameter.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointParameter.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/EndpointParameter.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointParameterSource.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/EndpointParameterSource.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointParameterSource.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/EndpointParameterSource.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointResponse.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/EndpointResponse.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/EndpointResponse.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/EndpointResponse.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/InvocationOperationExtensions.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/InvocationOperationExtensions.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/InvocationOperationExtensions.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/InvocationOperationExtensions.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Model/ConstructorParameter.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Model/ConstructorParameter.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Model/ConstructorParameter.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Model/ConstructorParameter.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Model/EndpointParameterExtensions.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Model/EndpointParameterExtensions.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Model/EndpointParameterExtensions.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Model/EndpointParameterExtensions.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Model/ParameterLookupKey.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Model/ParameterLookupKey.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Model/ParameterLookupKey.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/Model/ParameterLookupKey.cs diff --git a/src/Http/Http.Extensions/gen/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs similarity index 100% rename from src/Http/Http.Extensions/gen/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs rename to src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.RequestDelegateGenerator/StaticRouteHandlerModel/StaticRouteHandlerModel.Emitter.cs diff --git a/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/Microsoft.AspNetCore.Http.ValidationsGenerator.csproj b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/Microsoft.AspNetCore.Http.ValidationsGenerator.csproj new file mode 100644 index 000000000000..710a337f2bea --- /dev/null +++ b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/Microsoft.AspNetCore.Http.ValidationsGenerator.csproj @@ -0,0 +1,33 @@ + + + + netstandard2.0 + true + false + true + false + enable + true + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/ValidationsGenerator.cs b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/ValidationsGenerator.cs new file mode 100644 index 000000000000..ac7be3762c0d --- /dev/null +++ b/src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/ValidationsGenerator.cs @@ -0,0 +1,14 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.CodeAnalysis; + +namespace Microsoft.AspNetCore.Http.ValidationsGenerator; + +public sealed partial class ValidationsGenerator : IIncrementalGenerator +{ + public void Initialize(IncrementalGeneratorInitializationContext context) + { + return; + } +} diff --git a/src/Http/Http.Extensions/test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj b/src/Http/Http.Extensions/test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj index 4a35778afa55..1f85948b515f 100644 --- a/src/Http/Http.Extensions/test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj +++ b/src/Http/Http.Extensions/test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj @@ -3,7 +3,7 @@ $(DefaultNetCoreTargetFramework) - $(Features.Replace('nullablePublicOnly', '') + $(Features.Replace('nullablePublicOnly', '')) true @@ -21,6 +21,8 @@ + + @@ -29,7 +31,9 @@ - + + + diff --git a/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGenerator.Parameters.cs b/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGenerator.Parameters.cs new file mode 100644 index 000000000000..6a6def95f50a --- /dev/null +++ b/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGenerator.Parameters.cs @@ -0,0 +1,44 @@ +// 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.ValidationsGenerator.Tests; + +public partial class ValidationsGeneratorTests : ValidationsGeneratorTestBase +{ + [Fact] + public async Task CanValidateParameters() + { + var source = """ +using System; +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Routing; + +var builder = WebApplication.CreateBuilder(); + +var app = builder.Build(); + +app.MapGet("/params", ( + [Range(10, 100)] int value1, + [Range(10, 100), Display(Name = "Valid identifier")] int value2, + [Required] string value3 = "some-value", + [CustomValidation(ErrorMessage = "Value must be an even number")] int value4 = 4, + [CustomValidation, Range(10, 100)] int value5 = 10) => "OK"); + +app.Run(); + +public class CustomValidationAttribute : ValidationAttribute +{ + public override bool IsValid(object? value) => value is int number && number % 2 == 0; +} +"""; + await Verify(source, out var compilation); + VerifyEndpoint(compilation, "/params", async endpoint => + { + var context = CreateHttpContext(); + context.Request.QueryString = new QueryString("?value1=5&value2=5&value3=&value4=3&value5=5"); + await endpoint.RequestDelegate(context); + Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode); + }); + } +} diff --git a/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGeneratorTestBase.cs b/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGeneratorTestBase.cs new file mode 100644 index 000000000000..7ff9dcc706a3 --- /dev/null +++ b/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGeneratorTestBase.cs @@ -0,0 +1,534 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Reflection; +using System.Runtime.Loader; +using System.Text; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.InternalTesting; +using Microsoft.AspNetCore.Routing; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.Text; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Http.ValidationsGenerator.Tests; + +[UsesVerify] +public class ValidationsGeneratorTestBase : LoggedTestBase +{ + private static readonly CSharpParseOptions ParseOptions = new CSharpParseOptions(LanguageVersion.Preview) + .WithFeatures([new KeyValuePair("InterceptorsNamespaces", "Microsoft.AspNetCore.Http.Validations.Generated")]); + + internal static Task Verify(string source, out Compilation compilation) + { + var references = AppDomain.CurrentDomain.GetAssemblies() + .Where(assembly => !assembly.IsDynamic && !string.IsNullOrWhiteSpace(assembly.Location)) + .Select(assembly => MetadataReference.CreateFromFile(assembly.Location)) + .Concat( + [ + MetadataReference.CreateFromFile(typeof(WebApplicationBuilder).Assembly.Location), + MetadataReference.CreateFromFile(typeof(EndpointRouteBuilderExtensions).Assembly.Location), + MetadataReference.CreateFromFile(typeof(IApplicationBuilder).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Microsoft.AspNetCore.Mvc.ApiExplorer.IApiDescriptionProvider).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Microsoft.AspNetCore.Mvc.ControllerBase).Assembly.Location), + MetadataReference.CreateFromFile(typeof(MvcCoreMvcBuilderExtensions).Assembly.Location), + MetadataReference.CreateFromFile(typeof(TypedResults).Assembly.Location), + MetadataReference.CreateFromFile(typeof(System.Text.Json.Nodes.JsonArray).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Console).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Uri).Assembly.Location), + MetadataReference.CreateFromFile(typeof(System.ComponentModel.DataAnnotations.ValidationAttribute).Assembly.Location), + MetadataReference.CreateFromFile(typeof(RouteData).Assembly.Location), + MetadataReference.CreateFromFile(typeof(IFeatureCollection).Assembly.Location), + MetadataReference.CreateFromFile(typeof(ValidateOptionsResult).Assembly.Location), + MetadataReference.CreateFromFile(typeof(IHttpMethodMetadata).Assembly.Location), + MetadataReference.CreateFromFile(typeof(IResult).Assembly.Location), + MetadataReference.CreateFromFile(typeof(HttpJsonServiceExtensions).Assembly.Location) + ]); + var inputCompilation = CSharpCompilation.Create("OpenApiXmlCommentGeneratorSample", + [CSharpSyntaxTree.ParseText(source, options: ParseOptions, path: "Program.cs")], + references, + new CSharpCompilationOptions(OutputKind.ConsoleApplication)); + var generator = new ValidationsGenerator(); + var driver = CSharpGeneratorDriver.Create(generators: [generator.AsSourceGenerator()], parseOptions: ParseOptions); + return Verifier + .Verify(driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out compilation, out var diagnostics)) + .UseDirectory(SkipOnHelixAttribute.OnHelix() + ? Path.Combine(Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT"), "snapshots") + : "snapshots"); + } + + internal static void VerifyEndpoint(Compilation compilation, string routePattern, Action verifyFunc) + { + var assemblyName = compilation.AssemblyName; + var symbolsName = Path.ChangeExtension(assemblyName, "pdb"); + + var output = new MemoryStream(); + var pdb = new MemoryStream(); + + var emitOptions = new EmitOptions( + debugInformationFormat: DebugInformationFormat.PortablePdb, + pdbFilePath: symbolsName, + outputNameOverride: $"TestProject-{Guid.NewGuid()}"); + + var embeddedTexts = new List(); + + foreach (var syntaxTree in compilation.SyntaxTrees) + { + var text = syntaxTree.GetText(); + var encoding = text.Encoding ?? Encoding.UTF8; + var buffer = encoding.GetBytes(text.ToString()); + var sourceText = SourceText.From(buffer, buffer.Length, encoding, canBeEmbedded: true); + + var syntaxRootNode = (CSharpSyntaxNode)syntaxTree.GetRoot(); + var newSyntaxTree = CSharpSyntaxTree.Create(syntaxRootNode, options: ParseOptions, encoding: encoding, path: syntaxTree.FilePath); + + compilation = compilation.ReplaceSyntaxTree(syntaxTree, newSyntaxTree); + + embeddedTexts.Add(EmbeddedText.FromSource(syntaxTree.FilePath, sourceText)); + } + + var result = compilation.Emit(output, pdb, options: emitOptions, embeddedTexts: embeddedTexts); + + Assert.Empty(result.Diagnostics.Where(d => d.Severity > DiagnosticSeverity.Warning)); + Assert.True(result.Success); + + output.Position = 0; + pdb.Position = 0; + + var assembly = AssemblyLoadContext.Default.LoadFromStream(output, pdb); + + void ConfigureHostBuilder(object hostBuilder) + { + ((IHostBuilder)hostBuilder).ConfigureServices((context, services) => + { + services.AddSingleton(); + services.AddSingleton(); + }); + } + + var waitForStartTcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + void OnEntryPointExit(Exception exception) + { + // If the entry point exited, we'll try to complete the wait + if (exception != null) + { + waitForStartTcs.TrySetException(exception); + } + else + { + waitForStartTcs.TrySetResult(0); + } + } + + var factory = HostFactoryResolver.ResolveHostFactory(assembly, + stopApplication: false, + configureHostBuilder: ConfigureHostBuilder, + entrypointCompleted: OnEntryPointExit); + + if (factory == null) + { + return; + } + + var services = ((IHost)factory([$"--{HostDefaults.ApplicationKey}={assemblyName}"])).Services; + + var applicationLifetime = services.GetRequiredService(); + using (var registration = applicationLifetime.ApplicationStarted.Register(() => waitForStartTcs.TrySetResult(0))) + { + waitForStartTcs.Task.Wait(); + var targetAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(assembly => assembly.GetName().Name == "Microsoft.AspNetCore.Routing"); + var serviceType = targetAssembly.GetType("Microsoft.AspNetCore.Routing.EndpointDataSource", throwOnError: false); + + if (serviceType == null) + { + return; + } + + var service = services.GetService(serviceType) ?? throw new InvalidOperationException("Could not resolve EndpointDataSource."); + var endpoints = (IReadOnlyList)serviceType.GetProperty("Endpoints", BindingFlags.Instance | BindingFlags.Public).GetValue(service); + var endpoint = endpoints.FirstOrDefault(endpoint => endpoint is RouteEndpoint routeEndpoint && routeEndpoint.RoutePattern.RawText == routePattern); + verifyFunc(endpoint); + } + } + + private sealed class NoopHostLifetime : IHostLifetime + { + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + public Task WaitForStartAsync(CancellationToken cancellationToken) => Task.CompletedTask; + } + + private sealed class NoopServer : IServer + { + public IFeatureCollection Features { get; } = new FeatureCollection(); + public void Dispose() { } + public Task StartAsync(IHttpApplication application, CancellationToken cancellationToken) where TContext : notnull => Task.CompletedTask; + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + } + + private sealed class HostFactoryResolver + { + private const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; + + public const string BuildWebHost = nameof(BuildWebHost); + public const string CreateWebHostBuilder = nameof(CreateWebHostBuilder); + public const string CreateHostBuilder = nameof(CreateHostBuilder); + private const string TimeoutEnvironmentKey = "DOTNET_HOST_FACTORY_RESOLVER_DEFAULT_TIMEOUT_IN_SECONDS"; + + // The amount of time we wait for the diagnostic source events to fire + private static readonly TimeSpan s_defaultWaitTimeout = SetupDefaultTimeout(); + + private static TimeSpan SetupDefaultTimeout() + { + if (Debugger.IsAttached) + { + return Timeout.InfiniteTimeSpan; + } + + if (uint.TryParse(Environment.GetEnvironmentVariable(TimeoutEnvironmentKey), out uint timeoutInSeconds)) + { + return TimeSpan.FromSeconds((int)timeoutInSeconds); + } + + return TimeSpan.FromMinutes(5); + } + + public static Func ResolveWebHostFactory(Assembly assembly) + { + return ResolveFactory(assembly, BuildWebHost); + } + + public static Func ResolveWebHostBuilderFactory(Assembly assembly) + { + return ResolveFactory(assembly, CreateWebHostBuilder); + } + + public static Func ResolveHostBuilderFactory(Assembly assembly) + { + return ResolveFactory(assembly, CreateHostBuilder); + } + + // This helpers encapsulates all of the complex logic required to: + // 1. Execute the entry point of the specified assembly in a different thread. + // 2. Wait for the diagnostic source events to fire + // 3. Give the caller a chance to execute logic to mutate the IHostBuilder + // 4. Resolve the instance of the applications's IHost + // 5. Allow the caller to determine if the entry point has completed + public static Func ResolveHostFactory(Assembly assembly, + TimeSpan waitTimeout = default, + bool stopApplication = true, + Action configureHostBuilder = null, + Action entrypointCompleted = null) + { + if (assembly.EntryPoint is null) + { + return null; + } + + return args => new HostingListener(args, assembly.EntryPoint, waitTimeout == default ? s_defaultWaitTimeout : waitTimeout, stopApplication, configureHostBuilder, entrypointCompleted).CreateHost(); + } + + private static Func ResolveFactory(Assembly assembly, string name) + { + var programType = assembly.EntryPoint.DeclaringType; + if (programType == null) + { + return null; + } + + var factory = programType.GetMethod(name, DeclaredOnlyLookup); + if (!IsFactory(factory)) + { + return null; + } + + return args => (T)factory!.Invoke(null, [args])!; + } + + // TReturn Factory(string[] args); + private static bool IsFactory(MethodInfo factory) + { + return factory != null + && typeof(TReturn).IsAssignableFrom(factory.ReturnType) + && factory.GetParameters().Length == 1 + && typeof(string[]).Equals(factory.GetParameters()[0].ParameterType); + } + + // Used by EF tooling without any Hosting references. Looses some return type safety checks. + public static Func ResolveServiceProviderFactory(Assembly assembly, TimeSpan waitTimeout = default) + { + // Prefer the older patterns by default for back compat. + var webHostFactory = ResolveWebHostFactory(assembly); + if (webHostFactory != null) + { + return args => + { + var webHost = webHostFactory(args); + return GetServiceProvider(webHost); + }; + } + + var webHostBuilderFactory = ResolveWebHostBuilderFactory(assembly); + if (webHostBuilderFactory != null) + { + return args => + { + var webHostBuilder = webHostBuilderFactory(args); + var webHost = Build(webHostBuilder); + return GetServiceProvider(webHost); + }; + } + + var hostBuilderFactory = ResolveHostBuilderFactory(assembly); + if (hostBuilderFactory != null) + { + return args => + { + var hostBuilder = hostBuilderFactory(args); + var host = Build(hostBuilder); + return GetServiceProvider(host); + }; + } + + var hostFactory = ResolveHostFactory(assembly, waitTimeout: waitTimeout); + if (hostFactory != null) + { + return args => + { + static bool IsApplicationNameArg(string arg) + => arg.Equals("--applicationName", StringComparison.OrdinalIgnoreCase) || + arg.Equals("/applicationName", StringComparison.OrdinalIgnoreCase); + + if (!args.Any(arg => IsApplicationNameArg(arg)) && assembly.GetName().Name is string assemblyName) + { + args = [.. args, .. new[] { "--applicationName", assemblyName }]; + } + + var host = hostFactory(args); + return GetServiceProvider(host); + }; + } + + return null; + } + + private static object Build(object builder) + { + var buildMethod = builder.GetType().GetMethod("Build"); + return buildMethod.Invoke(builder, []); + } + + private static IServiceProvider GetServiceProvider(object host) + { + if (host == null) + { + return null; + } + var hostType = host.GetType(); + var servicesProperty = hostType.GetProperty("Services", DeclaredOnlyLookup); + return (IServiceProvider)servicesProperty.GetValue(host); + } + + private sealed class HostingListener : IObserver, IObserver> + { + private readonly string[] _args; + private readonly MethodInfo _entryPoint; + private readonly TimeSpan _waitTimeout; + private readonly bool _stopApplication; + + private readonly TaskCompletionSource _hostTcs = new(); + private IDisposable _disposable; + private readonly Action _configure; + private readonly Action _entrypointCompleted; + private static readonly AsyncLocal _currentListener = new(); + + public HostingListener(string[] args, MethodInfo entryPoint, TimeSpan waitTimeout, bool stopApplication, Action configure, Action entrypointCompleted) + { + _args = args; + _entryPoint = entryPoint; + _waitTimeout = waitTimeout; + _stopApplication = stopApplication; + _configure = configure; + _entrypointCompleted = entrypointCompleted; + } + + public object CreateHost() + { + using var subscription = DiagnosticListener.AllListeners.Subscribe(this); + + // Kick off the entry point on a new thread so we don't block the current one + // in case we need to timeout the execution + var thread = new Thread(() => + { + Exception exception = null; + + try + { + // Set the async local to the instance of the HostingListener so we can filter events that + // aren't scoped to this execution of the entry point. + _currentListener.Value = this; + + var parameters = _entryPoint.GetParameters(); + if (parameters.Length == 0) + { + _entryPoint.Invoke(null, []); + } + else + { + _entryPoint.Invoke(null, new object[] { _args }); + } + + // Try to set an exception if the entry point returns gracefully, this will force + // build to throw + _hostTcs.TrySetException(new InvalidOperationException("The entry point exited without ever building an IHost.")); + } + catch (TargetInvocationException tie) when (tie.InnerException.GetType().Name == "HostAbortedException") + { + // The host was stopped by our own logic + } + catch (TargetInvocationException tie) + { + exception = tie.InnerException ?? tie; + + // Another exception happened, propagate that to the caller + _hostTcs.TrySetException(exception); + } + catch (Exception ex) + { + exception = ex; + + // Another exception happened, propagate that to the caller + _hostTcs.TrySetException(ex); + } + finally + { + // Signal that the entry point is completed + _entrypointCompleted.Invoke(exception); + } + }) + { + // Make sure this doesn't hang the process + IsBackground = true + }; + + // Start the thread + thread.Start(); + + try + { + // Wait before throwing an exception + if (!_hostTcs.Task.Wait(_waitTimeout)) + { + throw new InvalidOperationException($"Timed out waiting for the entry point to build the IHost after {s_defaultWaitTimeout}. This timeout can be modified using the '{TimeoutEnvironmentKey}' environment variable."); + } + } + catch (AggregateException) when (_hostTcs.Task.IsCompleted) + { + // Lets this propagate out of the call to GetAwaiter().GetResult() + } + + Debug.Assert(_hostTcs.Task.IsCompleted); + + return _hostTcs.Task.GetAwaiter().GetResult(); + } + + public void OnCompleted() + { + _disposable.Dispose(); + } + + public void OnError(Exception error) + { + + } + + public void OnNext(DiagnosticListener value) + { + if (_currentListener.Value != this) + { + // Ignore events that aren't for this listener + return; + } + + if (value.Name == "Microsoft.Extensions.Hosting") + { + _disposable = value.Subscribe(this); + } + } + + public void OnNext(KeyValuePair value) + { + if (_currentListener.Value != this) + { + // Ignore events that aren't for this listener + return; + } + + if (value.Key == "HostBuilding") + { + _configure.Invoke(value.Value!); + } + + if (value.Key == "HostBuilt") + { + _hostTcs.TrySetResult(value.Value!); + + if (_stopApplication) + { + // Stop the host from running further + ThrowHostAborted(); + } + } + } + + // HostFactoryResolver is used by tools that explicitly don't want to reference Microsoft.Extensions.Hosting assemblies. + // So don't depend on the public HostAbortedException directly. Instead, load the exception type dynamically if it can + // be found. If it can't (possibly because the app is using an older version), throw a private exception with the same name. + private static void ThrowHostAborted() + { + var publicHostAbortedExceptionType = Type.GetType("Microsoft.Extensions.Hosting.HostAbortedException, Microsoft.Extensions.Hosting.Abstractions", throwOnError: false); + if (publicHostAbortedExceptionType != null) + { + throw (Exception)Activator.CreateInstance(publicHostAbortedExceptionType)!; + } + else + { + throw new HostAbortedException(); + } + } + + private sealed class HostAbortedException : Exception + { + } + } + } + + internal HttpContext CreateHttpContext(IServiceProvider serviceProvider = null) + { + var httpContext = new DefaultHttpContext(); + httpContext.RequestServices = serviceProvider ?? CreateServiceProvider(); + + var outStream = new MemoryStream(); + httpContext.Response.Body = outStream; + + return httpContext; + } + + internal ServiceProvider CreateServiceProvider(Action configureServices = null) + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddSingleton(LoggerFactory); + if (configureServices is not null) + { + configureServices(serviceCollection); + } + return serviceCollection.BuildServiceProvider(); + } +} diff --git a/src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidateParameters.verified.txt b/src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidateParameters.verified.txt new file mode 100644 index 000000000000..22fdca1b2686 --- /dev/null +++ b/src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidateParameters.verified.txt @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/Http/Http/perf/Microbenchmarks/Microsoft.AspNetCore.Http.Microbenchmarks.csproj b/src/Http/Http/perf/Microbenchmarks/Microsoft.AspNetCore.Http.Microbenchmarks.csproj index 216ac33d03c1..54d99f9254e5 100644 --- a/src/Http/Http/perf/Microbenchmarks/Microsoft.AspNetCore.Http.Microbenchmarks.csproj +++ b/src/Http/Http/perf/Microbenchmarks/Microsoft.AspNetCore.Http.Microbenchmarks.csproj @@ -33,7 +33,7 @@ - + diff --git a/src/Http/HttpAbstractions.slnf b/src/Http/HttpAbstractions.slnf index dbf53c6c4c39..944dfd7c7739 100644 --- a/src/Http/HttpAbstractions.slnf +++ b/src/Http/HttpAbstractions.slnf @@ -20,7 +20,8 @@ "src\\Http\\Http.Abstractions\\perf\\Microbenchmarks\\Microsoft.AspNetCore.Http.Abstractions.Microbenchmarks.csproj", "src\\Http\\Http.Abstractions\\src\\Microsoft.AspNetCore.Http.Abstractions.csproj", "src\\Http\\Http.Abstractions\\test\\Microsoft.AspNetCore.Http.Abstractions.Tests.csproj", - "src\\Http\\Http.Extensions\\gen\\Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj", + "src\\Http\\Http.Extensions\\gen\\Microsoft.AspNetCore.Http.RequestDelegateGenerator\\Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj", + "src\\Http\\Http.Extensions\\gen\\Microsoft.AspNetCore.Http.ValidationsGenerator\\Microsoft.AspNetCore.Http.ValidationsGenerator.csproj", "src\\Http\\Http.Extensions\\src\\Microsoft.AspNetCore.Http.Extensions.csproj", "src\\Http\\Http.Extensions\\test\\Microsoft.AspNetCore.Http.Extensions.Tests.csproj", "src\\Http\\Http.Features\\src\\Microsoft.AspNetCore.Http.Features.csproj", @@ -71,4 +72,4 @@ "src\\WebEncoders\\src\\Microsoft.Extensions.WebEncoders.csproj" ] } -} \ No newline at end of file +} diff --git a/src/Http/samples/MinimalSample/MinimalSample.csproj b/src/Http/samples/MinimalSample/MinimalSample.csproj index 7783a82fe5d8..f4a02094cafb 100644 --- a/src/Http/samples/MinimalSample/MinimalSample.csproj +++ b/src/Http/samples/MinimalSample/MinimalSample.csproj @@ -19,7 +19,7 @@ - + diff --git a/src/Identity/Core/src/Microsoft.AspNetCore.Identity.csproj b/src/Identity/Core/src/Microsoft.AspNetCore.Identity.csproj index 3111899516c0..f3faa30a2af4 100644 --- a/src/Identity/Core/src/Microsoft.AspNetCore.Identity.csproj +++ b/src/Identity/Core/src/Microsoft.AspNetCore.Identity.csproj @@ -33,6 +33,6 @@ - + diff --git a/src/Identity/Identity.slnf b/src/Identity/Identity.slnf index c04a7e9af558..bd61ba373015 100644 --- a/src/Identity/Identity.slnf +++ b/src/Identity/Identity.slnf @@ -21,7 +21,7 @@ "src\\Http\\Authentication.Core\\src\\Microsoft.AspNetCore.Authentication.Core.csproj", "src\\Http\\Headers\\src\\Microsoft.Net.Http.Headers.csproj", "src\\Http\\Http.Abstractions\\src\\Microsoft.AspNetCore.Http.Abstractions.csproj", - "src\\Http\\Http.Extensions\\gen\\Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj", + "src\\Http\\Http.Extensions\\gen\\Microsoft.AspNetCore.Http.RequestDelegateGenerator\\Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj", "src\\Http\\Http.Extensions\\src\\Microsoft.AspNetCore.Http.Extensions.csproj", "src\\Http\\Http.Features\\src\\Microsoft.AspNetCore.Http.Features.csproj", "src\\Http\\Http.Results\\src\\Microsoft.AspNetCore.Http.Results.csproj", @@ -96,4 +96,4 @@ "src\\WebEncoders\\src\\Microsoft.Extensions.WebEncoders.csproj" ] } -} \ No newline at end of file +} diff --git a/src/Mvc/Mvc.slnf b/src/Mvc/Mvc.slnf index 61da89ec072d..0274a70c32ba 100644 --- a/src/Mvc/Mvc.slnf +++ b/src/Mvc/Mvc.slnf @@ -28,7 +28,7 @@ "src\\Http\\Authentication.Core\\src\\Microsoft.AspNetCore.Authentication.Core.csproj", "src\\Http\\Headers\\src\\Microsoft.Net.Http.Headers.csproj", "src\\Http\\Http.Abstractions\\src\\Microsoft.AspNetCore.Http.Abstractions.csproj", - "src\\Http\\Http.Extensions\\gen\\Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj", + "src\\Http\\Http.Extensions\\gen\\Microsoft.AspNetCore.Http.RequestDelegateGenerator\\Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj", "src\\Http\\Http.Extensions\\src\\Microsoft.AspNetCore.Http.Extensions.csproj", "src\\Http\\Http.Features\\src\\Microsoft.AspNetCore.Http.Features.csproj", "src\\Http\\Http.Results\\src\\Microsoft.AspNetCore.Http.Results.csproj", @@ -152,4 +152,4 @@ "src\\WebEncoders\\src\\Microsoft.Extensions.WebEncoders.csproj" ] } -} \ No newline at end of file +} diff --git a/src/OpenApi/sample/Sample.csproj b/src/OpenApi/sample/Sample.csproj index ec10629f5d71..f68e61f29ba8 100644 --- a/src/OpenApi/sample/Sample.csproj +++ b/src/OpenApi/sample/Sample.csproj @@ -31,7 +31,7 @@ - + diff --git a/src/OpenApi/src/Microsoft.AspNetCore.OpenApi.csproj b/src/OpenApi/src/Microsoft.AspNetCore.OpenApi.csproj index 83bf4a785c74..bea66b4fe4ae 100644 --- a/src/OpenApi/src/Microsoft.AspNetCore.OpenApi.csproj +++ b/src/OpenApi/src/Microsoft.AspNetCore.OpenApi.csproj @@ -43,7 +43,7 @@ - + From 8d88c391bed85244f23668a82ffbac3b2d53b410 Mon Sep 17 00:00:00 2001 From: Safia Abdalla Date: Wed, 19 Feb 2025 04:46:22 -0800 Subject: [PATCH 2/2] Add ValidationsGenerator snapshots to HelixContent --- .../test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj | 1 + .../test/ValidationsGenerator/ValidationsGeneratorTestBase.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Http/Http.Extensions/test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj b/src/Http/Http.Extensions/test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj index 1f85948b515f..b45c15cbe792 100644 --- a/src/Http/Http.Extensions/test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj +++ b/src/Http/Http.Extensions/test/Microsoft.AspNetCore.Http.Extensions.Tests.csproj @@ -45,5 +45,6 @@ + diff --git a/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGeneratorTestBase.cs b/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGeneratorTestBase.cs index 7ff9dcc706a3..b8740de3e928 100644 --- a/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGeneratorTestBase.cs +++ b/src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGeneratorTestBase.cs @@ -61,7 +61,7 @@ internal static Task Verify(string source, out Compilation compilation) return Verifier .Verify(driver.RunGeneratorsAndUpdateCompilation(inputCompilation, out compilation, out var diagnostics)) .UseDirectory(SkipOnHelixAttribute.OnHelix() - ? Path.Combine(Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT"), "snapshots") + ? Path.Combine(Environment.GetEnvironmentVariable("HELIX_WORKITEM_ROOT"), "ValidationsGenerator", "snapshots") : "snapshots"); }