0

Within my Asp.Net Core v5 application we have the following models

public class StorageRecordTypeMetadataBase
{
    public string PropertyName { get; set; }
    public bool Required { get; set; }
}

public class StringRecordTypeMetadata: StorageRecordTypeMetadataBase
{
    public string? ValidationRegex { get; set; }
}

public class NumericRecordTypeMetadata : StorageRecordTypeMetadataBase
{
    public int MinValue { get; set; }
    public int MaxValue { get; set; }
}

In my application Startup.cs I have registered Swagger and NSwag setup as following:

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSwaggerDocument();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseOpenApi();
        app.UseSwaggerUi3();
     }

}

In order to support polymorphism, I have followed the guideline as written by NSwag creator: Guide on inheritance in NSwag, and here is how my model looks like updated:

[JsonConverter(typeof(JsonInheritanceConverter), "discriminator")]
[KnownType(typeof(StringRecordTypeMetadata))]
[KnownType(typeof(NumericRecordTypeMetadata))]
public class StorageRecordTypeMetadataBase
{
    public string PropertyName { get; set; }
    public bool Required { get; set; }
}

As soon as I run the application, swagger fails as swagger.json could not be generated. Upon investigating the issue I can see the following error message once I try to manually navigate to /swagger/v1/swagger.json

System.MissingMethodException: Method not found: 'System.String Namotion.Reflection.XmlDocsExtensions.GetXmlDocsSummary(System.Reflection.MemberInfo)'. at NSwag.Generation.Processors.OperationSummaryAndDescriptionProcessor.ProcessSummary(OperationProcessorContext context, List1 attributes) at NSwag.Generation.Processors.OperationSummaryAndDescriptionProcessor.Process(OperationProcessorContext context) at NSwag.Generation.AspNetCore.AspNetCoreOpenApiDocumentGenerator.RunOperationProcessors(OpenApiDocument document, ApiDescription apiDescription, Type controllerType, MethodInfo methodInfo, OpenApiOperationDescription operationDescription, List1 allOperations, OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver) at NSwag.Generation.AspNetCore.AspNetCoreOpenApiDocumentGenerator.AddOperationDescriptionsToDocument(OpenApiDocument document, Type controllerType, List1 operations, OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver) at NSwag.Generation.AspNetCore.AspNetCoreOpenApiDocumentGenerator.GenerateForControllers(OpenApiDocument document, IGrouping2[] apiGroups, OpenApiSchemaResolver schemaResolver) at NSwag.Generation.AspNetCore.AspNetCoreOpenApiDocumentGenerator.GenerateAsync(ApiDescriptionGroupCollection apiDescriptionGroups) at NSwag.Generation.AspNetCore.AspNetCoreOpenApiDocumentGenerator.GenerateAsync(Object serviceProvider) at NSwag.AspNetCore.OpenApiDocumentProvider.GenerateAsync(String documentName) at NSwag.AspNetCore.Middlewares.OpenApiDocumentMiddleware.GenerateDocumentAsync(HttpContext context) at NSwag.AspNetCore.Middlewares.OpenApiDocumentMiddleware.GetDocumentAsync(HttpContext context) at NSwag.AspNetCore.Middlewares.OpenApiDocumentMiddleware.GetDocumentAsync(HttpContext context) at NSwag.AspNetCore.Middlewares.OpenApiDocumentMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

I have tried to include the referenced package Namotion.Reflection even myself but that did not help either. Is there anything that I have missed during my configuration?

This was supposed to add discriminator field within the base model so that it would be automatically recognized when I generate my models on front end (React) side. I can achieve this behavior by moving away from NSwag, to Swashbuckle like following:

public void ConfigureServices(IServiceCollection services)
{
    ...
        services.AddSwaggerGen(c =>
       {
           c.UseAllOfForInheritance();
           c.SelectSubTypesUsing(baseType =>
           {
               return typeof(StorageRecordType).Assembly.GetTypes().Where(type => type.IsSubclassOf(baseType));
           });

           c.SelectDiscriminatorNameUsing((baseType) => "itemType");
           c.SelectDiscriminatorValueUsing((subType) => subType.Name);
       });
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseSwagger((SwaggerOptions c) => { });
        app.UseSwaggerUI();
     }

}

However this completely breaks the NSwag generation process on my React side. Methods from all controllers are put together into a single Client (instead of being separated per controller name), plus some of the classes required in the parameters seem to be gone as well.

How can I fix the NSwag in order to get the discriminator value in my swagger.json response?

Robert J.
  • 2,631
  • 8
  • 32
  • 59
  • Is this really a polymorphism issue? Did already try simplifying your models temporarily? Maybe you can narrow down the problem that way. – Jan Köhler Jan 26 '22 at 07:14
  • Models have been simplified for this case. In reality we have more sub-types that inherit from the base class with their own set on unique properties. Therefore merging them into one huge class does not seem ideal from our perspective – Robert J. Jan 26 '22 at 07:35

1 Answers1

2

Ok so the issue was, that I was using older version of Nswag.AspNetCore. Instead of version 13.10.8 I upgraded to 13.15.5, which works great with package NJsonSchema v 10.6.6

Robert J.
  • 2,631
  • 8
  • 32
  • 59