Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
If Microsoft.AspNetCore.OpenApi is used to document an endpoint that does not have an explicit HTTP method (e.g. with [HttpGet]
) then rendering the OpenAPI document fails with an HTTP 500 due to the following exception:
[2025-03-13 13:15:45Z] fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: Unsupported HTTP method:
at ApiDescriptionExtensions.GetOperationType(ApiDescription apiDescription)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOperationsAsync(IGrouping`2 descriptions, HashSet`1 capturedTags, IServiceProvider scopedServiceProvider, IOpenApiOperationTransformer[] operationTransformers, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiPathsAsync(HashSet`1 capturedTags, IServiceProvider scopedServiceProvider, IOpenApiOperationTransformer[] operationTransformers, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiDocumentAsync(IServiceProvider scopedServiceProvider, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Builder.OpenApiEndpointRouteBuilderExtensions.<>c__DisplayClass0_0.<<MapOpenApi>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Http.Generated.<GeneratedRouteBuilderExtensions_g>F56B68D2B55B5B7B373BA2E4796D897848BC0F04A969B1AF6260183E8B9E0BAF2__GeneratedRouteBuilderExtensionsCore.<>c__DisplayClass2_0.<<MapGet0>g__RequestHandler|5>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
The exception is coming from here:
aspnetcore/src/OpenApi/src/Extensions/ApiDescriptionExtensions.cs
Lines 20 to 32 in f470910
My hunch is that the operation isn't set by MVC in this case, with the rest of the framework treating it as a GET, but that isn't catered for by the switch statement, which then throws an exception.
The exception is easily avoided by adding the relevant attribute, such as:
using WebApi.Models;
using Microsoft.AspNetCore.Mvc;
namespace WebApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class TimeController(TimeProvider timeProvider) : ControllerBase
{
+ [HttpGet]
public ActionResult<TimeModel> Now()
=> Ok(new TimeModel { UtcNow = timeProvider.GetUtcNow() });
}
Expected Behavior
The endpoint is rendered in the OpenAPI document as an HTTP GET to match MVC's behaviour when the endpoint is invoked.
Steps To Reproduce
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<RootNamespace>WebApi</RootNamespace>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
</ItemGroup>
</Project>
using System.Text.Json;
using WebApi;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton(TimeProvider.System);
builder.Services.AddControllers().AddJsonOptions((p) => ConfigureJsonSerialization(p.JsonSerializerOptions));
builder.Services.ConfigureHttpJsonOptions((p) => ConfigureJsonSerialization(p.SerializerOptions));
builder.Services.AddOpenApi();
var app = builder.Build();
app.UseRouting();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Time}/{action=Now}/{id?}");
app.MapOpenApi();
app.Run();
static void ConfigureJsonSerialization(JsonSerializerOptions options)
=> options.TypeInfoResolverChain.Add(MvcSerializerContext.Default);
using WebApi.Models;
using Microsoft.AspNetCore.Mvc;
namespace WebApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class TimeController(TimeProvider timeProvider) : ControllerBase
{
public ActionResult<TimeModel> Now()
=> Ok(new TimeModel { UtcNow = timeProvider.GetUtcNow() });
}
namespace WebApi.Models;
public class TimeModel
{
public DateTimeOffset UtcNow { get; set; }
}
using System.Text.Json.Serialization;
using WebApi.Models;
namespace WebApi;
[JsonSerializable(typeof(DateTimeOffset))]
[JsonSerializable(typeof(TimeModel))]
[JsonSourceGenerationOptions(
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
WriteIndented = true)]
public sealed partial class MvcSerializerContext : JsonSerializerContext;
Exceptions (if any)
[2025-03-13 13:15:45Z] fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: Unsupported HTTP method:
at ApiDescriptionExtensions.GetOperationType(ApiDescription apiDescription)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOperationsAsync(IGrouping`2 descriptions, HashSet`1 capturedTags, IServiceProvider scopedServiceProvider, IOpenApiOperationTransformer[] operationTransformers, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiPathsAsync(HashSet`1 capturedTags, IServiceProvider scopedServiceProvider, IOpenApiOperationTransformer[] operationTransformers, IOpenApiSchemaTransformer[] schemaTransformers, CancellationToken cancellationToken)
at Microsoft.AspNetCore.OpenApi.OpenApiDocumentService.GetOpenApiDocumentAsync(IServiceProvider scopedServiceProvider, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Builder.OpenApiEndpointRouteBuilderExtensions.<>c__DisplayClass0_0.<<MapOpenApi>b__0>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Http.Generated.<GeneratedRouteBuilderExtensions_g>F56B68D2B55B5B7B373BA2E4796D897848BC0F04A969B1AF6260183E8B9E0BAF2__GeneratedRouteBuilderExtensionsCore.<>c__DisplayClass2_0.<<MapGet0>g__RequestHandler|5>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
.NET Version
9.0.201
Anything else?
No response