Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<TargetFramework>net10.0</TargetFramework>
<AssemblyTitle>Example API</AssemblyTitle>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<OpenApiGenerateDocuments>false</OpenApiGenerateDocuments>
<OpenApiGenerateDocumentsOnBuild>false</OpenApiGenerateDocumentsOnBuild>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case build-time generation was previously broken already (which I would expect it to), then the package should set these by default.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was definitely working before

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know. I'll continue investigations then.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. I updated PR description. It's working already on main and I'll try to look how can I make it work with the changes in this PR.

</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -44,12 +43,12 @@ private static void ApplyApiVersioning( EndpointBuilder builder )

private static Task InterceptRequestServices( HttpContext context, RequestDelegate action )
{
if ( context.RequestServices is not KeyedServiceContainer requestServices )
if ( context.RequestServices is not AggregateKeyedServiceProvider serviceProvider )
{
requestServices = context.RequestServices.GetRequiredService<KeyedServiceContainer>();
serviceProvider = context.RequestServices.GetRequiredService<AggregateKeyedServiceProvider>();
}

context.RequestServices = requestServices;
context.RequestServices = serviceProvider;
return action( context );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
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;
using System.Net;
using System.Runtime.CompilerServices;

internal sealed class ConfigureOpenApiOptions(
XmlCommentsTransformer xmlComments,
Expand Down Expand Up @@ -48,7 +49,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 );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.

#pragma warning disable IDE0130

namespace Microsoft.Extensions.DependencyInjection;

internal sealed class AggregateKeyedServiceProvider( IServiceProvider parent ) : IKeyedServiceProvider
{
private readonly IServiceProvider parent = parent;
private readonly List<IServiceProvider> providers = [];

public object? GetKeyedService( Type serviceType, object? serviceKey )
{
if ( providers.Count == 0 )
{
return parent.GetKeyedService( serviceType, serviceKey );
}

foreach ( var provider in providers )
{
if ( provider.GetKeyedService( serviceType, serviceKey ) is { } service )
{
return service;
}
}
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed

return null;
}

public object GetRequiredKeyedService( Type serviceType, object? serviceKey )
{
if ( providers.Count == 0 )
{
return parent.GetRequiredKeyedService( serviceType, serviceKey );
}

for ( int i = 0; i < providers.Count - 1; i++ )
{
if ( providers[i].GetKeyedService( serviceType, serviceKey ) is { } service )
{
return service;
}
}

return providers[providers.Count - 1].GetRequiredKeyedService( serviceType, serviceKey );
}

public object? GetService( Type serviceType )
=> parent.GetService( serviceType );

public void Add( IServiceCollection serviceCollection, IServiceCollection parentServiceCollection )
{
foreach ( var descriptor in parentServiceCollection )
{
serviceCollection.Add( descriptor );
}

providers.Add( serviceCollection.BuildServiceProvider() );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ 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;
using Microsoft.Extensions.Options;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Reflection;
using static Microsoft.Extensions.DependencyInjection.ServiceDescriptor;
using EM = Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions;
Expand Down Expand Up @@ -64,18 +65,13 @@ private static void AddOpenApiServices( IApiVersioningBuilder builder, Assembly[

var services = builder.Services;

services.AddTransient( NewRequestServices );
services.Add( Singleton( Type.IDocumentProvider, ResolveDocumentProvider ) );
services.AddTransient( serviceProvider => NewRequestServices( serviceProvider, services ) );

services.AddSingleton<VersionedOpenApiOptionsFactory>();
services.TryAddEnumerable( Transient<IPostConfigureOptions<OpenApiOptions>, ConfigureOpenApiOptions>() );
services.TryAdd( Singleton<IOptionsFactory<VersionedOpenApiOptions>>( EM.GetRequiredService<VersionedOpenApiOptionsFactory> ) );
services.AddTransient( sp => new XmlCommentsFile( assemblies, sp.GetRequiredService<IHostEnvironment>() ) );
services.TryAddTransient( sp => new XmlCommentsTransformer( sp.GetRequiredService<XmlCommentsFile>() ) );

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
Expand All @@ -94,53 +90,19 @@ 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<JsonOptions> ) );
}

private static object ResolveDocumentProvider( IServiceProvider provider ) =>
provider.GetRequiredService<KeyedServiceContainer>().GetRequiredService( Type.IDocumentProvider );

[UnconditionalSuppressMessage( "ILLink", "IL3050" )]
private static KeyedServiceContainer NewRequestServices( IServiceProvider services )
private static AggregateKeyedServiceProvider NewRequestServices( IServiceProvider services, IServiceCollection parentServiceCollection )
{
var provider = services.GetRequiredService<IApiVersionDescriptionProvider>();
var container = new KeyedServiceContainer( services );
var type = typeof( IOpenApiDocumentProvider );
var container = new AggregateKeyedServiceProvider( services );
var descriptions = provider.ApiVersionDescriptions;
var names = new List<string>( 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 );
var serviceCollection = new ServiceCollection();
serviceCollection.AddOpenApi( description.GroupName );
container.Add( serviceCollection, parentServiceCollection );
}

return container;
Expand Down

This file was deleted.

111 changes: 0 additions & 111 deletions src/AspNetCore/WebApi/src/Asp.Versioning.OpenApi/Reflection/Class.cs

This file was deleted.

Loading
Loading