using Asp.Versioning; using Asp.Versioning.ApiExplorer; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.Extensions.Options; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; using System.Text; using System.Text.Json; namespace Sufi.Demo.PeopleDirectory.UI.Server.Extensions { /// /// Extension class. /// public static class ServiceCollectionExtensions { internal static void RegisterSwagger(this IServiceCollection services) { services.ConfigureOptions(); services.AddSwaggerGen(c => { //TODO - Lowercase Swagger Documents //c.DocumentFilter(); //Refer - https://gist.github.com/rafalkasa/01d5e3b265e5aa075678e0adfd54e23f // include all project's xml comments var baseDirectory = AppDomain.CurrentDomain.BaseDirectory; foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { if (!assembly.IsDynamic) { var xmlFile = $"{assembly.GetName().Name}.xml"; var xmlPath = Path.Combine(baseDirectory, xmlFile); if (File.Exists(xmlPath)) { c.IncludeXmlComments(xmlPath); } } } c.OperationFilter(); }) .AddApiVersioning(config => { config.DefaultApiVersion = new ApiVersion(1, 0); config.AssumeDefaultVersionWhenUnspecified = true; config.ApiVersionReader = new UrlSegmentApiVersionReader(); }) .AddApiExplorer(options => { options.GroupNameFormat = "'v'VVV"; options.SubstituteApiVersionInUrl = true; }); } } internal class ConfigureSwaggerGenOptions(IApiVersionDescriptionProvider provider) : IConfigureOptions { public void Configure(SwaggerGenOptions options) { foreach (var description in provider.ApiVersionDescriptions) { options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description)); } } private static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description) { var text = new StringBuilder("This application is for demo purposes by Sufi only."); var info = new OpenApiInfo { Title = "Sufi.Demo.App", Version = description.ApiVersion.ToString(), License = new OpenApiLicense { Name = "MIT License", Url = new Uri("https://opensource.org/licenses/MIT") } }; if (description.IsDeprecated) { text.Append("This Api version has been deprecated."); } if (description.SunsetPolicy is SunsetPolicy policy && policy.Date is DateTimeOffset when) { text.Append(" The Api will be sunset on ") .Append(when.Date.ToShortDateString()) .Append('.'); } info.Description = text.ToString(); return info; } } internal class SwaggerDefaultValues : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { var apiDescription = context.ApiDescription; operation.Deprecated |= apiDescription.IsDeprecated(); foreach (var responseType in context.ApiDescription.SupportedResponseTypes) { var responseKey = responseType.IsDefaultResponse ? "default" : responseType.StatusCode.ToString(); var response = operation.Responses[responseKey]; foreach (var contentType in response.Content.Keys) { if (!responseType.ApiResponseFormats.Any(x => x.MediaType == contentType)) { response.Content.Remove(contentType); } } } if (operation.Parameters == null) { return; } foreach (var parameter in operation.Parameters) { var description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name); parameter.Description ??= description.ModelMetadata.Description; if (parameter.Schema.Default == null && description.DefaultValue != null && description.DefaultValue is not DBNull && description.ModelMetadata is ModelMetadata modelMetadata) { var json = JsonSerializer.Serialize(description.DefaultValue, modelMetadata.ModelType); parameter.Schema.Default = OpenApiAnyFactory.CreateFromJson(json); } parameter.Required |= description.IsRequired; } } } }