How to ignore/alter model parameter in asp.net core with Swashbuckle.AspNetCore.Swagger

2.4k views Asked by At

My project references the following packages;

  1. Swashbuckle.AspNetCore.Filters v6.0.0
  2. Swashbuckle.AspNetCore.Swagger v5.6.3
  3. Swashbuckle.AspNetCore.SwaggerGen v5.6.3
  4. Swashbuckle.AspNetCore.SwaggerNewtonSoft v5.6.3
  5. Microsoft.AspNetCore.OData v7.5.0

Here's the issue:

I have a controller called "TestController". In it, there is a single [HttpGet] method called Test.

The method is decorated as follows;

[HttpGet]
[SwaggerOperation(OperationId = nameof(Test))]
public IActionResult Test([FromQuery] string id, [FromQuery] ODataQueryOptions<SearchOptions> oData)
{
    // ...
}

Since I'm using Swashbuckle, the expected results should be that there is a get method named Test with a bunch of query parameters returned to the documentation UI.

However, instead I see an exception. The exception says;

Failed to generate Scheme for type - ODataQueryOptions<`T>. See inner exception

Inspecting the inner exception shows that swagger is attempting to build what-looks to be a scheme of a bunch of system types (eg. HttpContext, response, request, etc...).

I believe this is happening b/c the ODataQueryOption<`T> class comes with a number of contextual properties to help facilitate URI parsing.

See more about that class here: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnet.odata.query.odataqueryoptions?view=odata-aspnetcore-7.0

The exceptions and random google searches have lead me down the path of adding custom IOperationFilter, ISchemeFilters, and IParameterFilters (these all are Swagger specific configuration 'filters').

I've tried to remove the operation all-together by setting properties to null. I've attempted the same with Scheme and Parameter filters... All with no luck. And no documentation to help...

Example of my attempts:

class ParamFilter : IParameterFilter {
    public void Apply(OpenApiParameter parameter, ParameterFilterContext context) {
        parameter.Scheme = null;
        parameter.Reference = null;
    }
}

class SchemeFilter : ISchemeFilter {
    public void Apply(OpenApiScheme scheme, SchemeFilterContext context) {
        scheme.Items = null;
        scheme.Reference = null;
        scheme.Reference = null;
    }
}

// Note: this never gets hit by the debugger. App throws exception before invocation.
class OperationFilter : IOperationFilter {
    public void Apply(OpenApiOperation operation, OperationFilterContext context) {
        operation.Parameters.clear()
    }
}

Nothing worked. Same exception.

At this point my question is fairly simple;

How can I remove the ODataQueryOption parameter from swagger documentation generation?

EDIT: Adding exception messages

  • Failed to generate Schema for type - Microsoft.AspNet.OData.Query.ODataQueryOptions`1[SearchOptions]. See inner exception
  • Failed to generate Schema for type - Microsoft.AspNetCore.Http.HttpRequest. See inner exception
  • Failed to generate Schema for type - Microsoft.AspNetCore.Http.HttpContext. See inner exception
  • Failed to generate Schema for type - Microsoft.AspNetCore.Http.Authentication.AuthenticationManager. See inner exception
  • Could not load type 'Microsoft.AspNetCore.Http.Features.Authentication.AuthenticateContext' from assembly 'Microsoft.AspNetCore.Http.Features, Version=3.1.8.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
2

There are 2 answers

0
Rena On

It could work well in my project:

Action(Be sure remove [FromQuery] on ODataQueryOptions):

[HttpGet]
[EnableQuery]
public IActionResult Test Get([FromQuery] string id, ODataQueryOptions<SearchOptions> ODataQueryOptions)
{
    //...
}

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddOData();
    services.AddControllers();

    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
    });

    SetOutputFormatters(services);
}

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

    app.UseHttpsRedirection();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
        endpoints.EnableDependencyInjection();
        endpoints.Select().Filter().Expand().MaxTop(10);
        endpoints.MapODataRoute("odata", "odata", GetEdmModel());
    });

    app.UseSwagger();

    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
    });
}

IEdmModel GetEdmModel()
{
    var builder = new ODataConventionModelBuilder();
    builder.EntitySet<WeatherForecast>("WeatherForecast");
    return builder.GetEdmModel();
}

private static void SetOutputFormatters(IServiceCollection services)
{
    services.AddMvcCore(options =>
    {
        IEnumerable<ODataOutputFormatter> outputFormatters =
            options.OutputFormatters.OfType<ODataOutputFormatter>()
                .Where(foramtter => foramtter.SupportedMediaTypes.Count == 0);

        foreach (var outputFormatter in outputFormatters)
        {
            outputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/odata"));
        }
    });
}
0
jbojcic On

Try setting the mapping for ODataQueryOptions with options.MapType(typeof(ODataQueryOptions<>), () => new ());