using System.Diagnostics.Eventing.Reader; using System.Runtime.CompilerServices; using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; namespace NejCommon.Controllers { public class TypedResultsMetadataProvider : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { var responseType = context.MethodInfo.ReturnType; //Console.WriteLine(context.MethodInfo.DeclaringType.Name); //Console.WriteLine(context.MethodInfo.Name); //Console.WriteLine(responseType); var t = IsSubclassOfRawGeneric(typeof(Microsoft.AspNetCore.Http.HttpResults.Results<,>), responseType); if (t == null) { return; } var parArg = t.GetGenericArguments(); if (operation.Responses.ContainsKey("200")) operation.Responses.Remove("200"); foreach (var arg in parArg) { if (arg == typeof(NotFound)) { operation.Responses.Add("404", new OpenApiResponse { Description = "Not found" }); } else if (arg == typeof(Ok)) { operation.Responses.Add("200", new OpenApiResponse { Description = "Success" }); } else if (IsSubclassOfRawGeneric(typeof(Ok<>), arg) != null) { var okArg = IsSubclassOfRawGeneric(typeof(Ok<>), arg).GetGenericArguments()[0]; Console.WriteLine("Adding: " + okArg); //get or generate the schema var schema = context.SchemaGenerator.GenerateSchema(okArg, context.SchemaRepository); operation.Responses.Add("200", new OpenApiResponse { Description = "Success", Content = { { "application/json", new OpenApiMediaType { Schema = schema } } } }); } else if (arg == typeof(CreatedAtRoute)) { operation.Responses.Add("201", new OpenApiResponse { Description = "Success" }); } else if (IsSubclassOfRawGeneric(typeof(CreatedAtRoute<>), arg) != null) { if (operation.Responses.ContainsKey("201")) operation.Responses.Remove("201"); var okArg = IsSubclassOfRawGeneric(typeof(CreatedAtRoute<>), arg).GetGenericArguments()[0]; Console.WriteLine("Adding: " + okArg); //get or generate the schema var schema = context.SchemaGenerator.GenerateSchema(okArg, context.SchemaRepository); operation.Responses.Add("201", new OpenApiResponse { Description = "Success", Content = { { "application/json", new OpenApiMediaType { Schema = schema } } } }); } else if (arg == typeof(BadRequest)) { operation.Responses.Add("400", new OpenApiResponse { Description = "There was an error" }); } else if (IsSubclassOfRawGeneric(typeof(BadRequest<>), arg) != null) { if (operation.Responses.ContainsKey("400")) operation.Responses.Remove("400"); var okArg = IsSubclassOfRawGeneric(typeof(BadRequest<>), arg).GetGenericArguments()[0]; Console.WriteLine("Adding: " + okArg); //get or generate the schema var schema = context.SchemaGenerator.GenerateSchema(okArg, context.SchemaRepository); operation.Responses.Add("400", new OpenApiResponse { Description = "There was an error", Content = { { "application/json", new OpenApiMediaType { Schema = schema } } } }); } else if (arg == typeof(FileStreamHttpResult)){ operation.Responses.Add("200", new OpenApiResponse { Description = "Success", Content = { { "application/octet-stream", new OpenApiMediaType { Schema = new OpenApiSchema { Type = "string", Format = "binary" } } } } }); } else { Console.WriteLine("Unknown type: " + arg); } } } static Type? IsSubclassOfRawGeneric(Type generic, Type toCheck) { while (toCheck != null && toCheck != typeof(object)) { //if Task is used, we need to check the underlying type var realTypeNoTask = toCheck.IsGenericType && toCheck.GetGenericTypeDefinition() == typeof(Task<>) ? toCheck.GetGenericArguments()[0] : toCheck; var cur = realTypeNoTask.IsGenericType ? realTypeNoTask.GetGenericTypeDefinition() : realTypeNoTask; //Console.WriteLine(cur); if (generic == cur) { return realTypeNoTask; } toCheck = toCheck.BaseType; } return null; } } }