Search code examples
c#swaggerasp.net-core-webapiopenapi

How replace OneOf to AnyOf in swagger generation


I have a c# code that generates swagger

    services.AddSwaggerGen(options =>
    {
        options.UseOneOfForPolymorphism();
        options.SelectDiscriminatorNameUsing(_ => "messageType");
        options.SwaggerDoc("v1", new OpenApiInfo
        {
            Version = "v1",
            Title = "MyTitle",
            Description = "MyDescription",
            Contact = new OpenApiContact
            {

                Name = "MyName",
                Email = "mymail@gmail.com"

            }

        });
        options.UseAllOfToExtendReferenceSchemas();
    });

How can I replace 'OneOf' that generated by UseOneOfForPolymorphism method with 'AnyOf' in generated swagger?


Solution

  • We can replace OneOf with AnyOf by using custom SchemaFilter method in generated swagger doc.

    Here is a link about implement OneOf in asp.net core.

    And we can follow the suggestion below to replace the OneOf with AnyOf.

    Test Result

    enter image description here

    My Test Code

    1. OneOfToAnyOfSchemaFilter.cs

    using Microsoft.OpenApi.Models;
    using Swashbuckle.AspNetCore.SwaggerGen;
    
    namespace WebApplication1
    {
        public class OneOfToAnyOfSchemaFilter : ISchemaFilter
        {
            public void Apply(OpenApiSchema schema, SchemaFilterContext context)
            {
                if (schema.OneOf != null && schema.OneOf.Any())
                {
                    schema.AnyOf = schema.OneOf;
                    schema.OneOf = null;
                }
            }
        }
    }
    

    2. Program.cs

    using Microsoft.OpenApi.Models;
    using Swashbuckle.AspNetCore.SwaggerGen;
    using WebApplication1;
    
    var builder = WebApplication.CreateBuilder(args);
    
    // Add services to the container.
    
    builder.Services.AddControllers();
    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen(options =>
    {
        options.UseAllOfForInheritance();
        options.UseOneOfForPolymorphism();
    
        options.SelectSubTypesUsing(baseType =>
            typeof(Program).Assembly.GetTypes().Where(type => type.IsSubclassOf(baseType))
        );
    
        //options.UseOneOfForPolymorphism();
        options.SelectDiscriminatorNameUsing(_ => "messageType");
        options.SwaggerDoc("v1", new OpenApiInfo
        {
            Version = "v1",
            Title = "MyTitle",
            Description = "MyDescription",
            Contact = new OpenApiContact
            {
                Name = "MyName",
                Email = "mymail@gmail.com"
            }
        });
        options.UseAllOfToExtendReferenceSchemas();
        // Register our custom SchemaFilter
        options.SchemaFilter<OneOfToAnyOfSchemaFilter>();
    });
    
    var app = builder.Build();
    
    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }
    
    app.UseHttpsRedirection();
    
    app.UseAuthorization();
    
    app.MapControllers();
    
    app.Run();
    

    3. WeatherForecast.cs

    namespace WebApplication1
    {
        public class WeatherForecast
        {
            public DateTime Date { get; set; }
    
            public int TemperatureC { get; set; }
    
            public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    
            public string? Summary { get; set; }
        }
    
        public class WeatherForecastWithLocation : WeatherForecast
        {
            public string? Location { get; set; }
        }
    }
    

    4. WeatherForecastController.cs

    using Microsoft.AspNetCore.Mvc;
    
    namespace WebApplication1.Controllers
    {
        [ApiController]
        [Route("[controller]")]
        public class WeatherForecastController : ControllerBase
        {
            private static readonly string[] Summaries = new[]
            {
                "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
            };
    
            private readonly ILogger<WeatherForecastController> _logger;
    
            public WeatherForecastController(ILogger<WeatherForecastController> logger)
            {
                _logger = logger;
            }
            [HttpGet(Name = "GetWeatherForecast")]
            public IEnumerable<WeatherForecast> Get() =>
                DateTime.Now.Minute < 30
                    ? Enumerable.Range(1, 5).Select(index => new WeatherForecast
                    {
                        Date = DateTime.Now.AddDays(index),
                        TemperatureC = Random.Shared.Next(-20, 55),
                        Summary = Summaries[Random.Shared.Next(Summaries.Length)]
                    })
                    : Enumerable.Range(1, 5).Select(index => new WeatherForecastWithLocation
                    {
                        Date = DateTime.Now.AddDays(index),
                        TemperatureC = Random.Shared.Next(-20, 55),
                        Summary = Summaries[Random.Shared.Next(Summaries.Length)],
                        Location = "London"
                    })
                    .ToArray();
        }
    }