3

I'm currently in the process of upgrading to .NET 10 from .NET 9, but unfortunately as usual the documentation of breaking changes seems to be lacking when it comes to certain functionality and features.

I am using Scalar and as such I am applying a number of transforms to my documents, mainly to perform path modification for when we deploy our application to Kubernetes under a subdomain and also to add bearer authentication support.

In my Program.cs, I have the following defined where akspath is just a string variable that comes from config:

builder.Services.AddOpenApi("my-api", options =>
            {
                options.AddDocumentTransformer<BearerSecuritySchemeTransformer>();

                if (!string.IsNullOrWhiteSpace(aksPath) && !builder.Environment.IsDevelopment())
                {
                    options.AddDocumentTransformer<UrlPrefixTransformer>();
                }
            });

My transformer code is as follows (BearerSecuritySchemeTransformer):

public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
{
    var authenticationSchemes = await _authenticationSchemeProvider.GetAllSchemesAsync();

    if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
    {
        var requirements = new Dictionary<string, OpenApiSecurityScheme>
        {
            ["Bearer"] = new OpenApiSecurityScheme
            {
                Type = SecuritySchemeType.Http,
                Scheme = "bearer",
                In = ParameterLocation.Header,
                BearerFormat = "JWT"
            }
        };

        document.Components ??= new OpenApiComponents();
        document.Components.SecuritySchemes = requirements;

        foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations))
        {
            operation.Value.Security.Add(new OpenApiSecurityRequirement
            {
                [new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = "Bearer", Type = ReferenceType.SecurityScheme } }] = Array.Empty<string>()
            });
        }
    }
}

And UrlPrefixTransformer:

public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context,
        CancellationToken cancellationToken)
{
    var path = string.Empty;

    if (!string.IsNullOrWhiteSpace(_urlPrefix))
    {
        path = $"/{_urlPrefix}";
    }

    document.Servers = new List<OpenApiServer>
        {
            new() { Url = path }
        };
}

If I update all of the Nuget packages in my solution to the .NET 10 versions and leave Microsoft.AspNetCore.OpenApi at version 9.0.11, then everything appears to work as expected and I can see my scalar API definition documents with no runtime errors.

However, the moment I update to version 10.0.0, I am confronted with a host of errors with the OpenApiSecurity schemes completely changing in structure.

I found a reference here of how to amend my definitions to fit with .NET 10 https://learn.microsoft.com/en-us/aspnet/core/fundamentals/openapi/customize-openapi?view=aspnetcore-10.0

where they suggest doing the following:

internal sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider) : IOpenApiDocumentTransformer
{
    public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
    {
        var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
        if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
        {
            // Add the security scheme at the document level
            var securitySchemes = new Dictionary<string, IOpenApiSecurityScheme>
            {
                ["Bearer"] = new OpenApiSecurityScheme
                {
                    Type = SecuritySchemeType.Http,
                    Scheme = "bearer", // "bearer" refers to the header name here
                    In = ParameterLocation.Header,
                    BearerFormat = "Json Web Token"
                }
            };
            document.Components ??= new OpenApiComponents();
            document.Components.SecuritySchemes = securitySchemes;

            // Apply it as a requirement for all operations
            foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations))
            {
                operation.Value.Security ??= [];
                operation.Value.Security.Add(new OpenApiSecurityRequirement
                {
                    [new OpenApiSecuritySchemeReference("Bearer", document)] = []
                });
            }
        }
    }
}

If I use that recommendation, my solution compiles and runs however, if I hit my scalar docs I see a blank definition with document 'my-api' could not be loaded and if I check the debug logs, the following issues are logged:

System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.AspNetCore.OpenApi.Generated.<OpenApiXmlCommentSupport_generated>F821B935A564B6EA7D37ADF4B1A672CA2DD9CE6F88563F940522F766DFE640041__XmlCommentOperationTransformer.TransformAsync(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken) in /Users/jason/Src/myAPI/myAPI/obj/Debug/net10.0/Microsoft.AspNetCore.OpenApi.SourceGenerators/Microsoft.AspNetCore.OpenApi.SourceGenerators.XmlCommentGenerator/OpenApiXmlCommentSupport.generated.cs:line 858

Given these errors are from internal source generation within .NET which I'm not explicitly using myself, and the fact I am using the snippet they provided I feel like this is either a bug or I am missing something.

Has anyone had similar issues and have been able to get around this?

1
  • In .NET 10, there is a lot of security changes in there. Microsoft.AspNetCore.OpenAPI nuget package is conflicting with security packages in .NET 10. Commented Nov 19 at 1:49

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.