.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

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.