mattfrear/Swashbuckle.AspNetCore.Filters

SwaggerGeneratorException: Failed to generate Operation for action

alekdavisintel opened this issue · 2 comments

In a POST method (creating a group) I am trying to implement three request and response examples: problem details object would be returned for everything except HTTP 200 status code, an input group object (with fewer non-null properties) and an output group object (with more initialized properties). When I add the SwaggerRequestExample and SwaggerResponseExample attributes to the POST method, the following exception occurs:

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
      Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorException: Failed to generate Operation for action - MyNamesapce.MyController.Post (MyMicroservice). See inner exception
       ---> System.NullReferenceException: Object reference not set to an instance of an object.
         at Swashbuckle.AspNetCore.Filters.Extensions.ServiceProviderExtensions.InvokeGetExamples(Type exampleProviderType, Object exampleProviderObject)
         at Swashbuckle.AspNetCore.Filters.Extensions.ServiceProviderExtensions.GetExampleWithExamplesProviderType(IServiceProvider serviceProvider, Type examplesProviderType)
         at Swashbuckle.AspNetCore.Filters.ExamplesOperationFilter.SetResponseExamples(OpenApiOperation operation, OperationFilterContext context)
         at Swashbuckle.AspNetCore.Filters.ExamplesOperationFilter.Apply(OpenApiOperation operation, OperationFilterContext context)
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperation(ApiDescription apiDescription, SchemaRepository schemaRepository)
         --- End of inner exception stack trace ---
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperation(ApiDescription apiDescription, SchemaRepository schemaRepository)
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperations(IEnumerable`1 apiDescriptions, SchemaRepository schemaRepository)
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GeneratePaths(IEnumerable`1 apiDescriptions, SchemaRepository schemaRepository)
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwagger(String documentName, String host, String basePath)
         at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
         at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

My method is decorated as:

[SwaggerOperation("Create")]
[SwaggerResponse(StatusCodes.Status200OK, "Contains Id of the created group.", typeof(Group))]
[SwaggerResponse(StatusCodes.Status400BadRequest, "ERROR INFO HERE", typeof(ProblemDetails))]
[SwaggerRequestExample(typeof(Group), typeof(GroupPostExample))]
[SwaggerResponseExample(StatusCodes.Status200OK, typeof(GroupGetExample))]
[SwaggerResponseExample(StatusCodes.Status400BadRequest, typeof(ProblemDetailsExample))]
[Route("api/v1/groups")]
[HttpPost]
public ActionResult<Group> Create
(
    Group group
)

I added examples on startup:

services
    .AddSwaggerExamplesFromAssemblyOf<ProblemDetailsExample>()
    .AddSwaggerExamplesFromAssemblyOf<GroupGetExample>()
    .AddSwaggerExamplesFromAssemblyOf<GroupPostExample>();

In AddSwaggerGen, I include example filters:

services.AddSwaggerGen(
    options => {
        ...
        options.ExampleFilters();
        ...
    });

Example classes are pretty straightforward:

public class GroupPostExample : IExamplesProvider<Group>
{
    Group IExamplesProvider<Group>.GetExamples()
    {
        Group group = new Group()
        {
            DisplayName = "Fonzie Fans",
            Description = "Everyone who likes Fonzie."
        };

        return group;
    }
}

public class GroupGetExample : IExamplesProvider<Group>
{
    Group IExamplesProvider<Group>.GetExamples()
    {

        Group group = new Group()
        {
            Id = Guid.NewGuid().ToString(),
            DisplayName = "Fonzie Fans",
            Description = "Everyone who likes Fonzie.",
            SecurityEnabled = true
        };

        return group;
    }
}

public class ProblemDetailsExample : IExamplesProvider<ProblemDetails>
{
    ProblemDetails IExamplesProvider<ProblemDetails>.GetExamples()
    {
        ServiceCodeType code = ServiceCodeType.BadRequest;

        ProblemDetails problemDetails = new ProblemDetails()
        {
            Detail = code.ToDetail(),
            Status = code.ToStatus(),
            Type = code.ToType(),
            Title = code.ToTitle(),
            Instance = null
        };
        
        problemDetails.SetErrorDetails(code, Guid.NewGuid().ToString());

        return problemDetails;
    }
}

If I comment out the SwaggerRequestExample and SwaggerResponseExample decorators, I do not get an error, but Swagger (obviously) shows a single example (GroupPostExample).

Any idea what can be going on here?

Hi Alek

Your GetExamples method declaration looks strange. Try changing:

public class GroupPostExample : IExamplesProvider<Group>
{
    Group IExamplesProvider<Group>.GetExamples()

to

public class GroupPostExample : IExamplesProvider<Group>
{
    public Group GetExamples()

Possibly a duplicate of #130.

Ah, thank you, thank you, thank you! That was it!