Skip to content

Commit

Permalink
Imported Tingle.AspNetCore.Swagger (#220)
Browse files Browse the repository at this point in the history
  • Loading branch information
mburumaxwell committed Mar 19, 2024
1 parent c289a62 commit 6318f23
Show file tree
Hide file tree
Showing 54 changed files with 2,604 additions and 3 deletions.
1 change: 1 addition & 0 deletions .github/workflows/cleanup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
- { name: 'Tingle.AspNetCore.Authorization' }
- { name: 'Tingle.AspNetCore.DataProtection.MongoDB' }
- { name: 'Tingle.AspNetCore.JsonPatch.NewtonsoftJson' }
- { name: 'Tingle.AspNetCore.Swagger' }
- { name: 'Tingle.AspNetCore.Tokens' }
- { name: 'Tingle.Extensions.Caching.MongoDB' }
- { name: 'Tingle.Extensions.DataAnnotations' }
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This repository contains projects/libraries for adding useful functionality to .
|[`Tingle.AspNetCore.Authorization`](https://www.nuget.org/packages/Tingle.AspNetCore.Authorization/)|Additional authorization functionality such as handlers and requirements. See [docs](./src/Tingle.AspNetCore.Authorization/README.md) and [sample](./samples/AuthorizationSample)|
|[`Tingle.AspNetCore.DataProtection.MongoDB`](https://www.nuget.org/packages/Tingle.AspNetCore.DataProtection.MongoDB/)|Data Protection store in [MongoDB](https://mongodb.com) for ASP.NET Core. See [docs](./src/Tingle.AspNetCore.DataProtection.MongoDB/README.md) and [sample](./samples/DataProtectionMongoDBSample).|
|[`Tingle.AspNetCore.JsonPatch.NewtonsoftJson`](https://www.nuget.org/packages/Tingle.AspNetCore.JsonPatch.NewtonsoftJson/)|Helpers for validation when working with JsonPatch in ASP.NET Core. See [docs](./src/Tingle.AspNetCore.JsonPatch.NewtonsoftJson/README.md) and [blog](https://maxwellweru.com/blog/2020-11-17-immutable-properties-with-json-patch-in-aspnet-core).|
|[`Tingle.AspNetCore.Swagger`](https://www.nuget.org/packages/Tingle.AspNetCore.Swagger/)|Usability extensions for Swagger middleware including smaller ReDoc support. See [docs](./src/Tingle.AspNetCore.Swagger/README.md).|
|[`Tingle.AspNetCore.Tokens`](https://www.nuget.org/packages/Tingle.AspNetCore.Tokens/)|Support for generation of continuation tokens in ASP.NET Core with optional expiry. Useful for pagination, user invite tokens, expiring operation tokens, etc. This is availed through the `ContinuationToken<T>` and `TimedContinuationToken<T>` types. See [docs](./src/Tingle.AspNetCore.Tokens/README.md) and [sample](./samples/TokensSample).|
|[`Tingle.Extensions.Caching.MongoDB`](https://www.nuget.org/packages/Tingle.Extensions.Caching.MongoDB/)|Distributed caching implemented with [MongoDB](https://mongodb.com) on top of `IDistributedCache`, inspired by [CosmosCache](https://github.com/Azure/Microsoft.Extensions.Caching.Cosmos). See [docs](./src/Tingle.Extensions.Caching.MongoDB/README.md) and [sample](./samples/AspNetCoreSessionState)|
|[`Tingle.Extensions.DataAnnotations`](https://www.nuget.org/packages/Tingle.Extensions.DataAnnotations/)|Additional data validation attributes in the `System.ComponentModel.DataAnnotations` namespace. Some of this should have been present in the framework but are very specific to some use cases. For example `FiveStarRatingAttribute`. See [docs](./src/Tingle.Extensions.DataAnnotations/README.md).|
Expand Down
14 changes: 14 additions & 0 deletions Tingle.Extensions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tingle.AspNetCore.DataProte
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tingle.AspNetCore.JsonPatch.NewtonsoftJson", "src\Tingle.AspNetCore.JsonPatch.NewtonsoftJson\Tingle.AspNetCore.JsonPatch.NewtonsoftJson.csproj", "{82B17C91-B96A-4290-A623-6867912A4C8E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tingle.AspNetCore.Swagger", "src\Tingle.AspNetCore.Swagger\Tingle.AspNetCore.Swagger.csproj", "{C8093B92-5322-4B24-B71B-497340E5C5AA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tingle.AspNetCore.Tokens", "src\Tingle.AspNetCore.Tokens\Tingle.AspNetCore.Tokens.csproj", "{B545B88C-4BE0-43FB-AE87-47706D479C6B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tingle.Extensions.Caching.MongoDB", "src\Tingle.Extensions.Caching.MongoDB\Tingle.Extensions.Caching.MongoDB.csproj", "{0C6BE46B-FFBF-497C-82D9-6148364D24E8}"
Expand Down Expand Up @@ -55,6 +57,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tingle.AspNetCore.DataProte
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tingle.AspNetCore.JsonPatch.NewtonsoftJson.Tests", "tests\Tingle.AspNetCore.JsonPatch.NewtonsoftJson.Tests\Tingle.AspNetCore.JsonPatch.NewtonsoftJson.Tests.csproj", "{55B3650C-36C6-4C05-B6A2-B4CBC3DC3E4C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tingle.AspNetCore.Swagger.Tests", "tests\Tingle.AspNetCore.Swagger.Tests\Tingle.AspNetCore.Swagger.Tests.csproj", "{AAA0315A-779D-4F1E-89CA-EA78A5B6E3ED}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tingle.AspNetCore.Tokens.Tests", "tests\Tingle.AspNetCore.Tokens.Tests\Tingle.AspNetCore.Tokens.Tests.csproj", "{FB2F8961-9F8F-4B35-ACAC-CCBEA2A89684}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tingle.Extensions.Caching.MongoDB.Tests", "tests\Tingle.Extensions.Caching.MongoDB.Tests\Tingle.Extensions.Caching.MongoDB.Tests.csproj", "{0EA063C6-9A97-4DE8-9344-5D2BDD301134}"
Expand Down Expand Up @@ -128,6 +132,10 @@ Global
{82B17C91-B96A-4290-A623-6867912A4C8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{82B17C91-B96A-4290-A623-6867912A4C8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{82B17C91-B96A-4290-A623-6867912A4C8E}.Release|Any CPU.Build.0 = Release|Any CPU
{C8093B92-5322-4B24-B71B-497340E5C5AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C8093B92-5322-4B24-B71B-497340E5C5AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C8093B92-5322-4B24-B71B-497340E5C5AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C8093B92-5322-4B24-B71B-497340E5C5AA}.Release|Any CPU.Build.0 = Release|Any CPU
{B545B88C-4BE0-43FB-AE87-47706D479C6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B545B88C-4BE0-43FB-AE87-47706D479C6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B545B88C-4BE0-43FB-AE87-47706D479C6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -196,6 +204,10 @@ Global
{55B3650C-36C6-4C05-B6A2-B4CBC3DC3E4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55B3650C-36C6-4C05-B6A2-B4CBC3DC3E4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55B3650C-36C6-4C05-B6A2-B4CBC3DC3E4C}.Release|Any CPU.Build.0 = Release|Any CPU
{AAA0315A-779D-4F1E-89CA-EA78A5B6E3ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AAA0315A-779D-4F1E-89CA-EA78A5B6E3ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AAA0315A-779D-4F1E-89CA-EA78A5B6E3ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AAA0315A-779D-4F1E-89CA-EA78A5B6E3ED}.Release|Any CPU.Build.0 = Release|Any CPU
{FB2F8961-9F8F-4B35-ACAC-CCBEA2A89684}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FB2F8961-9F8F-4B35-ACAC-CCBEA2A89684}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FB2F8961-9F8F-4B35-ACAC-CCBEA2A89684}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down Expand Up @@ -293,6 +305,7 @@ Global
{22690754-DCFB-4CD2-968D-239C1952B52C} = {9546186D-D4E1-4EDB-956E-1F81C7F4DB72}
{6F93ED1D-6475-46F2-A7DB-B2A5F9DB5A83} = {9546186D-D4E1-4EDB-956E-1F81C7F4DB72}
{82B17C91-B96A-4290-A623-6867912A4C8E} = {9546186D-D4E1-4EDB-956E-1F81C7F4DB72}
{C8093B92-5322-4B24-B71B-497340E5C5AA} = {9546186D-D4E1-4EDB-956E-1F81C7F4DB72}
{B545B88C-4BE0-43FB-AE87-47706D479C6B} = {9546186D-D4E1-4EDB-956E-1F81C7F4DB72}
{0C6BE46B-FFBF-497C-82D9-6148364D24E8} = {9546186D-D4E1-4EDB-956E-1F81C7F4DB72}
{51FA6572-8EB6-4291-8D02-BB736057A50E} = {9546186D-D4E1-4EDB-956E-1F81C7F4DB72}
Expand All @@ -310,6 +323,7 @@ Global
{E67CB6B9-6F42-4E63-9603-810B5B9FBF57} = {815F0941-3B70-4705-A583-AF627559595C}
{E28F4E8D-148B-4583-A27D-E1DA2CC08167} = {815F0941-3B70-4705-A583-AF627559595C}
{55B3650C-36C6-4C05-B6A2-B4CBC3DC3E4C} = {815F0941-3B70-4705-A583-AF627559595C}
{AAA0315A-779D-4F1E-89CA-EA78A5B6E3ED} = {815F0941-3B70-4705-A583-AF627559595C}
{FB2F8961-9F8F-4B35-ACAC-CCBEA2A89684} = {815F0941-3B70-4705-A583-AF627559595C}
{0EA063C6-9A97-4DE8-9344-5D2BDD301134} = {815F0941-3B70-4705-A583-AF627559595C}
{8E3530BB-ED60-4A2C-9BD2-C6879D67B4BD} = {815F0941-3B70-4705-A583-AF627559595C}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#if NET8_0_OR_GREATER
using Asp.Versioning.ApiExplorer;
#endif
using Microsoft.Extensions.Options;
#if NET8_0_OR_GREATER
using Microsoft.OpenApi.Models;
#endif
using Swashbuckle.AspNetCore.SwaggerGen;
using Tingle.AspNetCore.Swagger.Filters;

namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
/// Extensions for <see cref="IServiceCollection"/>
/// </summary>
public static class IServiceCollectionExtensions
{
/// <summary>
/// Adds conversion of XML comments extracted for Swagger to markdown.
/// </summary>
/// <param name="services">the service collection to use</param>
/// <returns></returns>
public static IServiceCollection AddSwaggerXmlToMarkdown(this IServiceCollection services)
{
return services.AddTransient<IPostConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerGenXmlToMarkdown>();
}

/// <summary>
/// Adds enum descriptions.
/// This should be called after all XML documents have been added.
/// </summary>
/// <param name="services">the service collection to use</param>
/// <returns></returns>
public static IServiceCollection AddSwaggerEnumDescriptions(this IServiceCollection services)
{
return services.AddTransient<IPostConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerGenEnumDescriptions>();
}

#if NET8_0_OR_GREATER

/// <summary>
/// Adds swagger documents for api version descriptions declared in code.
/// This is resolved through <see cref="IApiVersionDescriptionProvider.ApiVersionDescriptions"/>
/// </summary>
/// <param name="services">the service collection to use</param>
/// <param name="title">the title of the documents</param>
/// <param name="description">the description of the documents, if any</param>
/// <param name="deprecationSuffix">the suffix to add for deprecated versions</param>
/// <param name="skipDeprecated">set true to skip versions marked as deprecated</param>
/// <param name="customize">an action to customize the created instance of <see cref="OpenApiInfo"/> before adding it</param>
/// <returns></returns>
public static IServiceCollection AddSwaggerDocsAutoDiscovery(this IServiceCollection services,
string? title = null,
string? description = null,
bool skipDeprecated = false,
string deprecationSuffix = "[deprecated]",
Action<OpenApiInfo>? customize = null)
{
return services.AddTransient<IConfigureOptions<SwaggerGenOptions>>(serviceProvider =>
{
void configureAllVersions(IEnumerable<ApiVersionDescription> versions, SwaggerGenOptions options)
{
options.AddDocuments(versions: versions,
title: title,
description: description,
skipDeprecated: skipDeprecated,
deprecationSuffix: deprecationSuffix,
customize: customize);
}
var provider = serviceProvider.GetRequiredService<IApiVersionDescriptionProvider>();
return new ConfigureSwaggerGenAddDocs(provider, configureAllVersions);
});
}

/// <summary>
/// Configures the Swagger generation options.
/// </summary>
/// <remarks>
/// This allows API versioning to define a Swagger document per API version after the
/// <see cref="IApiVersionDescriptionProvider"/> service has been resolved from the service container.
/// </remarks>
/// <param name="provider">the <see cref="IApiVersionDescriptionProvider">provider</see> used to generate Swagger documents.</param>
/// <param name="configure">the action to call when configuring</param>
internal class ConfigureSwaggerGenAddDocs(IApiVersionDescriptionProvider provider, Action<IEnumerable<ApiVersionDescription>, SwaggerGenOptions> configure)
: IConfigureOptions<SwaggerGenOptions>
{
/// <inheritdoc />
public void Configure(SwaggerGenOptions options) => configure?.Invoke(provider.ApiVersionDescriptions, options);
}

#endif
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Swashbuckle.AspNetCore.SwaggerGen;
using Tingle.AspNetCore.Swagger;
using Tingle.AspNetCore.Swagger.Filters.Documents;

namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
/// Extensions for <see cref="SwaggerGenOptions"/>
/// </summary>
public static partial class SwaggerGenExtensions
{
/// <summary>
/// Add logo for ReDoc to the document using the vendor extension <c>x-logo</c>
/// </summary>
/// <param name="options"></param>
/// <param name="logo">The logo details</param>
/// <returns></returns>
/// <seealso cref="ReDocLogoDocumentFilter" />
public static SwaggerGenOptions AddReDocLogo(this SwaggerGenOptions options, OpenApiReDocLogo logo)
{
options.DocumentFilter<ReDocLogoDocumentFilter>(logo);
return options;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#if NET8_0_OR_GREATER
using Asp.Versioning.ApiExplorer;
#endif
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace Microsoft.Extensions.DependencyInjection;

/// <summary>
/// Extensions for <see cref="SwaggerGenOptions"/>
/// </summary>
public static partial class SwaggerGenExtensions
{
/// <summary>
/// Adds a swagger document
/// </summary>
/// <param name="options"></param>
/// <param name="documentName">the name of the document e.g. v1</param>
/// <param name="versionName">the name of the version e.g. v1-2019</param>
/// <param name="title">the title of the document</param>
/// <param name="description">the description of the document, if any</param>
/// <param name="customize">an action to customize the created instance of <see cref="OpenApiInfo"/> before adding it</param>
/// <returns></returns>
public static SwaggerGenOptions AddDocument(this SwaggerGenOptions options,
string documentName,
string? versionName = null,
string? title = null,
string? description = null,
Action<OpenApiInfo>? customize = null)
{
var info = new OpenApiInfo
{
Version = versionName ?? documentName,
Title = title,
Description = description,
};
customize?.Invoke(info);
options.SwaggerDoc(documentName, info);
return options;
}

#if NET8_0_OR_GREATER

/// <summary>
/// Adds a swagger document from an API version description
/// </summary>
/// <param name="options"></param>
/// <param name="version">the API version description</param>
/// <param name="title">the title of the document</param>
/// <param name="description">the description of the document, if any</param>
/// <param name="deprecationSuffix">the suffix to add for deprecated versions</param>
/// <param name="customize">an action to customize the created instance of <see cref="OpenApiInfo"/> before adding it</param>
/// <returns></returns>
public static SwaggerGenOptions AddDocument(this SwaggerGenOptions options,
ApiVersionDescription version,
string? title = null,
string? description = null,
string? deprecationSuffix = "[deprecated]",
Action<OpenApiInfo>? customize = null)
{
var finalTitle = title;
if (version.IsDeprecated) finalTitle += $" {deprecationSuffix}";
var info = new OpenApiInfo
{
Version = version.ApiVersion.ToString(),
Title = finalTitle,
Description = description,
};
customize?.Invoke(info);
options.SwaggerDoc(version.GroupName, info);
return options;
}

/// <summary>
/// Adds swagger documents for each API version description provided
/// </summary>
/// <param name="options"></param>
/// <param name="versions">the versions for which to add swagger documents</param>
/// <param name="title">the title of the documents</param>
/// <param name="description">the description of the documents, if any</param>
/// <param name="deprecationSuffix">the suffix to add for deprecated versions</param>
/// <param name="skipDeprecated">set true to skip versions marked as deprecated</param>
/// <param name="customize">an action to customize the created instance of <see cref="OpenApiInfo"/> before adding it</param>
/// <returns></returns>
public static SwaggerGenOptions AddDocuments(this SwaggerGenOptions options,
IEnumerable<ApiVersionDescription> versions,
string? title = null,
string? description = null,
bool skipDeprecated = false,
string deprecationSuffix = "[deprecated]",
Action<OpenApiInfo>? customize = null)
{
// add a swagger document for each discovered API version
foreach (var v in versions)
{
// skip deprecated versions if specified
if (skipDeprecated && v.IsDeprecated) continue;

// add document
options.AddDocument(
version: v,
title: title,
description: description,
deprecationSuffix: deprecationSuffix,
customize: customize);
}

return options;
}
#endif

}
Loading

0 comments on commit 6318f23

Please sign in to comment.