diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index af2c322c..e9826925 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,5 @@ # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.177.0/containers/dotnet/.devcontainer/base.Dockerfile -# [Choice] .NET version: use "latest" or a specific version like "10.0" -ARG VARIANT="10.0" +# [Choice] .NET version: use "latest" or a specific version like "11.0" +ARG VARIANT="11.0" FROM mcr.microsoft.com/vscode/devcontainers/dotnet \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f5b7641d..088d7275 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -20,7 +20,7 @@ "remoteEnv": { "PATH": "${containerWorkspaceFolder}/.dotnet:${containerEnv:PATH}", "DOTNET_MULTILEVEL_LOOKUP": "0", - "TARGET": "net10.0", + "TARGET": "net11.0", "DOTNET_WATCH_SUPPRESS_LAUNCH_BROWSER": "true" }, // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a63376fb..40f7f558 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -31,7 +31,7 @@ jobs: uses: actions/setup-dotnet@v4 id: installdotnet with: - dotnet-version: 10.0.x + dotnet-version: 11.0.x - name: Create temporary global.json run: echo '{"sdk":{"version":"${{ steps.installdotnet.outputs.dotnet-version }}"}}' > ./global.json diff --git a/build/nuget.props b/build/nuget.props index 066bd7bf..8ec64b45 100644 --- a/build/nuget.props +++ b/build/nuget.props @@ -36,7 +36,7 @@ - + diff --git a/build/steps-ci.yml b/build/steps-ci.yml index 795501b8..c4492675 100644 --- a/build/steps-ci.yml +++ b/build/steps-ci.yml @@ -8,7 +8,8 @@ steps: displayName: Install .NET SDK inputs: packageType: sdk - version: 10.0.x # https://github.com/dotnet/core/blob/main/release-notes/releases-index.json + includePreviewVersions: true + version: 11.0.x # https://github.com/dotnet/core/blob/main/release-notes/releases-index.json - script: > dotnet test @@ -29,4 +30,4 @@ steps: displayName: Publish Code Coverage inputs: codeCoverageTool: Cobertura - summaryFileLocation: $(System.DefaultWorkingDirectory)/**/*.cobertura.xml \ No newline at end of file + summaryFileLocation: $(System.DefaultWorkingDirectory)/**/*.cobertura.xml diff --git a/build/test.targets b/build/test.targets index 4bea8d90..796527a0 100644 --- a/build/test.targets +++ b/build/test.targets @@ -11,7 +11,7 @@ - + @@ -22,4 +22,4 @@ - \ No newline at end of file + diff --git a/examples/AspNetCore/OData/ODataAdvancedExample/ODataAdvancedExample.csproj b/examples/AspNetCore/OData/ODataAdvancedExample/ODataAdvancedExample.csproj index ed77dfd1..ca39e69e 100644 --- a/examples/AspNetCore/OData/ODataAdvancedExample/ODataAdvancedExample.csproj +++ b/examples/AspNetCore/OData/ODataAdvancedExample/ODataAdvancedExample.csproj @@ -1,7 +1,7 @@  - net10.0 + net11.0 diff --git a/examples/AspNetCore/OData/ODataBasicExample/ODataBasicExample.csproj b/examples/AspNetCore/OData/ODataBasicExample/ODataBasicExample.csproj index ed77dfd1..ca39e69e 100644 --- a/examples/AspNetCore/OData/ODataBasicExample/ODataBasicExample.csproj +++ b/examples/AspNetCore/OData/ODataBasicExample/ODataBasicExample.csproj @@ -1,7 +1,7 @@  - net10.0 + net11.0 diff --git a/examples/AspNetCore/OData/ODataConventionsExample/ODataConventionsExample.csproj b/examples/AspNetCore/OData/ODataConventionsExample/ODataConventionsExample.csproj index ed77dfd1..ca39e69e 100644 --- a/examples/AspNetCore/OData/ODataConventionsExample/ODataConventionsExample.csproj +++ b/examples/AspNetCore/OData/ODataConventionsExample/ODataConventionsExample.csproj @@ -1,7 +1,7 @@  - net10.0 + net11.0 diff --git a/examples/AspNetCore/OData/ODataOpenApiExample/ODataOpenApiExample.csproj b/examples/AspNetCore/OData/ODataOpenApiExample/ODataOpenApiExample.csproj index 3726e694..f631f6d7 100644 --- a/examples/AspNetCore/OData/ODataOpenApiExample/ODataOpenApiExample.csproj +++ b/examples/AspNetCore/OData/ODataOpenApiExample/ODataOpenApiExample.csproj @@ -1,7 +1,7 @@  - net10.0 + net11.0 Example API true diff --git a/examples/AspNetCore/OData/SomeODataOpenApiExample/SomeODataOpenApiExample.csproj b/examples/AspNetCore/OData/SomeODataOpenApiExample/SomeODataOpenApiExample.csproj index 3726e694..f631f6d7 100644 --- a/examples/AspNetCore/OData/SomeODataOpenApiExample/SomeODataOpenApiExample.csproj +++ b/examples/AspNetCore/OData/SomeODataOpenApiExample/SomeODataOpenApiExample.csproj @@ -1,7 +1,7 @@  - net10.0 + net11.0 Example API true diff --git a/examples/AspNetCore/WebApi/BasicExample/BasicExample.csproj b/examples/AspNetCore/WebApi/BasicExample/BasicExample.csproj index 8a8854b8..6d217204 100644 --- a/examples/AspNetCore/WebApi/BasicExample/BasicExample.csproj +++ b/examples/AspNetCore/WebApi/BasicExample/BasicExample.csproj @@ -1,7 +1,7 @@  - net10.0 + net11.0 diff --git a/examples/AspNetCore/WebApi/ByNamespaceExample/ByNamespaceExample.csproj b/examples/AspNetCore/WebApi/ByNamespaceExample/ByNamespaceExample.csproj index 8a8854b8..6d217204 100644 --- a/examples/AspNetCore/WebApi/ByNamespaceExample/ByNamespaceExample.csproj +++ b/examples/AspNetCore/WebApi/ByNamespaceExample/ByNamespaceExample.csproj @@ -1,7 +1,7 @@  - net10.0 + net11.0 diff --git a/examples/AspNetCore/WebApi/ConventionsExample/ConventionsExample.csproj b/examples/AspNetCore/WebApi/ConventionsExample/ConventionsExample.csproj index 8a8854b8..6d217204 100644 --- a/examples/AspNetCore/WebApi/ConventionsExample/ConventionsExample.csproj +++ b/examples/AspNetCore/WebApi/ConventionsExample/ConventionsExample.csproj @@ -1,7 +1,7 @@  - net10.0 + net11.0 diff --git a/examples/AspNetCore/WebApi/MinimalApiExample/MinimalApiExample.csproj b/examples/AspNetCore/WebApi/MinimalApiExample/MinimalApiExample.csproj index 55862198..d66c3d0d 100644 --- a/examples/AspNetCore/WebApi/MinimalApiExample/MinimalApiExample.csproj +++ b/examples/AspNetCore/WebApi/MinimalApiExample/MinimalApiExample.csproj @@ -1,7 +1,7 @@  - net10.0 + net11.0 enable diff --git a/examples/AspNetCore/WebApi/MinimalOpenApiExample/MinimalOpenApiExample.csproj b/examples/AspNetCore/WebApi/MinimalOpenApiExample/MinimalOpenApiExample.csproj index 0c742552..37fdd0dd 100644 --- a/examples/AspNetCore/WebApi/MinimalOpenApiExample/MinimalOpenApiExample.csproj +++ b/examples/AspNetCore/WebApi/MinimalOpenApiExample/MinimalOpenApiExample.csproj @@ -1,7 +1,7 @@  - net10.0 + net11.0 Example API true diff --git a/examples/AspNetCore/WebApi/OpenApiExample/OpenApiExample.csproj b/examples/AspNetCore/WebApi/OpenApiExample/OpenApiExample.csproj index 0c742552..37fdd0dd 100644 --- a/examples/AspNetCore/WebApi/OpenApiExample/OpenApiExample.csproj +++ b/examples/AspNetCore/WebApi/OpenApiExample/OpenApiExample.csproj @@ -1,7 +1,7 @@  - net10.0 + net11.0 Example API true diff --git a/examples/Directory.Packages.props b/examples/Directory.Packages.props index fa0294ae..01a8e118 100644 --- a/examples/Directory.Packages.props +++ b/examples/Directory.Packages.props @@ -12,9 +12,9 @@ - - - + + + \ No newline at end of file diff --git a/global.json b/global.json index f850054d..3a368497 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,8 @@ { + "sdk": { + "version": "11.0.100-preview.6.26359.118" + }, "test": { - "runner": "Microsoft.Testing.Platform" + "runner": "Microsoft.Testing.Platform" } } \ No newline at end of file diff --git a/src/Abstractions/src/Asp.Versioning.Abstractions/Asp.Versioning.Abstractions.csproj b/src/Abstractions/src/Asp.Versioning.Abstractions/Asp.Versioning.Abstractions.csproj index b7e841cf..7d2c6517 100644 --- a/src/Abstractions/src/Asp.Versioning.Abstractions/Asp.Versioning.Abstractions.csproj +++ b/src/Abstractions/src/Asp.Versioning.Abstractions/Asp.Versioning.Abstractions.csproj @@ -1,18 +1,18 @@  - 10.0.0 - 10.0.0.0 + 11.0.0 + 11.0.0.0 $(DefaultTargetFramework);netstandard1.0;netstandard2.0 API Versioning Abstractions The abstractions library for API versioning. Asp.Versioning Asp;AspNet;AspNetCore;Versioning - + $(NoWarn);NU1903 @@ -59,7 +59,7 @@ - + - \ No newline at end of file + diff --git a/src/AspNet/OData/src/Asp.Versioning.WebApi.OData.ApiExplorer/Asp.Versioning.WebApi.OData.ApiExplorer.csproj b/src/AspNet/OData/src/Asp.Versioning.WebApi.OData.ApiExplorer/Asp.Versioning.WebApi.OData.ApiExplorer.csproj index 9e5f7ed2..4d1fc2be 100644 --- a/src/AspNet/OData/src/Asp.Versioning.WebApi.OData.ApiExplorer/Asp.Versioning.WebApi.OData.ApiExplorer.csproj +++ b/src/AspNet/OData/src/Asp.Versioning.WebApi.OData.ApiExplorer/Asp.Versioning.WebApi.OData.ApiExplorer.csproj @@ -1,8 +1,8 @@  - 10.0.0 - 10.0.0.0 + 11.0.0 + 11.0.0.0 net45;net472 Asp.Versioning ASP.NET Web API Versioning API Explorer for OData v4.0 diff --git a/src/AspNet/OData/src/Asp.Versioning.WebApi.OData/Asp.Versioning.WebApi.OData.csproj b/src/AspNet/OData/src/Asp.Versioning.WebApi.OData/Asp.Versioning.WebApi.OData.csproj index e820e9f1..f0dab811 100644 --- a/src/AspNet/OData/src/Asp.Versioning.WebApi.OData/Asp.Versioning.WebApi.OData.csproj +++ b/src/AspNet/OData/src/Asp.Versioning.WebApi.OData/Asp.Versioning.WebApi.OData.csproj @@ -1,8 +1,8 @@  - 10.0.0 - 10.0.0.0 + 11.0.0 + 11.0.0.0 net45;net472 Asp.Versioning API Versioning for ASP.NET Web API with OData v4.0 @@ -15,7 +15,7 @@ - + diff --git a/src/AspNet/WebApi/src/Asp.Versioning.WebApi.ApiExplorer/Asp.Versioning.WebApi.ApiExplorer.csproj b/src/AspNet/WebApi/src/Asp.Versioning.WebApi.ApiExplorer/Asp.Versioning.WebApi.ApiExplorer.csproj index d30a6e08..63e9725c 100644 --- a/src/AspNet/WebApi/src/Asp.Versioning.WebApi.ApiExplorer/Asp.Versioning.WebApi.ApiExplorer.csproj +++ b/src/AspNet/WebApi/src/Asp.Versioning.WebApi.ApiExplorer/Asp.Versioning.WebApi.ApiExplorer.csproj @@ -1,8 +1,8 @@  - 10.0.0 - 10.0.0.0 + 11.0.0 + 11.0.0.0 net45;net472 ASP.NET Web API Versioning API Explorer The API Explorer extensions for ASP.NET Web API Versioning. diff --git a/src/AspNet/WebApi/src/Asp.Versioning.WebApi/Asp.Versioning.WebApi.csproj b/src/AspNet/WebApi/src/Asp.Versioning.WebApi/Asp.Versioning.WebApi.csproj index 0ce3f7f9..5b5e1be4 100644 --- a/src/AspNet/WebApi/src/Asp.Versioning.WebApi/Asp.Versioning.WebApi.csproj +++ b/src/AspNet/WebApi/src/Asp.Versioning.WebApi/Asp.Versioning.WebApi.csproj @@ -1,8 +1,8 @@  - 10.0.0 - 10.0.0.0 + 11.0.0 + 11.0.0.0 net45;net472 ASP.NET Web API Versioning A service API versioning library for Microsoft ASP.NET Web API. diff --git a/src/AspNetCore/Acceptance/Asp.Versioning.Mvc.Acceptance.Tests/Asp.Versioning.Mvc.Acceptance.Tests.csproj b/src/AspNetCore/Acceptance/Asp.Versioning.Mvc.Acceptance.Tests/Asp.Versioning.Mvc.Acceptance.Tests.csproj index fd42b0c1..74ea1519 100644 --- a/src/AspNetCore/Acceptance/Asp.Versioning.Mvc.Acceptance.Tests/Asp.Versioning.Mvc.Acceptance.Tests.csproj +++ b/src/AspNetCore/Acceptance/Asp.Versioning.Mvc.Acceptance.Tests/Asp.Versioning.Mvc.Acceptance.Tests.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/Asp.Versioning.OData.ApiExplorer.csproj b/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/Asp.Versioning.OData.ApiExplorer.csproj index 58b26ce0..4d2a5292 100644 --- a/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/Asp.Versioning.OData.ApiExplorer.csproj +++ b/src/AspNetCore/OData/src/Asp.Versioning.OData.ApiExplorer/Asp.Versioning.OData.ApiExplorer.csproj @@ -1,8 +1,8 @@  - 10.0.0 - 10.0.0.0 + 11.0.0 + 11.0.0.0 $(DefaultTargetFramework) Asp.Versioning ASP.NET Core API Versioning API Explorer for OData v4.0 diff --git a/src/AspNetCore/OData/src/Asp.Versioning.OData/Asp.Versioning.OData.csproj b/src/AspNetCore/OData/src/Asp.Versioning.OData/Asp.Versioning.OData.csproj index 22c8b2db..2b18b65e 100644 --- a/src/AspNetCore/OData/src/Asp.Versioning.OData/Asp.Versioning.OData.csproj +++ b/src/AspNetCore/OData/src/Asp.Versioning.OData/Asp.Versioning.OData.csproj @@ -1,15 +1,15 @@  - 10.0.0 - 10.0.0.0 + 11.0.0 + 11.0.0.0 $(DefaultTargetFramework) Asp.Versioning ASP.NET Core API Versioning with OData v4.0 A service API versioning library for Microsoft ASP.NET Core with OData v4.0. Asp;AspNet;AspNetCore;Versioning;OData true - + $(NoWarn);NU5104 diff --git a/src/AspNetCore/OData/src/Asp.Versioning.OData/Routing/VersionedAttributeRoutingConvention.cs b/src/AspNetCore/OData/src/Asp.Versioning.OData/Routing/VersionedAttributeRoutingConvention.cs index 45cf92d5..941ffcc3 100644 --- a/src/AspNetCore/OData/src/Asp.Versioning.OData/Routing/VersionedAttributeRoutingConvention.cs +++ b/src/AspNetCore/OData/src/Asp.Versioning.OData/Routing/VersionedAttributeRoutingConvention.cs @@ -65,7 +65,7 @@ public override bool AppliesToAction( ODataControllerActionContext context ) // REF: https://github.com/OData/AspNetCoreOData/blob/main/src/Microsoft.AspNetCore.OData/Routing/Conventions/AttributeRoutingConvention.cs#L238 private static string? FindRelatedODataPrefix( string routeTemplate, string[] prefixes ) { - if ( routeTemplate.StartsWith( '/' ) ) + if ( routeTemplate.StartsWith( '/', StringComparison.Ordinal ) ) { routeTemplate = routeTemplate[1..]; } @@ -175,7 +175,7 @@ private static void NormalizeAttributeRouteTemplates( ODataControllerActionConte // route template pattern. // // REF: https://github.com/OData/AspNetCoreOData/blob/main/src/Microsoft.AspNetCore.OData/Routing/Conventions/AttributeRoutingConvention.cs#L181 - if ( attributeRoute.Template is string template && template.StartsWith( '/' ) ) + if ( attributeRoute.Template is string template && template.StartsWith( '/', StringComparison.Ordinal ) ) { attributeRoute.Template = template.TrimStart( '/' ); } diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.Http/Asp.Versioning.Http.csproj b/src/AspNetCore/WebApi/src/Asp.Versioning.Http/Asp.Versioning.Http.csproj index 7e0cff50..47662a9b 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.Http/Asp.Versioning.Http.csproj +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.Http/Asp.Versioning.Http.csproj @@ -1,8 +1,8 @@  - 10.0.0 - 10.0.0.0 + 11.0.0 + 11.0.0.0 $(DefaultTargetFramework) Asp.Versioning ASP.NET Core API Versioning @@ -12,7 +12,7 @@ $(NoWarn);NU1903 diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/Asp.Versioning.Mvc.ApiExplorer.csproj b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/Asp.Versioning.Mvc.ApiExplorer.csproj index f57ca019..e9f43459 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/Asp.Versioning.Mvc.ApiExplorer.csproj +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc.ApiExplorer/Asp.Versioning.Mvc.ApiExplorer.csproj @@ -1,8 +1,8 @@  - 10.0.0 - 10.0.0.0 + 11.0.0 + 11.0.0.0 $(DefaultTargetFramework) Asp.Versioning.ApiExplorer ASP.NET Core API Versioning API Explorer diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/Asp.Versioning.Mvc.csproj b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/Asp.Versioning.Mvc.csproj index 1c851426..ae03195b 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/Asp.Versioning.Mvc.csproj +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.Mvc/Asp.Versioning.Mvc.csproj @@ -1,8 +1,8 @@  - 10.0.0 - 10.0.0.0 + 11.0.0 + 11.0.0.0 $(DefaultTargetFramework) Asp.Versioning ASP.NET Core API Versioning diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Asp.Versioning.OpenApi.csproj b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Asp.Versioning.OpenApi.csproj index b2ad49ce..c006f2eb 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Asp.Versioning.OpenApi.csproj +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Asp.Versioning.OpenApi.csproj @@ -1,8 +1,8 @@  - 10.0.0 - 10.0.0.0 + 11.0.0 + 11.0.0.0 $(DefaultTargetFramework) Asp.Versioning.OpenApi ASP.NET Core API Versioning @@ -16,8 +16,8 @@ - - + + diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Builder/IEndpointConventionBuilderExtensions.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Builder/IEndpointConventionBuilderExtensions.cs index aa2559fe..3baa14ff 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Builder/IEndpointConventionBuilderExtensions.cs +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Builder/IEndpointConventionBuilderExtensions.cs @@ -6,7 +6,6 @@ namespace Microsoft.AspNetCore.Builder; using Asp.Versioning; using Asp.Versioning.ApiExplorer; -using Asp.Versioning.OpenApi.Reflection; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; @@ -29,27 +28,7 @@ public static class IEndpointConventionBuilderExtensions /// The original endpoint convention builder. public IEndpointConventionBuilder WithDocumentPerVersion() { - builder.Finally( ApplyApiVersioning ); return builder; } } - - private static void ApplyApiVersioning( EndpointBuilder builder ) - { - if ( builder.RequestDelegate is { } action ) - { - builder.RequestDelegate = context => InterceptRequestServices( context, action ); - } - } - - private static Task InterceptRequestServices( HttpContext context, RequestDelegate action ) - { - if ( context.RequestServices is not KeyedServiceContainer requestServices ) - { - requestServices = context.RequestServices.GetRequiredService(); - } - - context.RequestServices = requestServices; - return action( context ); - } } \ No newline at end of file diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Configuration/ConfigureOpenApiOptions.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Configuration/ConfigureOpenApiOptions.cs index a32f8413..a99a4839 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Configuration/ConfigureOpenApiOptions.cs +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Configuration/ConfigureOpenApiOptions.cs @@ -5,7 +5,6 @@ namespace Asp.Versioning.OpenApi.Configuration; using Asp.Versioning.ApiExplorer; -using Asp.Versioning.OpenApi.Reflection; using Asp.Versioning.OpenApi.Transformers; using Microsoft.AspNetCore.OpenApi; using Microsoft.Extensions.Options; @@ -48,7 +47,6 @@ private static void Configure( VersionedOpenApiOptions versionedOptions, XmlComm var options = versionedOptions.Document; var apiExplorer = new ApiExplorerTransformer( versionedOptions ); - options.SetDocumentName( versionedOptions.Description.GroupName ); options.AddDocumentTransformer( apiExplorer ); options.AddSchemaTransformer( apiExplorer ); options.AddOperationTransformer( apiExplorer ); diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/DependencyInjection/IApiVersioningBuilderExtensions.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/DependencyInjection/IApiVersioningBuilderExtensions.cs index b0acea8e..aa39bf8e 100644 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/DependencyInjection/IApiVersioningBuilderExtensions.cs +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/DependencyInjection/IApiVersioningBuilderExtensions.cs @@ -8,9 +8,7 @@ namespace Microsoft.Extensions.DependencyInjection; using Asp.Versioning.ApiExplorer; using Asp.Versioning.OpenApi; using Asp.Versioning.OpenApi.Configuration; -using Asp.Versioning.OpenApi.Reflection; using Asp.Versioning.OpenApi.Transformers; -using Microsoft.AspNetCore.Http.Json; using Microsoft.AspNetCore.OpenApi; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; @@ -64,18 +62,13 @@ private static void AddOpenApiServices( IApiVersioningBuilder builder, Assembly[ var services = builder.Services; - services.AddTransient( NewRequestServices ); - services.Add( Singleton( Type.IDocumentProvider, ResolveDocumentProvider ) ); + services.AddSingleton(); services.AddSingleton(); + services.AddOpenApiCore(); services.TryAddEnumerable( Transient, ConfigureOpenApiOptions>() ); services.TryAdd( Singleton>( EM.GetRequiredService ) ); services.AddTransient( sp => new XmlCommentsFile( assemblies, sp.GetRequiredService() ) ); services.TryAddTransient( sp => new XmlCommentsTransformer( sp.GetRequiredService() ) ); - - if ( GetJsonConfiguration() is { } descriptor ) - { - services.TryAddEnumerable( descriptor ); - } } // NOTE: The calling assembly must be captured at the call site that invokes AddOpenApi. In 99% of the cases that @@ -93,56 +86,4 @@ private static Assembly[] GetAssemblies( Assembly callingAssembly ) return [.. assemblies]; } - - // HACK: the json configuration is internal; this approach negates the use of reflection - // REF: https://github.com/dotnet/aspnetcore/blob/08a9fc2c3864d99759ab3d71cfda868d852bfc4b/src/OpenApi/src/Extensions/OpenApiServiceCollectionExtensions.cs#L121 - private static ServiceDescriptor? GetJsonConfiguration() - { - var services = new ServiceCollection(); - services.AddOpenApi( "*" ); - return services.SingleOrDefault( sd => sd.ServiceType == typeof( IConfigureOptions ) ); - } - - private static object ResolveDocumentProvider( IServiceProvider provider ) => - provider.GetRequiredService().GetRequiredService( Type.IDocumentProvider ); - - [UnconditionalSuppressMessage( "ILLink", "IL3050" )] - private static KeyedServiceContainer NewRequestServices( IServiceProvider services ) - { - var provider = services.GetRequiredService(); - var container = new KeyedServiceContainer( services ); - var type = typeof( IOpenApiDocumentProvider ); - var descriptions = provider.ApiVersionDescriptions; - var names = new List( descriptions.Count ); - - for ( var i = 0; i < descriptions.Count; i++ ) - { - var description = descriptions[i]; - - // REF: https://github.com/dotnet/aspnetcore/blob/319e87fd950a99f3baae2aa79db3d4fb68783d85/src/OpenApi/src/Extensions/OpenApiServiceCollectionExtensions.cs#L64 -#pragma warning disable CA1308 // Normalize strings to uppercase - var key = description.GroupName.ToLowerInvariant(); -#pragma warning restore CA1308 - - names.Add( key ); - container.AddService( Type.OpenApiSchemaService, key, Class.OpenApiSchemaService.New ); - container.AddService( Type.OpenApiDocumentService, key, Class.OpenApiDocumentService.New ); - container.AddService( type, key, ( sp, k ) => sp.GetRequiredKeyedService( Type.OpenApiDocumentService, k ) ); - } - - if ( names.Count > 0 ) - { - var array = Array.CreateInstance( Type.NamedService, names.Count ); - - for ( var i = 0; i < names.Count; i++ ) - { - array.SetValue( Class.NamedService.New( names[i] ), i ); - } - - container.AddService( Type.IDocumentProvider, Class.OpenApiDocumentProvider.New ); - container.AddService( Type.IEnumerableOfNamedService, array ); - } - - return container; - } } \ No newline at end of file diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/DependencyInjection/KeyedServiceContainer.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/DependencyInjection/KeyedServiceContainer.cs deleted file mode 100644 index 13f8f3d1..00000000 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/DependencyInjection/KeyedServiceContainer.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. - -#pragma warning disable IDE0130 - -namespace Microsoft.Extensions.DependencyInjection; - -using System.ComponentModel.Design; - -internal sealed class KeyedServiceContainer( IServiceProvider parent ) : ServiceContainer( parent ), IKeyedServiceProvider -{ - private readonly IServiceProvider parent = parent; - private readonly Dictionary keyedServices = []; - private bool disposed; - - private object? GetKeyedService( Type serviceType, object? serviceKey ) - { - if ( serviceKey is not null && keyedServices.TryGetValue( serviceKey, out var container ) ) - { - if ( container.GetService( serviceType ) is { } service ) - { - return service; - } - } - - return default; - } - - object? IKeyedServiceProvider.GetKeyedService( Type serviceType, object? serviceKey ) => - GetKeyedService( serviceType, serviceKey ) ?? parent.GetKeyedService( serviceType, serviceKey ); - - object IKeyedServiceProvider.GetRequiredKeyedService( Type serviceType, object? serviceKey ) => - GetKeyedService( serviceType, serviceKey ) ?? parent.GetRequiredKeyedService( serviceType, serviceKey ); - - public void AddService( Type serviceType, Func activator ) => - AddService( serviceType, ( sp, _ ) => activator( sp ) ); - - public void AddService( Type serviceType, string serviceKey, Func activator ) - { - if ( !keyedServices.TryGetValue( serviceKey, out var container ) ) - { - keyedServices.Add( serviceKey, container = new() ); - } - - container.AddService( serviceType, ( _, _ ) => activator( this, serviceKey ) ); - } - - protected override void Dispose( bool disposing ) - { - base.Dispose( disposing ); - - if ( disposed ) - { - return; - } - - disposed = true; - - foreach ( var container in keyedServices.Values ) - { - container.Dispose(); - } - } -} \ No newline at end of file diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/OpenApiVersionedDocumentNamesProvider.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/OpenApiVersionedDocumentNamesProvider.cs new file mode 100644 index 00000000..de623959 --- /dev/null +++ b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/OpenApiVersionedDocumentNamesProvider.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. + +namespace Asp.Versioning.OpenApi; + +using Asp.Versioning.ApiExplorer; +using Microsoft.AspNetCore.OpenApi; + +#pragma warning disable + +internal sealed class OpenApiVersionedDocumentNamesResolver : IAdditionalOpenApiDocumentNameResolver +{ + private readonly IApiVersionDescriptionProvider provider; + + public OpenApiVersionedDocumentNamesResolver( IApiVersionDescriptionProvider provider ) + { + this.provider = provider; + } + + public IEnumerable ResolveDocumentNames() + { + var descriptions = provider.ApiVersionDescriptions; + var names = new string[descriptions.Count]; + for (var i = 0; i < names.Length; i++) + { + names[i] = descriptions[i].GroupName; + } + + return names; + } +} \ No newline at end of file diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Reflection/Class.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Reflection/Class.cs deleted file mode 100644 index 4d4ec845..00000000 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Reflection/Class.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. - -namespace Asp.Versioning.OpenApi.Reflection; - -using Microsoft.AspNetCore.Hosting.Server; -using Microsoft.AspNetCore.Http.Json; -using Microsoft.AspNetCore.Mvc.ApiExplorer; -using Microsoft.AspNetCore.OpenApi; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; -using System.Linq.Expressions; -using static System.Linq.Expressions.Expression; - -// HACK: all of these types are internal in Microsoft.AspNetCore.OpenApi -// REF: https://github.com/dotnet/aspnetcore/tree/main/src/OpenApi/src -internal static class Class -{ - public static class OpenApiDocumentService - { - private static readonly Func factory = NewFactory(); - - public static object New( IServiceProvider serviceProvider, string documentName ) => factory( serviceProvider, documentName ); - - private static Func NewFactory() - { - var constructor = Type.OpenApiDocumentService.GetConstructors().Single(); - var serviceProvider = Parameter( typeof( IServiceProvider ), "serviceProvider" ); - var documentName = Parameter( typeof( string ), "documentName" ); - var getRequiredService = typeof( ServiceProviderServiceExtensions ).GetMethod( - nameof( ServiceProviderServiceExtensions.GetRequiredService ), - [typeof( IServiceProvider ), typeof( System.Type )] )!; - var apiDescriptionGroupCollectionProvider = typeof( IApiDescriptionGroupCollectionProvider ); - var hostEnvironment = typeof( IHostEnvironment ); - var optionsMonitor = typeof( IOptionsMonitor ); - var server = typeof( IServer ); - var body = Expression.New( - constructor, - documentName, - Convert( Call( getRequiredService, serviceProvider, Constant( apiDescriptionGroupCollectionProvider ) ), apiDescriptionGroupCollectionProvider ), - Convert( Call( getRequiredService, serviceProvider, Constant( hostEnvironment ) ), hostEnvironment ), - Convert( Call( getRequiredService, serviceProvider, Constant( optionsMonitor ) ), optionsMonitor ), - serviceProvider, - Convert( Call( getRequiredService, serviceProvider, Constant( server ) ), server ) ); - var lambda = Lambda>( body, serviceProvider, documentName ); - - return lambda.Compile(); - } - } - - public static class OpenApiSchemaService - { - private static readonly Func factory = NewFactory(); - - public static object New( IServiceProvider serviceProvider, string documentName ) => factory( serviceProvider, documentName ); - - private static Func NewFactory() - { - var constructor = Type.OpenApiSchemaService.GetConstructors().Single(); - var serviceProvider = Parameter( typeof( IServiceProvider ), "serviceProvider" ); - var documentName = Parameter( typeof( string ), "documentName" ); - var getRequiredService = typeof( ServiceProviderServiceExtensions ).GetMethod( - nameof( ServiceProviderServiceExtensions.GetRequiredService ), - [typeof( IServiceProvider ), typeof( System.Type )] )!; - var jsonOptions = typeof( IOptions ); - var optionsMonitor = typeof( IOptionsMonitor ); - var body = Expression.New( - constructor, - documentName, - Convert( Call( getRequiredService, serviceProvider, Constant( jsonOptions ) ), jsonOptions ), - Convert( Call( getRequiredService, serviceProvider, Constant( optionsMonitor ) ), optionsMonitor ) ); - var lambda = Lambda>( body, serviceProvider, documentName ); - - return lambda.Compile(); - } - } - - public static class OpenApiDocumentProvider - { - private static readonly Func factory = NewFactory(); - - public static object New( IServiceProvider serviceProvider ) => factory( serviceProvider ); - - private static Func NewFactory() - { - var constructor = Type.OpenApiDocumentProvider.GetConstructors().Single(); - var serviceProvider = Parameter( typeof( IServiceProvider ), "serviceProvider" ); - var body = Expression.New( constructor, serviceProvider ); - var lambda = Lambda>( body, serviceProvider ); - - return lambda.Compile(); - } - } - - public static class NamedService - { - private static readonly Func factory = NewFactory(); - - public static object New( string name ) => factory( name ); - - private static Func NewFactory() - { - var constructor = Type.NamedService.GetConstructors().Single(); - var name = Parameter( typeof( string ), "name" ); - var body = Expression.New( constructor, name ); - var lambda = Lambda>( body, name ); - - return lambda.Compile(); - } - } -} \ No newline at end of file diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Reflection/Property.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Reflection/Property.cs deleted file mode 100644 index b8c7cec0..00000000 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Reflection/Property.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. - -namespace Asp.Versioning.OpenApi.Reflection; - -using Microsoft.AspNetCore.OpenApi; -using static System.Linq.Expressions.Expression; -using static System.Reflection.BindingFlags; - -// HACK: all of these properties are internal in Microsoft.AspNetCore.OpenApi -// REF: https://github.com/dotnet/aspnetcore/tree/main/src/OpenApi/src -internal static class Property -{ - private static readonly Action setDocumentName = NewSetDocumentName(); - - extension( OpenApiOptions options ) - { - public void SetDocumentName( string value ) => setDocumentName( options, value ); - } - - private static Action NewSetDocumentName() - { - var options = Parameter( typeof( OpenApiOptions ), "options" ); - var documentName = Parameter( typeof( string ), "documentName" ); - var property = typeof( OpenApiOptions ).GetProperty( nameof( OpenApiOptions.DocumentName ), Instance | NonPublic | Public )!; - var body = Assign( Property( options, property ), documentName ); - var lambda = Lambda>( body, options, documentName ); - - return lambda.Compile(); - } -} \ No newline at end of file diff --git a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Reflection/Type.cs b/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Reflection/Type.cs deleted file mode 100644 index 14e85ea8..00000000 --- a/src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Reflection/Type.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. - -namespace Asp.Versioning.OpenApi.Reflection; - -using static System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes; - -// HACK: all of these types are internal in Microsoft.AspNetCore.OpenApi -// REF: https://github.com/dotnet/aspnetcore/tree/main/src/OpenApi/src -internal static class Type -{ - [DynamicallyAccessedMembers( PublicConstructors )] - public static readonly System.Type IDocumentProvider = System.Type.GetType( "Microsoft.Extensions.ApiDescriptions.IDocumentProvider, Microsoft.AspNetCore.OpenApi", throwOnError: true )!; - - [DynamicallyAccessedMembers( PublicConstructors )] - public static readonly System.Type NamedService = System.Type.GetType( "Microsoft.AspNetCore.OpenApi.NamedService`1[[Microsoft.AspNetCore.OpenApi.OpenApiDocumentService, Microsoft.AspNetCore.OpenApi]], Microsoft.AspNetCore.OpenApi", throwOnError: true )!; - - public static readonly System.Type IEnumerableOfNamedService = System.Type.GetType( "System.Collections.Generic.IEnumerable`1[[Microsoft.AspNetCore.OpenApi.NamedService`1[[Microsoft.AspNetCore.OpenApi.OpenApiDocumentService, Microsoft.AspNetCore.OpenApi]], Microsoft.AspNetCore.OpenApi]], System.Private.CoreLib", throwOnError: true )!; - - [DynamicallyAccessedMembers( PublicConstructors )] - public static readonly System.Type OpenApiDocumentProvider = System.Type.GetType( "Microsoft.Extensions.ApiDescriptions.OpenApiDocumentProvider, Microsoft.AspNetCore.OpenApi", throwOnError: true )!; - - [DynamicallyAccessedMembers( PublicConstructors )] - public static readonly System.Type OpenApiDocumentService = System.Type.GetType( "Microsoft.AspNetCore.OpenApi.OpenApiDocumentService, Microsoft.AspNetCore.OpenApi", throwOnError: true )!; - - [DynamicallyAccessedMembers( PublicConstructors )] - public static readonly System.Type OpenApiSchemaService = System.Type.GetType( "Microsoft.AspNetCore.OpenApi.OpenApiSchemaService, Microsoft.AspNetCore.OpenApi", throwOnError: true )!; -} \ No newline at end of file diff --git a/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Content/v1-minimal.json b/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Content/v1-minimal.json index 7702c254..e2277378 100644 --- a/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Content/v1-minimal.json +++ b/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Content/v1-minimal.json @@ -1,13 +1,13 @@ { - "openapi": "3.1.1", + "openapi": "3.2.0", "info": { "title": "Test API | v1", - "description": "The API was deprecated on 1/1/2026. The API was sunset on 2/10/2026.\r\n\r\n### Links\r\n\r\n- [Version Deprecation Policy](http://my.api.com/policies/versions/deprecated.html)\r\n- [Version Sunset Policy](http://my.api.com/policies/versions/sunset.html)", + "description": "The API was deprecated on 01/01/2026. The API was sunset on 02/10/2026.\n\n### Links\n\n- [Version Deprecation Policy](http://my.api.com/policies/versions/deprecated.html)\n- [Version Sunset Policy](http://my.api.com/policies/versions/sunset.html)", "version": "1.0" }, "servers": [ { - "url": "http://localhost/" + "url": "http://localhost" } ], "paths": { @@ -37,8 +37,10 @@ "description": "The requested API version", "required": true, "schema": { - "type": "string", - "enum": [ "1.0" ] + "enum": [ + "1.0" + ], + "type": "string" } } ], diff --git a/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Content/v1-mixed.json b/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Content/v1-mixed.json index 944e40bf..bf6b0fb7 100644 --- a/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Content/v1-mixed.json +++ b/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Content/v1-mixed.json @@ -1,13 +1,13 @@ { - "openapi": "3.1.1", + "openapi": "3.2.0", "info": { "title": "Test API | v1", - "description": "The API was deprecated on 1/1/2026. The API was sunset on 2/10/2026.\r\n\r\n### Links\r\n\r\n- [Version Deprecation Policy](http://my.api.com/policies/versions/deprecated.html)\r\n- [Version Sunset Policy](http://my.api.com/policies/versions/sunset.html)", + "description": "The API was deprecated on 01/01/2026. The API was sunset on 02/10/2026.\n\n### Links\n\n- [Version Deprecation Policy](http://my.api.com/policies/versions/deprecated.html)\n- [Version Sunset Policy](http://my.api.com/policies/versions/sunset.html)", "version": "1.0" }, "servers": [ { - "url": "http://localhost/" + "url": "http://localhost" } ], "paths": { @@ -37,8 +37,10 @@ "description": "The requested API version", "required": true, "schema": { - "type": "string", - "enum": [ "1.0" ] + "enum": [ + "1.0" + ], + "type": "string" } } ], @@ -92,8 +94,10 @@ "description": "The requested API version", "required": true, "schema": { - "type": "string", - "enum": [ "1.0" ] + "enum": [ + "1.0" + ], + "type": "string" } } ], diff --git a/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Content/v1.json b/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Content/v1.json index fc463d7a..f83bcf9b 100644 --- a/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Content/v1.json +++ b/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/Content/v1.json @@ -1,13 +1,13 @@ { - "openapi": "3.1.1", + "openapi": "3.2.0", "info": { "title": "Test API | v1", - "description": "The API was deprecated on 1/1/2026. The API was sunset on 2/10/2026.\r\n\r\n### Links\r\n\r\n- [Version Deprecation Policy](http://my.api.com/policies/versions/deprecated.html)\r\n- [Version Sunset Policy](http://my.api.com/policies/versions/sunset.html)", + "description": "The API was deprecated on 01/01/2026. The API was sunset on 02/10/2026.\n\n### Links\n\n- [Version Deprecation Policy](http://my.api.com/policies/versions/deprecated.html)\n- [Version Sunset Policy](http://my.api.com/policies/versions/sunset.html)", "version": "1.0" }, "servers": [ { - "url": "http://localhost/" + "url": "http://localhost" } ], "paths": { @@ -39,8 +39,10 @@ "description": "The requested API version", "required": true, "schema": { - "type": "string", - "enum": ["1.0"] + "enum": [ + "1.0" + ], + "type": "string" } } ], diff --git a/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/OpenApiDocumentDescriptionOptionsTest.cs b/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/OpenApiDocumentDescriptionOptionsTest.cs index e85d4136..ad548e9d 100644 --- a/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/OpenApiDocumentDescriptionOptionsTest.cs +++ b/src/AspNetCore/WebApi/test/Asp.Versioning.OpenApi.Tests/OpenApiDocumentDescriptionOptionsTest.cs @@ -23,7 +23,7 @@ public void deprecation_notice_should_be_default_without_a_date() public void deprecation_notice_should_return_expected_message() { // arrange - var expected = "The API was deprecated on 2/8/2026."; + var expected = "The API was deprecated on 02/08/2026."; var options = new OpenApiDocumentDescriptionOptions(); var date = new DateTimeOffset( new DateTime( 2026, 2, 8 ) ); var policy = new DeprecationPolicy( date ); @@ -53,7 +53,7 @@ public void sunset_notice_should_be_null_without_a_date() public void sunset_notice_should_return_expected_message() { // arrange - var expected = "The API was sunset on 2/8/2026."; + var expected = "The API was sunset on 02/08/2026."; var options = new OpenApiDocumentDescriptionOptions(); var date = new DateTimeOffset( new DateTime( 2026, 2, 8 ) ); var policy = new SunsetPolicy( date ); diff --git a/src/Client/src/Asp.Versioning.Http.Client/Asp.Versioning.Http.Client.csproj b/src/Client/src/Asp.Versioning.Http.Client/Asp.Versioning.Http.Client.csproj index 5dcd6170..019be475 100644 --- a/src/Client/src/Asp.Versioning.Http.Client/Asp.Versioning.Http.Client.csproj +++ b/src/Client/src/Asp.Versioning.Http.Client/Asp.Versioning.Http.Client.csproj @@ -1,8 +1,8 @@  - 10.0.0 - 10.0.0.0 + 11.0.0 + 11.0.0.0 $(DefaultTargetFramework);netstandard1.1;netstandard2.0 Asp.Versioning.Http API Versioning Client Extensions @@ -11,7 +11,7 @@ $(NoWarn);NU1903 @@ -48,7 +48,7 @@ - + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index d3f5e202..c0400553 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,8 +2,8 @@ - net10.0 - 10.0 + net11.0 + 11.0 $(DotNetReleaseBasePackageVersion).0 .net $([MSBuild]::EnsureTrailingSlash($([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), .gitignore))))