File: Transformers\DelegateOpenApiDocumentTransformer.cs
Web Access
Project: src\src\OpenApi\src\Microsoft.AspNetCore.OpenApi.csproj (Microsoft.AspNetCore.OpenApi)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
 
namespace Microsoft.AspNetCore.OpenApi;
 
internal sealed class DelegateOpenApiDocumentTransformer : IOpenApiDocumentTransformer
{
    private readonly Func<OpenApiDocument, OpenApiDocumentTransformerContext, CancellationToken, Task>? _documentTransformer;
    private readonly Func<OpenApiOperation, OpenApiOperationTransformerContext, CancellationToken, Task>? _operationTransformer;
 
    public DelegateOpenApiDocumentTransformer(Func<OpenApiDocument, OpenApiDocumentTransformerContext, CancellationToken, Task> transformer)
    {
        _documentTransformer = transformer;
    }
 
    public DelegateOpenApiDocumentTransformer(Func<OpenApiOperation, OpenApiOperationTransformerContext, CancellationToken, Task> transformer)
    {
        _operationTransformer = transformer;
    }
 
    public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
    {
        if (_documentTransformer != null)
        {
            await _documentTransformer(document, context, cancellationToken);
        }
 
        if (_operationTransformer != null)
        {
            var documentService = context.ApplicationServices.GetRequiredKeyedService<OpenApiDocumentService>(context.DocumentName);
            foreach (var pathItem in document.Paths.Values)
            {
                for (var i = 0; i < OpenApiConstants.OperationTypes.Length; i++)
                {
                    var operationType = OpenApiConstants.OperationTypes[i];
                    if (!pathItem.Operations.TryGetValue(operationType, out var operation))
                    {
                        continue;
                    }
 
                    if (operation.Extensions.TryGetValue(OpenApiConstants.DescriptionId, out var descriptionIdExtension) &&
                        descriptionIdExtension is OpenApiString { Value: var descriptionId } &&
                        documentService.TryGetCachedOperationTransformerContext(descriptionId, out var operationContext))
                    {
                        await _operationTransformer(operation, operationContext, cancellationToken);
                    }
                    else
                    {
                        // If the cached operation transformer context was not found, throw an exception.
                        // This can occur if the `x-aspnetcore-id` extension attribute was removed by the
                        // user in another operation transformer or if the lookup for operation transformer
                        // context resulted in a cache miss. As an alternative here, we could just to implement
                        // the "slow-path" and look up the ApiDescription associated with the OpenApiOperation
                        // using the OperationType and given path, but we'll avoid this for now.
                        throw new InvalidOperationException("Cached operation transformer context not found. Please ensure that the operation contains the `x-aspnetcore-id` extension attribute.");
                    }
                }
            }
        }
    }
}