.NET 9 Open API Migration not returning the API Schema

Divakaran, D (Dipu) 0 Reputation points
2025-02-25T22:48:20.3233333+00:00

I am migrating a .NET 6 API application to .NET 9.

Installed the Microsoft.AspNetCore.OpenApi and Microsoft.Extensions.ApiDescription.Server packages with version 9.0.2. I am keeping the Swashbuckle.AspNetCore 6.5.0 for the UI experience.

Here is the relevant piece of program.cs

public static class Program

{

public static void Main(string[] args)

{

    var builder = WebApplication.CreateBuilder(args);

    var config = GetAppSettingConfigurations();

    if (config["AppConfiguration:EnableSerilog"].ToBoolean())

    {

        builder.Services.AddSerilog(config =>

        {

            config.ReadFrom.Configuration(builder.Configuration);

        });

    }

    builder.Services.AddOpenApi("internal");

    builder.Host.ConfigureLogging();

    builder.Host.ConfigureAppConfiguration();

    var startup = new Startup(builder.Configuration);

    startup.ConfigureServices(builder.Services);

    var app = builder.Build();

    if (app.Environment.IsDevelopment())

    {

        app.MapOpenApi();

    }

    startup.Configure(app, app.Environment);

    

    app.Run();

}

private static IHostBuilder ConfigureAppConfiguration(this IHostBuilder host) =>

    host.ConfigureAppConfiguration(

        (hostingContext, ctxConfig) =>

        {

            ctxConfig.AddEnvironmentVariables("AppConfiguration");

        });

private static IHostBuilder ConfigureLogging(this IHostBuilder host) =>

    host.ConfigureLogging(

        (hostingContext, logging) =>

        {

            var instrumentationKey =

                hostingContext.Configuration["ApplicationInsights:InstrumentationKey"];

            var loggingSection = hostingContext.Configuration.GetSection("Logging");

            logging.AddConfiguration(loggingSection);

            logging.AddConsole();

            logging.AddDebug();

            logging.AddEventSourceLogger();

            logging.AddApplicationInsights(instrumentationKey);

            if (hostingContext.Configuration["ApplicationInsights:EnableSerilog"].ToBoolean())

            {

                logging.AddSerilog();

            }

        });

private static IConfigurationRoot GetAppSettingConfigurations() =>

            new ConfigurationBuilder()

        .SetBasePath(Directory.GetCurrentDirectory())

        .AddJsonFile("appsettings.json", false, true)

        .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", true)

        .AddEnvironmentVariables()

        .Build();

}

And the program.cs

public class Startup

{

 private const string _apiName = "Client API";

 public Startup(IConfiguration configuration)

 {

     Configuration = configuration;

 }

 public IConfiguration Configuration { get; }

 /// <summary>

 ///     Configures the application.

 ///     It is called by the runtime and configures the HTTP request pipeline and is where middleware is setup.

 /// </summary>

 /// <param name="app">The application builder.</param>

 /// <param name="env">The web host environment.</param>

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)

 {

     if (env.IsDevelopment())

     {

         app.UseDeveloperExceptionPage();

     }

     else

     {

         app.UseHsts();

     }

     if (Configuration.GetSection("AppConfiguration")["EnableSerilog"].ToBoolean())

     {

         app.UseSerilogRequestLogging();

     }

    // app.UseSwagger();

     app.UseSwaggerUI(

         c =>

         {

             c.SwaggerEndpoint(

                 "/openapi/v1.json",

                 _apiName);

         });

     app.UseHttpsRedirection();

     app.UseRouting();

     app.UseAuthorization();

     app.UseEndpoints(endpoints => { endpoints.MapControllers(); });

 }

 /// <summary>

 ///     Configures the services. It is called by the runtime.

 /// </summary>

 /// <param name="services">The service collection.</param>

 public void ConfigureServices(IServiceCollection services)

 {

     services.AddMvc()

         .SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

     services.AddMvc(options => { options.Filters.Add<UnhandledExceptionFilterAttribute>(); });

     services.AddControllersWithViews()

         .AddJsonOptions(

             options =>

                 options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));

     ConfigureAutoMapper(services);

     ConfigureDependency(services);

     ConfigureFluentValidation(services);

     services.AddApplicationInsightsTelemetry();

 }

 /// <summary>Configures the dependency injection collection.</summary>

 /// <param name="services">The services.</param>

 private static void ConfigureDependency(IServiceCollection services)

 {

     // Application Insight / Telemetry

     services.AddScoped<IDependencyTelemetryClient, DependencyTelemetryClient>();

     //Services

     services.AddScoped<IConfigurationService, ConfigurationService>();

     services.AddScoped<IClientService, ClientService>();

     // Repository

     services.AddScoped<IClientRepository, ClientRepository>();

     // UCI Layer

     services.AddScoped<IUciClientFactory, UciClientFactory>();

     services.AddScoped(x => x.GetService<IUciClientFactory>().CreateFactory());

 }

 /// <summary>

 ///     Configures the fluent validation so that it will trigger when ModelState.isValid is called.

 /// </summary>

 /// <remarks>

 ///     It will execute the correct validator (if found via dependency injection), then execute the data annotation on

 ///     that model.

 /// </remarks>

 /// <param name="services">The services.</param>

 private static void ConfigureFluentValidation(IServiceCollection services)

 {

     services.AddMvc()

         .AddFluentValidation();

     // Dependency Injection using Add Transient instead of Add Scope per documentation. https://fluentvalidation.net/aspnet

 }

 /// <summary>Configures the automatic mapper system.</summary>

 /// <param name="services">The services.</param>

 private void ConfigureAutoMapper(IServiceCollection services)

 {

     var config = new MapperConfiguration(cfg => { cfg.AddProfile(new UciClientMappingProfile()); });

     var mapper = config.CreateMapper();

     mapper.ConfigurationProvider.AssertConfigurationIsValid();

     services.AddSingleton(mapper);

 }

}

