diff --git a/Directory.Build.targets b/Directory.Build.targets index d5cae3c30..01e334870 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -2,7 +2,7 @@ - + diff --git a/Directory.Packages.props b/Directory.Packages.props index 9d89fa39a..91f0856d9 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -97,6 +97,8 @@ + + @@ -104,6 +106,7 @@ + @@ -157,4 +160,4 @@ - \ No newline at end of file + diff --git a/docs/openapi/migration-from-swashbuckle.md b/docs/openapi/migration-from-swashbuckle.md new file mode 100644 index 000000000..322cbd4a9 --- /dev/null +++ b/docs/openapi/migration-from-swashbuckle.md @@ -0,0 +1,79 @@ +# Migration from Swashbuckle to Microsoft OpenAPI + +Ark.Tools now uses `Microsoft.AspNetCore.OpenApi` as the default generator in `ArkStartupWebApiCommon`. +Existing applications can keep the legacy Swashbuckle generator by overriding: + +```csharp +public override bool UseSwashbuckleOpenApi => true; +``` + +Swagger UI and Redoc are still hosted by the API and read the same `/swagger/docs/{documentName}` specification route. +The route serves build-generated JSON. In production builds, runtime document generation is not mapped and the route returns `404` if the generated file is missing. + +## Build-time generation + +Application projects that use the Microsoft OpenAPI path should reference `Microsoft.Extensions.ApiDescription.Server`. +This enables OpenAPI JSON generation during normal `dotnet build`. + +Recommended project settings: + +```xml + + $(MSBuildProjectDirectory)/bin/$(Configuration)/$(TargetFramework)/ + --openapi-version OpenApi3_1 + +``` + +Build-time generation starts the application entry point with a mock server. +Guard startup code that performs external side effects, migrations, outbound calls, or hosted background work during document generation. + +## Step-by-step migration + +1. Remove any `UseSwashbuckleOpenApi` override, or leave it set to `false`, so `ArkStartupWebApiCommon` registers Microsoft OpenAPI. +2. Add `Microsoft.Extensions.ApiDescription.Server` to the application project. +3. Set `OpenApiDocumentsDirectory` to the application output directory and keep `OpenApiGenerateDocumentsOptions` on `OpenApi3_1` so production serves static, build-generated specs from `/swagger/docs/{documentName}`. +4. Keep the build-time `AddOpenApi(...)` calls in the application project. The Microsoft source generator needs these calls in the application assembly, while Ark.Tools keeps the runtime serving path guarded by the generator selection in the base startup class. +5. Move Swashbuckle `ISchemaFilter` and `IOperationFilter` customizations to `ConfigureMicrosoftOpenApi` with `IOpenApiSchemaTransformer` and `IOpenApiOperationTransformer`. +6. Keep Swagger UI options and OAuth UI configuration. Add Microsoft OpenAPI document transformers for security schemes previously added with `ConfigureSwaggerGen`. +7. Build the application and verify the expected `{ProjectName}_v*.json` files are generated in the application output directory. + +The `samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface` project demonstrates these steps by: + +- generating OpenAPI files at build time, +- configuring schema and operation transformers in `ConfigureMicrosoftOpenApi`, +- preserving Swagger UI OAuth setup, and +- adding OAuth security schemes with Microsoft OpenAPI document transformers, and +- skipping hosted background workers while `dotnet-getdocument` generates the specification. + +## Swashbuckle attributes + +Swashbuckle-specific attributes are not interpreted automatically by Microsoft OpenAPI. +Prefer ASP.NET Core metadata, XML comments, and Ark.Tools/Microsoft OpenAPI transformers for new code. + +| Swashbuckle attribute | Recommended replacement | Notes | +| --- | --- | --- | +| `SwaggerOperationAttribute` | Drop-in compatibility is registered by default. | Ark.Tools maps `Summary`, `Description`, `OperationId`, and `Tags` through a Microsoft OpenAPI operation transformer. Prefer XML comments or native endpoint metadata for new code. | +| `SwaggerResponseAttribute` | Drop-in compatibility is registered by default; `ProducesResponseTypeAttribute` is preferred for new code. | Ark.Tools maps status code, description, response type/schema, and explicit content types through a Microsoft OpenAPI operation transformer. Use `ProducesResponseTypeAttribute` only when you do not need Swashbuckle's description/content-type metadata. | +| `SwaggerParameterAttribute` | XML comments, `FromQuery`/`FromRoute` metadata, or an operation transformer | Use native binding metadata for required and source information. | +| `SwaggerRequestBodyAttribute` | ASP.NET Core request metadata plus XML comments or an operation transformer | Prefer deterministic transformers for examples and descriptions. | +| `SwaggerSchemaAttribute` | System.Text.Json metadata, XML comments, or `IOpenApiSchemaTransformer` | Swashbuckle schema filters remain legacy-only. | +| `SwaggerTagAttribute` | Controller/action grouping metadata or document/operation transformers | Use generator-neutral tag metadata where possible. | +| `SwaggerSchemaFilterAttribute` | `IOpenApiSchemaTransformer` | Treat this as Swashbuckle-only during the transition. | + +## Swashbuckle filters + +| Swashbuckle extension point | Microsoft OpenAPI replacement | +| --- | --- | +| `IDocumentFilter` | `IOpenApiDocumentTransformer` | +| `IOperationFilter` | `IOpenApiOperationTransformer` | +| `ISchemaFilter` | `IOpenApiSchemaTransformer` | +| `IExamplesProvider` from `Swashbuckle.AspNetCore.Filters` | Prefer a generator-neutral example model or an operation/schema transformer that writes examples deterministically. | + +Current Ark.Tools defaults provide Microsoft OpenAPI equivalents for default problem responses, NodaTime schema formats, flags enum query parameters, OData media type cleanup, versioned document selection, and stable operation IDs. + +## Compatibility guidance + +- Use the Microsoft OpenAPI default for new applications. +- Override `UseSwashbuckleOpenApi` only when existing Swashbuckle filters or attributes cannot be migrated immediately. +- Keep Swagger UI and Redoc pointed at `/swagger/docs/{documentName}` so UI routes do not change while the generator changes. +- Move custom Swashbuckle filters to generator-neutral Ark.Tools options or Microsoft OpenAPI transformers before the .NET 12 removal window. diff --git a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.Tests/packages.lock.json b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.Tests/packages.lock.json index 4a77774b1..530a70629 100644 --- a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.Tests/packages.lock.json +++ b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.Tests/packages.lock.json @@ -843,6 +843,14 @@ "Microsoft.Spatial": "[9.0.0-preview.4, 10.0.0)" } }, + "Microsoft.AspNetCore.OpenApi": { + "type": "Transitive", + "resolved": "10.0.7", + "contentHash": "vKiAcGXG0BwNVw3bOjjWRLnp9tR18dR7MiwpvC94h0yFS+zfnzGHzS/JmmgwUdRixrGxrlIMRAWrVc+2DfAGlg==", + "dependencies": { + "Microsoft.OpenApi": "2.0.0" + } + }, "Microsoft.AspNetCore.WebUtilities": { "type": "Transitive", "resolved": "2.1.1", @@ -1944,6 +1952,11 @@ "Swashbuckle.AspNetCore.SwaggerGen": "10.0.0" } }, + "Swashbuckle.AspNetCore.ReDoc": { + "type": "Transitive", + "resolved": "10.1.7", + "contentHash": "aoVMCDlS4v6X6EgaowPxSSDwdvIP0NQNJR42lq+iQCVFaGRCN67wALoAZYddyxGQeBoiKSdATvP+psj7OVCuPw==" + }, "Swashbuckle.AspNetCore.Swagger": { "type": "Transitive", "resolved": "10.1.7", @@ -2187,6 +2200,7 @@ "Ark.Reference.Core.Application": "[0.9.1, )", "Ark.Tools.AspNetCore": "[1.0.0, )", "Azure.Extensions.AspNetCore.Configuration.Secrets": "[1.5.0, )", + "Microsoft.Extensions.ApiDescription.Server": "[10.0.7, )", "Microsoft.Identity.Web": "[4.8.0, )" } }, @@ -2224,6 +2238,7 @@ "FluentValidation": "[12.1.1, )", "Hellang.Middleware.ProblemDetails": "[6.5.1, )", "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", + "Microsoft.AspNetCore.OpenApi": "[10.0.7, )", "NetEscapades.AspNetCore.SecurityHeaders": "[1.3.1, )", "SimpleInjector.Integration.AspNetCore.Mvc.Core": "[5.5.0, )" } @@ -2288,6 +2303,7 @@ "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", "Swashbuckle.AspNetCore.Annotations": "[10.1.7, )", "Swashbuckle.AspNetCore.Filters": "[10.0.1, )", + "Swashbuckle.AspNetCore.ReDoc": "[10.1.7, )", "Swashbuckle.AspNetCore.Swagger": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerGen": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerUI": "[10.1.7, )" @@ -2545,6 +2561,12 @@ "System.Security.Cryptography.Xml": "10.0.7" } }, + "Microsoft.Extensions.ApiDescription.Server": { + "type": "CentralTransitive", + "requested": "[10.0.7, )", + "resolved": "10.0.7", + "contentHash": "VBNJzdInUkjhL/Habj16j3kMHIccjjuWg2zILcapH2QDq5GJF4bfQzJvt2gynuT98PkTpLUvPAsPeefKBDT/mg==" + }, "Microsoft.Identity.Web": { "type": "CentralTransitive", "requested": "[4.8.0, )", diff --git a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Ark.Reference.Core.WebInterface.csproj b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Ark.Reference.Core.WebInterface.csproj index 32437d7c2..9da316ff0 100644 --- a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Ark.Reference.Core.WebInterface.csproj +++ b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Ark.Reference.Core.WebInterface.csproj @@ -3,10 +3,13 @@ AspNetCoreModuleV2 inprocess + $(MSBuildProjectDirectory)/bin/$(Configuration)/$(TargetFramework)/ + --openapi-version OpenApi3_1 + diff --git a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Program.cs b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Program.cs index caced4264..39b043809 100644 --- a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Program.cs +++ b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Program.cs @@ -49,7 +49,10 @@ public static IHostBuilder Config(this IHostBuilder builder, string[] args) }) .ConfigureServices((ctx, services) => { - services.AddSingleton(); + if (!IsRunningUnderOpenApiGenerator()) + { + services.AddSingleton(); + } // remember to add LOCAL_DEBUG to launchSetting.json when developing in local if (Environment.GetEnvironmentVariable("LOCAL_DEBUG") == "True") @@ -63,6 +66,15 @@ public static IHostBuilder Config(this IHostBuilder builder, string[] args) }); } + private static bool IsRunningUnderOpenApiGenerator() + { + var entryAssemblyName = System.Reflection.Assembly.GetEntryAssembly()?.GetName().Name; + return string.Equals(entryAssemblyName, "GetDocument.Insider", StringComparison.Ordinal) + || string.Equals(entryAssemblyName, "dotnet-getdocument", StringComparison.OrdinalIgnoreCase) + || Environment.GetCommandLineArgs().Any(arg => arg.Contains("dotnet-getdocument", StringComparison.OrdinalIgnoreCase)) + || AppDomain.CurrentDomain.GetAssemblies().Any(assembly => string.Equals(assembly.GetName().Name, "Microsoft.Extensions.ApiDescription.Tool", StringComparison.Ordinal)); + } + public static async Task Main(string[] args) { diff --git a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Startup.cs b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Startup.cs index 142a71361..56ce93b03 100644 --- a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Startup.cs +++ b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Startup.cs @@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.OpenApi; using Microsoft.AspNetCore.Mvc.Authorization; using Microsoft.Identity.Web; using Microsoft.IdentityModel.Tokens; @@ -38,6 +39,24 @@ public override OpenApiInfo MakeInfo(ApiVersion version) Version = version.ToString("VVVV", CultureInfo.InvariantCulture), }; + /// + protected override void ConfigureMicrosoftOpenApi(string documentName, OpenApiOptions options) + { + base.ConfigureMicrosoftOpenApi(documentName, options); + + options.AddSchemaTransformer(async (schema, context, cancellationToken) => + { + if (context.JsonTypeInfo.Type != typeof(double?[,])) + { + return; + } + + schema.Type = JsonSchemaType.Array; + schema.Items = await context.GetOrCreateSchemaAsync(typeof(double?[]), null, cancellationToken).ConfigureAwait(false); + }); + options.AddOperationTransformer(); + } + public Startup(IConfiguration config, IWebHostEnvironment webHostEnvironment) : base(config, webHostEnvironment) { @@ -47,6 +66,12 @@ public override void ConfigureServices(IServiceCollection services) { base.ConfigureServices(services); + // The Microsoft OpenAPI source generator requires application-level AddOpenApi calls to generate build-time documents. + foreach (var version in Versions) + { + services.AddOpenApi($"v{version.ToString("VVVV", CultureInfo.InvariantCulture)}"); + } + // Configure System.Text.Json source generation with Ark defaults // Using JsonTypeInfoResolver.Combine to merge application and ProblemDetails contexts // See: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation @@ -168,4 +193,4 @@ protected override void RegisterContainer(IServiceProvider services) services.GetService()) ; } -} \ No newline at end of file +} diff --git a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Utils/Ex.cs b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Utils/Ex.cs index 0ee185abe..fd57cb696 100644 --- a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Utils/Ex.cs +++ b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Utils/Ex.cs @@ -2,6 +2,7 @@ using Ark.Tools.AspNetCore.Swashbuckle; using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.OpenApi; using Microsoft.Identity.Web; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi; @@ -133,27 +134,28 @@ public static void ConfigureAuthentication(this IServiceCollection services, ICo public static IServiceCollection ArkConfigureSwaggerEntraId(this IServiceCollection services, string instance, string domain, string clientId, string tenantId) { - services.ConfigureSwaggerGen(c => + var oauthScheme = new OpenApiSecurityScheme { - var oauthScheme = new OpenApiSecurityScheme - { - Type = SecuritySchemeType.OAuth2, + Type = SecuritySchemeType.OAuth2, - Flows = new OpenApiOAuthFlows() + Flows = new OpenApiOAuthFlows() + { + Implicit = new OpenApiOAuthFlow() { - Implicit = new OpenApiOAuthFlow() + AuthorizationUrl = new Uri($"{instance}/{tenantId}/oauth2/v2.0/authorize"), + TokenUrl = new Uri($"{instance}/{tenantId}/oauth2/v2.0/token"), + Scopes = new Dictionary(StringComparer.Ordinal) { - AuthorizationUrl = new Uri($"{instance}/{tenantId}/oauth2/v2.0/authorize"), - TokenUrl = new Uri($"{instance}/{tenantId}/oauth2/v2.0/token"), - Scopes = new Dictionary(StringComparer.Ordinal) - { - { "openid", "Grant access to user" }, - { $"api://{clientId}/access_as_user", "Default scope to retrieve user permissions" } - } + { "openid", "Grant access to user" }, + { $"api://{clientId}/access_as_user", "Default scope to retrieve user permissions" } } - }, - Scheme = "oauth2" - }; + } + }, + Scheme = "oauth2" + }; + + services.ConfigureSwaggerGen(c => + { c.AddSecurityDefinition("oauth2", oauthScheme); c.AddSecurityRequirement((document) => new OpenApiSecurityRequirement() { @@ -161,6 +163,8 @@ [new OpenApiSecuritySchemeReference("oauth2", document)] = ["openid"] }); }); + services.ConfigureMicrosoftOpenApiOAuth2(oauthScheme); + services.ArkConfigureSwaggerUI(c => { c.OAuthClientId(clientId); @@ -174,25 +178,25 @@ [new OpenApiSecuritySchemeReference("oauth2", document)] = ["openid"] public static IServiceCollection ArkConfigureSwaggerIdentityServer(this IServiceCollection services, string domain, string clientId, string swaggerscope) { - services.ConfigureSwaggerGen(c => + var oauthScheme = new OpenApiSecurityScheme { - var oauthScheme = new OpenApiSecurityScheme + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows() { - Type = SecuritySchemeType.OAuth2, - Flows = new OpenApiOAuthFlows() + Implicit = new OpenApiOAuthFlow() { - Implicit = new OpenApiOAuthFlow() + AuthorizationUrl = new Uri($"https://{domain}/connect/authorize"), + Scopes = new Dictionary(StringComparer.Ordinal) { - AuthorizationUrl = new Uri($"https://{domain}/connect/authorize"), - Scopes = new Dictionary(StringComparer.Ordinal) - { - { swaggerscope, "Grant access to user" } - } + { swaggerscope, "Grant access to user" } } - }, - Scheme = "oauth2" - }; + } + }, + Scheme = "oauth2" + }; + services.ConfigureSwaggerGen(c => + { c.AddSecurityDefinition("oauth2", oauthScheme); c.AddSecurityRequirement((document) => new OpenApiSecurityRequirement() @@ -201,6 +205,8 @@ [new OpenApiSecuritySchemeReference("oauth2", document)] = ["openid"] }); }); + services.ConfigureMicrosoftOpenApiOAuth2(oauthScheme); + services.ArkConfigureSwaggerUI(c => { c.OAuthClientId(clientId); @@ -212,4 +218,24 @@ [new OpenApiSecuritySchemeReference("oauth2", document)] = ["openid"] return services; } -} \ No newline at end of file + + private static void ConfigureMicrosoftOpenApiOAuth2(this IServiceCollection services, OpenApiSecurityScheme oauthScheme) + { + services.ConfigureAll(options => + { + options.AddDocumentTransformer((document, context, cancellationToken) => + { + document.Components ??= new OpenApiComponents(); + document.Components.SecuritySchemes ??= new Dictionary(StringComparer.Ordinal); + document.Components.SecuritySchemes["oauth2"] = oauthScheme; + document.Security ??= []; + document.Security.Add(new OpenApiSecurityRequirement + { + [new OpenApiSecuritySchemeReference("oauth2", document)] = ["openid"] + }); + + return Task.CompletedTask; + }); + }); + } +} diff --git a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Utils/MultiPartJsonOperationFilter.cs b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Utils/MultiPartJsonOperationFilter.cs index a50337906..fa3682631 100644 --- a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Utils/MultiPartJsonOperationFilter.cs +++ b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/Utils/MultiPartJsonOperationFilter.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.OpenApi; using Microsoft.Extensions.Options; using Microsoft.OpenApi; @@ -15,7 +16,7 @@ namespace Ark.Reference.Core.WebInterface.Utils; /// /// Aggregates form fields in Swagger to one JSON field and add example. /// -public class MultiPartJsonOperationFilter : IOperationFilter +public class MultiPartJsonOperationFilter : IOperationFilter { private readonly IServiceProvider _serviceProvider; private readonly IOptions _jsonOptions; @@ -141,13 +142,135 @@ private void _addExample(PropertyInfo propertyInfo, OpenApiSchema openApiSchema) return example; } - private static PropertyInfo? _getPropertyInfo(ParameterDescriptor descriptor) => - descriptor.ParameterType.GetProperties() - .SingleOrDefault(f => f.GetCustomAttribute() != null); -} + private static PropertyInfo? _getPropertyInfo(ParameterDescriptor descriptor) => + descriptor.ParameterType.GetProperties() + .SingleOrDefault(f => f.GetCustomAttribute() != null); +} + +/// +/// Aggregates form fields in Microsoft OpenAPI to one JSON field and add example. +/// +public class MultiPartJsonOperationTransformer : IOpenApiOperationTransformer +{ + private readonly IServiceProvider _serviceProvider; + private readonly IOptions _jsonOptions; + + /// + /// Creates + /// + public MultiPartJsonOperationTransformer(IServiceProvider serviceProvider, IOptions jsonOptions) + { + _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); + _jsonOptions = jsonOptions; + } + + /// + public async Task TransformAsync(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken) + { + var descriptors = context.Description.ActionDescriptor.Parameters.ToList(); + foreach (var descriptor in descriptors) + { + var propertyInfo = _getPropertyInfo(descriptor); + + if (propertyInfo is null || operation.RequestBody?.Content is null || operation.RequestBody.Content.Count == 0) + { + continue; + } + + var mediaType = operation.RequestBody.Content.First().Value; + + if (mediaType.Schema is not OpenApiSchema schema || schema.Properties is null) + { + continue; + } + + var groupedProperties = schema.Properties + .GroupBy(pair => pair.Key.Split('.')[0], StringComparer.Ordinal); + + var schemaProperties = new Dictionary(StringComparer.Ordinal); + + foreach (var property in groupedProperties) + { + if (property.Key == propertyInfo.Name) + { + _addEncoding(mediaType, propertyInfo); + + var openApiSchema = await _getSchema(context, propertyInfo, cancellationToken).ConfigureAwait(false); + schemaProperties.Add(property.Key, openApiSchema); + } + else + { + schemaProperties.Add(property.Key, property.First().Value); + } + } + + schema.Properties = schemaProperties; + } + } + + private async Task _getSchema(OpenApiOperationTransformerContext context, PropertyInfo propertyInfo, CancellationToken cancellationToken) + { + var schema = await context.GetOrCreateSchemaAsync(propertyInfo.PropertyType, null, cancellationToken).ConfigureAwait(false); + + if (schema is OpenApiSchema openApiSchema) + { + _addDescription(openApiSchema, openApiSchema.Title); + _addExample(propertyInfo, openApiSchema); + } + + return schema; + } + + private static void _addDescription(OpenApiSchema openApiSchema, string? SchemaDisplayName) + { + openApiSchema.Description += $"\n See {SchemaDisplayName} model."; + } + + private static void _addEncoding(OpenApiMediaType mediaType, PropertyInfo propertyInfo) + { + if (mediaType.Encoding == null) + mediaType.Encoding = new Dictionary(StringComparer.Ordinal); + + mediaType.Encoding = mediaType.Encoding + .Where(pair => !pair.Key.Contains(propertyInfo.Name, StringComparison.OrdinalIgnoreCase)) + .ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.Ordinal); + + mediaType.Encoding.Add(propertyInfo.Name, new OpenApiEncoding() + { + ContentType = "application/json", + Explode = false + }); + } + + private void _addExample(PropertyInfo propertyInfo, OpenApiSchema openApiSchema) + { + var example = _getExampleFor(propertyInfo.PropertyType); + + if (example == null) + return; + + var json = JsonSerializer.SerializeToNode(example, _jsonOptions.Value.JsonSerializerOptions); + openApiSchema.Example = json; + } + + private object? _getExampleFor(Type parameterType) + { + var makeGenericType = typeof(IExamplesProvider<>).MakeGenericType(parameterType); + var method = makeGenericType.GetMethod("GetExamples"); + var exampleProvider = _serviceProvider.GetService(makeGenericType); + if (exampleProvider == null) + return null; + var example = method?.Invoke(exampleProvider, null); + return example; + } + + private static PropertyInfo? _getPropertyInfo(ParameterDescriptor descriptor) => + descriptor.ParameterType.GetProperties() + .SingleOrDefault(f => f.GetCustomAttribute() != null); +} /// /// Suggest that this form file should be deserialized from JSON. /// -public sealed class FromJsonAttribute : FromFormAttribute { } \ No newline at end of file +public sealed class FromJsonAttribute : FromFormAttribute { } diff --git a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/packages.lock.json b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/packages.lock.json index 0ccfcdfed..df79c5dc8 100644 --- a/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/packages.lock.json +++ b/samples/Ark.ReferenceProject/Core/Ark.Reference.Core.WebInterface/packages.lock.json @@ -37,6 +37,12 @@ "resolved": "10.0.203", "contentHash": "wAY0s+xokbBwVXxm6n7Q1kS4onWinN7qpV2RpkKXMQ0K1SGNsAy46mUFR5SReLQjy5ib9U8bfpnVUEiyZplA1A==" }, + "Microsoft.Extensions.ApiDescription.Server": { + "type": "Direct", + "requested": "[10.0.7, )", + "resolved": "10.0.7", + "contentHash": "VBNJzdInUkjhL/Habj16j3kMHIccjjuWg2zILcapH2QDq5GJF4bfQzJvt2gynuT98PkTpLUvPAsPeefKBDT/mg==" + }, "Microsoft.Identity.Web": { "type": "Direct", "requested": "[4.8.0, )", @@ -524,6 +530,14 @@ "Microsoft.Spatial": "[9.0.0-preview.4, 10.0.0)" } }, + "Microsoft.AspNetCore.OpenApi": { + "type": "Transitive", + "resolved": "10.0.7", + "contentHash": "vKiAcGXG0BwNVw3bOjjWRLnp9tR18dR7MiwpvC94h0yFS+zfnzGHzS/JmmgwUdRixrGxrlIMRAWrVc+2DfAGlg==", + "dependencies": { + "Microsoft.OpenApi": "2.0.0" + } + }, "Microsoft.Azure.Amqp": { "type": "Transitive", "resolved": "2.7.0", @@ -1138,6 +1152,11 @@ "Swashbuckle.AspNetCore.SwaggerGen": "10.0.0" } }, + "Swashbuckle.AspNetCore.ReDoc": { + "type": "Transitive", + "resolved": "10.1.7", + "contentHash": "aoVMCDlS4v6X6EgaowPxSSDwdvIP0NQNJR42lq+iQCVFaGRCN67wALoAZYddyxGQeBoiKSdATvP+psj7OVCuPw==" + }, "Swashbuckle.AspNetCore.Swagger": { "type": "Transitive", "resolved": "10.1.7", @@ -1392,6 +1411,7 @@ "FluentValidation": "[12.1.1, )", "Hellang.Middleware.ProblemDetails": "[6.5.1, )", "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", + "Microsoft.AspNetCore.OpenApi": "[10.0.7, )", "NetEscapades.AspNetCore.SecurityHeaders": "[1.3.1, )", "SimpleInjector.Integration.AspNetCore.Mvc.Core": "[5.5.0, )" } @@ -1456,6 +1476,7 @@ "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", "Swashbuckle.AspNetCore.Annotations": "[10.1.7, )", "Swashbuckle.AspNetCore.Filters": "[10.0.1, )", + "Swashbuckle.AspNetCore.ReDoc": "[10.1.7, )", "Swashbuckle.AspNetCore.Swagger": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerGen": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerUI": "[10.1.7, )" diff --git a/samples/Ark.ReferenceProject/Directory.Packages.props b/samples/Ark.ReferenceProject/Directory.Packages.props index 17a6ef960..9c9c081d8 100644 --- a/samples/Ark.ReferenceProject/Directory.Packages.props +++ b/samples/Ark.ReferenceProject/Directory.Packages.props @@ -39,6 +39,7 @@ + diff --git a/samples/ProblemDetailsSample/packages.lock.json b/samples/ProblemDetailsSample/packages.lock.json index a37b729f7..69eebb1e8 100644 --- a/samples/ProblemDetailsSample/packages.lock.json +++ b/samples/ProblemDetailsSample/packages.lock.json @@ -579,6 +579,7 @@ "FluentValidation": "[12.1.1, )", "Hellang.Middleware.ProblemDetails": "[6.5.1, )", "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", + "Microsoft.AspNetCore.OpenApi": "[10.0.7, )", "NetEscapades.AspNetCore.SecurityHeaders": "[1.3.1, )", "SimpleInjector.Integration.AspNetCore.Mvc.Core": "[5.5.0, )" } @@ -643,6 +644,7 @@ "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", "Swashbuckle.AspNetCore.Annotations": "[10.1.7, )", "Swashbuckle.AspNetCore.Filters": "[10.0.1, )", + "Swashbuckle.AspNetCore.ReDoc": "[10.1.7, )", "Swashbuckle.AspNetCore.Swagger": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerGen": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerUI": "[10.1.7, )" @@ -1056,6 +1058,15 @@ "Microsoft.Spatial": "[9.0.0-preview.4, 10.0.0)" } }, + "Microsoft.AspNetCore.OpenApi": { + "type": "CentralTransitive", + "requested": "[10.0.7, )", + "resolved": "10.0.7", + "contentHash": "vKiAcGXG0BwNVw3bOjjWRLnp9tR18dR7MiwpvC94h0yFS+zfnzGHzS/JmmgwUdRixrGxrlIMRAWrVc+2DfAGlg==", + "dependencies": { + "Microsoft.OpenApi": "2.0.0" + } + }, "Microsoft.Data.SqlClient": { "type": "CentralTransitive", "requested": "[7.0.1, )", @@ -1256,6 +1267,12 @@ "Swashbuckle.AspNetCore.SwaggerGen": "10.0.0" } }, + "Swashbuckle.AspNetCore.ReDoc": { + "type": "CentralTransitive", + "requested": "[10.1.7, )", + "resolved": "10.1.7", + "contentHash": "aoVMCDlS4v6X6EgaowPxSSDwdvIP0NQNJR42lq+iQCVFaGRCN67wALoAZYddyxGQeBoiKSdATvP+psj7OVCuPw==" + }, "Swashbuckle.AspNetCore.Swagger": { "type": "CentralTransitive", "requested": "[10.1.7, )", diff --git a/samples/TestLinkGenerator/packages.lock.json b/samples/TestLinkGenerator/packages.lock.json index bce6b533d..af1deccdc 100644 --- a/samples/TestLinkGenerator/packages.lock.json +++ b/samples/TestLinkGenerator/packages.lock.json @@ -697,6 +697,7 @@ "FluentValidation": "[12.1.1, )", "Hellang.Middleware.ProblemDetails": "[6.5.1, )", "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", + "Microsoft.AspNetCore.OpenApi": "[10.0.7, )", "NetEscapades.AspNetCore.SecurityHeaders": "[1.3.1, )", "SimpleInjector.Integration.AspNetCore.Mvc.Core": "[5.5.0, )" } @@ -761,6 +762,7 @@ "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", "Swashbuckle.AspNetCore.Annotations": "[10.1.7, )", "Swashbuckle.AspNetCore.Filters": "[10.0.1, )", + "Swashbuckle.AspNetCore.ReDoc": "[10.1.7, )", "Swashbuckle.AspNetCore.Swagger": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerGen": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerUI": "[10.1.7, )" @@ -1165,6 +1167,15 @@ "Microsoft.Spatial": "[9.0.0-preview.4, 10.0.0)" } }, + "Microsoft.AspNetCore.OpenApi": { + "type": "CentralTransitive", + "requested": "[10.0.7, )", + "resolved": "10.0.7", + "contentHash": "vKiAcGXG0BwNVw3bOjjWRLnp9tR18dR7MiwpvC94h0yFS+zfnzGHzS/JmmgwUdRixrGxrlIMRAWrVc+2DfAGlg==", + "dependencies": { + "Microsoft.OpenApi": "2.0.0" + } + }, "Microsoft.Data.SqlClient": { "type": "CentralTransitive", "requested": "[7.0.1, )", @@ -1365,6 +1376,12 @@ "Swashbuckle.AspNetCore.SwaggerGen": "10.0.0" } }, + "Swashbuckle.AspNetCore.ReDoc": { + "type": "CentralTransitive", + "requested": "[10.1.7, )", + "resolved": "10.1.7", + "contentHash": "aoVMCDlS4v6X6EgaowPxSSDwdvIP0NQNJR42lq+iQCVFaGRCN67wALoAZYddyxGQeBoiKSdATvP+psj7OVCuPw==" + }, "Swashbuckle.AspNetCore.Swagger": { "type": "CentralTransitive", "requested": "[10.1.7, )", diff --git a/samples/WebApplicationDemo/Startup.cs b/samples/WebApplicationDemo/Startup.cs index d3f6879ba..7474e11e5 100644 --- a/samples/WebApplicationDemo/Startup.cs +++ b/samples/WebApplicationDemo/Startup.cs @@ -36,6 +36,8 @@ public Startup(IConfiguration configuration, IHostEnvironment env) public override IEnumerable Versions => ApiVersions.All; + public override bool UseSwashbuckleOpenApi => HostEnvironment.IsEnvironment("IntegrationTests"); + public override OpenApiInfo MakeInfo(ApiVersion version) => new() { @@ -48,6 +50,11 @@ public override void ConfigureServices(IServiceCollection services) { base.ConfigureServices(services); + foreach (var version in Versions) + { + services.AddOpenApi($"v{version.ToString("VVVV", CultureInfo.InvariantCulture)}"); + } + var auth0Scheme = "Auth0"; var audience = "Audience"; var domain = "Domain"; @@ -178,4 +185,4 @@ protected override void RegisterContainer(IServiceProvider services) var apiHost = new ApiHost(cfg) .WithContainer(Container); } -} \ No newline at end of file +} diff --git a/samples/WebApplicationDemo/WebApplicationDemo.csproj b/samples/WebApplicationDemo/WebApplicationDemo.csproj index 24a390849..8ee6a82eb 100644 --- a/samples/WebApplicationDemo/WebApplicationDemo.csproj +++ b/samples/WebApplicationDemo/WebApplicationDemo.csproj @@ -4,6 +4,8 @@ net10.0 false enable + $(MSBuildProjectDirectory)/bin/$(Configuration)/$(TargetFramework)/ + --openapi-version OpenApi3_1 @@ -11,6 +13,8 @@ + + @@ -26,4 +30,5 @@ + diff --git a/samples/WebApplicationDemo/packages.lock.json b/samples/WebApplicationDemo/packages.lock.json index 0be6e7068..b447d4c37 100644 --- a/samples/WebApplicationDemo/packages.lock.json +++ b/samples/WebApplicationDemo/packages.lock.json @@ -2,6 +2,21 @@ "version": 2, "dependencies": { "net10.0": { + "Microsoft.AspNetCore.OpenApi": { + "type": "Direct", + "requested": "[10.0.7, )", + "resolved": "10.0.7", + "contentHash": "vKiAcGXG0BwNVw3bOjjWRLnp9tR18dR7MiwpvC94h0yFS+zfnzGHzS/JmmgwUdRixrGxrlIMRAWrVc+2DfAGlg==", + "dependencies": { + "Microsoft.OpenApi": "2.0.0" + } + }, + "Microsoft.Extensions.ApiDescription.Server": { + "type": "Direct", + "requested": "[10.0.7, )", + "resolved": "10.0.7", + "contentHash": "VBNJzdInUkjhL/Habj16j3kMHIccjjuWg2zILcapH2QDq5GJF4bfQzJvt2gynuT98PkTpLUvPAsPeefKBDT/mg==" + }, "Microsoft.Identity.Web": { "type": "Direct", "requested": "[4.8.0, )", @@ -720,6 +735,7 @@ "FluentValidation": "[12.1.1, )", "Hellang.Middleware.ProblemDetails": "[6.5.1, )", "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", + "Microsoft.AspNetCore.OpenApi": "[10.0.7, )", "NetEscapades.AspNetCore.SecurityHeaders": "[1.3.1, )", "SimpleInjector.Integration.AspNetCore.Mvc.Core": "[5.5.0, )" } @@ -784,6 +800,7 @@ "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", "Swashbuckle.AspNetCore.Annotations": "[10.1.7, )", "Swashbuckle.AspNetCore.Filters": "[10.0.1, )", + "Swashbuckle.AspNetCore.ReDoc": "[10.1.7, )", "Swashbuckle.AspNetCore.Swagger": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerGen": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerUI": "[10.1.7, )" @@ -1455,6 +1472,12 @@ "Swashbuckle.AspNetCore.SwaggerGen": "10.0.0" } }, + "Swashbuckle.AspNetCore.ReDoc": { + "type": "CentralTransitive", + "requested": "[10.1.7, )", + "resolved": "10.1.7", + "contentHash": "aoVMCDlS4v6X6EgaowPxSSDwdvIP0NQNJR42lq+iQCVFaGRCN67wALoAZYddyxGQeBoiKSdATvP+psj7OVCuPw==" + }, "Swashbuckle.AspNetCore.Swagger": { "type": "CentralTransitive", "requested": "[10.1.7, )", diff --git a/src/aspnetcore/Ark.Tools.AspNetCore.ApplicationInsights/packages.lock.json b/src/aspnetcore/Ark.Tools.AspNetCore.ApplicationInsights/packages.lock.json index 5cdae6e83..b6ecd2689 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore.ApplicationInsights/packages.lock.json +++ b/src/aspnetcore/Ark.Tools.AspNetCore.ApplicationInsights/packages.lock.json @@ -70,12 +70,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/aspnetcore/Ark.Tools.AspNetCore.Auth0/packages.lock.json b/src/aspnetcore/Ark.Tools.AspNetCore.Auth0/packages.lock.json index 5e19ce72a..e34897ac5 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore.Auth0/packages.lock.json +++ b/src/aspnetcore/Ark.Tools.AspNetCore.Auth0/packages.lock.json @@ -93,12 +93,6 @@ "Polly.Core": "8.6.6" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Auth0.Core": { "type": "Transitive", "resolved": "7.45.1", diff --git a/src/aspnetcore/Ark.Tools.AspNetCore.BasicAuthAuth0Proxy/packages.lock.json b/src/aspnetcore/Ark.Tools.AspNetCore.BasicAuthAuth0Proxy/packages.lock.json index da339ea25..4f1cd263d 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore.BasicAuthAuth0Proxy/packages.lock.json +++ b/src/aspnetcore/Ark.Tools.AspNetCore.BasicAuthAuth0Proxy/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Auth0.Core": { "type": "Transitive", "resolved": "7.45.1", diff --git a/src/aspnetcore/Ark.Tools.AspNetCore.BasicAuthAzureActiveDirectoryProxy/packages.lock.json b/src/aspnetcore/Ark.Tools.AspNetCore.BasicAuthAzureActiveDirectoryProxy/packages.lock.json index fa98c7fa6..041b501bd 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore.BasicAuthAzureActiveDirectoryProxy/packages.lock.json +++ b/src/aspnetcore/Ark.Tools.AspNetCore.BasicAuthAzureActiveDirectoryProxy/packages.lock.json @@ -83,12 +83,6 @@ "Polly.Core": "8.6.6" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/aspnetcore/Ark.Tools.AspNetCore.CommaSeparatedParameters/packages.lock.json b/src/aspnetcore/Ark.Tools.AspNetCore.CommaSeparatedParameters/packages.lock.json index 117afcee6..7d75ee203 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore.CommaSeparatedParameters/packages.lock.json +++ b/src/aspnetcore/Ark.Tools.AspNetCore.CommaSeparatedParameters/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/aspnetcore/Ark.Tools.AspNetCore.HealthChecks/packages.lock.json b/src/aspnetcore/Ark.Tools.AspNetCore.HealthChecks/packages.lock.json index 8a077d519..0e38a424f 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore.HealthChecks/packages.lock.json +++ b/src/aspnetcore/Ark.Tools.AspNetCore.HealthChecks/packages.lock.json @@ -166,12 +166,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "AspNetCore.HealthChecks.UI.Core": { "type": "Transitive", "resolved": "9.0.0", diff --git a/src/aspnetcore/Ark.Tools.AspNetCore.MessagePack/packages.lock.json b/src/aspnetcore/Ark.Tools.AspNetCore.MessagePack/packages.lock.json index 6aaf966ea..ad7608fa2 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore.MessagePack/packages.lock.json +++ b/src/aspnetcore/Ark.Tools.AspNetCore.MessagePack/packages.lock.json @@ -66,12 +66,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "MessagePack.Annotations": { "type": "Transitive", "resolved": "3.1.4", diff --git a/src/aspnetcore/Ark.Tools.AspNetCore.NestedStartup/packages.lock.json b/src/aspnetcore/Ark.Tools.AspNetCore.NestedStartup/packages.lock.json index 117afcee6..7d75ee203 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore.NestedStartup/packages.lock.json +++ b/src/aspnetcore/Ark.Tools.AspNetCore.NestedStartup/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/aspnetcore/Ark.Tools.AspNetCore.RavenDb/packages.lock.json b/src/aspnetcore/Ark.Tools.AspNetCore.RavenDb/packages.lock.json index c439f8a85..29adbc43b 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore.RavenDb/packages.lock.json +++ b/src/aspnetcore/Ark.Tools.AspNetCore.RavenDb/packages.lock.json @@ -67,12 +67,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/aspnetcore/Ark.Tools.AspNetCore.Swashbuckle/Ark.Tools.AspNetCore.Swashbuckle.csproj b/src/aspnetcore/Ark.Tools.AspNetCore.Swashbuckle/Ark.Tools.AspNetCore.Swashbuckle.csproj index 1ccc3dbf0..dd4c865ee 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore.Swashbuckle/Ark.Tools.AspNetCore.Swashbuckle.csproj +++ b/src/aspnetcore/Ark.Tools.AspNetCore.Swashbuckle/Ark.Tools.AspNetCore.Swashbuckle.csproj @@ -41,6 +41,7 @@ + diff --git a/src/aspnetcore/Ark.Tools.AspNetCore.Swashbuckle/packages.lock.json b/src/aspnetcore/Ark.Tools.AspNetCore.Swashbuckle/packages.lock.json index 74928ea08..6e195a6c4 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore.Swashbuckle/packages.lock.json +++ b/src/aspnetcore/Ark.Tools.AspNetCore.Swashbuckle/packages.lock.json @@ -77,12 +77,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Swashbuckle.AspNetCore.Annotations": { "type": "Direct", "requested": "[10.1.7, )", @@ -103,6 +97,12 @@ "Swashbuckle.AspNetCore.SwaggerGen": "10.0.0" } }, + "Swashbuckle.AspNetCore.ReDoc": { + "type": "Direct", + "requested": "[10.1.7, )", + "resolved": "10.1.7", + "contentHash": "aoVMCDlS4v6X6EgaowPxSSDwdvIP0NQNJR42lq+iQCVFaGRCN67wALoAZYddyxGQeBoiKSdATvP+psj7OVCuPw==" + }, "Swashbuckle.AspNetCore.Swagger": { "type": "Direct", "requested": "[10.1.7, )", diff --git a/src/aspnetcore/Ark.Tools.AspNetCore/Ark.Tools.AspNetCore.csproj b/src/aspnetcore/Ark.Tools.AspNetCore/Ark.Tools.AspNetCore.csproj index ccabd9edf..78c81678d 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore/Ark.Tools.AspNetCore.csproj +++ b/src/aspnetcore/Ark.Tools.AspNetCore/Ark.Tools.AspNetCore.csproj @@ -35,6 +35,7 @@ + diff --git a/src/aspnetcore/Ark.Tools.AspNetCore/Startup/ArkMicrosoftOpenApiExtensions.cs b/src/aspnetcore/Ark.Tools.AspNetCore/Startup/ArkMicrosoftOpenApiExtensions.cs new file mode 100644 index 000000000..11cc36bdf --- /dev/null +++ b/src/aspnetcore/Ark.Tools.AspNetCore/Startup/ArkMicrosoftOpenApiExtensions.cs @@ -0,0 +1,467 @@ +// Copyright (C) 2024 Ark Energy S.r.l. All rights reserved. +// Licensed under the MIT License. See LICENSE file for license information. +using Ark.Tools.Core.Reflection; +using Ark.Tools.AspNetCore.Swashbuckle; + +using Asp.Versioning; + +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ApiExplorer; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.OpenApi; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OpenApi; + +using NodaTime; + +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization.Metadata; + +using Swashbuckle.AspNetCore.Annotations; + +namespace Ark.Tools.AspNetCore.Startup; + +internal static class ArkMicrosoftOpenApiExtensions +{ + public static IServiceCollection AddArkMicrosoftOpenApiVersions(this IServiceCollection services, IEnumerable versions, Func infoBuilder, Action? configureOptions = null) + { + foreach (var version in versions) + { + var documentName = ToDocumentName(version); + var info = infoBuilder(version); + + services.AddOpenApi(documentName, options => + { + options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1; + options.ShouldInclude = description => string.Equals(description.GroupName, documentName, StringComparison.Ordinal); + options.CreateSchemaReferenceId = CreateSchemaReferenceId; + + options.AddDocumentTransformer((document, context, cancellationToken) => + { + document.Info = info; + return Task.CompletedTask; + }); + options.AddSchemaTransformer(ApplyNodaTimeSchema); + options.AddOperationTransformer(ApplySwaggerOperationAttribute); + options.AddOperationTransformer(ApplySwaggerResponseAttributes); + options.AddOperationTransformer(ApplySwaggerDefaultValues); + options.AddOperationTransformer(ApplyODataMediaTypeCleanup); + options.AddOperationTransformer(ApplyOperationId); + options.AddOperationTransformer(ApplyFlaggedEnums); + options.AddOperationTransformer(ApplyDefaultResponses); + configureOptions?.Invoke(documentName, options); + }); + } + + services.ArkConfigureSwaggerUI(c => + { + foreach (var version in versions) + { + var documentName = ToDocumentName(version); + c.SwaggerEndpoint($@"docs/{documentName}", $@"{documentName} Docs"); + } + }); + + return services; + } + + public static string ToDocumentName(ApiVersion version) + => $"v{version.ToString("VVVV", CultureInfo.InvariantCulture)}"; + + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "OpenAPI schema IDs are generated during document generation and follow the existing Swashbuckle naming policy.")] + private static string CreateSchemaReferenceId(JsonTypeInfo jsonTypeInfo) + => ReflectionHelper.GetCSTypeName(jsonTypeInfo.Type).Replace($"{jsonTypeInfo.Type.Namespace}.", string.Empty, StringComparison.Ordinal); + + public static async Task WriteOpenApiDocumentAsync(HttpContext context) + { + var documentName = context.Request.RouteValues["documentName"]?.ToString(); + if (string.IsNullOrWhiteSpace(documentName)) + { + context.Response.StatusCode = StatusCodes.Status404NotFound; + return; + } + + var staticDocumentPath = FindBuildGeneratedDocument(documentName); + if (staticDocumentPath is not null) + { + context.Response.ContentType = "application/json"; + await context.Response.SendFileAsync(staticDocumentPath, context.RequestAborted).ConfigureAwait(false); + return; + } + +#if DEBUG + await WriteRuntimeGeneratedOpenApiDocumentAsync(context, documentName).ConfigureAwait(false); +#else + context.Response.StatusCode = StatusCodes.Status404NotFound; +#endif + } + +#if DEBUG + private static async Task WriteRuntimeGeneratedOpenApiDocumentAsync(HttpContext context, string documentName) + { + var provider = context.RequestServices.GetKeyedService(documentName); + if (provider is null) + { + context.Response.StatusCode = StatusCodes.Status404NotFound; + return; + } + + var document = await provider.GetOpenApiDocumentAsync(context.RequestAborted).ConfigureAwait(false); + context.Response.ContentType = "application/json"; + var json = await document.SerializeAsJsonAsync(OpenApiSpecVersion.OpenApi3_1, context.RequestAborted).ConfigureAwait(false); + await context.Response.WriteAsync(json, context.RequestAborted).ConfigureAwait(false); + } +#endif + + private static string? FindBuildGeneratedDocument(string documentName) + { + var entryAssemblyName = Assembly.GetEntryAssembly()?.GetName().Name ?? AppDomain.CurrentDomain.FriendlyName; + var baseDirectory = AppContext.BaseDirectory; + var candidates = new[] + { + Path.Combine(baseDirectory, $"{entryAssemblyName}_{documentName}.json"), + Path.Combine(baseDirectory, $"{entryAssemblyName}.json"), + Path.Combine(baseDirectory, $"{documentName}.json") + }; + + return candidates.FirstOrDefault(File.Exists); + } + + private static Task ApplyNodaTimeSchema(OpenApiSchema schema, OpenApiSchemaTransformerContext context, CancellationToken cancellationToken) + { + var type = Nullable.GetUnderlyingType(context.JsonTypeInfo.Type) ?? context.JsonTypeInfo.Type; + var schemaInfo = GetNodaTimeSchemaInfo(type); + if (schemaInfo is null) + { + return Task.CompletedTask; + } + + schema.Type = JsonSchemaType.String; + schema.Format = schemaInfo.Value.Format; + schema.Example = schemaInfo.Value.Example; + + if (Nullable.GetUnderlyingType(context.JsonTypeInfo.Type) is not null) + { + schema.Type |= JsonSchemaType.Null; + } + + return Task.CompletedTask; + } + + private static (string? Format, string Example)? GetNodaTimeSchemaInfo(Type type) + { + if (type == typeof(LocalDate)) + { + return ("date", "2016-01-21"); + } + + if (type == typeof(LocalDateTime)) + { + return ("date-time", "2016-01-21T15:01:01.999999999"); + } + + if (type == typeof(Instant)) + { + return ("date-time", "2016-01-21T15:01:01.999999999Z"); + } + + if (type == typeof(OffsetDateTime)) + { + return ("date-time", "2016-01-21T15:01:01.999999999+02:00"); + } + + if (type == typeof(ZonedDateTime)) + { + return (null, "2016-01-21T15:01:01.999999999+02:00 Europe/Rome"); + } + + if (type == typeof(LocalTime)) + { + return ("time", "14:01:00.999999999"); + } + + if (type == typeof(DateTimeZone)) + { + return (null, "Europe/Rome"); + } + + if (type == typeof(Period)) + { + return ("duration", "P1Y2M-3DT4H"); + } + + return null; + } + + private static Task ApplySwaggerOperationAttribute(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken) + { + var attribute = GetLastActionMetadata(context); + if (attribute is null) + { + return Task.CompletedTask; + } + + operation.Summary = attribute.Summary ?? operation.Summary; + operation.Description = attribute.Description ?? operation.Description; + operation.OperationId = attribute.OperationId ?? operation.OperationId; + + if (attribute.Tags is { Length: > 0 }) + { + operation.Tags = attribute.Tags + .Select(tag => new OpenApiTagReference(tag, context.Document)) + .ToHashSet(); + } + + return Task.CompletedTask; + } + + private static async Task ApplySwaggerResponseAttributes(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken) + { + var attributes = GetActionMetadata(context).ToArray(); + if (attributes.Length == 0) + { + return; + } + + operation.Responses ??= new OpenApiResponses(); + + foreach (var attribute in attributes) + { + var responseKey = attribute.StatusCode.ToString(CultureInfo.InvariantCulture); + if (!operation.Responses.TryGetValue(responseKey, out var response)) + { + response = new OpenApiResponse(); + operation.Responses.Add(responseKey, response); + } + + response.Description = attribute.Description ?? response.Description; + + if (attribute.Type is null || attribute.Type == typeof(void)) + { + continue; + } + + var schema = await context.GetOrCreateSchemaAsync(attribute.Type, null, cancellationToken).ConfigureAwait(false); + var contentTypes = attribute.ContentTypes is { Length: > 0 } + ? attribute.ContentTypes + : ["application/json"]; + + var content = contentTypes.ToDictionary( + contentType => contentType, + _ => new OpenApiMediaType { Schema = schema }, + StringComparer.Ordinal); + + if (response is OpenApiResponse openApiResponse) + { + openApiResponse.Content = content; + } + else + { + operation.Responses[responseKey] = new OpenApiResponse + { + Description = response.Description, + Content = content + }; + } + } + } + + private static TAttribute? GetLastActionMetadata(OpenApiOperationTransformerContext context) + where TAttribute : Attribute + => context.Description.ActionDescriptor.EndpointMetadata.OfType().LastOrDefault() + ?? (context.Description.ActionDescriptor is ControllerActionDescriptor cad ? cad.MethodInfo.GetCustomAttribute() : null); + + private static IEnumerable GetActionMetadata(OpenApiOperationTransformerContext context) + where TAttribute : Attribute + { + var metadata = context.Description.ActionDescriptor.EndpointMetadata.OfType(); + if (context.Description.ActionDescriptor is ControllerActionDescriptor cad) + { + metadata = metadata.Concat(cad.MethodInfo.GetCustomAttributes()); + } + + return metadata.Distinct(); + } + + [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "Default parameter values are serialized only while generating OpenAPI metadata.")] + private static Task ApplySwaggerDefaultValues(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken) + { + var apiDescription = context.Description; + operation.Deprecated |= apiDescription.IsDeprecated; + + if (operation.Responses is not null) + { + foreach (var responseType in apiDescription.SupportedResponseTypes) + { + var responseKey = responseType.IsDefaultResponse ? "default" : responseType.StatusCode.ToString(CultureInfo.InvariantCulture); + if (!operation.Responses.TryGetValue(responseKey, out var response) || response.Content is null) + { + continue; + } + + foreach (var contentType in response.Content.Keys.ToArray()) + { + if (!responseType.ApiResponseFormats.Any(x => string.Equals(x.MediaType, contentType, StringComparison.Ordinal))) + { + response.Content.Remove(contentType); + } + } + } + } + + if (operation.Parameters is null) + { + return Task.CompletedTask; + } + + foreach (var parameter in operation.Parameters.OfType()) + { + var description = apiDescription.ParameterDescriptions.FirstOrDefault(p => string.Equals(p.Name, parameter.Name, StringComparison.Ordinal)); + if (description is null) + { + continue; + } + + parameter.Description ??= description.ModelMetadata?.Description; + + if (parameter.Schema is OpenApiSchema schema && schema.Default is null && description.DefaultValue is not null && description.ModelMetadata is not null) + { + schema.Default = JsonSerializer.SerializeToNode(description.DefaultValue, description.ModelMetadata.ModelType, ArkSerializerOptions.JsonOptions); + } + + parameter.Required |= description.IsRequired; + } + + return Task.CompletedTask; + } + + private static Task ApplyODataMediaTypeCleanup(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken) + { + if (context.Description.ActionDescriptor is not ControllerActionDescriptor cad + || Attribute.IsDefined(cad.ControllerTypeInfo, typeof(Microsoft.AspNetCore.OData.Routing.Attributes.ODataAttributeRoutingAttribute))) + { + return Task.CompletedTask; + } + + if (operation.Responses is not null) + { + foreach (var response in operation.Responses.Values) + { + RemoveODataMediaTypes(response.Content); + } + } + + if (operation.Parameters is not null) + { + foreach (var parameter in operation.Parameters.OfType()) + { + RemoveODataMediaTypes(parameter.Content); + } + } + + RemoveODataMediaTypes(operation.RequestBody?.Content); + + return Task.CompletedTask; + } + + private static void RemoveODataMediaTypes(IDictionary? content) + { + if (content is null) + { + return; + } + + foreach (var contentType in content.Keys.ToArray()) + { + if (contentType.Contains("odata", StringComparison.OrdinalIgnoreCase)) + { + content.Remove(contentType); + } + } + } + + private static Task ApplyOperationId(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken) + { + if (context.Description.ActionDescriptor is ControllerActionDescriptor) + { + operation.OperationId = $@"{context.Description.HttpMethod}{context.Description.RelativePath? + .Replace("v{api-version}", string.Empty, StringComparison.Ordinal) + .Replace("/", "_", StringComparison.Ordinal) + .Replace("{", "_", StringComparison.Ordinal) + .Replace("}", "_", StringComparison.Ordinal)}"; + } + + return Task.CompletedTask; + } + + private static Task ApplyFlaggedEnums(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken) + { + if (operation.Parameters is null) + { + return Task.CompletedTask; + } + + var queryEnumParams = operation.Parameters.OfType() + .Where(param => param.In == ParameterLocation.Query) + .Join(context.Description.ParameterDescriptions, o => o.Name, i => i.Name, (o, i) => new { o, i }, StringComparer.Ordinal) + .Where(x => + { + var type = x.i.Type; + if (type is null) + { + return false; + } + + type = Nullable.GetUnderlyingType(type) ?? type; + return type.IsEnum && type.IsDefined(typeof(FlagsAttribute), false); + }) + .Select(x => x.o) + .ToArray(); + + foreach (var param in queryEnumParams) + { + var schema = param.Schema; + param.Schema = new OpenApiSchema { Type = JsonSchemaType.Array, Items = schema }; + param.Style = ParameterStyle.Simple; + param.Explode = false; + } + + return Task.CompletedTask; + } + + private static async Task ApplyDefaultResponses(OpenApiOperation operation, OpenApiOperationTransformerContext context, CancellationToken cancellationToken) + { + operation.Responses ??= new OpenApiResponses(); + + var problemDetailsSchema = await context.GetOrCreateSchemaAsync(typeof(Microsoft.AspNetCore.Mvc.ProblemDetails), null, cancellationToken).ConfigureAwait(false); + var validationProblemDetailsSchema = await context.GetOrCreateSchemaAsync(typeof(ValidationProblemDetails), null, cancellationToken).ConfigureAwait(false); + + AddResponseIfMissing(operation, "401", "Unauthorized", problemDetailsSchema); + AddResponseIfMissing(operation, "403", "Not enough permissions", problemDetailsSchema); + AddResponseIfMissing(operation, "400", "Invalid payload", validationProblemDetailsSchema); + AddResponseIfMissing(operation, "500", "Internal server error. Retry later or contact support.", problemDetailsSchema); + } + + private static void AddResponseIfMissing(OpenApiOperation operation, string statusCode, string description, IOpenApiSchema schema) + { + if (operation.Responses is null || operation.Responses.ContainsKey(statusCode)) + { + return; + } + + operation.Responses.Add(statusCode, new OpenApiResponse + { + Description = description, + Content = new Dictionary(StringComparer.Ordinal) + { + ["application/json"] = new OpenApiMediaType + { + Schema = schema + } + } + }); + } +} diff --git a/src/aspnetcore/Ark.Tools.AspNetCore/Startup/ArkStartupWebApiCommon.cs b/src/aspnetcore/Ark.Tools.AspNetCore/Startup/ArkStartupWebApiCommon.cs index b6f13d099..69c4f16f3 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore/Startup/ArkStartupWebApiCommon.cs +++ b/src/aspnetcore/Ark.Tools.AspNetCore/Startup/ArkStartupWebApiCommon.cs @@ -11,10 +11,10 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Formatters; -using Microsoft.AspNetCore.OData; - -using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.AspNetCore.OData; + +using Microsoft.AspNetCore.ResponseCompression; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -24,9 +24,10 @@ -using SimpleInjector; - -using Swashbuckle.AspNetCore.SwaggerUI; +using SimpleInjector; + +using Swashbuckle.AspNetCore.ReDoc; +using Swashbuckle.AspNetCore.SwaggerUI; using System.Text.Json; @@ -36,7 +37,17 @@ public abstract class ArkStartupWebApiCommon { public IConfiguration Configuration { get; } public Container Container { get; } = new Container(); - public IHostEnvironment HostEnvironment { get; } + public IHostEnvironment HostEnvironment { get; } + + /// + /// Gets a value indicating whether the legacy Swashbuckle generator should be used instead of Microsoft OpenAPI. + /// + public virtual bool UseSwashbuckleOpenApi => false; + + /// + /// Gets a value indicating whether the Microsoft OpenAPI generator should be used instead of the legacy Swashbuckle generator. + /// + protected bool UseMicrosoftOpenApi => !UseSwashbuckleOpenApi; protected ArkStartupWebApiCommon(IConfiguration configuration, IHostEnvironment hostEnvironment) { @@ -134,51 +145,58 @@ public virtual void ConfigureServices(IServiceCollection services) }) ; - services.AddSwaggerGen(c => - { - c.DocInclusionPredicate((docName, apiDesc) => apiDesc.GroupName == docName); - - c.MapNodaTimeTypes(); - - c.OperationFilter(); - c.OperationFilter(); - c.OperationFilter(); - c.OperationFilter(); - - - c.UseOneOfForPolymorphism(); - c.UseAllOfForInheritance(); - c.UseAllOfToExtendReferenceSchemas(); - - c.CustomOperationIds(x => x.HttpMethod + " " + x.RelativePath); - c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); - - c.OperationFilter(); - - c.IncludeXmlCommentsForAssembly(this.GetType().Assembly); - - c.CustomSchemaIds((type) => Ark.Tools.Core.Reflection.ReflectionHelper.GetCSTypeName(type).Replace($"{type.Namespace}.", @"", StringComparison.Ordinal)); - c.SelectSubTypesUsing(t => - { - if (t.IsGenericTypeDefinition) return Enumerable.Empty(); - return t.Assembly.GetTypes() - .Where(subType => subType.IsSubclassOf(t) && !subType.IsGenericTypeDefinition); - }); - c.SupportNonNullableReferenceTypes(); - - c.EnableAnnotations(); - }); - - services.ArkConfigureSwaggerVersions(Versions, MakeInfo); - - services.ArkConfigureSwagger(c => + if (UseSwashbuckleOpenApi) + { + services.AddSwaggerGen(c => + { + c.DocInclusionPredicate((docName, apiDesc) => apiDesc.GroupName == docName); + + c.MapNodaTimeTypes(); + + c.OperationFilter(); + c.OperationFilter(); + c.OperationFilter(); + c.OperationFilter(); + + + c.UseOneOfForPolymorphism(); + c.UseAllOfForInheritance(); + c.UseAllOfToExtendReferenceSchemas(); + + c.CustomOperationIds(x => x.HttpMethod + " " + x.RelativePath); + c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); + + c.OperationFilter(); + + c.IncludeXmlCommentsForAssembly(this.GetType().Assembly); + + c.CustomSchemaIds((type) => Ark.Tools.Core.Reflection.ReflectionHelper.GetCSTypeName(type).Replace($"{type.Namespace}.", @"", StringComparison.Ordinal)); + c.SelectSubTypesUsing(t => + { + if (t.IsGenericTypeDefinition) return Enumerable.Empty(); + return t.Assembly.GetTypes() + .Where(subType => subType.IsSubclassOf(t) && !subType.IsGenericTypeDefinition); + }); + c.SupportNonNullableReferenceTypes(); + + c.EnableAnnotations(); + }); + + services.ArkConfigureSwaggerVersions(Versions, MakeInfo); + } + else + { + services.AddArkMicrosoftOpenApiVersions(Versions, MakeInfo, ConfigureMicrosoftOpenApi); + } + + services.ArkConfigureSwagger(c => { c.RouteTemplate = "swagger/docs/{documentName}"; }); - services.ArkConfigureSwaggerUI(c => - { - c.RoutePrefix = "swagger"; + services.ArkConfigureSwaggerUI(c => + { + c.RoutePrefix = "swagger"; c.DefaultModelExpandDepth(2); c.DefaultModelRendering(ModelRendering.Model); @@ -191,8 +209,15 @@ public virtual void ConfigureServices(IServiceCollection services) c.MaxDisplayedTags(100); c.ShowExtensions(); c.EnableValidator(); - c.EnableTryItOutByDefault(); - }); + c.EnableTryItOutByDefault(); + }); + + services.Configure(c => + { + c.RoutePrefix = "redoc"; + c.DocumentTitle = "API Docs"; + c.SpecUrl = $"/swagger/docs/{ArkMicrosoftOpenApiExtensions.ToDocumentName(Versions.First())}"; + }); // Configure System.Text.Json with Ark defaults mvcBuilder.AddJsonOptions(options => @@ -235,11 +260,20 @@ private void _integrateSimpleInjectorContainer(IServiceCollection services) RegisterContainer(); } - public abstract IEnumerable Versions { get; } - - public abstract OpenApiInfo MakeInfo(ApiVersion version); - - [RequiresUnreferencedCode("Configure uses ProblemDetails router which dynamically resolves types for diagnostic purposes.")] + public abstract IEnumerable Versions { get; } + + public abstract OpenApiInfo MakeInfo(ApiVersion version); + + /// + /// Configures the Microsoft OpenAPI document generator for a specific document. + /// + /// The OpenAPI document name. + /// The OpenAPI generator options. + protected virtual void ConfigureMicrosoftOpenApi(string documentName, Microsoft.AspNetCore.OpenApi.OpenApiOptions options) + { + } + + [RequiresUnreferencedCode("Configure uses ProblemDetails router which dynamically resolves types for diagnostic purposes.")] public virtual void Configure(IApplicationBuilder app) { app.UseSimpleInjector(Container); @@ -264,12 +298,16 @@ public virtual void Configure(IApplicationBuilder app) app.UseODataRouteDebug(); } - app.UseSwagger(options => - { - options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1; - }); - - app.UseSwaggerUI(); + if (UseSwashbuckleOpenApi) + { + app.UseSwagger(options => + { + options.OpenApiVersion = OpenApiSpecVersion.OpenApi3_1; + }); + } + + app.UseSwaggerUI(); + app.UseReDoc(); app.UseAuthentication(); app.UseAuthorization(); @@ -279,10 +317,17 @@ public virtual void Configure(IApplicationBuilder app) app.UseEndpoints(endpoints => { - endpoints.MapArkHealthChecks(); - endpoints.MapControllers(); - endpoints.Redirect("/", "/swagger"); - }); + endpoints.MapArkHealthChecks(); + endpoints.MapControllers(); + if (UseMicrosoftOpenApi) + { +#if DEBUG + endpoints.MapOpenApi("/openapi/{documentName}.json"); +#endif + endpoints.MapGet("swagger/docs/{documentName}", ArkMicrosoftOpenApiExtensions.WriteOpenApiDocumentAsync); + } + endpoints.Redirect("/", "/swagger"); + }); //app.UseMvc(_mvcRoute); //Not Usable without setting MVC opt.EnableEndpointRouting = false; @@ -300,4 +345,4 @@ protected virtual void RegisterContainer() protected virtual void RegisterContainer(IServiceProvider services) { } -} \ No newline at end of file +} diff --git a/src/aspnetcore/Ark.Tools.AspNetCore/packages.lock.json b/src/aspnetcore/Ark.Tools.AspNetCore/packages.lock.json index 4e38c079d..70c3128b1 100644 --- a/src/aspnetcore/Ark.Tools.AspNetCore/packages.lock.json +++ b/src/aspnetcore/Ark.Tools.AspNetCore/packages.lock.json @@ -66,6 +66,15 @@ "Microsoft.Spatial": "[9.0.0-preview.4, 10.0.0)" } }, + "Microsoft.AspNetCore.OpenApi": { + "type": "Direct", + "requested": "[10.0.7, )", + "resolved": "10.0.7", + "contentHash": "vKiAcGXG0BwNVw3bOjjWRLnp9tR18dR7MiwpvC94h0yFS+zfnzGHzS/JmmgwUdRixrGxrlIMRAWrVc+2DfAGlg==", + "dependencies": { + "Microsoft.OpenApi": "2.0.0" + } + }, "Microsoft.CodeAnalysis.BannedApiAnalyzers": { "type": "Direct", "requested": "[4.14.0, )", @@ -113,12 +122,6 @@ "resolved": "1.3.1", "contentHash": "wccVMVSGq9nQ43SjJl1s/VaAo+iWauJYWiZy/Hkvszk2vCQdq7aRn7GL3LTBMsnHuI13JRMfCi9Lk8747+njUg==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "SimpleInjector.Integration.AspNetCore.Mvc.Core": { "type": "Direct", "requested": "[5.5.0, )", @@ -760,6 +763,7 @@ "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", "Swashbuckle.AspNetCore.Annotations": "[10.1.7, )", "Swashbuckle.AspNetCore.Filters": "[10.0.1, )", + "Swashbuckle.AspNetCore.ReDoc": "[10.1.7, )", "Swashbuckle.AspNetCore.Swagger": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerGen": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerUI": "[10.1.7, )" @@ -1291,6 +1295,12 @@ "Swashbuckle.AspNetCore.SwaggerGen": "10.0.0" } }, + "Swashbuckle.AspNetCore.ReDoc": { + "type": "CentralTransitive", + "requested": "[10.1.7, )", + "resolved": "10.1.7", + "contentHash": "aoVMCDlS4v6X6EgaowPxSSDwdvIP0NQNJR42lq+iQCVFaGRCN67wALoAZYddyxGQeBoiKSdATvP+psj7OVCuPw==" + }, "Swashbuckle.AspNetCore.Swagger": { "type": "CentralTransitive", "requested": "[10.1.7, )", diff --git a/src/common/Ark.Tasks/packages.lock.json b/src/common/Ark.Tasks/packages.lock.json index 10f954992..3b56f7a55 100644 --- a/src/common/Ark.Tasks/packages.lock.json +++ b/src/common/Ark.Tasks/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/common/Ark.Tools.Activity/packages.lock.json b/src/common/Ark.Tools.Activity/packages.lock.json index 593feee70..812c23200 100644 --- a/src/common/Ark.Tools.Activity/packages.lock.json +++ b/src/common/Ark.Tools.Activity/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Azure.Core": { "type": "Transitive", "resolved": "1.53.0", diff --git a/src/common/Ark.Tools.ApplicationInsights.HostedService/packages.lock.json b/src/common/Ark.Tools.ApplicationInsights.HostedService/packages.lock.json index a224af5d3..9e79672ea 100644 --- a/src/common/Ark.Tools.ApplicationInsights.HostedService/packages.lock.json +++ b/src/common/Ark.Tools.ApplicationInsights.HostedService/packages.lock.json @@ -71,12 +71,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Azure.Core": { "type": "Transitive", "resolved": "1.53.0", diff --git a/src/common/Ark.Tools.ApplicationInsights/packages.lock.json b/src/common/Ark.Tools.ApplicationInsights/packages.lock.json index 3813d1675..61c84e241 100644 --- a/src/common/Ark.Tools.ApplicationInsights/packages.lock.json +++ b/src/common/Ark.Tools.ApplicationInsights/packages.lock.json @@ -110,12 +110,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Bcl.Cryptography": { "type": "Transitive", "resolved": "9.0.13", diff --git a/src/common/Ark.Tools.Auth0/packages.lock.json b/src/common/Ark.Tools.Auth0/packages.lock.json index 41fdf1796..78b048556 100644 --- a/src/common/Ark.Tools.Auth0/packages.lock.json +++ b/src/common/Ark.Tools.Auth0/packages.lock.json @@ -103,12 +103,6 @@ "Polly": "7.1.1" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Auth0.Core": { "type": "Transitive", "resolved": "7.45.1", diff --git a/src/common/Ark.Tools.Authorization/packages.lock.json b/src/common/Ark.Tools.Authorization/packages.lock.json index 2e7162cf3..26b137250 100644 --- a/src/common/Ark.Tools.Authorization/packages.lock.json +++ b/src/common/Ark.Tools.Authorization/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.Core/packages.lock.json b/src/common/Ark.Tools.Core/packages.lock.json index af4ab0043..92c41ba0d 100644 --- a/src/common/Ark.Tools.Core/packages.lock.json +++ b/src/common/Ark.Tools.Core/packages.lock.json @@ -61,12 +61,6 @@ "resolved": "3.3.2", "contentHash": "8hI5b1ENTKQCaPyU6YHpYiMwj5aJKZ4Mnv0bLbhk65Dd44gQsXenUohMzyiIphANa8LdW6vcOvpY/l1urvx4dw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/common/Ark.Tools.EventSourcing.RavenDb/packages.lock.json b/src/common/Ark.Tools.EventSourcing.RavenDb/packages.lock.json index 641b52b2f..9a0fedb35 100644 --- a/src/common/Ark.Tools.EventSourcing.RavenDb/packages.lock.json +++ b/src/common/Ark.Tools.EventSourcing.RavenDb/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.EventSourcing.Rebus/packages.lock.json b/src/common/Ark.Tools.EventSourcing.Rebus/packages.lock.json index 057ac6488..a5bbd0156 100644 --- a/src/common/Ark.Tools.EventSourcing.Rebus/packages.lock.json +++ b/src/common/Ark.Tools.EventSourcing.Rebus/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Azure.Core": { "type": "Transitive", "resolved": "1.53.0", diff --git a/src/common/Ark.Tools.EventSourcing.SimpleInjector/packages.lock.json b/src/common/Ark.Tools.EventSourcing.SimpleInjector/packages.lock.json index a113ab9d2..ab37409d0 100644 --- a/src/common/Ark.Tools.EventSourcing.SimpleInjector/packages.lock.json +++ b/src/common/Ark.Tools.EventSourcing.SimpleInjector/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/common/Ark.Tools.EventSourcing/packages.lock.json b/src/common/Ark.Tools.EventSourcing/packages.lock.json index 30abff49e..8e5265b7e 100644 --- a/src/common/Ark.Tools.EventSourcing/packages.lock.json +++ b/src/common/Ark.Tools.EventSourcing/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/common/Ark.Tools.FtpClient.ArxOne/packages.lock.json b/src/common/Ark.Tools.FtpClient.ArxOne/packages.lock.json index f9634d744..feb5ca8e3 100644 --- a/src/common/Ark.Tools.FtpClient.ArxOne/packages.lock.json +++ b/src/common/Ark.Tools.FtpClient.ArxOne/packages.lock.json @@ -61,12 +61,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.FtpClient.Core/packages.lock.json b/src/common/Ark.Tools.FtpClient.Core/packages.lock.json index 69b7c767d..da7884eda 100644 --- a/src/common/Ark.Tools.FtpClient.Core/packages.lock.json +++ b/src/common/Ark.Tools.FtpClient.Core/packages.lock.json @@ -70,12 +70,6 @@ "Polly.Core": "8.6.6" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.FtpClient.FluentFtp/packages.lock.json b/src/common/Ark.Tools.FtpClient.FluentFtp/packages.lock.json index e09a88058..2ee7f7745 100644 --- a/src/common/Ark.Tools.FtpClient.FluentFtp/packages.lock.json +++ b/src/common/Ark.Tools.FtpClient.FluentFtp/packages.lock.json @@ -61,12 +61,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.FtpClient.FtpProxy/packages.lock.json b/src/common/Ark.Tools.FtpClient.FtpProxy/packages.lock.json index c18ac5d37..06292ad9b 100644 --- a/src/common/Ark.Tools.FtpClient.FtpProxy/packages.lock.json +++ b/src/common/Ark.Tools.FtpClient.FtpProxy/packages.lock.json @@ -85,12 +85,6 @@ "Polly": "7.1.1" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Auth0.Core": { "type": "Transitive", "resolved": "7.45.1", diff --git a/src/common/Ark.Tools.FtpClient.SftpClient/FtpPathExtensions.cs b/src/common/Ark.Tools.FtpClient.SftpClient/FtpPathExtensions.cs index 40a9a7f57..1c373f2e4 100644 --- a/src/common/Ark.Tools.FtpClient.SftpClient/FtpPathExtensions.cs +++ b/src/common/Ark.Tools.FtpClient.SftpClient/FtpPathExtensions.cs @@ -49,7 +49,13 @@ public static string GetFtpPath(this string path, params string[] segments) if (tpath == null) return null; - lastslash = tpath.LastIndexOf('/', StringComparison.Ordinal); +#if NET10_0_OR_GREATER +#pragma warning disable MA0074 // Polyfill supplies LastIndexOf(char, StringComparison) only for lower target frameworks. + lastslash = tpath.LastIndexOf('/'); +#pragma warning restore MA0074 +#else + lastslash = tpath.LastIndexOf('/', StringComparison.Ordinal); +#endif if (lastslash < 0) return tpath; @@ -82,4 +88,4 @@ public static DateTime GetFtpDate(this string date, DateTimeStyles style) return DateTime.MinValue; } -} \ No newline at end of file +} diff --git a/src/common/Ark.Tools.FtpClient.SftpClient/packages.lock.json b/src/common/Ark.Tools.FtpClient.SftpClient/packages.lock.json index 8de6bbe9e..0ca759f98 100644 --- a/src/common/Ark.Tools.FtpClient.SftpClient/packages.lock.json +++ b/src/common/Ark.Tools.FtpClient.SftpClient/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "SSH.NET": { "type": "Direct", "requested": "[2025.1.0, )", diff --git a/src/common/Ark.Tools.Hosting/packages.lock.json b/src/common/Ark.Tools.Hosting/packages.lock.json index 1d4702e12..3f1283f39 100644 --- a/src/common/Ark.Tools.Hosting/packages.lock.json +++ b/src/common/Ark.Tools.Hosting/packages.lock.json @@ -167,12 +167,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Azure.Core": { "type": "Transitive", "resolved": "1.53.0", diff --git a/src/common/Ark.Tools.Http/packages.lock.json b/src/common/Ark.Tools.Http/packages.lock.json index 718f08466..77df80f8b 100644 --- a/src/common/Ark.Tools.Http/packages.lock.json +++ b/src/common/Ark.Tools.Http/packages.lock.json @@ -96,12 +96,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "CacheCow.Common": { "type": "Transitive", "resolved": "2.13.1", diff --git a/src/common/Ark.Tools.NLog.Configuration/packages.lock.json b/src/common/Ark.Tools.NLog.Configuration/packages.lock.json index 289fc3747..89a3080b9 100644 --- a/src/common/Ark.Tools.NLog.Configuration/packages.lock.json +++ b/src/common/Ark.Tools.NLog.Configuration/packages.lock.json @@ -114,12 +114,6 @@ "NLog": "6.1.1" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.NLog.ConfigurationManager/packages.lock.json b/src/common/Ark.Tools.NLog.ConfigurationManager/packages.lock.json index b0466433f..18a0bd42f 100644 --- a/src/common/Ark.Tools.NLog.ConfigurationManager/packages.lock.json +++ b/src/common/Ark.Tools.NLog.ConfigurationManager/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "System.Configuration.ConfigurationManager": { "type": "Direct", "requested": "[10.0.7, )", diff --git a/src/common/Ark.Tools.NLog/packages.lock.json b/src/common/Ark.Tools.NLog/packages.lock.json index 6d25c1975..c6024d696 100644 --- a/src/common/Ark.Tools.NLog/packages.lock.json +++ b/src/common/Ark.Tools.NLog/packages.lock.json @@ -129,12 +129,6 @@ "NLog": "6.1.1" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Slack.Webhooks": { "type": "Direct", "requested": "[1.1.5, )", diff --git a/src/common/Ark.Tools.NewtonsoftJson/packages.lock.json b/src/common/Ark.Tools.NewtonsoftJson/packages.lock.json index cc80eec44..0c659129a 100644 --- a/src/common/Ark.Tools.NewtonsoftJson/packages.lock.json +++ b/src/common/Ark.Tools.NewtonsoftJson/packages.lock.json @@ -61,12 +61,6 @@ "resolved": "13.0.4", "contentHash": "pdgNNMai3zv51W5aq268sujXUyx7SNdE2bj1wZcWjAQrKMFZV260lbqYop1d2GM67JI1huLRwxo9ZqnfF/lC6A==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/common/Ark.Tools.Nodatime.Dapper/packages.lock.json b/src/common/Ark.Tools.Nodatime.Dapper/packages.lock.json index 98a256bd1..741c419b6 100644 --- a/src/common/Ark.Tools.Nodatime.Dapper/packages.lock.json +++ b/src/common/Ark.Tools.Nodatime.Dapper/packages.lock.json @@ -61,12 +61,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/common/Ark.Tools.Nodatime.Json/packages.lock.json b/src/common/Ark.Tools.Nodatime.Json/packages.lock.json index ecd749321..3ee3e7d6c 100644 --- a/src/common/Ark.Tools.Nodatime.Json/packages.lock.json +++ b/src/common/Ark.Tools.Nodatime.Json/packages.lock.json @@ -71,12 +71,6 @@ "NodaTime": "[3.0.0, 4.0.0)" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/common/Ark.Tools.Nodatime.SystemTextJson/packages.lock.json b/src/common/Ark.Tools.Nodatime.SystemTextJson/packages.lock.json index 05ead28b0..2ac6b7e98 100644 --- a/src/common/Ark.Tools.Nodatime.SystemTextJson/packages.lock.json +++ b/src/common/Ark.Tools.Nodatime.SystemTextJson/packages.lock.json @@ -64,12 +64,6 @@ "NodaTime": "[3.0.0, 4.0.0)" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/common/Ark.Tools.Nodatime/packages.lock.json b/src/common/Ark.Tools.Nodatime/packages.lock.json index 30abff49e..8e5265b7e 100644 --- a/src/common/Ark.Tools.Nodatime/packages.lock.json +++ b/src/common/Ark.Tools.Nodatime/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/common/Ark.Tools.Outbox.Rebus/packages.lock.json b/src/common/Ark.Tools.Outbox.Rebus/packages.lock.json index 9a2de45d8..79da31a7c 100644 --- a/src/common/Ark.Tools.Outbox.Rebus/packages.lock.json +++ b/src/common/Ark.Tools.Outbox.Rebus/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Azure.Core": { "type": "Transitive", "resolved": "1.53.0", diff --git a/src/common/Ark.Tools.Outbox.SqlServer/packages.lock.json b/src/common/Ark.Tools.Outbox.SqlServer/packages.lock.json index 43bcd1e3b..f8216382e 100644 --- a/src/common/Ark.Tools.Outbox.SqlServer/packages.lock.json +++ b/src/common/Ark.Tools.Outbox.SqlServer/packages.lock.json @@ -76,12 +76,6 @@ "Polly.Core": "8.6.6" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.Outbox/packages.lock.json b/src/common/Ark.Tools.Outbox/packages.lock.json index 30abff49e..8e5265b7e 100644 --- a/src/common/Ark.Tools.Outbox/packages.lock.json +++ b/src/common/Ark.Tools.Outbox/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/common/Ark.Tools.RavenDb.Auditing/packages.lock.json b/src/common/Ark.Tools.RavenDb.Auditing/packages.lock.json index afd217143..ebe3d4d7f 100644 --- a/src/common/Ark.Tools.RavenDb.Auditing/packages.lock.json +++ b/src/common/Ark.Tools.RavenDb.Auditing/packages.lock.json @@ -85,12 +85,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "SimpleInjector": { "type": "Direct", "requested": "[5.5.1, )", diff --git a/src/common/Ark.Tools.RavenDb/packages.lock.json b/src/common/Ark.Tools.RavenDb/packages.lock.json index 451dfab9c..95a541ff5 100644 --- a/src/common/Ark.Tools.RavenDb/packages.lock.json +++ b/src/common/Ark.Tools.RavenDb/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "RavenDB.Client": { "type": "Direct", "requested": "[7.2.1, )", diff --git a/src/common/Ark.Tools.Rebus/packages.lock.json b/src/common/Ark.Tools.Rebus/packages.lock.json index 2146bc107..59a1f4179 100644 --- a/src/common/Ark.Tools.Rebus/packages.lock.json +++ b/src/common/Ark.Tools.Rebus/packages.lock.json @@ -66,12 +66,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Rebus": { "type": "Direct", "requested": "[8.9.2, )", diff --git a/src/common/Ark.Tools.Reqnroll/packages.lock.json b/src/common/Ark.Tools.Reqnroll/packages.lock.json index 90530c359..89e68f241 100644 --- a/src/common/Ark.Tools.Reqnroll/packages.lock.json +++ b/src/common/Ark.Tools.Reqnroll/packages.lock.json @@ -81,12 +81,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Reqnroll": { "type": "Direct", "requested": "[3.3.4, )", diff --git a/src/common/Ark.Tools.SimpleInjector/packages.lock.json b/src/common/Ark.Tools.SimpleInjector/packages.lock.json index d858bc3e9..91d603ade 100644 --- a/src/common/Ark.Tools.SimpleInjector/packages.lock.json +++ b/src/common/Ark.Tools.SimpleInjector/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "SimpleInjector": { "type": "Direct", "requested": "[5.5.1, )", diff --git a/src/common/Ark.Tools.Solid.Authorization/packages.lock.json b/src/common/Ark.Tools.Solid.Authorization/packages.lock.json index 8722e64bb..1ccf8a0df 100644 --- a/src/common/Ark.Tools.Solid.Authorization/packages.lock.json +++ b/src/common/Ark.Tools.Solid.Authorization/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.Solid.FluentValidaton/packages.lock.json b/src/common/Ark.Tools.Solid.FluentValidaton/packages.lock.json index 5e8ef38e8..757505689 100644 --- a/src/common/Ark.Tools.Solid.FluentValidaton/packages.lock.json +++ b/src/common/Ark.Tools.Solid.FluentValidaton/packages.lock.json @@ -61,12 +61,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.Solid.SimpleInjector/packages.lock.json b/src/common/Ark.Tools.Solid.SimpleInjector/packages.lock.json index 594dff480..5b38b8ebb 100644 --- a/src/common/Ark.Tools.Solid.SimpleInjector/packages.lock.json +++ b/src/common/Ark.Tools.Solid.SimpleInjector/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.Solid/packages.lock.json b/src/common/Ark.Tools.Solid/packages.lock.json index 2e7162cf3..26b137250 100644 --- a/src/common/Ark.Tools.Solid/packages.lock.json +++ b/src/common/Ark.Tools.Solid/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.Sql.Oracle/packages.lock.json b/src/common/Ark.Tools.Sql.Oracle/packages.lock.json index 8f70fb1ef..bb8f4ff24 100644 --- a/src/common/Ark.Tools.Sql.Oracle/packages.lock.json +++ b/src/common/Ark.Tools.Sql.Oracle/packages.lock.json @@ -66,12 +66,6 @@ "System.Security.Cryptography.Pkcs": "8.0.1" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.Sql.SqlServer/packages.lock.json b/src/common/Ark.Tools.Sql.SqlServer/packages.lock.json index 498358bfc..5c5dd4f85 100644 --- a/src/common/Ark.Tools.Sql.SqlServer/packages.lock.json +++ b/src/common/Ark.Tools.Sql.SqlServer/packages.lock.json @@ -73,12 +73,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/common/Ark.Tools.Sql/packages.lock.json b/src/common/Ark.Tools.Sql/packages.lock.json index 30abff49e..8e5265b7e 100644 --- a/src/common/Ark.Tools.Sql/packages.lock.json +++ b/src/common/Ark.Tools.Sql/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/common/Ark.Tools.SystemTextJson/packages.lock.json b/src/common/Ark.Tools.SystemTextJson/packages.lock.json index c426abdc9..0473429d6 100644 --- a/src/common/Ark.Tools.SystemTextJson/packages.lock.json +++ b/src/common/Ark.Tools.SystemTextJson/packages.lock.json @@ -61,12 +61,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.Build.Tasks.Git": { "type": "Transitive", "resolved": "10.0.203", diff --git a/src/resourcewatcher/Ark.Tools.ResourceWatcher.ApplicationInsights/packages.lock.json b/src/resourcewatcher/Ark.Tools.ResourceWatcher.ApplicationInsights/packages.lock.json index e170835f2..5b0c3d856 100644 --- a/src/resourcewatcher/Ark.Tools.ResourceWatcher.ApplicationInsights/packages.lock.json +++ b/src/resourcewatcher/Ark.Tools.ResourceWatcher.ApplicationInsights/packages.lock.json @@ -68,12 +68,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Azure.Core": { "type": "Transitive", "resolved": "1.53.0", diff --git a/src/resourcewatcher/Ark.Tools.ResourceWatcher.Sql/packages.lock.json b/src/resourcewatcher/Ark.Tools.ResourceWatcher.Sql/packages.lock.json index c7aa18469..7425ea67e 100644 --- a/src/resourcewatcher/Ark.Tools.ResourceWatcher.Sql/packages.lock.json +++ b/src/resourcewatcher/Ark.Tools.ResourceWatcher.Sql/packages.lock.json @@ -61,12 +61,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/resourcewatcher/Ark.Tools.ResourceWatcher.Testing/packages.lock.json b/src/resourcewatcher/Ark.Tools.ResourceWatcher.Testing/packages.lock.json index 9ad67eaa2..3539ec1bc 100644 --- a/src/resourcewatcher/Ark.Tools.ResourceWatcher.Testing/packages.lock.json +++ b/src/resourcewatcher/Ark.Tools.ResourceWatcher.Testing/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost.Ftp/packages.lock.json b/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost.Ftp/packages.lock.json index 68dd17073..8d1ca72f4 100644 --- a/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost.Ftp/packages.lock.json +++ b/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost.Ftp/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost.Hosting/packages.lock.json b/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost.Hosting/packages.lock.json index 349cc3aa3..5eb7c3d83 100644 --- a/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost.Hosting/packages.lock.json +++ b/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost.Hosting/packages.lock.json @@ -113,12 +113,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Azure.Core": { "type": "Transitive", "resolved": "1.53.0", diff --git a/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost.Sql/packages.lock.json b/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost.Sql/packages.lock.json index 99671a68a..b1cee6365 100644 --- a/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost.Sql/packages.lock.json +++ b/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost.Sql/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost/packages.lock.json b/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost/packages.lock.json index 4342225e9..8839f4271 100644 --- a/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost/packages.lock.json +++ b/src/resourcewatcher/Ark.Tools.ResourceWatcher.WorkerHost/packages.lock.json @@ -55,12 +55,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/src/resourcewatcher/Ark.Tools.ResourceWatcher/packages.lock.json b/src/resourcewatcher/Ark.Tools.ResourceWatcher/packages.lock.json index bd5f1dd46..2b52ab6a3 100644 --- a/src/resourcewatcher/Ark.Tools.ResourceWatcher/packages.lock.json +++ b/src/resourcewatcher/Ark.Tools.ResourceWatcher/packages.lock.json @@ -61,12 +61,6 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/tests/Ark.Tools.Core.Tests/packages.lock.json b/tests/Ark.Tools.Core.Tests/packages.lock.json index 14fb80690..f22b9e6e1 100644 --- a/tests/Ark.Tools.Core.Tests/packages.lock.json +++ b/tests/Ark.Tools.Core.Tests/packages.lock.json @@ -148,12 +148,6 @@ "MSTest.Analyzers": "4.2.1" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.CodeCoverage": { "type": "Transitive", "resolved": "18.4.0", diff --git a/tests/Ark.Tools.Nodatime.Tests/packages.lock.json b/tests/Ark.Tools.Nodatime.Tests/packages.lock.json index e989aedde..a8e12c599 100644 --- a/tests/Ark.Tools.Nodatime.Tests/packages.lock.json +++ b/tests/Ark.Tools.Nodatime.Tests/packages.lock.json @@ -148,12 +148,6 @@ "MSTest.Analyzers": "4.2.1" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Microsoft.CodeCoverage": { "type": "Transitive", "resolved": "18.4.0", diff --git a/tests/Ark.Tools.ResourceWatcher.Tests/packages.lock.json b/tests/Ark.Tools.ResourceWatcher.Tests/packages.lock.json index df4aabee5..605be8fc4 100644 --- a/tests/Ark.Tools.ResourceWatcher.Tests/packages.lock.json +++ b/tests/Ark.Tools.ResourceWatcher.Tests/packages.lock.json @@ -198,12 +198,6 @@ "NodaTime": "3.3.2" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Reqnroll.MSTest": { "type": "Direct", "requested": "[3.3.4, )", diff --git a/tests/Ark.Tools.Sql.Oracle.Tests/packages.lock.json b/tests/Ark.Tools.Sql.Oracle.Tests/packages.lock.json index a2a2a4a71..faa2760e6 100644 --- a/tests/Ark.Tools.Sql.Oracle.Tests/packages.lock.json +++ b/tests/Ark.Tools.Sql.Oracle.Tests/packages.lock.json @@ -148,12 +148,6 @@ "MSTest.Analyzers": "4.2.1" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", diff --git a/tests/WebApplicationDemo.Tests/packages.lock.json b/tests/WebApplicationDemo.Tests/packages.lock.json index b5d86f21f..0b40b33b8 100644 --- a/tests/WebApplicationDemo.Tests/packages.lock.json +++ b/tests/WebApplicationDemo.Tests/packages.lock.json @@ -154,12 +154,6 @@ "MSTest.Analyzers": "4.2.1" } }, - "Polyfill": { - "type": "Direct", - "requested": "[10.3.0, )", - "resolved": "10.3.0", - "contentHash": "5GDzIb+7qvrftxO+POQc2HAInFnQIw2NKdxjqmAVJ7l+P10djdmKW6dcjnHitUX59TTQZ/Ok0qcHUSasl/Cs1A==" - }, "Reqnroll.MSTest": { "type": "Direct", "requested": "[3.3.4, )", @@ -970,6 +964,7 @@ "FluentValidation": "[12.1.1, )", "Hellang.Middleware.ProblemDetails": "[6.5.1, )", "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", + "Microsoft.AspNetCore.OpenApi": "[10.0.7, )", "NetEscapades.AspNetCore.SecurityHeaders": "[1.3.1, )", "SimpleInjector.Integration.AspNetCore.Mvc.Core": "[5.5.0, )" } @@ -1034,6 +1029,7 @@ "Microsoft.AspNetCore.OData": "[10.0.0-preview.2, )", "Swashbuckle.AspNetCore.Annotations": "[10.1.7, )", "Swashbuckle.AspNetCore.Filters": "[10.0.1, )", + "Swashbuckle.AspNetCore.ReDoc": "[10.1.7, )", "Swashbuckle.AspNetCore.Swagger": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerGen": "[10.1.7, )", "Swashbuckle.AspNetCore.SwaggerUI": "[10.1.7, )" @@ -1196,6 +1192,8 @@ "Ark.Tools.Solid": "[1.0.0, )", "Ark.Tools.Solid.FluentValidaton": "[1.0.0, )", "Ark.Tools.Solid.SimpleInjector": "[1.0.0, )", + "Microsoft.AspNetCore.OpenApi": "[10.0.7, )", + "Microsoft.Extensions.ApiDescription.Server": "[10.0.7, )", "Microsoft.Identity.Web": "[4.8.0, )" } }, @@ -1542,6 +1540,15 @@ "Microsoft.Spatial": "[9.0.0-preview.4, 10.0.0)" } }, + "Microsoft.AspNetCore.OpenApi": { + "type": "CentralTransitive", + "requested": "[10.0.7, )", + "resolved": "10.0.7", + "contentHash": "vKiAcGXG0BwNVw3bOjjWRLnp9tR18dR7MiwpvC94h0yFS+zfnzGHzS/JmmgwUdRixrGxrlIMRAWrVc+2DfAGlg==", + "dependencies": { + "Microsoft.OpenApi": "2.0.0" + } + }, "Microsoft.Data.SqlClient": { "type": "CentralTransitive", "requested": "[7.0.1, )", @@ -1559,6 +1566,12 @@ "System.Security.Cryptography.Pkcs": "9.0.13" } }, + "Microsoft.Extensions.ApiDescription.Server": { + "type": "CentralTransitive", + "requested": "[10.0.7, )", + "resolved": "10.0.7", + "contentHash": "VBNJzdInUkjhL/Habj16j3kMHIccjjuWg2zILcapH2QDq5GJF4bfQzJvt2gynuT98PkTpLUvPAsPeefKBDT/mg==" + }, "Microsoft.Identity.Client": { "type": "CentralTransitive", "requested": "[4.83.3, )", @@ -1777,6 +1790,12 @@ "Swashbuckle.AspNetCore.SwaggerGen": "10.0.0" } }, + "Swashbuckle.AspNetCore.ReDoc": { + "type": "CentralTransitive", + "requested": "[10.1.7, )", + "resolved": "10.1.7", + "contentHash": "aoVMCDlS4v6X6EgaowPxSSDwdvIP0NQNJR42lq+iQCVFaGRCN67wALoAZYddyxGQeBoiKSdATvP+psj7OVCuPw==" + }, "Swashbuckle.AspNetCore.Swagger": { "type": "CentralTransitive", "requested": "[10.1.7, )",