using System; using System.Linq; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; namespace NejCommon.Controllers { public class IApiDescriptionVisibilitySchemaFilter : ISchemaFilter { List schemas = new List(); public void Apply(OpenApiSchema schema, SchemaFilterContext context) { RemoveSchemas(context); //Get the .net type of the schema var type = context.Type; //Get attributes that imlement IApiDescriptionVisibilityProvider interface var attributes = type.GetCustomAttributes(typeof(IApiDescriptionVisibilityProvider), true).Select(a => a as IApiDescriptionVisibilityProvider); //If there are no attributes, then return if (!attributes.Any()) return; var ignore = attributes.Any(a => a.IgnoreApi); //If the schema is ignored, then remove it from the schema repository if (!ignore) return; schemas.Add(schema); RemoveSchemas(context); } public void RemoveSchemas(SchemaFilterContext context) { foreach (var schema in schemas) { var key = context.SchemaRepository.Schemas.FirstOrDefault(k => k.Value == schema).Key; if (string.IsNullOrWhiteSpace(key)) continue; //Console.WriteLine($"Removing schema {key}"); context.SchemaRepository.Schemas.Remove(key); } } } public class OrphanedFilter : IDocumentFilter { public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { // Add all paths parameters, bodies, responses and query parameters to a list var ops = swaggerDoc.Paths.SelectMany(p => p.Value.Operations).ToList(); var Parameters = ops .SelectMany(o => o.Value.Parameters) .Select(x => x.Schema).ToList(); var requst = ops .Select(o => o.Value.RequestBody) .Where(c => c != null) .SelectMany(x => x.Content) .Select(c => c.Value.Schema).ToList(); var res = ops .SelectMany(o => o.Value.Responses) .SelectMany(r => r.Value.Content) .Select(c => c.Value.Schema).ToList(); var usedSchemas = Parameters.Union(requst).Union(res).Distinct(); /* Console.WriteLine($"Used schemas: {string.Join(", ", swaggerDoc.Components.Parameters)}"); var usedSchemas = swaggerDoc.Components.Parameters.Select(x => x.Value.Schema). Union(swaggerDoc.Components.RequestBodies.Select(x => x.Value.Content).SelectMany(x => x.Values).Select(x => x.Schema)). Union(swaggerDoc.Components.Responses.Select(x => x.Value.Content).SelectMany(x => x.Values).Select(x => x.Schema)). Distinct(); */ var schemas = usedSchemas.ToList(); var currentSchemas = new Dictionary(); foreach(var sch in schemas){ ExpandSchemas(context.SchemaRepository, currentSchemas, sch); } //Console.WriteLine($"Used schemas: {string.Join(", ", currentSchemas.Keys)}"); var orphanedSchemas = swaggerDoc.Components.Schemas.Where(x => !currentSchemas.ContainsKey(x.Key)).ToDictionary(x => x.Key, x => x.Value); //Console.WriteLine($"Unused schemas: {string.Join(", ", orphanedSchemas.Keys)}"); swaggerDoc.Components.Schemas = swaggerDoc.Components.Schemas.Where(x => currentSchemas.ContainsKey(x.Key)).ToDictionary(x => x.Key, x => x.Value); } public static void ExpandSchemas(SchemaRepository repo, Dictionary currentSchemas, OpenApiSchema schemaToExpand) { if(schemaToExpand == null) return; if(schemaToExpand.Type == "array") schemaToExpand = schemaToExpand.Items; var selfRef = schemaToExpand.Reference?.Id; var properties = schemaToExpand.Properties.Values.ToList(); if(selfRef != null && !currentSchemas.ContainsKey(selfRef) && repo.Schemas.ContainsKey(selfRef)) { var sch = repo.Schemas[selfRef]; currentSchemas.Add(selfRef, sch); ExpandSchemas(repo, currentSchemas, sch); } foreach(var sch in properties) { ExpandSchemas(repo, currentSchemas, sch); } } } }