Here is the controller code too

[ApiController]

public class ClientController : ControllerBase

{

private readonly IClientService _clientService;

private readonly ILogger _logger;

public ClientController(

    ILogger<ClientController> logger,

    IClientService clientService)

{

    _logger = logger;

    _clientService = clientService;

}

/// <summary>Retrieve all the details of the client.</summary>

/// <param name="wwId">The world wide unique WwId.</param>

/// <returns>Returns detail client</returns>

[Route("clients/{wwId}")]

[HttpGet]

[ProducesResponseType(typeof(Client), StatusCodes.Status200OK)]

[ProducesResponseType(StatusCodes.Status404NotFound)]

[ProducesResponseType(StatusCodes.Status401Unauthorized)]

[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]

[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]

public async Task<IActionResult> GetClient([FromRoute] [Required] int wwId)

{

    using var scope = _logger.BeginScope(

        "GetClient => ScopeId: {ScopeId}; WwId: {WwId}",

        Guid.NewGuid(),

        wwId);

    _logger.LogInformation("GetClient => Started");

    ModelState.CheckModelValidation();

    var request = new GetClientRequest

    {

        WwId = wwId

    };

    var results = await _clientService.GetClientAsync(request);

    return Ok(results);

}

}

Executed the application and trying to get the /openapi/v1.json . It is returning 404 error without any proper exception details from debug. Can someone provide insight on it?

ASP.NET Core Training
ASP.NET Core Training
ASP.NET Core: A set of technologies in the .NET Framework for building web applications and XML web services.Training: Instruction to develop new skills.
36 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Pradeep M 6,315 Reputation points Microsoft Vendor
    2025-02-26T05:47:23.0733333+00:00

    Hi Divakaran, D (Dipu)

    Thank you for reaching out to Microsoft Q & A forum. 

    Here are some steps to resolve the 404 issue with /openapi/v1.json: 

    1.Ensure OpenAPI is properly registered  Replace builder.Services.AddOpenApi("internal"); with: 

    builder.Services.AddOpenApi();
    
    

    This ensures the OpenAPI services are correctly set up. 

    2.Correct the OpenAPI endpoint mapping  Make sure app.MapOpenApi(); is placed before app.UseRouting(); to ensure it is properly registered. 

    3.Enable Swagger middleware  If you are using Swashbuckle, make sure app.UseSwagger(); is not commented out, and verify the Swagger UI mapping: 

    app.UseSwaggerUI(c => c.SwaggerEndpoint("/openapi/v1.json", "Client API"));
    
    

     Ensure the endpoint name matches the OpenAPI document name. 

    4.Check project configuration  In your .csproj file, confirm that OpenAPI document generation is enabled: 

    <OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
    
    

    This allows OpenAPI documents to be generated at build time. 

    5.Enable logging for debugging  To capture potential errors, add: 

    builder.Logging.AddDebug();
    builder.Logging.AddConsole();
    
    

     This can help identify if there are any underlying issues. 

    After making these changes, rebuild and test the /openapi/v1.json endpoint again. 

    Please feel free to contact us if you have any additional questions.     

    If you have found the answer provided to be helpful, please click on the "Accept answer/Upvote" button so that it is useful for other members in the Microsoft Q&A community.  


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.