diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bc38da9f39..7c9116d405 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,6 +48,11 @@ jobs: dotnet-version: | 8.0.* 9.0.* + - name: Setup .NET 10 preview + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.* + dotnet-quality: 'preview' - name: Show installed versions shell: pwsh run: | @@ -166,6 +171,11 @@ jobs: dotnet-version: | 8.0.* 9.0.* + - name: Setup .NET 10 preview + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.* + dotnet-quality: 'preview' - name: Git checkout uses: actions/checkout@v4 - name: Restore tools @@ -221,6 +231,11 @@ jobs: dotnet-version: | 8.0.* 9.0.* + - name: Setup .NET 10 preview + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.* + dotnet-quality: 'preview' - name: Git checkout uses: actions/checkout@v4 with: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 508d210158..455071b122 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -29,6 +29,11 @@ jobs: dotnet-version: | 8.0.* 9.0.* + - name: Setup .NET 10 preview + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.* + dotnet-quality: 'preview' - name: Git checkout uses: actions/checkout@v4 - name: Initialize CodeQL diff --git a/Directory.Build.props b/Directory.Build.props index 1ef255f56e..4664c01565 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -15,6 +15,12 @@ direct + + + true + $(NoWarn);NU1903;NU5104;NU1608 + + + 10.0.*-* + 9.0.0-pr.3283.* + + + 10.0.*-* + 9.0.0-pr.3283.* + 10.0.*-* + 10.0.*-* + 9.0.*-* + + N/A diff --git a/src/Examples/DapperExample/DapperExample.csproj b/src/Examples/DapperExample/DapperExample.csproj index ed7bd358eb..b2c71ee0f8 100644 --- a/src/Examples/DapperExample/DapperExample.csproj +++ b/src/Examples/DapperExample/DapperExample.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0;net9.0;net8.0 @@ -14,6 +14,7 @@ + diff --git a/src/Examples/DatabasePerTenantExample/DatabasePerTenantExample.csproj b/src/Examples/DatabasePerTenantExample/DatabasePerTenantExample.csproj index 3edc993428..c7cee804b1 100644 --- a/src/Examples/DatabasePerTenantExample/DatabasePerTenantExample.csproj +++ b/src/Examples/DatabasePerTenantExample/DatabasePerTenantExample.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0;net9.0;net8.0 diff --git a/src/Examples/GettingStarted/GettingStarted.csproj b/src/Examples/GettingStarted/GettingStarted.csproj index 611aeb37a5..806fdf45a5 100644 --- a/src/Examples/GettingStarted/GettingStarted.csproj +++ b/src/Examples/GettingStarted/GettingStarted.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0;net9.0;net8.0 diff --git a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj index 768a2de827..319c72b262 100644 --- a/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj +++ b/src/Examples/JsonApiDotNetCoreExample/JsonApiDotNetCoreExample.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0 true GeneratedSwagger diff --git a/src/Examples/JsonApiDotNetCoreExample/SetOpenApiServerAtBuildTimeFilter.cs b/src/Examples/JsonApiDotNetCoreExample/SetOpenApiServerAtBuildTimeFilter.cs index 894c0d0966..7bf87d56c3 100644 --- a/src/Examples/JsonApiDotNetCoreExample/SetOpenApiServerAtBuildTimeFilter.cs +++ b/src/Examples/JsonApiDotNetCoreExample/SetOpenApiServerAtBuildTimeFilter.cs @@ -16,6 +16,8 @@ public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { if (_httpContextAccessor.HttpContext == null) { + swaggerDoc.Servers ??= new List(); + swaggerDoc.Servers.Add(new OpenApiServer { Url = "https://localhost:44340" diff --git a/src/Examples/MultiDbContextExample/MultiDbContextExample.csproj b/src/Examples/MultiDbContextExample/MultiDbContextExample.csproj index 611aeb37a5..806fdf45a5 100644 --- a/src/Examples/MultiDbContextExample/MultiDbContextExample.csproj +++ b/src/Examples/MultiDbContextExample/MultiDbContextExample.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0;net9.0;net8.0 diff --git a/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj b/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj index 15a485c08f..e50874f733 100644 --- a/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj +++ b/src/Examples/NoEntityFrameworkExample/NoEntityFrameworkExample.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0;net9.0;net8.0 diff --git a/src/Examples/OpenApiKiotaClientExample/OpenApiKiotaClientExample.csproj b/src/Examples/OpenApiKiotaClientExample/OpenApiKiotaClientExample.csproj index 8f65b2b688..8dd3e2e4df 100644 --- a/src/Examples/OpenApiKiotaClientExample/OpenApiKiotaClientExample.csproj +++ b/src/Examples/OpenApiKiotaClientExample/OpenApiKiotaClientExample.csproj @@ -1,6 +1,6 @@ - net9.0 + net10.0 diff --git a/src/Examples/OpenApiNSwagClientExample/OpenApiNSwagClientExample.csproj b/src/Examples/OpenApiNSwagClientExample/OpenApiNSwagClientExample.csproj index c30833a39a..079e43121c 100644 --- a/src/Examples/OpenApiNSwagClientExample/OpenApiNSwagClientExample.csproj +++ b/src/Examples/OpenApiNSwagClientExample/OpenApiNSwagClientExample.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 diff --git a/src/Examples/ReportsExample/ReportsExample.csproj b/src/Examples/ReportsExample/ReportsExample.csproj index 6ade1386be..73a16ddf4f 100644 --- a/src/Examples/ReportsExample/ReportsExample.csproj +++ b/src/Examples/ReportsExample/ReportsExample.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0;net9.0;net8.0 diff --git a/src/JsonApiDotNetCore.Annotations/JsonApiDotNetCore.Annotations.csproj b/src/JsonApiDotNetCore.Annotations/JsonApiDotNetCore.Annotations.csproj index ed36e0797c..68bd9ac569 100644 --- a/src/JsonApiDotNetCore.Annotations/JsonApiDotNetCore.Annotations.csproj +++ b/src/JsonApiDotNetCore.Annotations/JsonApiDotNetCore.Annotations.csproj @@ -1,6 +1,6 @@ - net8.0;netstandard1.0 + net10.0;net8.0;netstandard1.0 true true JsonApiDotNetCore diff --git a/src/JsonApiDotNetCore.OpenApi.Client.Kiota/JsonApiDotNetCore.OpenApi.Client.Kiota.csproj b/src/JsonApiDotNetCore.OpenApi.Client.Kiota/JsonApiDotNetCore.OpenApi.Client.Kiota.csproj index 640b949477..fce1fb7c40 100644 --- a/src/JsonApiDotNetCore.OpenApi.Client.Kiota/JsonApiDotNetCore.OpenApi.Client.Kiota.csproj +++ b/src/JsonApiDotNetCore.OpenApi.Client.Kiota/JsonApiDotNetCore.OpenApi.Client.Kiota.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0;net8.0 true true false diff --git a/src/JsonApiDotNetCore.OpenApi.Client.NSwag/JsonApiDotNetCore.OpenApi.Client.NSwag.csproj b/src/JsonApiDotNetCore.OpenApi.Client.NSwag/JsonApiDotNetCore.OpenApi.Client.NSwag.csproj index 20e2306730..550f284509 100644 --- a/src/JsonApiDotNetCore.OpenApi.Client.NSwag/JsonApiDotNetCore.OpenApi.Client.NSwag.csproj +++ b/src/JsonApiDotNetCore.OpenApi.Client.NSwag/JsonApiDotNetCore.OpenApi.Client.NSwag.csproj @@ -1,6 +1,6 @@  - net8.0 + net10.0;net8.0 true true false diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ConfigureSwaggerGenOptions.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ConfigureSwaggerGenOptions.cs index f3fb5198ca..13bac17d02 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ConfigureSwaggerGenOptions.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ConfigureSwaggerGenOptions.cs @@ -74,11 +74,12 @@ public void Configure(SwaggerGenOptions options) options.DocumentFilter(); options.DocumentFilter(); options.DocumentFilter(); + options.DocumentFilter(); } private List SelectDerivedTypes(Type baseType) { - if (BaseToDerivedSchemaTypes.TryGetValue(baseType, out Type? schemaOpenType)) + if (BaseToDerivedSchemaTypes.TryGetValue(baseType, out var schemaOpenType)) { return GetConstructedTypesFromResourceGraph(schemaOpenType); } @@ -90,7 +91,7 @@ private List SelectDerivedTypes(Type baseType) if (baseType.IsAssignableTo(typeof(IIdentifiable))) { - ResourceType? resourceType = _resourceGraph.FindResourceType(baseType); + var resourceType = _resourceGraph.FindResourceType(baseType); if (resourceType != null && resourceType.IsPartOfTypeHierarchy()) { @@ -105,9 +106,9 @@ private List GetConstructedTypesFromResourceGraph(Type schemaOpenType) { List constructedTypes = []; - foreach (ResourceType resourceType in _resourceGraph.GetResourceTypes()) + foreach (var resourceType in _resourceGraph.GetResourceTypes()) { - Type constructedType = schemaOpenType.MakeGenericType(resourceType.ClrType); + var constructedType = schemaOpenType.MakeGenericType(resourceType.ClrType); constructedTypes.Add(constructedType); } @@ -118,7 +119,7 @@ private List GetConstructedTypesForAtomicOperation() { List derivedTypes = []; - foreach (ResourceType resourceType in _resourceGraph.GetResourceTypes()) + foreach (var resourceType in _resourceGraph.GetResourceTypes()) { derivedTypes.AddRange(AtomicOperationDerivedSchemaTypes.Select(openType => openType.MakeGenericType(resourceType.ClrType))); } @@ -135,7 +136,7 @@ private static List GetResourceDerivedTypes(ResourceType baseType) private static void IncludeDerivedTypes(ResourceType baseType, List clrTypes) { - foreach (ResourceType derivedType in baseType.DirectlyDerivedTypes) + foreach (var derivedType in baseType.DirectlyDerivedTypes) { clrTypes.Add(derivedType.ClrType); IncludeDerivedTypes(derivedType, clrTypes); @@ -144,8 +145,8 @@ private static void IncludeDerivedTypes(ResourceType baseType, List clrTyp private static List GetOpenApiOperationTags(ApiDescription description, IControllerResourceMapping controllerResourceMapping) { - MethodInfo actionMethod = description.ActionDescriptor.GetActionMethod(); - ResourceType? resourceType = controllerResourceMapping.GetResourceTypeForController(actionMethod.ReflectedType); + var actionMethod = description.ActionDescriptor.GetActionMethod(); + var resourceType = controllerResourceMapping.GetResourceTypeForController(actionMethod.ReflectedType); return resourceType == null ? ["operations"] : [resourceType.PublicName]; } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/IncludeDependencyScanner.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/IncludeDependencyScanner.cs index 97f86e2834..31f0bc7766 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/IncludeDependencyScanner.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/IncludeDependencyScanner.cs @@ -37,7 +37,7 @@ private static void IncludeResourceType(ResourceType resourceType, ISet resourceTypesFound) { - foreach (ResourceType derivedType in resourceType.DirectlyDerivedTypes) + foreach (var derivedType in resourceType.DirectlyDerivedTypes) { IncludeResourceType(derivedType, resourceTypesFound); } @@ -45,7 +45,7 @@ private static void IncludeDerivedTypes(ResourceType resourceType, ISet resourceTypesFound) { - foreach (RelationshipAttribute relationship in resourceType.Relationships) + foreach (var relationship in resourceType.Relationships) { IncludeResourceType(relationship.RightType, resourceTypesFound); } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiActionDescriptorCollectionProvider.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiActionDescriptorCollectionProvider.cs index 6d63a540cd..1446f35e8b 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiActionDescriptorCollectionProvider.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiActionDescriptorCollectionProvider.cs @@ -41,13 +41,13 @@ public JsonApiActionDescriptorCollectionProvider(IActionDescriptorCollectionProv private ActionDescriptorCollection GetActionDescriptors() { - List newDescriptors = _defaultProvider.ActionDescriptors.Items.ToList(); - ActionDescriptor[] endpoints = newDescriptors.Where(IsVisibleJsonApiEndpoint).ToArray(); + var newDescriptors = _defaultProvider.ActionDescriptors.Items.ToList(); + var endpoints = newDescriptors.Where(IsVisibleJsonApiEndpoint).ToArray(); - foreach (ActionDescriptor endpoint in endpoints) + foreach (var endpoint in endpoints) { - MethodInfo actionMethod = endpoint.GetActionMethod(); - JsonApiEndpointMetadataContainer endpointMetadataContainer = _jsonApiEndpointMetadataProvider.Get(actionMethod); + var actionMethod = endpoint.GetActionMethod(); + var endpointMetadataContainer = _jsonApiEndpointMetadataProvider.Get(actionMethod); List replacementDescriptorsForEndpoint = [ @@ -62,7 +62,7 @@ .. AddJsonApiMetadataToAction(endpoint, endpointMetadataContainer.ResponseMetada } } - int descriptorVersion = _defaultProvider.ActionDescriptors.Version; + var descriptorVersion = _defaultProvider.ActionDescriptors.Version; return new ActionDescriptorCollection(newDescriptors.AsReadOnly(), descriptorVersion); } @@ -136,9 +136,9 @@ private static bool ProducesJsonApiResponseDocument(ActionDescriptor endpoint) if (produces != null) { - foreach (string contentType in produces.ContentTypes) + foreach (var contentType in produces.ContentTypes) { - if (MediaTypeHeaderValue.TryParse(contentType, out MediaTypeHeaderValue? headerValue)) + if (MediaTypeHeaderValue.TryParse(contentType, out var headerValue)) { if (headerValue.MediaType.Equals(DefaultMediaType, StringComparison.OrdinalIgnoreCase)) { @@ -156,14 +156,14 @@ private static List Expand(ActionDescriptor genericEndpoint, N { List expansion = []; - foreach ((string relationshipName, Type documentType) in metadata.DocumentTypesByRelationshipName) + foreach ((var relationshipName, var documentType) in metadata.DocumentTypesByRelationshipName) { if (genericEndpoint.AttributeRouteInfo == null) { throw new NotSupportedException("Only attribute routing is supported for JsonApiDotNetCore endpoints."); } - ActionDescriptor expandedEndpoint = Clone(genericEndpoint); + var expandedEndpoint = Clone(genericEndpoint); RemovePathParameter(expandedEndpoint.Parameters, "relationshipName"); @@ -179,11 +179,11 @@ private static List Expand(ActionDescriptor genericEndpoint, N private static void UpdateBodyParameterDescriptor(ActionDescriptor endpoint, Type documentType, string? parameterName) { - ControllerParameterDescriptor? requestBodyDescriptor = endpoint.GetBodyParameterDescriptor(); + var requestBodyDescriptor = endpoint.GetBodyParameterDescriptor(); if (requestBodyDescriptor == null) { - MethodInfo actionMethod = endpoint.GetActionMethod(); + var actionMethod = endpoint.GetActionMethod(); throw new InvalidConfigurationException( $"The action method '{actionMethod}' on type '{actionMethod.ReflectedType?.FullName}' contains no parameter with a [FromBody] attribute."); @@ -195,7 +195,7 @@ private static void UpdateBodyParameterDescriptor(ActionDescriptor endpoint, Typ private static ActionDescriptor Clone(ActionDescriptor descriptor) { - ActionDescriptor clone = descriptor.MemberwiseClone(); + var clone = descriptor.MemberwiseClone(); clone.AttributeRouteInfo = descriptor.AttributeRouteInfo!.MemberwiseClone(); clone.FilterDescriptors = descriptor.FilterDescriptors.Select(Clone).ToList(); clone.Parameters = descriptor.Parameters.Select(parameter => parameter.MemberwiseClone()).ToList(); @@ -204,7 +204,7 @@ private static ActionDescriptor Clone(ActionDescriptor descriptor) private static FilterDescriptor Clone(FilterDescriptor descriptor) { - IFilterMetadata clone = descriptor.Filter.MemberwiseClone(); + var clone = descriptor.Filter.MemberwiseClone(); return new FilterDescriptor(clone, descriptor.Scope) { @@ -214,7 +214,7 @@ private static FilterDescriptor Clone(FilterDescriptor descriptor) private static void RemovePathParameter(ICollection parameters, string parameterName) { - ParameterDescriptor descriptor = parameters.Single(parameterDescriptor => parameterDescriptor.Name == parameterName); + var descriptor = parameters.Single(parameterDescriptor => parameterDescriptor.Name == parameterName); parameters.Remove(descriptor); } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiDotNetCore.OpenApi.Swashbuckle.csproj b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiDotNetCore.OpenApi.Swashbuckle.csproj index 4a57ca1c85..8231ddf695 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiDotNetCore.OpenApi.Swashbuckle.csproj +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiDotNetCore.OpenApi.Swashbuckle.csproj @@ -1,6 +1,6 @@ - net8.0 + net10.0 true true false diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/EndpointResolver.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/EndpointResolver.cs index e4c074f081..7cd5d5877d 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/EndpointResolver.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/EndpointResolver.cs @@ -22,7 +22,7 @@ public JsonApiEndpoints GetEndpoint(MethodInfo controllerAction) return JsonApiEndpoints.None; } - IEnumerable httpMethodAttributes = controllerAction.GetCustomAttributes(true); + var httpMethodAttributes = controllerAction.GetCustomAttributes(true); return httpMethodAttributes.GetJsonApiEndpoint(); } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/JsonApiEndpointMetadataProvider.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/JsonApiEndpointMetadataProvider.cs index 6fd6f9e42e..63ca37b5ac 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/JsonApiEndpointMetadataProvider.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/JsonApiEndpointMetadataProvider.cs @@ -34,18 +34,18 @@ public JsonApiEndpointMetadataContainer Get(MethodInfo controllerAction) return new JsonApiEndpointMetadataContainer(AtomicOperationsRequestMetadata.Instance, AtomicOperationsResponseMetadata.Instance); } - JsonApiEndpoints endpoint = EndpointResolver.Instance.GetEndpoint(controllerAction); + var endpoint = EndpointResolver.Instance.GetEndpoint(controllerAction); if (endpoint == JsonApiEndpoints.None) { throw new NotSupportedException($"Unable to provide metadata for non-JSON:API endpoint '{controllerAction.ReflectedType!.FullName}'."); } - ResourceType? primaryResourceType = _controllerResourceMapping.GetResourceTypeForController(controllerAction.ReflectedType); + var primaryResourceType = _controllerResourceMapping.GetResourceTypeForController(controllerAction.ReflectedType); ConsistencyGuard.ThrowIf(primaryResourceType == null); - IJsonApiRequestMetadata? requestMetadata = GetRequestMetadata(endpoint, primaryResourceType); - IJsonApiResponseMetadata? responseMetadata = GetResponseMetadata(endpoint, primaryResourceType); + var requestMetadata = GetRequestMetadata(endpoint, primaryResourceType); + var responseMetadata = GetResponseMetadata(endpoint, primaryResourceType); return new JsonApiEndpointMetadataContainer(requestMetadata, responseMetadata); } @@ -63,21 +63,21 @@ public JsonApiEndpointMetadataContainer Get(MethodInfo controllerAction) private static PrimaryRequestMetadata GetPostResourceRequestMetadata(Type resourceClrType) { - Type documentType = typeof(CreateRequestDocument<>).MakeGenericType(resourceClrType); + var documentType = typeof(CreateRequestDocument<>).MakeGenericType(resourceClrType); return new PrimaryRequestMetadata(documentType); } private static PrimaryRequestMetadata GetPatchResourceRequestMetadata(Type resourceClrType) { - Type documentType = typeof(UpdateRequestDocument<>).MakeGenericType(resourceClrType); + var documentType = typeof(UpdateRequestDocument<>).MakeGenericType(resourceClrType); return new PrimaryRequestMetadata(documentType); } private RelationshipRequestMetadata GetRelationshipRequestMetadata(IEnumerable relationships, bool ignoreHasOneRelationships) { - IEnumerable relationshipsOfEndpoint = ignoreHasOneRelationships ? relationships.OfType() : relationships; + var relationshipsOfEndpoint = ignoreHasOneRelationships ? relationships.OfType() : relationships; IDictionary requestDocumentTypesByRelationshipName = relationshipsOfEndpoint.ToDictionary(relationship => relationship.PublicName, _nonPrimaryDocumentTypeFactory.GetForRelationshipRequest); @@ -99,8 +99,8 @@ private RelationshipRequestMetadata GetRelationshipRequestMetadata(IEnumerable) : typeof(PrimaryResponseDocument<>); - Type documentType = documentOpenType.MakeGenericType(resourceClrType); + var documentOpenType = endpointReturnsCollection ? typeof(CollectionResponseDocument<>) : typeof(PrimaryResponseDocument<>); + var documentType = documentOpenType.MakeGenericType(resourceClrType); return new PrimaryResponseMetadata(documentType); } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/NonPrimaryDocumentTypeFactory.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/NonPrimaryDocumentTypeFactory.cs index 7550d59ab3..af6f01cbf6 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/NonPrimaryDocumentTypeFactory.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/NonPrimaryDocumentTypeFactory.cs @@ -49,7 +49,7 @@ private Type Get(RelationshipAttribute relationship, DocumentOpenTypes types) { // @formatter:nested_ternary_style expanded - Type documentOpenType = relationship is HasManyAttribute + var documentOpenType = relationship is HasManyAttribute ? types.ManyDataOpenType : _resourceFieldValidationMetadataProvider.IsNullable(relationship) ? types.NullableSingleDataOpenType diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/RelationshipTypeFactory.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/RelationshipTypeFactory.cs index be5a6fd30c..3d8a2f34a5 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/RelationshipTypeFactory.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiMetadata/RelationshipTypeFactory.cs @@ -31,7 +31,7 @@ public Type GetForResponse(RelationshipAttribute relationship) // @formatter:nested_ternary_style expanded - Type relationshipDataOpenType = relationship is HasManyAttribute + var relationshipDataOpenType = relationship is HasManyAttribute ? typeof(ToManyInResponse<>) : _resourceFieldValidationMetadataProvider.IsNullable(relationship) ? typeof(NullableToOneInResponse<>) diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiRequestFormatMetadataProvider.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiRequestFormatMetadataProvider.cs index 6def822bd9..0862258539 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiRequestFormatMetadataProvider.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiRequestFormatMetadataProvider.cs @@ -28,7 +28,7 @@ public IReadOnlyList GetSupportedContentTypes(string contentType, Type o ArgumentException.ThrowIfNullOrEmpty(contentType); ArgumentNullException.ThrowIfNull(objectType); - if (JsonApiSchemaFacts.IsRequestBodySchemaType(objectType) && MediaTypeHeaderValue.TryParse(contentType, out MediaTypeHeaderValue? headerValue) && + if (JsonApiSchemaFacts.IsRequestBodySchemaType(objectType) && MediaTypeHeaderValue.TryParse(contentType, out var headerValue) && headerValue.MediaType.Equals(DefaultMediaType, StringComparison.OrdinalIgnoreCase)) { return new MediaTypeCollection diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaFacts.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaFacts.cs index bf91aed0e7..f744c2e6a4 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaFacts.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaFacts.cs @@ -34,7 +34,7 @@ internal static class JsonApiSchemaFacts public static bool IsRequestBodySchemaType(Type schemaType) { - Type lookupType = schemaType.ConstructedToOpenType(); + var lookupType = schemaType.ConstructedToOpenType(); return RequestBodySchemaTypes.Contains(lookupType); } @@ -42,13 +42,13 @@ public static bool HasNullableDataProperty(Type schemaType) { // Swashbuckle infers non-nullable because our Data properties are [Required]. - Type lookupType = schemaType.ConstructedToOpenType(); + var lookupType = schemaType.ConstructedToOpenType(); return SchemaTypesHavingNullableDataProperty.Contains(lookupType); } public static bool IsRelationshipInResponseType(Type schemaType) { - Type lookupType = schemaType.ConstructedToOpenType(); + var lookupType = schemaType.ConstructedToOpenType(); return RelationshipInResponseSchemaTypes.Contains(lookupType); } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaIdSelector.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaIdSelector.cs index 0e2fc803de..2252afd7e9 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaIdSelector.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/JsonApiSchemaIdSelector.cs @@ -87,20 +87,20 @@ public string GetSchemaId(Type type) { ArgumentNullException.ThrowIfNull(type); - ResourceType? resourceType = _resourceGraph.FindResourceType(type); + var resourceType = _resourceGraph.FindResourceType(type); if (resourceType != null) { return resourceType.PublicName.Singularize(); } - Type openType = type.ConstructedToOpenType(); + var openType = type.ConstructedToOpenType(); if (openType != type) { - if (SchemaTypeToTemplateMap.TryGetValue(openType, out string? schemaTemplate)) + if (SchemaTypeToTemplateMap.TryGetValue(openType, out var schemaTemplate)) { - Type resourceClrType = type.GetGenericArguments().First(); + var resourceClrType = type.GetGenericArguments().First(); resourceType = _resourceGraph.GetResourceType(resourceClrType); return ApplySchemaTemplate(schemaTemplate, resourceType, null, null); @@ -108,7 +108,7 @@ public string GetSchemaId(Type type) } else { - if (SchemaTypeToTemplateMap.TryGetValue(type, out string? schemaTemplate)) + if (SchemaTypeToTemplateMap.TryGetValue(type, out var schemaTemplate)) { return ApplySchemaTemplate(schemaTemplate, null, null, null); } @@ -120,7 +120,7 @@ public string GetSchemaId(Type type) private string ApplySchemaTemplate(string schemaTemplate, ResourceType? resourceType, string? relationshipName, AtomicOperationCode? operationCode) { - string schemaId = schemaTemplate; + var schemaId = schemaTemplate; schemaId = resourceType != null ? schemaId.Replace("[ResourceName]", resourceType.PublicName.Singularize()).Pascalize() @@ -136,9 +136,9 @@ private string ApplySchemaTemplate(string schemaTemplate, ResourceType? resource schemaId = schemaId.Replace("[OperationCode]", operationCode.Value.ToString().Pascalize()); } - string pascalCaseSchemaId = schemaId.Pascalize(); + var pascalCaseSchemaId = schemaId.Pascalize(); - JsonNamingPolicy? namingPolicy = _options.SerializerOptions.PropertyNamingPolicy; + var namingPolicy = _options.SerializerOptions.PropertyNamingPolicy; return namingPolicy != null ? namingPolicy.ConvertName(pascalCaseSchemaId) : pascalCaseSchemaId; } @@ -168,7 +168,7 @@ public string GetAtomicOperationDiscriminatorValue(AtomicOperationCode operation { ArgumentNullException.ThrowIfNull(relationship); - string schemaIdTemplate = operationCode switch + var schemaIdTemplate = operationCode switch { AtomicOperationCode.Add => AddToRelationshipAtomicOperationDiscriminatorValueTemplate, AtomicOperationCode.Remove => RemoveFromRelationshipAtomicOperationDiscriminatorValueTemplate, @@ -182,7 +182,7 @@ public string GetRelationshipAtomicOperationSchemaId(RelationshipAttribute relat { ArgumentNullException.ThrowIfNull(relationship); - string schemaIdTemplate = operationCode switch + var schemaIdTemplate = operationCode switch { AtomicOperationCode.Add => AddToRelationshipAtomicOperationSchemaIdTemplate, AtomicOperationCode.Remove => RemoveFromRelationshipAtomicOperationSchemaIdTemplate, diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/MicrosoftOpenApiCompatibilityExtensions.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/MicrosoftOpenApiCompatibilityExtensions.cs new file mode 100644 index 0000000000..176d5cba82 --- /dev/null +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/MicrosoftOpenApiCompatibilityExtensions.cs @@ -0,0 +1,24 @@ +using Microsoft.OpenApi.Models; + +namespace JsonApiDotNetCore.OpenApi.Swashbuckle; + +internal static class MicrosoftOpenApiCompatibilityExtensions +{ + public static void SetNullable(this OpenApiSchema schema, bool nullable) + { + ArgumentNullException.ThrowIfNull(schema); + + if (nullable) + { + schema.Type ??= JsonSchemaType.Null; + schema.Type |= JsonSchemaType.Null; + } + else + { + if (schema.Type != null) + { + schema.Type &= ~JsonSchemaType.Null; + } + } + } +} diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiDescriptionLinkProvider.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiDescriptionLinkProvider.cs index 278c2154a9..8d675d70ed 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiDescriptionLinkProvider.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiDescriptionLinkProvider.cs @@ -26,13 +26,13 @@ public OpenApiDescriptionLinkProvider(IOptionsMonitor s /// public string? GetUrl() { - SwaggerGeneratorOptions swaggerGeneratorOptions = _swaggerGeneratorOptionsMonitor.CurrentValue; + var swaggerGeneratorOptions = _swaggerGeneratorOptionsMonitor.CurrentValue; if (swaggerGeneratorOptions.SwaggerDocs.Count > 0) { - string latestVersionDocumentName = swaggerGeneratorOptions.SwaggerDocs.Last().Key; + var latestVersionDocumentName = swaggerGeneratorOptions.SwaggerDocs.Last().Key; - SwaggerOptions swaggerOptions = _swaggerOptionsMonitor.CurrentValue; + var swaggerOptions = _swaggerOptionsMonitor.CurrentValue; return swaggerOptions.RouteTemplate.Replace("{documentName}", latestVersionDocumentName).Replace("{extension:regex(^(json|ya?ml)$)}", "json"); } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiEndpointConvention.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiEndpointConvention.cs index 75649b85a8..f6439adb24 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiEndpointConvention.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiEndpointConvention.cs @@ -32,7 +32,7 @@ public void Apply(ActionModel action) { ArgumentNullException.ThrowIfNull(action); - JsonApiEndpointWrapper endpoint = JsonApiEndpointWrapper.FromActionModel(action); + var endpoint = JsonApiEndpointWrapper.FromActionModel(action); if (endpoint.IsUnknown) { @@ -42,7 +42,7 @@ public void Apply(ActionModel action) return; } - ResourceType? resourceType = _controllerResourceMapping.GetResourceTypeForController(action.Controller.ControllerType); + var resourceType = _controllerResourceMapping.GetResourceTypeForController(action.Controller.ControllerType); if (ShouldSuppressEndpoint(endpoint, resourceType)) { @@ -84,7 +84,7 @@ private bool ShouldSuppressEndpoint(JsonApiEndpointWrapper endpoint, ResourceTyp private static bool IsEndpointAvailable(JsonApiEndpoints endpoint, ResourceType resourceType) { - JsonApiEndpoints availableEndpoints = GetGeneratedControllerEndpoints(resourceType); + var availableEndpoints = GetGeneratedControllerEndpoints(resourceType); if (availableEndpoints == JsonApiEndpoints.None) { @@ -162,16 +162,16 @@ private static bool IsSecondaryOrRelationshipEndpoint(JsonApiEndpoints endpoint) private void SetResponseMetadata(ActionModel action, JsonApiEndpointWrapper endpoint, ResourceType? resourceType) { - JsonApiMediaType mediaType = GetMediaTypeForEndpoint(endpoint); + var mediaType = GetMediaTypeForEndpoint(endpoint); action.Filters.Add(new ProducesAttribute(mediaType.ToString())); - foreach (HttpStatusCode statusCode in GetSuccessStatusCodesForEndpoint(endpoint)) + foreach (var statusCode in GetSuccessStatusCodesForEndpoint(endpoint)) { // The return type is set later by JsonApiActionDescriptorCollectionProvider. action.Filters.Add(new ProducesResponseTypeAttribute((int)statusCode)); } - foreach (HttpStatusCode statusCode in GetErrorStatusCodesForEndpoint(endpoint, resourceType)) + foreach (var statusCode in GetErrorStatusCodesForEndpoint(endpoint, resourceType)) { action.Filters.Add(new ProducesResponseTypeAttribute(typeof(ErrorResponseDocument), (int)statusCode)); } @@ -244,7 +244,7 @@ private HttpStatusCode[] GetErrorStatusCodesForEndpoint(JsonApiEndpointWrapper e } // Condition doesn't apply to atomic operations, because Forbidden is also used when an operation is not accessible. - ClientIdGenerationMode clientIdGeneration = resourceType?.ClientIdGeneration ?? _options.ClientIdGeneration; + var clientIdGeneration = resourceType?.ClientIdGeneration ?? _options.ClientIdGeneration; HttpStatusCode[]? statusCodes = null; @@ -304,7 +304,7 @@ private void SetRequestMetadata(ActionModel action, JsonApiEndpointWrapper endpo { if (RequiresRequestBody(endpoint)) { - JsonApiMediaType mediaType = GetMediaTypeForEndpoint(endpoint); + var mediaType = GetMediaTypeForEndpoint(endpoint); action.Filters.Add(new ConsumesAttribute(mediaType.ToString())); } } @@ -336,7 +336,7 @@ public static JsonApiEndpointWrapper FromActionModel(ActionModel actionModel) return AtomicOperations; } - JsonApiEndpoints endpoint = EndpointResolver.Instance.GetEndpoint(actionModel.ActionMethod); + var endpoint = EndpointResolver.Instance.GetEndpoint(actionModel.ActionMethod); return new JsonApiEndpointWrapper(false, endpoint); } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiOperationIdSelector.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiOperationIdSelector.cs index ed11481e27..9e4829fbe4 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiOperationIdSelector.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiOperationIdSelector.cs @@ -53,17 +53,17 @@ public string GetOpenApiOperationId(ApiDescription endpoint) { ArgumentNullException.ThrowIfNull(endpoint); - MethodInfo actionMethod = endpoint.ActionDescriptor.GetActionMethod(); - ResourceType? primaryResourceType = _controllerResourceMapping.GetResourceTypeForController(actionMethod.ReflectedType); + var actionMethod = endpoint.ActionDescriptor.GetActionMethod(); + var primaryResourceType = _controllerResourceMapping.GetResourceTypeForController(actionMethod.ReflectedType); - string template = GetTemplate(endpoint); + var template = GetTemplate(endpoint); return ApplyTemplate(template, primaryResourceType, endpoint); } private static string GetTemplate(ApiDescription endpoint) { - Type bodyType = GetBodyType(endpoint); - ConsistencyGuard.ThrowIf(!SchemaOpenTypeToOpenApiOperationIdTemplateMap.TryGetValue(bodyType, out string? template)); + var bodyType = GetBodyType(endpoint); + ConsistencyGuard.ThrowIf(!SchemaOpenTypeToOpenApiOperationIdTemplateMap.TryGetValue(bodyType, out var template)); return template; } @@ -72,8 +72,8 @@ private static Type GetBodyType(ApiDescription endpoint) var producesResponseTypeAttribute = endpoint.ActionDescriptor.GetFilterMetadata(); ConsistencyGuard.ThrowIf(producesResponseTypeAttribute == null); - ControllerParameterDescriptor? requestBodyDescriptor = endpoint.ActionDescriptor.GetBodyParameterDescriptor(); - Type bodyType = (requestBodyDescriptor?.ParameterType ?? producesResponseTypeAttribute.Type).ConstructedToOpenType(); + var requestBodyDescriptor = endpoint.ActionDescriptor.GetBodyParameterDescriptor(); + var bodyType = (requestBodyDescriptor?.ParameterType ?? producesResponseTypeAttribute.Type).ConstructedToOpenType(); if (bodyType == typeof(CollectionResponseDocument<>) && endpoint.ParameterDescriptions.Count > 0) { @@ -88,13 +88,13 @@ private string ApplyTemplate(string openApiOperationIdTemplate, ResourceType? re ConsistencyGuard.ThrowIf(endpoint.RelativePath == null); ConsistencyGuard.ThrowIf(endpoint.HttpMethod == null); - string method = endpoint.HttpMethod.ToLowerInvariant(); - string relationshipName = openApiOperationIdTemplate.Contains("[RelationshipName]") ? endpoint.RelativePath.Split('/').Last() : string.Empty; + var method = endpoint.HttpMethod.ToLowerInvariant(); + var relationshipName = openApiOperationIdTemplate.Contains("[RelationshipName]") ? endpoint.RelativePath.Split('/').Last() : string.Empty; // @formatter:wrap_chained_method_calls chop_always // @formatter:wrap_before_first_method_call true - string pascalCaseOpenApiOperationId = openApiOperationIdTemplate + var pascalCaseOpenApiOperationId = openApiOperationIdTemplate .Replace("[Method]", method) .Replace("[PrimaryResourceName]", resourceType?.PublicName.Singularize()) .Replace("[RelationshipName]", relationshipName) @@ -103,7 +103,7 @@ private string ApplyTemplate(string openApiOperationIdTemplate, ResourceType? re // @formatter:wrap_before_first_method_call true restore // @formatter:wrap_chained_method_calls restore - JsonNamingPolicy? namingPolicy = _options.SerializerOptions.PropertyNamingPolicy; + var namingPolicy = _options.SerializerOptions.PropertyNamingPolicy; return namingPolicy != null ? namingPolicy.ConvertName(pascalCaseOpenApiOperationId) : pascalCaseOpenApiOperationId; } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiResourceObjectConverter.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiResourceObjectConverter.cs index dd7c9503e7..218a244c62 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiResourceObjectConverter.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiResourceObjectConverter.cs @@ -85,7 +85,7 @@ private bool IsOpenApiDiscriminator(string extensionNamespace, string extensionN private static void ValidateOpenApiDiscriminatorValue(ResourceType resourceType, string relativeJsonPointer, Utf8JsonReader reader) { - string? discriminatorValue = reader.GetString(); + var discriminatorValue = reader.GetString(); if (discriminatorValue != resourceType.PublicName) { diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiSchemaExtensions.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiSchemaExtensions.cs index 10095834b2..b56f4c2330 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiSchemaExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/OpenApiSchemaExtensions.cs @@ -1,4 +1,5 @@ using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; namespace JsonApiDotNetCore.OpenApi.Swashbuckle; @@ -9,11 +10,11 @@ public static void ReorderProperties(this OpenApiSchema fullSchema, IEnumerable< ArgumentNullException.ThrowIfNull(fullSchema); ArgumentNullException.ThrowIfNull(propertyNamesInOrder); - var propertiesInOrder = new Dictionary(); + var propertiesInOrder = new Dictionary(); - foreach (string propertyName in propertyNamesInOrder) + foreach (var propertyName in propertyNamesInOrder) { - if (fullSchema.Properties.TryGetValue(propertyName, out OpenApiSchema? schema)) + if (fullSchema.Properties.TryGetValue(propertyName, out var schema)) { propertiesInOrder.Add(propertyName, schema); } @@ -24,7 +25,7 @@ public static void ReorderProperties(this OpenApiSchema fullSchema, IEnumerable< fullSchema.Properties = propertiesInOrder; } - public static OpenApiSchema WrapInExtendedSchema(this OpenApiSchema source) + public static OpenApiSchema WrapInExtendedSchema(this IOpenApiSchema source) { ArgumentNullException.ThrowIfNull(source); @@ -34,11 +35,11 @@ public static OpenApiSchema WrapInExtendedSchema(this OpenApiSchema source) }; } - public static OpenApiSchema UnwrapLastExtendedSchema(this OpenApiSchema source) + public static IOpenApiSchema UnwrapLastExtendedSchema(this IOpenApiSchema source) { ArgumentNullException.ThrowIfNull(source); - if (source.AllOf is { Count: > 0 }) + if (source is OpenApiSchema && source.AllOf is { Count: > 0 }) { return source.AllOf.Last(); } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ResourceFieldValidationMetadataProvider.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ResourceFieldValidationMetadataProvider.cs index f0ce60c730..f6fa38592c 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ResourceFieldValidationMetadataProvider.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/ResourceFieldValidationMetadataProvider.cs @@ -30,7 +30,7 @@ public bool IsNullable(ResourceFieldAttribute field) return false; } - bool hasRequiredAttribute = field.Property.HasAttribute(); + var hasRequiredAttribute = field.Property.HasAttribute(); if (_options.ValidateModelState && hasRequiredAttribute) { @@ -38,7 +38,7 @@ public bool IsNullable(ResourceFieldAttribute field) } NullabilityInfoContext nullabilityContext = new(); - NullabilityInfo nullabilityInfo = nullabilityContext.Create(field.Property); + var nullabilityInfo = nullabilityContext.Create(field.Property); return nullabilityInfo.ReadState != NullabilityState.NotNull; } @@ -46,7 +46,7 @@ public bool IsRequired(ResourceFieldAttribute field) { ArgumentNullException.ThrowIfNull(field); - bool hasRequiredAttribute = field.Property.HasAttribute(); + var hasRequiredAttribute = field.Property.HasAttribute(); if (!_options.ValidateModelState) { @@ -59,8 +59,8 @@ public bool IsRequired(ResourceFieldAttribute field) } NullabilityInfoContext nullabilityContext = new(); - NullabilityInfo nullabilityInfo = nullabilityContext.Create(field.Property); - bool isRequiredValueType = field.Property.PropertyType.IsValueType && hasRequiredAttribute && nullabilityInfo.ReadState == NullabilityState.NotNull; + var nullabilityInfo = nullabilityContext.Create(field.Property); + var isRequiredValueType = field.Property.PropertyType.IsValueType && hasRequiredAttribute && nullabilityInfo.ReadState == NullabilityState.NotNull; if (isRequiredValueType) { @@ -73,7 +73,7 @@ public bool IsRequired(ResourceFieldAttribute field) private bool IsModelStateValidationRequired(ResourceFieldAttribute field) { - ModelMetadata modelMetadata = _modelMetadataProvider.GetMetadataForProperty(field.Type.ClrType, field.Property.Name); + var modelMetadata = _modelMetadataProvider.GetMetadataForProperty(field.Type.ClrType, field.Property.Name); // Non-nullable reference types are implicitly required, unless SuppressImplicitRequiredAttributeForNonNullableReferenceTypes is set. return modelMetadata.ValidatorMetadata.Any(validatorMetadata => validatorMetadata is RequiredAttribute); diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerationTracer.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerationTracer.cs index 6dbd6bb2f3..c941b1d311 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerationTracer.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerationTracer.cs @@ -62,11 +62,11 @@ public ISchemaGenerationTraceScope TraceStart(object generator, Type schemaOpenT private ISchemaGenerationTraceScope InnerTraceStart(object generator, Func getSchemaTypeName) { - ILogger logger = _loggerFactory.CreateLogger(generator.GetType()); + var logger = _loggerFactory.CreateLogger(generator.GetType()); if (logger.IsEnabled(LogLevel.Trace)) { - string schemaTypeName = getSchemaTypeName(); + var schemaTypeName = getSchemaTypeName(); return new SchemaGenerationTraceScope(logger, schemaTypeName); } @@ -77,8 +77,8 @@ private static string GetSchemaTypeName(Type type) { if (type.IsConstructedGenericType) { - string typeArguments = string.Join(',', type.GetGenericArguments().Select(GetSchemaTypeName)); - int arityIndex = type.Name.IndexOf('`'); + var typeArguments = string.Join(',', type.GetGenericArguments().Select(GetSchemaTypeName)); + var arityIndex = type.Name.IndexOf('`'); return $"{type.Name[..arityIndex]}<{typeArguments}>"; } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AtomicOperationCodeSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AtomicOperationCodeSchemaGenerator.cs index 78a25da441..4a7726ec07 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AtomicOperationCodeSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/AtomicOperationCodeSchemaGenerator.cs @@ -1,6 +1,7 @@ using JsonApiDotNetCore.Serialization.Objects; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; @@ -19,35 +20,28 @@ public AtomicOperationCodeSchemaGenerator(SchemaGenerationTracer schemaGeneratio _schemaIdSelector = schemaIdSelector; } - public OpenApiSchema GenerateSchema(AtomicOperationCode operationCode, SchemaRepository schemaRepository) + public OpenApiSchemaReference GenerateSchema(AtomicOperationCode operationCode, SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(schemaRepository); - string schemaId = _schemaIdSelector.GetAtomicOperationCodeSchemaId(operationCode); + var schemaId = _schemaIdSelector.GetAtomicOperationCodeSchemaId(operationCode); if (schemaRepository.Schemas.ContainsKey(schemaId)) { - return new OpenApiSchema - { - Reference = new OpenApiReference - { - Id = schemaId, - Type = ReferenceType.Schema - } - }; + return new OpenApiSchemaReference(schemaId); } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, operationCode); + using var traceScope = _schemaGenerationTracer.TraceStart(this, operationCode); - string enumValue = operationCode.ToString().ToLowerInvariant(); + var enumValue = operationCode.ToString().ToLowerInvariant(); var fullSchema = new OpenApiSchema { - Type = "string", - Enum = [new OpenApiString(enumValue)] + Type = JsonSchemaType.String, + Enum = [enumValue] }; - OpenApiSchema referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); + var referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); traceScope.TraceSucceeded(schemaId); return referenceSchema; diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataContainerSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataContainerSchemaGenerator.cs index c4b41dd0f5..da462a9161 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataContainerSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataContainerSchemaGenerator.cs @@ -3,6 +3,7 @@ using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiObjects.ResourceObjects; using JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; @@ -27,33 +28,33 @@ public DataContainerSchemaGenerator(SchemaGenerationTracer schemaGenerationTrace _resourceGraph = resourceGraph; } - public OpenApiSchema GenerateSchemaForCommonResourceDataInResponse(SchemaRepository schemaRepository) + public OpenApiSchemaReference GenerateSchemaForCommonResourceDataInResponse(SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(schemaRepository); return _dataSchemaGenerator.GenerateSchemaForCommonData(typeof(ResourceInResponse), schemaRepository); } - public OpenApiSchema GenerateSchema(Type dataContainerSchemaType, ResourceType resourceType, bool forRequestSchema, bool canIncludeRelated, + public OpenApiSchemaReference GenerateSchema(Type dataContainerSchemaType, ResourceType resourceType, bool forRequestSchema, bool canIncludeRelated, SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(dataContainerSchemaType); ArgumentNullException.ThrowIfNull(resourceType); ArgumentNullException.ThrowIfNull(schemaRepository); - if (schemaRepository.TryLookupByType(dataContainerSchemaType, out OpenApiSchema referenceSchemaForData)) + if (schemaRepository.TryLookupByType(dataContainerSchemaType, out var referenceSchemaForData)) { return referenceSchemaForData; } - Type dataConstructedType = GetElementTypeOfDataProperty(dataContainerSchemaType, resourceType); + var dataConstructedType = GetElementTypeOfDataProperty(dataContainerSchemaType, resourceType); if (schemaRepository.TryLookupByType(dataConstructedType, out _)) { return referenceSchemaForData; } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, dataConstructedType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, dataConstructedType); if (canIncludeRelated) { @@ -74,10 +75,10 @@ public OpenApiSchema GenerateSchema(Type dataContainerSchemaType, ResourceType r private static Type GetElementTypeOfDataProperty(Type dataContainerConstructedType, ResourceType resourceType) { - PropertyInfo? dataProperty = dataContainerConstructedType.GetProperty("Data"); + var dataProperty = dataContainerConstructedType.GetProperty("Data"); ConsistencyGuard.ThrowIf(dataProperty == null); - Type innerPropertyType = dataProperty.PropertyType.ConstructedToOpenType().IsAssignableTo(typeof(ICollection<>)) + var innerPropertyType = dataProperty.PropertyType.ConstructedToOpenType().IsAssignableTo(typeof(ICollection<>)) ? dataProperty.PropertyType.GenericTypeArguments[0] : dataProperty.PropertyType; @@ -93,15 +94,15 @@ private static Type GetElementTypeOfDataProperty(Type dataContainerConstructedTy private void GenerateReachableRelatedTypesInResponse(Type dataConstructedType, SchemaRepository schemaRepository) { - Type dataOpenType = dataConstructedType.GetGenericTypeDefinition(); + var dataOpenType = dataConstructedType.GetGenericTypeDefinition(); if (dataOpenType == typeof(DataInResponse<>)) { var resourceSchemaType = ResourceSchemaType.Create(dataConstructedType, _resourceGraph); - foreach (ResourceType relatedType in IncludeDependencyScanner.Instance.GetReachableRelatedTypes(resourceSchemaType.ResourceType)) + foreach (var relatedType in IncludeDependencyScanner.Instance.GetReachableRelatedTypes(resourceSchemaType.ResourceType)) { - Type resourceDataConstructedType = typeof(DataInResponse<>).MakeGenericType(relatedType.ClrType); + var resourceDataConstructedType = typeof(DataInResponse<>).MakeGenericType(relatedType.ClrType); _ = _dataSchemaGenerator.GenerateSchema(resourceDataConstructedType, false, schemaRepository); } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataSchemaGenerator.cs index 4d7783f780..08763a6993 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/DataSchemaGenerator.cs @@ -1,12 +1,16 @@ using System.Collections.Concurrent; using System.Reflection; using System.Runtime.CompilerServices; +using System.Text.Json; +using System.Text.Json.Nodes; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiMetadata; using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiObjects.ResourceObjects; using JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; @@ -79,7 +83,7 @@ public DataSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, Schema _resourceDocumentationReader = resourceDocumentationReader; } - public OpenApiSchema GenerateSchema(Type dataSchemaType, bool forRequestSchema, SchemaRepository schemaRepository) + public OpenApiSchemaReference GenerateSchema(Type dataSchemaType, bool forRequestSchema, SchemaRepository schemaRepository) { // For a given resource (identifier) type, we always generate the full type hierarchy. Discriminator mappings // are managed manually, because there's no way to intercept in the Swashbuckle recursive component schema generation. @@ -87,15 +91,15 @@ public OpenApiSchema GenerateSchema(Type dataSchemaType, bool forRequestSchema, ArgumentNullException.ThrowIfNull(dataSchemaType); ArgumentNullException.ThrowIfNull(schemaRepository); - if (schemaRepository.TryLookupByType(dataSchemaType, out OpenApiSchema referenceSchemaForData)) + if (schemaRepository.TryLookupByType(dataSchemaType, out var referenceSchemaForData)) { return referenceSchemaForData; } var resourceSchemaType = ResourceSchemaType.Create(dataSchemaType, _resourceGraph); - ResourceType resourceType = resourceSchemaType.ResourceType; + var resourceType = resourceSchemaType.ResourceType; - Type? commonDataSchemaType = GetCommonSchemaType(resourceSchemaType.SchemaOpenType); + var commonDataSchemaType = GetCommonSchemaType(resourceSchemaType.SchemaOpenType); if (commonDataSchemaType != null) { @@ -104,21 +108,21 @@ public OpenApiSchema GenerateSchema(Type dataSchemaType, bool forRequestSchema, if (resourceType.BaseType != null) { - ResourceType ultimateBaseResourceType = GetUltimateBaseType(resourceType); - Type ultimateBaseSchemaType = ChangeResourceTypeInSchemaType(dataSchemaType, ultimateBaseResourceType); + var ultimateBaseResourceType = GetUltimateBaseType(resourceType); + var ultimateBaseSchemaType = ChangeResourceTypeInSchemaType(dataSchemaType, ultimateBaseResourceType); _ = GenerateSchema(ultimateBaseSchemaType, forRequestSchema, schemaRepository); return schemaRepository.LookupByType(dataSchemaType); } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, dataSchemaType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, dataSchemaType); - referenceSchemaForData = _defaultSchemaGenerator.GenerateSchema(dataSchemaType, schemaRepository); - OpenApiSchema fullSchemaForData = schemaRepository.Schemas[referenceSchemaForData.Reference.Id]; + referenceSchemaForData = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(dataSchemaType, schemaRepository); + var fullSchemaForData = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForData.Reference.Id]; fullSchemaForData.AdditionalPropertiesAllowed = false; - OpenApiSchema inlineSchemaForData = fullSchemaForData.UnwrapLastExtendedSchema(); + var inlineSchemaForData = (OpenApiSchema)fullSchemaForData.UnwrapLastExtendedSchema(); SetAbstract(inlineSchemaForData, resourceSchemaType); SetResourceType(inlineSchemaForData, resourceType, schemaRepository); @@ -142,7 +146,7 @@ public OpenApiSchema GenerateSchema(Type dataSchemaType, bool forRequestSchema, if (RequiresRootObjectTypeInDataSchema(resourceSchemaType, forRequestSchema)) { - fullSchemaForData.Extensions[SetSchemaTypeToObjectDocumentFilter.RequiresRootObjectTypeKey] = new OpenApiBoolean(true); + fullSchemaForData.Extensions[SetSchemaTypeToObjectDocumentFilter.RequiresRootObjectTypeKey] = new OpenApiAny(true); } traceScope.TraceSucceeded(referenceSchemaForData.Reference.Id); @@ -202,26 +206,26 @@ public OpenApiSchema GenerateSchema(Type dataSchemaType, bool forRequestSchema, return boxedSchemaType.Value; } - public OpenApiSchema GenerateSchemaForCommonData(Type commonDataSchemaType, SchemaRepository schemaRepository) + public OpenApiSchemaReference GenerateSchemaForCommonData(Type commonDataSchemaType, SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(commonDataSchemaType); ArgumentNullException.ThrowIfNull(schemaRepository); - if (schemaRepository.TryLookupByType(commonDataSchemaType, out OpenApiSchema? referenceSchema)) + if (schemaRepository.TryLookupByType(commonDataSchemaType, out var referenceSchema)) { return referenceSchema; } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, commonDataSchemaType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, commonDataSchemaType); - OpenApiSchema referenceSchemaForResourceType = _resourceTypeSchemaGenerator.GenerateSchema(schemaRepository); - OpenApiSchema referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository); + var referenceSchemaForResourceType = _resourceTypeSchemaGenerator.GenerateSchema(schemaRepository); + var referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository); var fullSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Required = new SortedSet([JsonApiPropertyName.Type]), - Properties = new Dictionary + Properties = new Dictionary { [JsonApiPropertyName.Type] = referenceSchemaForResourceType.WrapInExtendedSchema(), [referenceSchemaForMeta.Reference.Id] = referenceSchemaForMeta.WrapInExtendedSchema() @@ -234,11 +238,11 @@ public OpenApiSchema GenerateSchemaForCommonData(Type commonDataSchemaType, Sche }, Extensions = { - ["x-abstract"] = new OpenApiBoolean(true) + ["x-abstract"] = new OpenApiAny(true) } }; - string schemaId = _schemaIdSelector.GetSchemaId(commonDataSchemaType); + var schemaId = _schemaIdSelector.GetSchemaId(commonDataSchemaType); referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); schemaRepository.RegisterType(commonDataSchemaType, schemaId); @@ -251,7 +255,7 @@ private static ResourceType GetUltimateBaseType(ResourceType resourceType) { return UltimateBaseResourceTypeCache.GetOrAdd(resourceType, type => { - ResourceType baseType = type; + var baseType = type; while (baseType.BaseType != null) { @@ -264,7 +268,7 @@ private static ResourceType GetUltimateBaseType(ResourceType resourceType) private static Type ChangeResourceTypeInSchemaType(Type schemaType, ResourceType resourceType) { - Type schemaOpenType = schemaType.ConstructedToOpenType(); + var schemaOpenType = schemaType.ConstructedToOpenType(); return schemaOpenType.MakeGenericType(resourceType.ClrType); } @@ -272,7 +276,7 @@ private static void SetAbstract(OpenApiSchema fullSchema, ResourceSchemaType res { if (resourceSchemaType.ResourceType.ClrType.IsAbstract && resourceSchemaType.SchemaOpenType != typeof(IdentifierInRequest<>)) { - fullSchema.Extensions["x-abstract"] = new OpenApiBoolean(true); + fullSchema.Extensions["x-abstract"] = new OpenApiAny(true); } } @@ -280,7 +284,7 @@ private void SetResourceType(OpenApiSchema fullSchema, ResourceType resourceType { if (fullSchema.Properties.ContainsKey(JsonApiPropertyName.Type)) { - OpenApiSchema referenceSchema = _resourceTypeSchemaGenerator.GenerateSchema(resourceType, schemaRepository); + var referenceSchema = _resourceTypeSchemaGenerator.GenerateSchema(resourceType, schemaRepository); fullSchema.Properties[JsonApiPropertyName.Type] = referenceSchema.WrapInExtendedSchema(); } } @@ -293,7 +297,7 @@ private void AdaptResourceIdentity(OpenApiSchema fullSchema, ResourceSchemaType return; } - bool hasAtomicOperationsEndpoint = _generationCacheSchemaGenerator.HasAtomicOperationsEndpoint(schemaRepository); + var hasAtomicOperationsEndpoint = _generationCacheSchemaGenerator.HasAtomicOperationsEndpoint(schemaRepository); if (!hasAtomicOperationsEndpoint) { @@ -302,7 +306,7 @@ private void AdaptResourceIdentity(OpenApiSchema fullSchema, ResourceSchemaType if (resourceSchemaType.SchemaOpenType == typeof(DataInCreateRequest<>)) { - ClientIdGenerationMode clientIdGeneration = resourceSchemaType.ResourceType.ClientIdGeneration ?? _options.ClientIdGeneration; + var clientIdGeneration = resourceSchemaType.ResourceType.ClientIdGeneration ?? _options.ClientIdGeneration; if (hasAtomicOperationsEndpoint) { @@ -341,7 +345,7 @@ private void SetResourceId(OpenApiSchema fullSchema, ResourceType resourceType, { if (fullSchema.Properties.ContainsKey(JsonApiPropertyName.Id)) { - OpenApiSchema idSchema = _resourceIdSchemaGenerator.GenerateSchema(resourceType, schemaRepository); + var idSchema = _resourceIdSchemaGenerator.GenerateSchema(resourceType, schemaRepository); fullSchema.Properties[JsonApiPropertyName.Id] = idSchema; } } @@ -349,7 +353,7 @@ private void SetResourceId(OpenApiSchema fullSchema, ResourceType resourceType, private void SetResourceFields(OpenApiSchema fullSchemaForData, ResourceSchemaType resourceSchemaType, bool forRequestSchema, SchemaRepository schemaRepository) { - bool schemaHasFields = fullSchemaForData.Properties.ContainsKey(JsonApiPropertyName.Attributes) && + var schemaHasFields = fullSchemaForData.Properties.ContainsKey(JsonApiPropertyName.Attributes) && fullSchemaForData.Properties.ContainsKey(JsonApiPropertyName.Relationships); if (schemaHasFields) @@ -365,10 +369,10 @@ private void SetResourceFields(OpenApiSchema fullSchemaForData, ResourceSchemaTy private void SetFieldSchemaMembers(OpenApiSchema fullSchemaForData, ResourceSchemaType resourceSchemaTypeForData, bool forRequestSchema, bool forAttributes, ResourceFieldSchemaBuilder fieldSchemaBuilder, SchemaRepository schemaRepository) { - string propertyNameInSchema = forAttributes ? JsonApiPropertyName.Attributes : JsonApiPropertyName.Relationships; + var propertyNameInSchema = forAttributes ? JsonApiPropertyName.Attributes : JsonApiPropertyName.Relationships; - OpenApiSchema referenceSchemaForFields = fullSchemaForData.Properties[propertyNameInSchema].UnwrapLastExtendedSchema(); - OpenApiSchema fullSchemaForFields = schemaRepository.Schemas[referenceSchemaForFields.Reference.Id]; + var referenceSchemaForFields = (OpenApiSchemaReference)fullSchemaForData.Properties[propertyNameInSchema].UnwrapLastExtendedSchema(); + var fullSchemaForFields = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForFields.Reference.Id]; fullSchemaForFields.AdditionalPropertiesAllowed = false; SetAbstract(fullSchemaForFields, resourceSchemaTypeForData); @@ -389,10 +393,10 @@ private void SetFieldSchemaMembers(OpenApiSchema fullSchemaForData, ResourceSche } else { - ResourceSchemaType resourceSchemaTypeForFields = + var resourceSchemaTypeForFields = GetResourceSchemaTypeForFieldsProperty(resourceSchemaTypeForData, forAttributes ? "Attributes" : "Relationships"); - Type? commonFieldsSchemaType = GetCommonSchemaType(resourceSchemaTypeForFields.SchemaOpenType); + var commonFieldsSchemaType = GetCommonSchemaType(resourceSchemaTypeForFields.SchemaOpenType); ConsistencyGuard.ThrowIf(commonFieldsSchemaType == null); _ = GenerateSchemaForCommonFields(commonFieldsSchemaType, schemaRepository); @@ -404,7 +408,7 @@ private void SetFieldSchemaMembers(OpenApiSchema fullSchemaForData, ResourceSche if (resourceSchemaTypeForFields.ResourceType.BaseType != null) { - ResourceSchemaType resourceSchemaTypeForBase = + var resourceSchemaTypeForBase = resourceSchemaTypeForFields.ChangeResourceType(resourceSchemaTypeForFields.ResourceType.BaseType); baseSchemaType = resourceSchemaTypeForBase.SchemaConstructedType; @@ -414,7 +418,7 @@ private void SetFieldSchemaMembers(OpenApiSchema fullSchemaForData, ResourceSche baseSchemaType = commonFieldsSchemaType; } - OpenApiSchema referenceSchemaForBase = schemaRepository.LookupByType(baseSchemaType); + var referenceSchemaForBase = schemaRepository.LookupByType(baseSchemaType); schemaRepository.Schemas[referenceSchemaForFields.Reference.Id] = new OpenApiSchema { @@ -430,29 +434,29 @@ private void SetFieldSchemaMembers(OpenApiSchema fullSchemaForData, ResourceSche private ResourceSchemaType GetResourceSchemaTypeForFieldsProperty(ResourceSchemaType resourceSchemaTypeForData, string propertyName) { - PropertyInfo? fieldsProperty = resourceSchemaTypeForData.SchemaConstructedType.GetProperty(propertyName); + var fieldsProperty = resourceSchemaTypeForData.SchemaConstructedType.GetProperty(propertyName); ConsistencyGuard.ThrowIf(fieldsProperty == null); - Type fieldsConstructedType = fieldsProperty.PropertyType; + var fieldsConstructedType = fieldsProperty.PropertyType; return ResourceSchemaType.Create(fieldsConstructedType, _resourceGraph); } - private OpenApiSchema GenerateSchemaForCommonFields(Type commonFieldsSchemaType, SchemaRepository schemaRepository) + private OpenApiSchemaReference GenerateSchemaForCommonFields(Type commonFieldsSchemaType, SchemaRepository schemaRepository) { - if (schemaRepository.TryLookupByType(commonFieldsSchemaType, out OpenApiSchema? referenceSchema)) + if (schemaRepository.TryLookupByType(commonFieldsSchemaType, out var referenceSchema)) { return referenceSchema; } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, commonFieldsSchemaType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, commonFieldsSchemaType); - OpenApiSchema referenceSchemaForResourceType = _resourceTypeSchemaGenerator.GenerateSchema(schemaRepository); + var referenceSchemaForResourceType = _resourceTypeSchemaGenerator.GenerateSchema(schemaRepository); var fullSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Required = new SortedSet([OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName]), - Properties = new Dictionary + Properties = new Dictionary { [OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName] = referenceSchemaForResourceType.WrapInExtendedSchema() }, @@ -464,11 +468,11 @@ private OpenApiSchema GenerateSchemaForCommonFields(Type commonFieldsSchemaType, }, Extensions = { - ["x-abstract"] = new OpenApiBoolean(true) + ["x-abstract"] = new OpenApiAny(true) } }; - string schemaId = _schemaIdSelector.GetSchemaId(commonFieldsSchemaType); + var schemaId = _schemaIdSelector.GetSchemaId(commonFieldsSchemaType); referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); schemaRepository.RegisterType(commonFieldsSchemaType, schemaId); @@ -480,16 +484,16 @@ private OpenApiSchema GenerateSchemaForCommonFields(Type commonFieldsSchemaType, private void MapInDiscriminator(ResourceSchemaType resourceSchemaType, bool forRequestSchema, string discriminatorPropertyName, SchemaRepository schemaRepository) { - OpenApiSchema referenceSchemaForDerived = schemaRepository.LookupByType(resourceSchemaType.SchemaConstructedType); + var referenceSchemaForDerived = schemaRepository.LookupByType(resourceSchemaType.SchemaConstructedType); - foreach (ResourceType? baseResourceType in GetBaseTypesToMapInto(resourceSchemaType, forRequestSchema)) + foreach (var baseResourceType in GetBaseTypesToMapInto(resourceSchemaType, forRequestSchema)) { - Type baseSchemaType = baseResourceType == null + var baseSchemaType = baseResourceType == null ? GetCommonSchemaType(resourceSchemaType.SchemaOpenType)! : resourceSchemaType.ChangeResourceType(baseResourceType).SchemaConstructedType; - OpenApiSchema referenceSchemaForBase = schemaRepository.LookupByType(baseSchemaType); - OpenApiSchema inlineSchemaForBase = schemaRepository.Schemas[referenceSchemaForBase.Reference.Id].UnwrapLastExtendedSchema(); + var referenceSchemaForBase = schemaRepository.LookupByType(baseSchemaType); + var inlineSchemaForBase = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForBase.Reference.Id].UnwrapLastExtendedSchema(); inlineSchemaForBase.Discriminator ??= new OpenApiDiscriminator { @@ -502,7 +506,7 @@ private void MapInDiscriminator(ResourceSchemaType resourceSchemaType, bool forR inlineSchemaForBase.Required.Add(discriminatorPropertyName); } - string publicName = resourceSchemaType.ResourceType.PublicName; + var publicName = resourceSchemaType.ResourceType.PublicName; if (inlineSchemaForBase.Discriminator.Mapping.TryAdd(publicName, referenceSchemaForDerived.Reference.ReferenceV3) && baseResourceType == null) { @@ -513,11 +517,11 @@ private void MapInDiscriminator(ResourceSchemaType resourceSchemaType, bool forR private static IEnumerable GetBaseTypesToMapInto(ResourceSchemaType resourceSchemaType, bool forRequestSchema) { - bool dependsOnCommonSchemaType = GetCommonSchemaType(resourceSchemaType.SchemaOpenType) != null; + var dependsOnCommonSchemaType = GetCommonSchemaType(resourceSchemaType.SchemaOpenType) != null; if (RepeatDiscriminatorInResponseDerivedTypes && !forRequestSchema) { - ResourceType? baseType = resourceSchemaType.ResourceType.BaseType; + var baseType = resourceSchemaType.ResourceType.BaseType; while (baseType != null) { @@ -542,12 +546,12 @@ private void MapInDiscriminator(ResourceSchemaType resourceSchemaType, bool forR private void MapResourceTypeInEnum(string publicName, SchemaRepository schemaRepository) { - string schemaId = _schemaIdSelector.GetResourceTypeSchemaId(null); - OpenApiSchema fullSchema = schemaRepository.Schemas[schemaId]; + var schemaId = _schemaIdSelector.GetResourceTypeSchemaId(null); + var fullSchema = schemaRepository.Schemas[schemaId]; - if (!fullSchema.Enum.Any(openApiAny => openApiAny is OpenApiString openApiString && openApiString.Value == publicName)) + if (!fullSchema.Enum.Any(openApiAny => openApiAny is JsonValue openApiString && openApiString.GetValueKind() == JsonValueKind.String && openApiString.GetValue() == publicName)) { - fullSchema.Enum.Add(new OpenApiString(publicName)); + fullSchema.Enum.Add(publicName); } } @@ -563,20 +567,20 @@ private void SetLinksVisibility(OpenApiSchema fullSchema, ResourceSchemaType res private void GenerateDataSchemasForDirectlyDerivedTypes(ResourceSchemaType resourceSchemaType, bool forRequestSchema, SchemaRepository schemaRepository) { - OpenApiSchema referenceSchemaForBase = schemaRepository.LookupByType(resourceSchemaType.SchemaConstructedType); + var referenceSchemaForBase = schemaRepository.LookupByType(resourceSchemaType.SchemaConstructedType); - foreach (ResourceType derivedType in resourceSchemaType.ResourceType.DirectlyDerivedTypes) + foreach (var derivedType in resourceSchemaType.ResourceType.DirectlyDerivedTypes) { - ResourceSchemaType resourceSchemaTypeForDerived = resourceSchemaType.ChangeResourceType(derivedType); - Type derivedSchemaType = resourceSchemaTypeForDerived.SchemaConstructedType; + var resourceSchemaTypeForDerived = resourceSchemaType.ChangeResourceType(derivedType); + var derivedSchemaType = resourceSchemaTypeForDerived.SchemaConstructedType; - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, resourceSchemaTypeForDerived.SchemaConstructedType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, resourceSchemaTypeForDerived.SchemaConstructedType); - OpenApiSchema referenceSchemaForDerived = _defaultSchemaGenerator.GenerateSchema(derivedSchemaType, schemaRepository); - OpenApiSchema fullSchemaForDerived = schemaRepository.Schemas[referenceSchemaForDerived.Reference.Id]; + var referenceSchemaForDerived = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(derivedSchemaType, schemaRepository); + var fullSchemaForDerived = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForDerived.Reference.Id]; fullSchemaForDerived.AdditionalPropertiesAllowed = false; - OpenApiSchema inlineSchemaForDerived = fullSchemaForDerived.UnwrapLastExtendedSchema(); + var inlineSchemaForDerived = (OpenApiSchema)fullSchemaForDerived.UnwrapLastExtendedSchema(); SetResourceFields(inlineSchemaForDerived, resourceSchemaTypeForDerived, forRequestSchema, schemaRepository); SetAbstract(inlineSchemaForDerived, resourceSchemaTypeForDerived); @@ -604,8 +608,8 @@ private void GenerateDataSchemasForDirectlyDerivedTypes(ResourceSchemaType resou if (RequiresRootObjectTypeInDataSchema(resourceSchemaTypeForDerived, forRequestSchema)) { - OpenApiSchema fullSchemaForData = schemaRepository.Schemas[referenceSchemaForDerived.Reference.Id]; - fullSchemaForData.Extensions[SetSchemaTypeToObjectDocumentFilter.RequiresRootObjectTypeKey] = new OpenApiBoolean(true); + var fullSchemaForData = schemaRepository.Schemas[referenceSchemaForDerived.Reference.Id]; + fullSchemaForData.Extensions[SetSchemaTypeToObjectDocumentFilter.RequiresRootObjectTypeKey] = new OpenApiAny(true); } GenerateDataSchemasForDirectlyDerivedTypes(resourceSchemaTypeForDerived, forRequestSchema, schemaRepository); @@ -616,7 +620,7 @@ private void GenerateDataSchemasForDirectlyDerivedTypes(ResourceSchemaType resou private static void RemoveProperties(OpenApiSchema fullSchema) { - foreach (string propertyName in fullSchema.Properties.Keys) + foreach (var propertyName in fullSchema.Properties.Keys) { fullSchema.Properties.Remove(propertyName); fullSchema.Required.Remove(propertyName); @@ -625,7 +629,7 @@ private static void RemoveProperties(OpenApiSchema fullSchema) private static bool RequiresRootObjectTypeInDataSchema(ResourceSchemaType resourceSchemaType, bool forRequestSchema) { - Type? commonDataSchemaType = GetCommonSchemaType(resourceSchemaType.SchemaOpenType); + var commonDataSchemaType = GetCommonSchemaType(resourceSchemaType.SchemaOpenType); if (forRequestSchema && (commonDataSchemaType == typeof(IdentifierInRequest) || (!resourceSchemaType.ResourceType.ClrType.IsAbstract && commonDataSchemaType is { IsGenericType: false }))) diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/LinksVisibilitySchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/LinksVisibilitySchemaGenerator.cs index 5c099a3fc1..217523e72f 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/LinksVisibilitySchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/LinksVisibilitySchemaGenerator.cs @@ -5,6 +5,7 @@ using JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents; using JsonApiDotNetCore.Resources.Annotations; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; @@ -75,9 +76,9 @@ public void UpdateSchemaForTopLevel(Type schemaType, OpenApiSchema fullSchemaFor ArgumentNullException.ThrowIfNull(schemaType); ArgumentNullException.ThrowIfNull(fullSchemaForLinksContainer); - Type lookupType = schemaType.ConstructedToOpenType(); + var lookupType = schemaType.ConstructedToOpenType(); - if (LinksInJsonApiSchemaTypes.TryGetValue(lookupType, out LinkTypes possibleLinkTypes)) + if (LinksInJsonApiSchemaTypes.TryGetValue(lookupType, out var possibleLinkTypes)) { UpdateLinksProperty(fullSchemaForLinksContainer, _lazyLinksVisibility.Value.TopLevelLinks, possibleLinkTypes, schemaRepository); } @@ -88,7 +89,7 @@ public void UpdateSchemaForResource(ResourceSchemaType resourceSchemaType, OpenA ArgumentNullException.ThrowIfNull(resourceSchemaType); ArgumentNullException.ThrowIfNull(fullSchemaForResourceData); - if (LinksInJsonApiSchemaTypes.TryGetValue(resourceSchemaType.SchemaOpenType, out LinkTypes possibleLinkTypes)) + if (LinksInJsonApiSchemaTypes.TryGetValue(resourceSchemaType.SchemaOpenType, out var possibleLinkTypes)) { UpdateLinksProperty(fullSchemaForResourceData, _lazyLinksVisibility.Value.ResourceLinks, possibleLinkTypes, schemaRepository); } @@ -99,9 +100,9 @@ public void UpdateSchemaForRelationship(Type schemaType, OpenApiSchema fullSchem ArgumentNullException.ThrowIfNull(schemaType); ArgumentNullException.ThrowIfNull(fullSchemaForRelationship); - Type lookupType = schemaType.ConstructedToOpenType(); + var lookupType = schemaType.ConstructedToOpenType(); - if (LinksInJsonApiSchemaTypes.TryGetValue(lookupType, out LinkTypes possibleLinkTypes)) + if (LinksInJsonApiSchemaTypes.TryGetValue(lookupType, out var possibleLinkTypes)) { UpdateLinksProperty(fullSchemaForRelationship, _lazyLinksVisibility.Value.RelationshipLinks, possibleLinkTypes, schemaRepository); } @@ -110,7 +111,7 @@ public void UpdateSchemaForRelationship(Type schemaType, OpenApiSchema fullSchem private void UpdateLinksProperty(OpenApiSchema fullSchemaForLinksContainer, LinkTypes visibleLinkTypes, LinkTypes possibleLinkTypes, SchemaRepository schemaRepository) { - OpenApiSchema referenceSchemaForLinks = fullSchemaForLinksContainer.Properties[JsonApiPropertyName.Links].UnwrapLastExtendedSchema(); + var referenceSchemaForLinks = (OpenApiSchemaReference)fullSchemaForLinksContainer.Properties[JsonApiPropertyName.Links].UnwrapLastExtendedSchema(); if ((visibleLinkTypes & possibleLinkTypes) == 0) { @@ -121,18 +122,18 @@ private void UpdateLinksProperty(OpenApiSchema fullSchemaForLinksContainer, Link } else if (visibleLinkTypes != possibleLinkTypes) { - string linksSchemaId = referenceSchemaForLinks.Reference.Id; + var linksSchemaId = referenceSchemaForLinks.Reference.Id; - if (schemaRepository.Schemas.TryGetValue(linksSchemaId, out OpenApiSchema? fullSchemaForLinks)) + if (schemaRepository.Schemas.TryGetValue(linksSchemaId, out var fullSchemaForLinks)) { - UpdateLinkProperties(fullSchemaForLinks, visibleLinkTypes); + UpdateLinkProperties((OpenApiSchema)fullSchemaForLinks, visibleLinkTypes); } } } private void UpdateLinkProperties(OpenApiSchema fullSchemaForLinks, LinkTypes availableLinkTypes) { - foreach (string propertyName in LinkTypeToPropertyNamesMap.Where(pair => !availableLinkTypes.HasFlag(pair.Key)).SelectMany(pair => pair.Value)) + foreach (var propertyName in LinkTypeToPropertyNamesMap.Where(pair => !availableLinkTypes.HasFlag(pair.Key)).SelectMany(pair => pair.Value)) { fullSchemaForLinks.Required.Remove(propertyName); fullSchemaForLinks.Properties.Remove(propertyName); @@ -154,15 +155,15 @@ public LinksVisibility(IJsonApiOptions options, IResourceGraph resourceGraph) var unionResourceLinks = LinkTypes.None; var unionRelationshipLinks = LinkTypes.None; - foreach (ResourceType resourceType in resourceGraph.GetResourceTypes()) + foreach (var resourceType in resourceGraph.GetResourceTypes()) { - LinkTypes topLevelLinks = GetTopLevelLinks(resourceType, options); + var topLevelLinks = GetTopLevelLinks(resourceType, options); unionTopLevelLinks |= topLevelLinks; - LinkTypes resourceLinks = GetResourceLinks(resourceType, options); + var resourceLinks = GetResourceLinks(resourceType, options); unionResourceLinks |= resourceLinks; - LinkTypes relationshipLinks = GetRelationshipLinks(resourceType, options); + var relationshipLinks = GetRelationshipLinks(resourceType, options); unionRelationshipLinks |= relationshipLinks; } @@ -185,12 +186,12 @@ private LinkTypes GetResourceLinks(ResourceType resourceType, IJsonApiOptions op private LinkTypes GetRelationshipLinks(ResourceType resourceType, IJsonApiOptions options) { - LinkTypes unionRelationshipLinks = resourceType.RelationshipLinks != LinkTypes.NotConfigured ? resourceType.RelationshipLinks : + var unionRelationshipLinks = resourceType.RelationshipLinks != LinkTypes.NotConfigured ? resourceType.RelationshipLinks : options.RelationshipLinks == LinkTypes.NotConfigured ? LinkTypes.None : options.RelationshipLinks; - foreach (RelationshipAttribute relationship in resourceType.Relationships) + foreach (var relationship in resourceType.Relationships) { - LinkTypes relationshipLinks = relationship.Links != LinkTypes.NotConfigured ? relationship.Links : + var relationshipLinks = relationship.Links != LinkTypes.NotConfigured ? relationship.Links : relationship.LeftType.RelationshipLinks != LinkTypes.NotConfigured ? relationship.LeftType.RelationshipLinks : options.RelationshipLinks == LinkTypes.NotConfigured ? LinkTypes.None : options.RelationshipLinks; diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/MetaSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/MetaSchemaGenerator.cs index 1e1bd07852..35b7c1b37f 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/MetaSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/MetaSchemaGenerator.cs @@ -1,5 +1,6 @@ using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiObjects; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; @@ -19,27 +20,27 @@ public MetaSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, JsonAp _schemaIdSelector = schemaIdSelector; } - public OpenApiSchema GenerateSchema(SchemaRepository schemaRepository) + public OpenApiSchemaReference GenerateSchema(SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(schemaRepository); - if (schemaRepository.TryLookupByType(SchemaType, out OpenApiSchema? referenceSchema)) + if (schemaRepository.TryLookupByType(SchemaType, out var referenceSchema)) { return referenceSchema; } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, SchemaType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, SchemaType); var fullSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AdditionalProperties = new OpenApiSchema { - Nullable = true + Type = JsonSchemaType.Null } }; - string schemaId = _schemaIdSelector.GetMetaSchemaId(); + var schemaId = _schemaIdSelector.GetMetaSchemaId(); referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); schemaRepository.RegisterType(SchemaType, schemaId); diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipIdentifierSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipIdentifierSchemaGenerator.cs index 98f176e8df..7972e7a995 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipIdentifierSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipIdentifierSchemaGenerator.cs @@ -2,6 +2,7 @@ using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiObjects.ResourceObjects; using JsonApiDotNetCore.Resources.Annotations; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; @@ -34,32 +35,25 @@ public RelationshipIdentifierSchemaGenerator(SchemaGenerationTracer schemaGenera _schemaIdSelector = schemaIdSelector; } - public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRepository schemaRepository) + public OpenApiSchemaReference GenerateSchema(RelationshipAttribute relationship, SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(relationship); ArgumentNullException.ThrowIfNull(schemaRepository); - string schemaId = _schemaIdSelector.GetRelationshipIdentifierSchemaId(relationship); + var schemaId = _schemaIdSelector.GetRelationshipIdentifierSchemaId(relationship); if (schemaRepository.Schemas.ContainsKey(schemaId)) { - return new OpenApiSchema - { - Reference = new OpenApiReference - { - Id = schemaId, - Type = ReferenceType.Schema - } - }; + return new OpenApiSchemaReference(schemaId); } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, relationship); + using var traceScope = _schemaGenerationTracer.TraceStart(this, relationship); - Type relationshipIdentifierConstructedType = typeof(RelationshipIdentifier<>).MakeGenericType(relationship.LeftType.ClrType); + var relationshipIdentifierConstructedType = typeof(RelationshipIdentifier<>).MakeGenericType(relationship.LeftType.ClrType); ConsistencyGuard.ThrowIf(schemaRepository.TryLookupByType(relationshipIdentifierConstructedType, out _)); - OpenApiSchema referenceSchemaForIdentifier = _defaultSchemaGenerator.GenerateSchema(relationshipIdentifierConstructedType, schemaRepository); - OpenApiSchema fullSchemaForIdentifier = schemaRepository.Schemas[referenceSchemaForIdentifier.Reference.Id]; + var referenceSchemaForIdentifier = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(relationshipIdentifierConstructedType, schemaRepository); + var fullSchemaForIdentifier = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForIdentifier.Reference.Id]; fullSchemaForIdentifier.Properties.Remove(JsonApiPropertyName.Meta); @@ -68,7 +62,7 @@ public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRe SetRelationship(fullSchemaForIdentifier, relationship, schemaRepository); schemaRepository.ReplaceSchemaId(relationshipIdentifierConstructedType, schemaId); - referenceSchemaForIdentifier.Reference.Id = schemaId; + referenceSchemaForIdentifier = new OpenApiSchemaReference(schemaId); traceScope.TraceSucceeded(schemaId); return referenceSchemaForIdentifier; @@ -76,19 +70,19 @@ public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRe private void SetResourceType(OpenApiSchema fullSchemaForIdentifier, ResourceType resourceType, SchemaRepository schemaRepository) { - OpenApiSchema referenceSchema = _resourceTypeSchemaGenerator.GenerateSchema(resourceType, schemaRepository); + var referenceSchema = _resourceTypeSchemaGenerator.GenerateSchema(resourceType, schemaRepository); fullSchemaForIdentifier.Properties[JsonApiPropertyName.Type] = referenceSchema.WrapInExtendedSchema(); } private void SetResourceId(OpenApiSchema fullSchemaForResourceData, ResourceType resourceType, SchemaRepository schemaRepository) { - OpenApiSchema idSchema = _resourceIdSchemaGenerator.GenerateSchema(resourceType, schemaRepository); + var idSchema = _resourceIdSchemaGenerator.GenerateSchema(resourceType, schemaRepository); fullSchemaForResourceData.Properties[JsonApiPropertyName.Id] = idSchema; } private void SetRelationship(OpenApiSchema fullSchemaForIdentifier, RelationshipAttribute relationship, SchemaRepository schemaRepository) { - OpenApiSchema referenceSchema = _relationshipNameSchemaGenerator.GenerateSchema(relationship, schemaRepository); + var referenceSchema = _relationshipNameSchemaGenerator.GenerateSchema(relationship, schemaRepository); fullSchemaForIdentifier.Properties[JsonApiPropertyName.Relationship] = referenceSchema.WrapInExtendedSchema(); } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipNameSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipNameSchemaGenerator.cs index 7f5c0c5d3a..6f0ee6076e 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipNameSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/RelationshipNameSchemaGenerator.cs @@ -1,6 +1,7 @@ using JsonApiDotNetCore.Resources.Annotations; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; @@ -19,34 +20,27 @@ public RelationshipNameSchemaGenerator(SchemaGenerationTracer schemaGenerationTr _schemaIdSelector = schemaIdSelector; } - public OpenApiSchema GenerateSchema(RelationshipAttribute relationship, SchemaRepository schemaRepository) + public OpenApiSchemaReference GenerateSchema(RelationshipAttribute relationship, SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(relationship); ArgumentNullException.ThrowIfNull(schemaRepository); - string schemaId = _schemaIdSelector.GetRelationshipNameSchemaId(relationship); + var schemaId = _schemaIdSelector.GetRelationshipNameSchemaId(relationship); if (schemaRepository.Schemas.ContainsKey(schemaId)) { - return new OpenApiSchema - { - Reference = new OpenApiReference - { - Id = schemaId, - Type = ReferenceType.Schema - } - }; + return new OpenApiSchemaReference(schemaId); } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, relationship); + using var traceScope = _schemaGenerationTracer.TraceStart(this, relationship); var fullSchema = new OpenApiSchema { - Type = "string", - Enum = [new OpenApiString(relationship.PublicName)] + Type = JsonSchemaType.String, + Enum = [relationship.PublicName] }; - OpenApiSchema referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); + var referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); traceScope.TraceSucceeded(schemaId); return referenceSchema; diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs index 21bc5020ed..f146fc374b 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceIdSchemaGenerator.cs @@ -1,5 +1,6 @@ using JsonApiDotNetCore.Configuration; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; @@ -27,10 +28,11 @@ public OpenApiSchema GenerateSchema(Type resourceIdClrType, SchemaRepository sch ArgumentNullException.ThrowIfNull(resourceIdClrType); ArgumentNullException.ThrowIfNull(schemaRepository); - OpenApiSchema idSchema = _defaultSchemaGenerator.GenerateSchema(resourceIdClrType, schemaRepository); - ConsistencyGuard.ThrowIf(idSchema.Reference != null); + var schema = _defaultSchemaGenerator.GenerateSchema(resourceIdClrType, schemaRepository); + ConsistencyGuard.ThrowIf(schema is OpenApiSchemaReference); - idSchema.Type = "string"; + var idSchema = (OpenApiSchema)schema; + idSchema.Type = JsonSchemaType.String; if (resourceIdClrType != typeof(string)) { diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceTypeSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceTypeSchemaGenerator.cs index eb933bedbe..bc34e6603a 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceTypeSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Components/ResourceTypeSchemaGenerator.cs @@ -2,6 +2,7 @@ using JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; @@ -20,34 +21,34 @@ public ResourceTypeSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer _schemaIdSelector = schemaIdSelector; } - public OpenApiSchema GenerateSchema(ResourceType resourceType, SchemaRepository schemaRepository) + public OpenApiSchemaReference GenerateSchema(ResourceType resourceType, SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(resourceType); ArgumentNullException.ThrowIfNull(schemaRepository); - if (schemaRepository.TryLookupByType(resourceType.ClrType, out OpenApiSchema? referenceSchema)) + if (schemaRepository.TryLookupByType(resourceType.ClrType, out var referenceSchema)) { return referenceSchema; } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, resourceType.ClrType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, resourceType.ClrType); var fullSchema = new OpenApiSchema { - Type = "string", - Enum = resourceType.ClrType.IsAbstract ? [] : [new OpenApiString(resourceType.PublicName)], + Type = JsonSchemaType.String, + Enum = resourceType.ClrType.IsAbstract ? [] : [resourceType.PublicName], Extensions = { - [StringEnumOrderingFilter.RequiresSortKey] = new OpenApiBoolean(true) + [StringEnumOrderingFilter.RequiresSortKey] = new OpenApiAny(true) } }; - foreach (ResourceType derivedType in resourceType.GetAllConcreteDerivedTypes()) + foreach (var derivedType in resourceType.GetAllConcreteDerivedTypes()) { - fullSchema.Enum.Add(new OpenApiString(derivedType.PublicName)); + fullSchema.Enum.Add(derivedType.PublicName); } - string schemaId = _schemaIdSelector.GetResourceTypeSchemaId(resourceType); + var schemaId = _schemaIdSelector.GetResourceTypeSchemaId(resourceType); referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); schemaRepository.RegisterType(resourceType.ClrType, schemaId); @@ -56,34 +57,27 @@ public OpenApiSchema GenerateSchema(ResourceType resourceType, SchemaRepository return referenceSchema; } - public OpenApiSchema GenerateSchema(SchemaRepository schemaRepository) + public OpenApiSchemaReference GenerateSchema(SchemaRepository schemaRepository) { - string schemaId = _schemaIdSelector.GetResourceTypeSchemaId(null); + var schemaId = _schemaIdSelector.GetResourceTypeSchemaId(null); if (schemaRepository.Schemas.ContainsKey(schemaId)) { - return new OpenApiSchema - { - Reference = new OpenApiReference - { - Id = schemaId, - Type = ReferenceType.Schema - } - }; + return new OpenApiSchemaReference(schemaId); } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this); + using var traceScope = _schemaGenerationTracer.TraceStart(this); var fullSchema = new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, Extensions = { - [StringEnumOrderingFilter.RequiresSortKey] = new OpenApiBoolean(true) + [StringEnumOrderingFilter.RequiresSortKey] = new OpenApiAny(true) } }; - OpenApiSchema referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); + var referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); traceScope.TraceSucceeded(schemaId); return referenceSchema; diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/AtomicOperationsDocumentSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/AtomicOperationsDocumentSchemaGenerator.cs index f128f89299..4682d98f0b 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/AtomicOperationsDocumentSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/AtomicOperationsDocumentSchemaGenerator.cs @@ -9,6 +9,8 @@ using JsonApiDotNetCore.Serialization.Objects; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Documents; @@ -68,12 +70,12 @@ public override bool CanGenerate(Type schemaType) return schemaType == typeof(OperationsRequestDocument) || schemaType == typeof(OperationsResponseDocument); } - protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository) + protected override OpenApiSchemaReference GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(schemaType); ArgumentNullException.ThrowIfNull(schemaRepository); - bool isRequestSchema = schemaType == typeof(OperationsRequestDocument); + var isRequestSchema = schemaType == typeof(OperationsRequestDocument); if (isRequestSchema) { @@ -84,39 +86,39 @@ protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaR GenerateSchemasForResponseDocument(schemaRepository); } - return _defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository); + return (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository); } private void GenerateSchemasForRequestDocument(SchemaRepository schemaRepository) { _ = GenerateSchemaForAbstractOperation(schemaRepository); - foreach (ResourceType resourceType in _resourceGraph.GetResourceTypes().Where(resourceType => resourceType.BaseType == null)) + foreach (var resourceType in _resourceGraph.GetResourceTypes().Where(resourceType => resourceType.BaseType == null)) { GenerateSchemaForOperation(resourceType, schemaRepository); } } - private OpenApiSchema GenerateSchemaForAbstractOperation(SchemaRepository schemaRepository) + private OpenApiSchemaReference GenerateSchemaForAbstractOperation(SchemaRepository schemaRepository) { - if (schemaRepository.TryLookupByType(AtomicOperationAbstractType, out OpenApiSchema? referenceSchema)) + if (schemaRepository.TryLookupByType(AtomicOperationAbstractType, out var referenceSchema)) { return referenceSchema; } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, AtomicOperationAbstractType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, AtomicOperationAbstractType); - OpenApiSchema referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository); + var referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository); var fullSchema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, Required = new SortedSet([OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName]), - Properties = new Dictionary + Properties = new Dictionary { - [OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName] = new() + [OpenApiMediaTypeExtension.FullyQualifiedOpenApiDiscriminatorPropertyName] = new OpenApiSchema() { - Type = "string" + Type = JsonSchemaType.String }, [referenceSchemaForMeta.Reference.Id] = referenceSchemaForMeta.WrapInExtendedSchema() }, @@ -128,11 +130,11 @@ private OpenApiSchema GenerateSchemaForAbstractOperation(SchemaRepository schema }, Extensions = { - ["x-abstract"] = new OpenApiBoolean(true) + ["x-abstract"] = new OpenApiAny(true) } }; - string schemaId = _schemaIdSelector.GetSchemaId(AtomicOperationAbstractType); + var schemaId = _schemaIdSelector.GetSchemaId(AtomicOperationAbstractType); referenceSchema = schemaRepository.AddDefinition(schemaId, fullSchema); schemaRepository.RegisterType(AtomicOperationAbstractType, schemaId); @@ -147,7 +149,7 @@ private void GenerateSchemaForOperation(ResourceType resourceType, SchemaReposit GenerateSchemaForResourceOperation(typeof(UpdateOperation<>), resourceType, AtomicOperationCode.Update, schemaRepository); GenerateSchemaForResourceOperation(typeof(DeleteOperation<>), resourceType, AtomicOperationCode.Remove, schemaRepository); - foreach (RelationshipAttribute relationship in GetRelationshipsInTypeHierarchy(resourceType)) + foreach (var relationship in GetRelationshipsInTypeHierarchy(resourceType)) { if (relationship is HasOneAttribute) { @@ -165,22 +167,22 @@ private void GenerateSchemaForOperation(ResourceType resourceType, SchemaReposit private void GenerateSchemaForResourceOperation(Type operationOpenType, ResourceType resourceType, AtomicOperationCode operationCode, SchemaRepository schemaRepository) { - WriteOperationKind writeOperation = GetKindOfResourceOperation(operationCode); + var writeOperation = GetKindOfResourceOperation(operationCode); if (IsResourceTypeEnabled(resourceType, writeOperation)) { - Type operationConstructedType = ChangeResourceTypeInSchemaType(operationOpenType, resourceType); + var operationConstructedType = ChangeResourceTypeInSchemaType(operationOpenType, resourceType); - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, operationConstructedType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, operationConstructedType); - bool needsEmptyDerivedSchema = resourceType.BaseType != null && _atomicOperationFilter.IsEnabled(resourceType.BaseType, writeOperation); + var needsEmptyDerivedSchema = resourceType.BaseType != null && _atomicOperationFilter.IsEnabled(resourceType.BaseType, writeOperation); if (!needsEmptyDerivedSchema) { - Type identifierSchemaType = typeof(IdentifierInRequest<>).MakeGenericType(resourceType.ClrType); + var identifierSchemaType = typeof(IdentifierInRequest<>).MakeGenericType(resourceType.ClrType); _ = _dataSchemaGenerator.GenerateSchema(identifierSchemaType, true, schemaRepository); - bool hasDataProperty = operationOpenType != typeof(DeleteOperation<>); + var hasDataProperty = operationOpenType != typeof(DeleteOperation<>); if (hasDataProperty) { @@ -188,15 +190,15 @@ private void GenerateSchemaForResourceOperation(Type operationOpenType, Resource } } - OpenApiSchema referenceSchemaForOperation = _defaultSchemaGenerator.GenerateSchema(operationConstructedType, schemaRepository); - OpenApiSchema fullSchemaForOperation = schemaRepository.Schemas[referenceSchemaForOperation.Reference.Id]; + var referenceSchemaForOperation = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(operationConstructedType, schemaRepository); + var fullSchemaForOperation = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForOperation.Reference.Id]; fullSchemaForOperation.AdditionalPropertiesAllowed = false; - OpenApiSchema inlineSchemaForOperation = fullSchemaForOperation.UnwrapLastExtendedSchema(); + var inlineSchemaForOperation = (OpenApiSchema)fullSchemaForOperation.UnwrapLastExtendedSchema(); if (needsEmptyDerivedSchema) { - Type baseOperationSchemaType = ChangeResourceTypeInSchemaType(operationOpenType, resourceType.BaseType!); - OpenApiSchema referenceSchemaForBaseOperation = schemaRepository.LookupByType(baseOperationSchemaType); + var baseOperationSchemaType = ChangeResourceTypeInSchemaType(operationOpenType, resourceType.BaseType!); + var referenceSchemaForBaseOperation = schemaRepository.LookupByType(baseOperationSchemaType); RemoveProperties(inlineSchemaForOperation); fullSchemaForOperation.AllOf[0] = referenceSchemaForBaseOperation; @@ -206,13 +208,13 @@ private void GenerateSchemaForResourceOperation(Type operationOpenType, Resource SetOperationCode(inlineSchemaForOperation, operationCode, schemaRepository); } - string discriminatorValue = _schemaIdSelector.GetAtomicOperationDiscriminatorValue(operationCode, resourceType); + var discriminatorValue = _schemaIdSelector.GetAtomicOperationDiscriminatorValue(operationCode, resourceType); MapInDiscriminator(referenceSchemaForOperation, discriminatorValue, schemaRepository); traceScope.TraceSucceeded(referenceSchemaForOperation.Reference.Id); } - foreach (ResourceType derivedType in resourceType.DirectlyDerivedTypes) + foreach (var derivedType in resourceType.DirectlyDerivedTypes) { GenerateSchemaForResourceOperation(operationOpenType, derivedType, operationCode, schemaRepository); } @@ -251,7 +253,7 @@ private static Type ChangeResourceTypeInSchemaType(Type schemaOpenType, Resource private static void RemoveProperties(OpenApiSchema fullSchema) { - foreach (string propertyName in fullSchema.Properties.Keys) + foreach (var propertyName in fullSchema.Properties.Keys) { fullSchema.Properties.Remove(propertyName); fullSchema.Required.Remove(propertyName); @@ -260,20 +262,20 @@ private static void RemoveProperties(OpenApiSchema fullSchema) private void SetOperationCode(OpenApiSchema fullSchema, AtomicOperationCode operationCode, SchemaRepository schemaRepository) { - OpenApiSchema referenceSchema = _atomicOperationCodeSchemaGenerator.GenerateSchema(operationCode, schemaRepository); + var referenceSchema = _atomicOperationCodeSchemaGenerator.GenerateSchema(operationCode, schemaRepository); fullSchema.Properties[JsonApiPropertyName.Op] = referenceSchema.WrapInExtendedSchema(); } - private static void MapInDiscriminator(OpenApiSchema referenceSchemaForOperation, string discriminatorValue, SchemaRepository schemaRepository) + private static void MapInDiscriminator(OpenApiSchemaReference referenceSchemaForOperation, string discriminatorValue, SchemaRepository schemaRepository) { - OpenApiSchema referenceSchemaForAbstractOperation = schemaRepository.LookupByType(AtomicOperationAbstractType); - OpenApiSchema fullSchemaForAbstractOperation = schemaRepository.Schemas[referenceSchemaForAbstractOperation.Reference.Id]; + var referenceSchemaForAbstractOperation = schemaRepository.LookupByType(AtomicOperationAbstractType); + var fullSchemaForAbstractOperation = schemaRepository.Schemas[referenceSchemaForAbstractOperation.Reference.Id]; fullSchemaForAbstractOperation.Discriminator.Mapping.Add(discriminatorValue, referenceSchemaForOperation.Reference.ReferenceV3); } private static HashSet GetRelationshipsInTypeHierarchy(ResourceType baseType) { - HashSet relationships = baseType.Relationships.ToHashSet(); + var relationships = baseType.Relationships.ToHashSet(); if (baseType.IsPartOfTypeHierarchy()) { @@ -285,7 +287,7 @@ private static HashSet GetRelationshipsInTypeHierarchy(Re private static void IncludeRelationshipsInDirectlyDerivedTypes(ResourceType baseType, HashSet relationships) { - foreach (ResourceType derivedType in baseType.DirectlyDerivedTypes) + foreach (var derivedType in baseType.DirectlyDerivedTypes) { IncludeRelationshipsInDerivedType(derivedType, relationships); } @@ -293,7 +295,7 @@ private static void IncludeRelationshipsInDirectlyDerivedTypes(ResourceType base private static void IncludeRelationshipsInDerivedType(ResourceType derivedType, HashSet relationships) { - foreach (RelationshipAttribute relationshipInDerivedType in derivedType.Relationships) + foreach (var relationshipInDerivedType in derivedType.Relationships) { relationships.Add(relationshipInDerivedType); } @@ -304,22 +306,22 @@ private static void IncludeRelationshipsInDerivedType(ResourceType derivedType, private void GenerateSchemaForRelationshipOperation(Type operationOpenType, RelationshipAttribute relationship, AtomicOperationCode operationCode, SchemaRepository schemaRepository) { - WriteOperationKind writeOperation = GetKindOfRelationshipOperation(operationCode); + var writeOperation = GetKindOfRelationshipOperation(operationCode); if (!IsRelationshipEnabled(relationship, writeOperation)) { return; } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, operationOpenType, relationship); + using var traceScope = _schemaGenerationTracer.TraceStart(this, operationOpenType, relationship); - RelationshipAttribute? relationshipInAnyBaseResourceType = GetRelationshipEnabledInAnyBase(relationship, writeOperation); + var relationshipInAnyBaseResourceType = GetRelationshipEnabledInAnyBase(relationship, writeOperation); - OpenApiSchema? referenceSchemaForRelationshipIdentifier; + OpenApiSchemaReference? referenceSchemaForRelationshipIdentifier; if (relationshipInAnyBaseResourceType == null) { - Type rightSchemaType = typeof(IdentifierInRequest<>).MakeGenericType(relationship.RightType.ClrType); + var rightSchemaType = typeof(IdentifierInRequest<>).MakeGenericType(relationship.RightType.ClrType); _ = _dataSchemaGenerator.GenerateSchema(rightSchemaType, true, schemaRepository); referenceSchemaForRelationshipIdentifier = _relationshipIdentifierSchemaGenerator.GenerateSchema(relationship, schemaRepository); @@ -329,19 +331,19 @@ private void GenerateSchemaForRelationshipOperation(Type operationOpenType, Rela referenceSchemaForRelationshipIdentifier = null; } - Type operationConstructedType = ChangeResourceTypeInSchemaType(operationOpenType, relationship.RightType); + var operationConstructedType = ChangeResourceTypeInSchemaType(operationOpenType, relationship.RightType); _ = _dataContainerSchemaGenerator.GenerateSchema(operationConstructedType, relationship.RightType, true, false, schemaRepository); // This complicated implementation that generates a temporary schema stems from the fact that GetSchemaId takes a Type. // We could feed it a constructed type with TLeftResource and TRightResource, but there's no way to include // the relationship name because there's no runtime Type available for it. - string schemaId = _schemaIdSelector.GetRelationshipAtomicOperationSchemaId(relationship, operationCode); + var schemaId = _schemaIdSelector.GetRelationshipAtomicOperationSchemaId(relationship, operationCode); - OpenApiSchema referenceSchemaForOperation = _defaultSchemaGenerator.GenerateSchema(operationConstructedType, schemaRepository); - OpenApiSchema fullSchemaForOperation = schemaRepository.Schemas[referenceSchemaForOperation.Reference.Id]; + var referenceSchemaForOperation = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(operationConstructedType, schemaRepository); + var fullSchemaForOperation = (OpenApiSchema)schemaRepository.Schemas[referenceSchemaForOperation.Reference.Id]; fullSchemaForOperation.AdditionalPropertiesAllowed = false; - OpenApiSchema inlineSchemaForOperation = fullSchemaForOperation.UnwrapLastExtendedSchema(); + var inlineSchemaForOperation = (OpenApiSchema)fullSchemaForOperation.UnwrapLastExtendedSchema(); SetOperationCode(inlineSchemaForOperation, operationCode, schemaRepository); if (referenceSchemaForRelationshipIdentifier != null) @@ -349,29 +351,23 @@ private void GenerateSchemaForRelationshipOperation(Type operationOpenType, Rela inlineSchemaForOperation.Properties[JsonApiPropertyName.Ref] = referenceSchemaForRelationshipIdentifier.WrapInExtendedSchema(); } - inlineSchemaForOperation.Properties[JsonApiPropertyName.Data].Nullable = _resourceFieldValidationMetadataProvider.IsNullable(relationship); + bool isNullable = _resourceFieldValidationMetadataProvider.IsNullable(relationship); + ((OpenApiSchema)inlineSchemaForOperation.Properties[JsonApiPropertyName.Data]).SetNullable(isNullable); schemaRepository.ReplaceSchemaId(operationConstructedType, schemaId); - referenceSchemaForOperation.Reference.Id = schemaId; + referenceSchemaForOperation = new OpenApiSchemaReference(schemaId); if (relationshipInAnyBaseResourceType != null) { RemoveProperties(inlineSchemaForOperation); - string baseRelationshipSchemaId = _schemaIdSelector.GetRelationshipAtomicOperationSchemaId(relationshipInAnyBaseResourceType, operationCode); + var baseRelationshipSchemaId = _schemaIdSelector.GetRelationshipAtomicOperationSchemaId(relationshipInAnyBaseResourceType, operationCode); ConsistencyGuard.ThrowIf(!schemaRepository.Schemas.ContainsKey(baseRelationshipSchemaId)); - fullSchemaForOperation.AllOf[0] = new OpenApiSchema - { - Reference = new OpenApiReference - { - Id = baseRelationshipSchemaId, - Type = ReferenceType.Schema - } - }; + fullSchemaForOperation.AllOf[0] = new OpenApiSchemaReference(baseRelationshipSchemaId); } - string discriminatorValue = _schemaIdSelector.GetAtomicOperationDiscriminatorValue(operationCode, relationship); + var discriminatorValue = _schemaIdSelector.GetAtomicOperationDiscriminatorValue(operationCode, relationship); MapInDiscriminator(referenceSchemaForOperation, discriminatorValue, schemaRepository); traceScope.TraceSucceeded(schemaId); @@ -454,7 +450,7 @@ private static bool IsToManyRelationshipEnabled(HasManyAttribute relationship, W private RelationshipAttribute? GetRelationshipEnabledInAnyBase(RelationshipAttribute relationship, WriteOperationKind writeOperation) { - RelationshipAttribute? relationshipInBaseResourceType = relationship.LeftType.BaseType?.FindRelationshipByPublicName(relationship.PublicName); + var relationshipInBaseResourceType = relationship.LeftType.BaseType?.FindRelationshipByPublicName(relationship.PublicName); while (relationshipInBaseResourceType != null) { @@ -473,7 +469,7 @@ private void GenerateSchemasForResponseDocument(SchemaRepository schemaRepositor { _ = _dataContainerSchemaGenerator.GenerateSchemaForCommonResourceDataInResponse(schemaRepository); - foreach (ResourceType resourceType in _resourceGraph.GetResourceTypes()) + foreach (var resourceType in _resourceGraph.GetResourceTypes()) { if (IsResourceTypeEnabled(resourceType, WriteOperationKind.CreateResource) || IsResourceTypeEnabled(resourceType, WriteOperationKind.UpdateResource)) diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/DocumentSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/DocumentSchemaGenerator.cs index 740b2fca43..72313c06f4 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/DocumentSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/DocumentSchemaGenerator.cs @@ -1,6 +1,7 @@ using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Documents; @@ -31,22 +32,22 @@ protected DocumentSchemaGenerator(SchemaGenerationTracer schemaGenerationTracer, public abstract bool CanGenerate(Type schemaType); - public OpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepository) + public OpenApiSchemaReference GenerateSchema(Type schemaType, SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(schemaType); ArgumentNullException.ThrowIfNull(schemaRepository); - if (schemaRepository.TryLookupByType(schemaType, out OpenApiSchema? referenceSchema)) + if (schemaRepository.TryLookupByType(schemaType, out var referenceSchema)) { return referenceSchema; } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, schemaType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, schemaType); _metaSchemaGenerator.GenerateSchema(schemaRepository); referenceSchema = GenerateDocumentSchema(schemaType, schemaRepository); - OpenApiSchema fullSchema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var fullSchema = (OpenApiSchema)schemaRepository.Schemas[referenceSchema.Reference.Id]; _linksVisibilitySchemaGenerator.UpdateSchemaForTopLevel(schemaType, fullSchema, schemaRepository); @@ -56,7 +57,7 @@ public OpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepo return referenceSchema; } - protected abstract OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository); + protected abstract OpenApiSchemaReference GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository); private void SetJsonApiVersion(OpenApiSchema fullSchema, SchemaRepository schemaRepository) { diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ErrorResponseDocumentSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ErrorResponseDocumentSchemaGenerator.cs index 3d305e889b..7f841f34c0 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ErrorResponseDocumentSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ErrorResponseDocumentSchemaGenerator.cs @@ -3,6 +3,7 @@ using JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; using JsonApiDotNetCore.Serialization.Objects; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Documents; @@ -34,25 +35,25 @@ public override bool CanGenerate(Type schemaType) return schemaType == typeof(ErrorResponseDocument); } - protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository) + protected override OpenApiSchemaReference GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(schemaType); ArgumentNullException.ThrowIfNull(schemaRepository); - OpenApiSchema referenceSchemaForErrorObject = GenerateSchemaForErrorObject(schemaRepository); - OpenApiSchema fullSchemaForErrorObject = schemaRepository.Schemas[referenceSchemaForErrorObject.Reference.Id]; + var referenceSchemaForErrorObject = GenerateSchemaForErrorObject(schemaRepository); + var fullSchemaForErrorObject = schemaRepository.Schemas[referenceSchemaForErrorObject.Reference.Id]; - OpenApiSchema referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository); + var referenceSchemaForMeta = _metaSchemaGenerator.GenerateSchema(schemaRepository); fullSchemaForErrorObject.Properties[JsonApiPropertyName.Meta] = referenceSchemaForMeta.WrapInExtendedSchema(); - return _defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository); + return (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository); } - private OpenApiSchema GenerateSchemaForErrorObject(SchemaRepository schemaRepository) + private OpenApiSchemaReference GenerateSchemaForErrorObject(SchemaRepository schemaRepository) { - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, ErrorObjectType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, ErrorObjectType); - OpenApiSchema referenceSchema = _defaultSchemaGenerator.GenerateSchema(ErrorObjectType, schemaRepository); + var referenceSchema = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(ErrorObjectType, schemaRepository); traceScope.TraceSucceeded(referenceSchema.Reference.Id); return referenceSchema; diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ResourceOrRelationshipDocumentSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ResourceOrRelationshipDocumentSchemaGenerator.cs index 767f0d0143..5b14fef527 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ResourceOrRelationshipDocumentSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/Documents/ResourceOrRelationshipDocumentSchemaGenerator.cs @@ -4,6 +4,7 @@ using JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; using JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Documents; @@ -53,26 +54,26 @@ public ResourceOrRelationshipDocumentSchemaGenerator(SchemaGenerationTracer sche public override bool CanGenerate(Type schemaType) { - Type schemaOpenType = schemaType.ConstructedToOpenType(); + var schemaOpenType = schemaType.ConstructedToOpenType(); return RequestDocumentSchemaTypes.Contains(schemaOpenType) || ResponseDocumentSchemaTypes.Contains(schemaOpenType); } - protected override OpenApiSchema GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository) + protected override OpenApiSchemaReference GenerateDocumentSchema(Type schemaType, SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(schemaType); ArgumentNullException.ThrowIfNull(schemaRepository); var resourceSchemaType = ResourceSchemaType.Create(schemaType, _resourceGraph); - bool isRequestSchema = RequestDocumentSchemaTypes.Contains(resourceSchemaType.SchemaOpenType); + var isRequestSchema = RequestDocumentSchemaTypes.Contains(resourceSchemaType.SchemaOpenType); _ = _dataContainerSchemaGenerator.GenerateSchema(schemaType, resourceSchemaType.ResourceType, isRequestSchema, !isRequestSchema, schemaRepository); - OpenApiSchema? referenceSchemaForDocument = _defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository); - OpenApiSchema inlineSchemaForDocument = schemaRepository.Schemas[referenceSchemaForDocument.Reference.Id].UnwrapLastExtendedSchema(); + var referenceSchemaForDocument = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(schemaType, schemaRepository); + var inlineSchemaForDocument = schemaRepository.Schemas[referenceSchemaForDocument.Reference.Id].UnwrapLastExtendedSchema(); if (JsonApiSchemaFacts.HasNullableDataProperty(resourceSchemaType.SchemaOpenType)) { - inlineSchemaForDocument.Properties[JsonApiPropertyName.Data].Nullable = true; + ((OpenApiSchema)inlineSchemaForDocument.Properties[JsonApiPropertyName.Data]).SetNullable(true); } return referenceSchemaForDocument; diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/GenerationCacheSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/GenerationCacheSchemaGenerator.cs index beba632ebf..aac843c766 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/GenerationCacheSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/GenerationCacheSchemaGenerator.cs @@ -1,9 +1,11 @@ using System.Reflection; +using System.Text.Json.Nodes; using JsonApiDotNetCore.OpenApi.Swashbuckle.JsonApiMetadata; using Microsoft.AspNetCore.Mvc.Abstractions; using Microsoft.AspNetCore.Mvc.Infrastructure; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators; @@ -36,32 +38,31 @@ public bool HasAtomicOperationsEndpoint(SchemaRepository schemaRepository) { ArgumentNullException.ThrowIfNull(schemaRepository); - OpenApiSchema fullSchema = GenerateFullSchema(schemaRepository); + var fullSchema = GenerateFullSchema(schemaRepository); - var hasAtomicOperationsEndpoint = (OpenApiBoolean)fullSchema.Properties[HasAtomicOperationsEndpointPropertyName].Default; - return hasAtomicOperationsEndpoint.Value; + return (bool)fullSchema.Properties[HasAtomicOperationsEndpointPropertyName].Default; } private OpenApiSchema GenerateFullSchema(SchemaRepository schemaRepository) { - if (schemaRepository.Schemas.TryGetValue(SchemaId, out OpenApiSchema? fullSchema)) + if (schemaRepository.Schemas.TryGetValue(SchemaId, out var schema)) { - return fullSchema; + return (OpenApiSchema)schema; } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this); + using var traceScope = _schemaGenerationTracer.TraceStart(this); - bool hasAtomicOperationsEndpoint = EvaluateHasAtomicOperationsEndpoint(); + var hasAtomicOperationsEndpoint = EvaluateHasAtomicOperationsEndpoint(); - fullSchema = new OpenApiSchema + var fullSchema = new OpenApiSchema { - Type = "object", - Properties = new Dictionary + Type = JsonSchemaType.Object, + Properties = new Dictionary { - [HasAtomicOperationsEndpointPropertyName] = new() + [HasAtomicOperationsEndpointPropertyName] = new OpenApiSchema() { - Type = "boolean", - Default = new OpenApiBoolean(hasAtomicOperationsEndpoint) + Type = JsonSchemaType.Boolean, + Default = hasAtomicOperationsEndpoint } } }; @@ -74,13 +75,13 @@ private OpenApiSchema GenerateFullSchema(SchemaRepository schemaRepository) private bool EvaluateHasAtomicOperationsEndpoint() { - IEnumerable actionDescriptors = + var actionDescriptors = _defaultProvider.ActionDescriptors.Items.Where(JsonApiActionDescriptorCollectionProvider.IsVisibleJsonApiEndpoint); - foreach (ActionDescriptor actionDescriptor in actionDescriptors) + foreach (var actionDescriptor in actionDescriptors) { - MethodInfo actionMethod = actionDescriptor.GetActionMethod(); - JsonApiEndpointMetadataContainer endpointMetadataContainer = _jsonApiEndpointMetadataProvider.Get(actionMethod); + var actionMethod = actionDescriptor.GetActionMethod(); + var endpointMetadataContainer = _jsonApiEndpointMetadataProvider.Get(actionMethod); if (endpointMetadataContainer.RequestMetadata is AtomicOperationsRequestMetadata) { diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/JsonApiSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/JsonApiSchemaGenerator.cs index 19d94eb48e..f7485a2f7b 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/JsonApiSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaGenerators/JsonApiSchemaGenerator.cs @@ -4,6 +4,8 @@ using JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Documents; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators; @@ -22,7 +24,7 @@ public JsonApiSchemaGenerator(ResourceIdSchemaGenerator resourceIdSchemaGenerato _documentSchemaGenerators = documentSchemaGenerators as DocumentSchemaGenerator[] ?? documentSchemaGenerators.ToArray(); } - public OpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepository, MemberInfo? memberInfo = null, ParameterInfo? parameterInfo = null, + public IOpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepository, MemberInfo? memberInfo = null, ParameterInfo? parameterInfo = null, ApiParameterRouteInfo? routeInfo = null) { ArgumentNullException.ThrowIfNull(schemaType); @@ -33,14 +35,14 @@ public OpenApiSchema GenerateSchema(Type schemaType, SchemaRepository schemaRepo return _resourceIdSchemaGenerator.GenerateSchema(schemaType, schemaRepository); } - DocumentSchemaGenerator schemaGenerator = GetDocumentSchemaGenerator(schemaType); - OpenApiSchema referenceSchema = schemaGenerator.GenerateSchema(schemaType, schemaRepository); + var schemaGenerator = GetDocumentSchemaGenerator(schemaType); + var referenceSchema = schemaGenerator.GenerateSchema(schemaType, schemaRepository); if (memberInfo != null || parameterInfo != null) { // For unknown reasons, Swashbuckle chooses to wrap request bodies in allOf, but not response bodies. // We just replicate that behavior here. See https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/861#issuecomment-1373631712. - referenceSchema = referenceSchema.WrapInExtendedSchema(); + return referenceSchema.WrapInExtendedSchema(); } return referenceSchema; @@ -55,7 +57,7 @@ private DocumentSchemaGenerator GetDocumentSchemaGenerator(Type schemaType) { DocumentSchemaGenerator? generator = null; - foreach (DocumentSchemaGenerator documentSchemaGenerator in _documentSchemaGenerators) + foreach (var documentSchemaGenerator in _documentSchemaGenerators) { if (documentSchemaGenerator.CanGenerate(schemaType)) { diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaRepositoryExtensions.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaRepositoryExtensions.cs index 669c50b4e0..76fc6e079d 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaRepositoryExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SchemaRepositoryExtensions.cs @@ -1,5 +1,6 @@ using System.Reflection; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle; @@ -11,7 +12,7 @@ internal static class SchemaRepositoryExtensions private static FieldInfo GetReservedIdsField() { - FieldInfo? field = typeof(SchemaRepository).GetField(ReservedIdsFieldName, BindingFlags.Instance | BindingFlags.NonPublic); + var field = typeof(SchemaRepository).GetField(ReservedIdsFieldName, BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { @@ -28,12 +29,12 @@ private static FieldInfo GetReservedIdsField() return field; } - public static OpenApiSchema LookupByType(this SchemaRepository schemaRepository, Type schemaType) + public static OpenApiSchemaReference LookupByType(this SchemaRepository schemaRepository, Type schemaType) { ArgumentNullException.ThrowIfNull(schemaRepository); ArgumentNullException.ThrowIfNull(schemaType); - if (!schemaRepository.TryLookupByType(schemaType, out OpenApiSchema? referenceSchema)) + if (!schemaRepository.TryLookupByType(schemaType, out var referenceSchema)) { throw new InvalidOperationException($"Reference schema for '{schemaType.Name}' does not exist."); } @@ -47,11 +48,11 @@ public static void ReplaceSchemaId(this SchemaRepository schemaRepository, Type ArgumentNullException.ThrowIfNull(oldSchemaType); ArgumentException.ThrowIfNullOrEmpty(newSchemaId); - if (schemaRepository.TryLookupByType(oldSchemaType, out OpenApiSchema? referenceSchema)) + if (schemaRepository.TryLookupByType(oldSchemaType, out var referenceSchema)) { - string oldSchemaId = referenceSchema.Reference.Id; + var oldSchemaId = referenceSchema.Reference.Id; - OpenApiSchema fullSchema = schemaRepository.Schemas[oldSchemaId]; + var fullSchema = schemaRepository.Schemas[oldSchemaId]; schemaRepository.Schemas.Remove(oldSchemaId); schemaRepository.Schemas.Add(newSchemaId, fullSchema); diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SetSchemaTypeToObjectDocumentFilter.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SetSchemaTypeToObjectDocumentFilter.cs index 2764f868e6..fad2d8fda2 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SetSchemaTypeToObjectDocumentFilter.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SetSchemaTypeToObjectDocumentFilter.cs @@ -11,12 +11,15 @@ internal sealed class SetSchemaTypeToObjectDocumentFilter : IDocumentFilter public void Apply(OpenApiDocument document, DocumentFilterContext context) { - foreach (OpenApiSchema schema in document.Components.Schemas.Values) + if (document.Components?.Schemas != null) { - if (schema.Extensions.ContainsKey(RequiresRootObjectTypeKey)) + foreach (var schema in document.Components.Schemas.Values) { - schema.Type = "object"; - schema.Extensions.Remove(RequiresRootObjectTypeKey); + if (schema.Extensions.ContainsKey(RequiresRootObjectTypeKey)) + { + ((OpenApiSchema)schema).Type = JsonSchemaType.Object; + schema.Extensions.Remove(RequiresRootObjectTypeKey); + } } } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SortDocumentFilter.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SortDocumentFilter.cs new file mode 100644 index 0000000000..e15f1551eb --- /dev/null +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SortDocumentFilter.cs @@ -0,0 +1,55 @@ +using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace JsonApiDotNetCore.OpenApi.Swashbuckle; + +internal sealed class SortSchemasFilter : IDocumentFilter +{ + // Should use SwaggerGeneratorOptions.SchemaComparer + private static readonly StringComparer DefaultStringComparer = StringComparer.Ordinal; + + public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) + { + // Workaround for the change that ordering is no longer applied. See https://github.com/microsoft/OpenAPI.NET/issues/1314#issuecomment-2836828481. + // Pending: https://github.com/microsoft/OpenAPI.NET/issues/2342 + + swaggerDoc.Components ??= new OpenApiComponents(); + + if (swaggerDoc.Components.Schemas != null) + { + swaggerDoc.Components.Schemas = new SortedDictionary(swaggerDoc.Components.Schemas, DefaultStringComparer).ToDictionary(); + + foreach (IOpenApiSchema schema in swaggerDoc.Components.Schemas.Values) + { + SortSchema(schema); + } + } + } + + private static void SortSchema(IOpenApiSchema schema) + { + if (schema is OpenApiSchema concreteSchema) + { + if (concreteSchema.Required != null) + { + concreteSchema.Required = new SortedSet(concreteSchema.Required, DefaultStringComparer).ToHashSet(); + } + + if (concreteSchema.Discriminator?.Mapping != null) + { + concreteSchema.Discriminator.Mapping = + new SortedDictionary(concreteSchema.Discriminator.Mapping, DefaultStringComparer).ToDictionary(); + } + + if (concreteSchema.AllOf != null) + { + foreach (IOpenApiSchema subSchema in concreteSchema.AllOf) + { + SortSchema(subSchema); + } + } + } + } +} diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/DocumentationOpenApiOperationFilter.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/DocumentationOpenApiOperationFilter.cs index 1b5c0d5f4c..32ba65068b 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/DocumentationOpenApiOperationFilter.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/DocumentationOpenApiOperationFilter.cs @@ -11,6 +11,7 @@ using Microsoft.Net.Http.Headers; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents; @@ -74,16 +75,16 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) ArgumentNullException.ThrowIfNull(operation); ArgumentNullException.ThrowIfNull(context); - bool hasHeadVerb = context.ApiDescription.HttpMethod == "HEAD"; + var hasHeadVerb = context.ApiDescription.HttpMethod == "HEAD"; if (hasHeadVerb) { operation.Responses.Clear(); } - MethodInfo actionMethod = context.ApiDescription.ActionDescriptor.GetActionMethod(); - string actionName = context.MethodInfo.Name; - ResourceType? resourceType = _controllerResourceMapping.GetResourceTypeForController(actionMethod.ReflectedType); + var actionMethod = context.ApiDescription.ActionDescriptor.GetActionMethod(); + var actionName = context.MethodInfo.Name; + var resourceType = _controllerResourceMapping.GetResourceTypeForController(actionMethod.ReflectedType); if (resourceType != null) { @@ -119,7 +120,7 @@ public void Apply(OpenApiOperation operation, OperationFilterContext context) } case GetSecondaryName or GetRelationshipName or PostRelationshipName or PatchRelationshipName or DeleteRelationshipName: { - RelationshipAttribute relationship = GetRelationshipFromRoute(context.ApiDescription, resourceType); + var relationship = GetRelationshipFromRoute(context.ApiDescription, resourceType); switch (actionName) { @@ -192,7 +193,7 @@ private static void ApplyGetPrimary(OpenApiOperation operation, ResourceType res } else if (operation.Parameters.Count == 1) { - string singularName = resourceType.PublicName.Singularize(); + var singularName = resourceType.PublicName.Singularize(); if (hasHeadVerb) { @@ -223,7 +224,7 @@ private static void ApplyGetPrimary(OpenApiOperation operation, ResourceType res private void ApplyPostResource(OpenApiOperation operation, ResourceType resourceType) { - string singularName = resourceType.PublicName.Singularize(); + var singularName = resourceType.PublicName.Singularize(); SetOperationSummary(operation, $"Creates a new {singularName}."); AddQueryStringParameters(operation, false); @@ -239,7 +240,7 @@ private void ApplyPostResource(OpenApiOperation operation, ResourceType resource SetResponseDescription(operation.Responses, HttpStatusCode.BadRequest, TextQueryStringOrRequestBodyBad); - ClientIdGenerationMode clientIdGeneration = resourceType.ClientIdGeneration ?? _options.ClientIdGeneration; + var clientIdGeneration = resourceType.ClientIdGeneration ?? _options.ClientIdGeneration; if (clientIdGeneration == ClientIdGenerationMode.Forbidden) { @@ -253,7 +254,7 @@ private void ApplyPostResource(OpenApiOperation operation, ResourceType resource private void ApplyPatchResource(OpenApiOperation operation, ResourceType resourceType) { - string singularName = resourceType.PublicName.Singularize(); + var singularName = resourceType.PublicName.Singularize(); SetOperationSummary(operation, $"Updates an existing {singularName}."); SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularName} to update."); @@ -276,7 +277,7 @@ private void ApplyPatchResource(OpenApiOperation operation, ResourceType resourc private void ApplyDeleteResource(OpenApiOperation operation, ResourceType resourceType) { - string singularName = resourceType.PublicName.Singularize(); + var singularName = resourceType.PublicName.Singularize(); SetOperationSummary(operation, $"Deletes an existing {singularName} by its identifier."); SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularName} to delete."); @@ -286,8 +287,8 @@ private void ApplyDeleteResource(OpenApiOperation operation, ResourceType resour private static void ApplyGetSecondary(OpenApiOperation operation, RelationshipAttribute relationship, bool hasHeadVerb) { - string singularLeftName = relationship.LeftType.PublicName.Singularize(); - string rightName = relationship is HasOneAttribute ? relationship.RightType.PublicName.Singularize() : relationship.RightType.PublicName; + var singularLeftName = relationship.LeftType.PublicName.Singularize(); + var rightName = relationship is HasOneAttribute ? relationship.RightType.PublicName.Singularize() : relationship.RightType.PublicName; if (hasHeadVerb) { @@ -326,9 +327,9 @@ relationship is HasOneAttribute private static void ApplyGetRelationship(OpenApiOperation operation, RelationshipAttribute relationship, bool hasHeadVerb) { - string singularLeftName = relationship.LeftType.PublicName.Singularize(); - string singularRightName = relationship.RightType.PublicName.Singularize(); - string ident = relationship is HasOneAttribute ? "identity" : "identities"; + var singularLeftName = relationship.LeftType.PublicName.Singularize(); + var singularRightName = relationship.RightType.PublicName.Singularize(); + var ident = relationship is HasOneAttribute ? "identity" : "identities"; if (hasHeadVerb) { @@ -368,8 +369,8 @@ relationship is HasOneAttribute private void ApplyPostRelationship(OpenApiOperation operation, RelationshipAttribute relationship) { - string singularLeftName = relationship.LeftType.PublicName.Singularize(); - string rightName = relationship.RightType.PublicName; + var singularLeftName = relationship.LeftType.PublicName.Singularize(); + var rightName = relationship.RightType.PublicName; SetOperationSummary(operation, $"Adds existing {rightName} to the {relationship} relationship of an individual {singularLeftName}."); SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularLeftName} to add {rightName} to."); @@ -386,9 +387,9 @@ private void ApplyPostRelationship(OpenApiOperation operation, RelationshipAttri private void ApplyPatchRelationship(OpenApiOperation operation, RelationshipAttribute relationship) { - bool isOptional = _resourceFieldValidationMetadataProvider.IsNullable(relationship); - string singularLeftName = relationship.LeftType.PublicName.Singularize(); - string rightName = relationship is HasOneAttribute ? relationship.RightType.PublicName.Singularize() : relationship.RightType.PublicName; + var isOptional = _resourceFieldValidationMetadataProvider.IsNullable(relationship); + var singularLeftName = relationship.LeftType.PublicName.Singularize(); + var rightName = relationship is HasOneAttribute ? relationship.RightType.PublicName.Singularize() : relationship.RightType.PublicName; SetOperationSummary(operation, relationship is HasOneAttribute @@ -420,8 +421,8 @@ relationship is HasOneAttribute private void ApplyDeleteRelationship(OpenApiOperation operation, RelationshipAttribute relationship) { - string singularLeftName = relationship.LeftType.PublicName.Singularize(); - string rightName = relationship.RightType.PublicName; + var singularLeftName = relationship.LeftType.PublicName.Singularize(); + var rightName = relationship.RightType.PublicName; SetOperationSummary(operation, $"Removes existing {rightName} from the {relationship} relationship of an individual {singularLeftName}."); SetParameterDescription(operation.Parameters[0], $"The identifier of the {singularLeftName} to remove {rightName} from."); @@ -440,7 +441,7 @@ private static RelationshipAttribute GetRelationshipFromRoute(ApiDescription api { ConsistencyGuard.ThrowIf(apiDescription.RelativePath == null); - string relationshipName = apiDescription.RelativePath.Split('/').Last(); + var relationshipName = apiDescription.RelativePath.Split('/').Last(); return resourceType.GetRelationshipByPublicName(relationshipName); } @@ -454,25 +455,25 @@ private static void SetOperationRemarks(OpenApiOperation operation, string descr operation.Description = XmlCommentsTextHelper.Humanize(description); } - private static void SetParameterDescription(OpenApiParameter parameter, string description) + private static void SetParameterDescription(IOpenApiParameter parameter, string description) { parameter.Description = XmlCommentsTextHelper.Humanize(description); } - private static void SetRequestBodyDescription(OpenApiRequestBody requestBody, string description) + private static void SetRequestBodyDescription(IOpenApiRequestBody requestBody, string description) { requestBody.Description = XmlCommentsTextHelper.Humanize(description); } private static void SetResponseDescription(OpenApiResponses responses, HttpStatusCode statusCode, string description) { - OpenApiResponse response = GetOrAddResponse(responses, statusCode); + var response = GetOrAddResponse(responses, statusCode); response.Description = XmlCommentsTextHelper.Humanize(description); } private static void SetResponseHeaderETag(OpenApiResponses responses, HttpStatusCode statusCode) { - OpenApiResponse response = GetOrAddResponse(responses, statusCode); + var response = GetOrAddResponse(responses, statusCode); response.Headers[HeaderNames.ETag] = new OpenApiHeader { @@ -480,14 +481,14 @@ private static void SetResponseHeaderETag(OpenApiResponses responses, HttpStatus Required = true, Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }; } private static void SetResponseHeaderContentLength(OpenApiResponses responses, HttpStatusCode statusCode) { - OpenApiResponse response = GetOrAddResponse(responses, statusCode); + var response = GetOrAddResponse(responses, statusCode); response.Headers[HeaderNames.ContentLength] = new OpenApiHeader { @@ -495,7 +496,7 @@ private static void SetResponseHeaderContentLength(OpenApiResponses responses, H Required = true, Schema = new OpenApiSchema { - Type = "integer", + Type = JsonSchemaType.Integer, Format = "int64" } }; @@ -503,7 +504,7 @@ private static void SetResponseHeaderContentLength(OpenApiResponses responses, H private static void SetResponseHeaderLocation(OpenApiResponses responses, HttpStatusCode statusCode, string resourceName) { - OpenApiResponse response = GetOrAddResponse(responses, statusCode); + var response = GetOrAddResponse(responses, statusCode); response.Headers[HeaderNames.Location] = new OpenApiHeader { @@ -511,17 +512,17 @@ private static void SetResponseHeaderLocation(OpenApiResponses responses, HttpSt Required = true, Schema = new OpenApiSchema { - Type = "string", + Type = JsonSchemaType.String, Format = "uri" } }; } - private static OpenApiResponse GetOrAddResponse(OpenApiResponses responses, HttpStatusCode statusCode) + private static IOpenApiResponse GetOrAddResponse(OpenApiResponses responses, HttpStatusCode statusCode) { - string responseCode = ((int)statusCode).ToString(); + var responseCode = ((int)statusCode).ToString(); - if (!responses.TryGetValue(responseCode, out OpenApiResponse? response)) + if (!responses.TryGetValue(responseCode, out var response)) { response = new OpenApiResponse(); responses.Add(responseCode, response); @@ -542,20 +543,21 @@ private static void AddQueryStringParameters(OpenApiOperation operation, bool is // - This makes NSwag produce a C# client with method signature: GetAsync(IDictionary? query) // when combined with true in the project file. + operation.Parameters ??= new List(); + operation.Parameters.Add(new OpenApiParameter { In = ParameterLocation.Query, Name = "query", Schema = new OpenApiSchema { - Type = "object", + Type = JsonSchemaType.Object, AdditionalProperties = new OpenApiSchema { - Type = "string", - Nullable = true + Type = JsonSchemaType.String|JsonSchemaType.Null, }, // Prevent SwaggerUI from producing sample, which fails when used because unknown query string parameters are blocked by default. - Example = new OpenApiString(string.Empty) + Example = string.Empty }, Description = isRelationshipEndpoint ? RelationshipQueryStringParameters : ResourceQueryStringParameters }); @@ -563,6 +565,8 @@ private static void AddQueryStringParameters(OpenApiOperation operation, bool is private static void AddRequestHeaderIfNoneMatch(OpenApiOperation operation) { + operation.Parameters ??= new List(); + operation.Parameters.Add(new OpenApiParameter { In = ParameterLocation.Header, @@ -570,7 +574,7 @@ private static void AddRequestHeaderIfNoneMatch(OpenApiOperation operation) Description = "A list of ETags, resulting in HTTP status 304 without a body, if one of them matches the current fingerprint.", Schema = new OpenApiSchema { - Type = "string" + Type = JsonSchemaType.String } }); } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/EndpointOrderingFilter.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/EndpointOrderingFilter.cs index 047ba4355a..7a7a057c5b 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/EndpointOrderingFilter.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/EndpointOrderingFilter.cs @@ -1,6 +1,8 @@ using System.Text.RegularExpressions; using JetBrains.Annotations; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents; @@ -13,30 +15,47 @@ public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) ArgumentNullException.ThrowIfNull(swaggerDoc); ArgumentNullException.ThrowIfNull(context); - KeyValuePair[] endpointsInOrder = swaggerDoc.Paths.OrderBy(GetPrimaryResourcePublicName) + var endpointsInOrder = swaggerDoc.Paths.OrderBy(GetPrimaryResourcePublicName) .ThenBy(GetRelationshipName).ThenBy(IsSecondaryEndpoint).ToArray(); + + swaggerDoc.Paths = new OpenApiPaths(); - swaggerDoc.Paths.Clear(); - - foreach ((string url, OpenApiPathItem path) in endpointsInOrder) + foreach ((var url, var path) in endpointsInOrder) { swaggerDoc.Paths.Add(url, path); } } - private static string GetPrimaryResourcePublicName(KeyValuePair entry) + private static string GetPrimaryResourcePublicName(KeyValuePair entry) { - return entry.Value.Operations.First().Value.Tags.First().Name; + if (entry.Value.Operations.Count > 0) + { + ISet? references = entry.Value.Operations.First().Value.Tags; + + if (references is { Count: > 0 }) + { + OpenApiTagReference openApiTagReference = references.First(); + + if (openApiTagReference.Name != null) + { + return openApiTagReference.Name; + } + } + } + + throw new InvalidOperationException($"Failed to find tag value for endpoint '{entry.Key}'."); + + } - private static bool IsSecondaryEndpoint(KeyValuePair entry) + private static bool IsSecondaryEndpoint(KeyValuePair entry) { return entry.Key.Contains("/relationships"); } - private static string GetRelationshipName(KeyValuePair entry) + private static string GetRelationshipName(KeyValuePair entry) { - Match match = RelationshipNameInUrlRegex().Match(entry.Key); + var match = RelationshipNameInUrlRegex().Match(entry.Key); return match.Success ? match.Groups["RelationshipName"].Value : string.Empty; } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/JsonApiDataContractResolver.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/JsonApiDataContractResolver.cs index dcc652c696..8337b90ba4 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/JsonApiDataContractResolver.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/JsonApiDataContractResolver.cs @@ -33,7 +33,7 @@ public DataContract GetDataContractForType(Type type) return DataContract.ForDynamic(typeof(object)); } - DataContract dataContract = _dataContractResolver.GetDataContractForType(type); + var dataContract = _dataContractResolver.GetDataContractForType(type); IList? replacementProperties = null; @@ -58,10 +58,10 @@ private static DataContract ReplacePropertiesInDataContract(DataContract dataCon private List GetDataPropertiesThatExistInResourceClrType(Type resourceClrType, DataContract dataContract) { - ResourceType resourceType = _resourceGraph.GetResourceType(resourceClrType); + var resourceType = _resourceGraph.GetResourceType(resourceClrType); List dataProperties = []; - foreach (DataProperty property in dataContract.ObjectProperties) + foreach (var property in dataContract.ObjectProperties) { if (property.MemberInfo.Name == nameof(Identifiable.Id)) { @@ -69,12 +69,12 @@ private List GetDataPropertiesThatExistInResourceClrType(Type reso continue; } - ResourceFieldAttribute? matchingField = resourceType.Fields.SingleOrDefault(field => + var matchingField = resourceType.Fields.SingleOrDefault(field => IsPropertyCompatibleWithMember(field.Property, property.MemberInfo)); if (matchingField != null) { - DataProperty matchingProperty = matchingField.PublicName != property.Name + var matchingProperty = matchingField.PublicName != property.Name ? ChangeDataPropertyName(property, matchingField.PublicName) : property; diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceDocumentationReader.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceDocumentationReader.cs index cd2727854c..a8289fca1d 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceDocumentationReader.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceDocumentationReader.cs @@ -16,11 +16,11 @@ internal sealed class ResourceDocumentationReader { ArgumentNullException.ThrowIfNull(resourceType); - XPathNavigator? navigator = GetNavigator(resourceType.ClrType.Assembly); + var navigator = GetNavigator(resourceType.ClrType.Assembly); if (navigator != null) { - string typeMemberName = XmlCommentsNodeNameHelper.GetMemberNameForType(resourceType.ClrType); + var typeMemberName = XmlCommentsNodeNameHelper.GetMemberNameForType(resourceType.ClrType); return GetSummary(navigator, typeMemberName); } @@ -31,11 +31,11 @@ internal sealed class ResourceDocumentationReader { ArgumentNullException.ThrowIfNull(attribute); - XPathNavigator? navigator = GetNavigator(attribute.Type.ClrType.Assembly); + var navigator = GetNavigator(attribute.Type.ClrType.Assembly); if (navigator != null) { - string propertyMemberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(attribute.Property); + var propertyMemberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(attribute.Property); return GetSummary(navigator, propertyMemberName); } @@ -46,11 +46,11 @@ internal sealed class ResourceDocumentationReader { ArgumentNullException.ThrowIfNull(relationship); - XPathNavigator? navigator = GetNavigator(relationship.Type.ClrType.Assembly); + var navigator = GetNavigator(relationship.Type.ClrType.Assembly); if (navigator != null) { - string propertyMemberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(relationship.Property); + var propertyMemberName = XmlCommentsNodeNameHelper.GetMemberNameForFieldOrProperty(relationship.Property); return GetSummary(navigator, propertyMemberName); } @@ -59,13 +59,13 @@ internal sealed class ResourceDocumentationReader private static XPathNavigator? GetNavigator(Assembly assembly) { - string assemblyPath = assembly.Location; + var assemblyPath = assembly.Location; if (!string.IsNullOrEmpty(assemblyPath)) { return NavigatorsByAssemblyPath.GetOrAdd(assemblyPath, path => { - string documentationPath = Path.ChangeExtension(path, ".xml"); + var documentationPath = Path.ChangeExtension(path, ".xml"); if (File.Exists(documentationPath)) { @@ -83,7 +83,7 @@ internal sealed class ResourceDocumentationReader private string? GetSummary(XPathNavigator navigator, string memberName) { - XPathNavigator? summaryNode = navigator.SelectSingleNode($"/doc/members/member[@name='{memberName}']/summary"); + var summaryNode = navigator.SelectSingleNode($"/doc/members/member[@name='{memberName}']/summary"); return summaryNode != null ? XmlCommentsTextHelper.Humanize(summaryNode.InnerXml) : null; } } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceFieldSchemaBuilder.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceFieldSchemaBuilder.cs index 31bf7be625..d60fcb75d9 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceFieldSchemaBuilder.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceFieldSchemaBuilder.cs @@ -4,6 +4,8 @@ using JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators.Components; using JsonApiDotNetCore.Resources.Annotations; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Swashbuckle.AspNetCore.SwaggerGen; namespace JsonApiDotNetCore.OpenApi.Swashbuckle.SwaggerComponents; @@ -20,7 +22,7 @@ internal sealed class ResourceFieldSchemaBuilder private readonly SchemaRepository _resourceSchemaRepository = new(); private readonly ResourceDocumentationReader _resourceDocumentationReader = new(); - private readonly IDictionary _schemasForResourceFields; + private readonly IDictionary _schemasForResourceFields; public ResourceFieldSchemaBuilder(SchemaGenerationTracer schemaGenerationTracer, SchemaGenerator defaultSchemaGenerator, DataSchemaGenerator dataSchemaGenerator, LinksVisibilitySchemaGenerator linksVisibilitySchemaGenerator, @@ -46,14 +48,14 @@ public ResourceFieldSchemaBuilder(SchemaGenerationTracer schemaGenerationTracer, _schemasForResourceFields = GetFieldSchemas(); } - private IDictionary GetFieldSchemas() + private IDictionary GetFieldSchemas() { - if (!_resourceSchemaRepository.TryLookupByType(_resourceSchemaType.ResourceType.ClrType, out OpenApiSchema referenceSchemaForResource)) + if (!_resourceSchemaRepository.TryLookupByType(_resourceSchemaType.ResourceType.ClrType, out var referenceSchemaForResource)) { - referenceSchemaForResource = _defaultSchemaGenerator.GenerateSchema(_resourceSchemaType.ResourceType.ClrType, _resourceSchemaRepository); + referenceSchemaForResource = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(_resourceSchemaType.ResourceType.ClrType, _resourceSchemaRepository); } - OpenApiSchema inlineSchemaForResource = _resourceSchemaRepository.Schemas[referenceSchemaForResource.Reference.Id].UnwrapLastExtendedSchema(); + var inlineSchemaForResource = _resourceSchemaRepository.Schemas[referenceSchemaForResource.Reference.Id].UnwrapLastExtendedSchema(); return inlineSchemaForResource.Properties; } @@ -63,11 +65,11 @@ public void SetMembersOfAttributes(OpenApiSchema fullSchemaForAttributes, bool f ArgumentNullException.ThrowIfNull(schemaRepository); AssertHasNoProperties(fullSchemaForAttributes); - AttrCapabilities requiredCapability = GetRequiredCapabilityForAttributes(_resourceSchemaType.SchemaOpenType); + var requiredCapability = GetRequiredCapabilityForAttributes(_resourceSchemaType.SchemaOpenType); - foreach ((string publicName, OpenApiSchema schemaForResourceField) in _schemasForResourceFields) + foreach ((var publicName, var schemaForResourceField) in _schemasForResourceFields) { - AttrAttribute? matchingAttribute = _resourceSchemaType.ResourceType.FindAttributeByPublicName(publicName); + var matchingAttribute = _resourceSchemaType.ResourceType.FindAttributeByPublicName(publicName); if (matchingAttribute != null && matchingAttribute.Capabilities.HasFlag(requiredCapability)) { @@ -86,18 +88,19 @@ public void SetMembersOfAttributes(OpenApiSchema fullSchemaForAttributes, bool f } } - bool isInlineSchemaType = schemaForResourceField.AllOf.Count == 0; + var isInlineSchemaType = schemaForResourceField.AllOf.Count == 0; // Schemas for types like enum and complex attributes are handled as reference schemas. if (!isInlineSchemaType) { - OpenApiSchema referenceSchemaForAttribute = schemaForResourceField.UnwrapLastExtendedSchema(); + var referenceSchemaForAttribute = (OpenApiSchemaReference)schemaForResourceField.UnwrapLastExtendedSchema(); EnsureAttributeSchemaIsExposed(referenceSchemaForAttribute, matchingAttribute, schemaRepository); } fullSchemaForAttributes.Properties.Add(matchingAttribute.PublicName, schemaForResourceField); - schemaForResourceField.Nullable = _resourceFieldValidationMetadataProvider.IsNullable(matchingAttribute); + bool isNullable = _resourceFieldValidationMetadataProvider.IsNullable(matchingAttribute); + ((OpenApiSchema)schemaForResourceField).SetNullable(isNullable); if (IsFieldRequired(matchingAttribute)) { @@ -130,19 +133,19 @@ private static AttrCapabilities GetRequiredCapabilityForAttributes(Type resource return capabilities.Value; } - private void EnsureAttributeSchemaIsExposed(OpenApiSchema referenceSchemaForAttribute, AttrAttribute attribute, SchemaRepository schemaRepository) + private void EnsureAttributeSchemaIsExposed(OpenApiSchemaReference referenceSchemaForAttribute, AttrAttribute attribute, SchemaRepository schemaRepository) { - Type nonNullableTypeInPropertyType = GetRepresentedTypeForAttributeSchema(attribute); + var nonNullableTypeInPropertyType = GetRepresentedTypeForAttributeSchema(attribute); if (schemaRepository.TryLookupByType(nonNullableTypeInPropertyType, out _)) { return; } - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, nonNullableTypeInPropertyType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, nonNullableTypeInPropertyType); - string schemaId = referenceSchemaForAttribute.Reference.Id; - OpenApiSchema fullSchema = _resourceSchemaRepository.Schemas[schemaId]; + var schemaId = referenceSchemaForAttribute.Reference.Id; + var fullSchema = (OpenApiSchema)_resourceSchemaRepository.Schemas[schemaId]; schemaRepository.AddDefinition(schemaId, fullSchema); schemaRepository.RegisterType(nonNullableTypeInPropertyType, schemaId); @@ -153,11 +156,11 @@ private void EnsureAttributeSchemaIsExposed(OpenApiSchema referenceSchemaForAttr private Type GetRepresentedTypeForAttributeSchema(AttrAttribute attribute) { NullabilityInfoContext nullabilityInfoContext = new(); - NullabilityInfo attributeNullabilityInfo = nullabilityInfoContext.Create(attribute.Property); + var attributeNullabilityInfo = nullabilityInfoContext.Create(attribute.Property); - bool isNullable = attributeNullabilityInfo is { ReadState: NullabilityState.Nullable, WriteState: NullabilityState.Nullable }; + var isNullable = attributeNullabilityInfo is { ReadState: NullabilityState.Nullable, WriteState: NullabilityState.Nullable }; - Type nonNullableTypeInPropertyType = isNullable + var nonNullableTypeInPropertyType = isNullable ? Nullable.GetUnderlyingType(attribute.Property.PropertyType) ?? attribute.Property.PropertyType : attribute.Property.PropertyType; @@ -166,7 +169,7 @@ private Type GetRepresentedTypeForAttributeSchema(AttrAttribute attribute) private bool IsFieldRequired(ResourceFieldAttribute field) { - bool isCreateResourceSchemaType = _resourceSchemaType.SchemaOpenType == typeof(DataInCreateRequest<>); + var isCreateResourceSchemaType = _resourceSchemaType.SchemaOpenType == typeof(DataInCreateRequest<>); return isCreateResourceSchemaType && _resourceFieldValidationMetadataProvider.IsRequired(field); } @@ -176,14 +179,14 @@ public void SetMembersOfRelationships(OpenApiSchema fullSchemaForRelationships, ArgumentNullException.ThrowIfNull(schemaRepository); AssertHasNoProperties(fullSchemaForRelationships); - foreach (string publicName in _schemasForResourceFields.Keys) + foreach (var publicName in _schemasForResourceFields.Keys) { - RelationshipAttribute? matchingRelationship = _resourceSchemaType.ResourceType.FindRelationshipByPublicName(publicName); + var matchingRelationship = _resourceSchemaType.ResourceType.FindRelationshipByPublicName(publicName); if (matchingRelationship != null) { - Type identifierSchemaOpenType = forRequestSchema ? typeof(IdentifierInRequest<>) : typeof(IdentifierInResponse<>); - Type identifierSchemaConstructedType = identifierSchemaOpenType.MakeGenericType(matchingRelationship.RightType.ClrType); + var identifierSchemaOpenType = forRequestSchema ? typeof(IdentifierInRequest<>) : typeof(IdentifierInResponse<>); + var identifierSchemaConstructedType = identifierSchemaOpenType.MakeGenericType(matchingRelationship.RightType.ClrType); _ = _dataSchemaGenerator.GenerateSchema(identifierSchemaConstructedType, forRequestSchema, schemaRepository); AddRelationshipSchemaToResourceData(matchingRelationship, fullSchemaForRelationships, schemaRepository); @@ -194,12 +197,12 @@ public void SetMembersOfRelationships(OpenApiSchema fullSchemaForRelationships, private void AddRelationshipSchemaToResourceData(RelationshipAttribute relationship, OpenApiSchema fullSchemaForRelationships, SchemaRepository schemaRepository) { - Type relationshipSchemaType = GetRelationshipSchemaType(relationship, _resourceSchemaType.SchemaOpenType); + var relationshipSchemaType = GetRelationshipSchemaType(relationship, _resourceSchemaType.SchemaOpenType); - OpenApiSchema referenceSchemaForRelationship = GetReferenceSchemaForRelationship(relationshipSchemaType, schemaRepository) ?? + var referenceSchemaForRelationship = GetReferenceSchemaForRelationship(relationshipSchemaType, schemaRepository) ?? CreateReferenceSchemaForRelationship(relationshipSchemaType, schemaRepository); - OpenApiSchema extendedReferenceSchemaForRelationship = referenceSchemaForRelationship.WrapInExtendedSchema(); + var extendedReferenceSchemaForRelationship = referenceSchemaForRelationship.WrapInExtendedSchema(); extendedReferenceSchemaForRelationship.Description = _resourceDocumentationReader.GetDocumentationForRelationship(relationship); fullSchemaForRelationships.Properties.Add(relationship.PublicName, extendedReferenceSchemaForRelationship); @@ -212,26 +215,26 @@ private void AddRelationshipSchemaToResourceData(RelationshipAttribute relations private Type GetRelationshipSchemaType(RelationshipAttribute relationship, Type openSchemaType) { - bool isResponseSchemaType = openSchemaType.IsAssignableTo(typeof(DataInResponse<>)); + var isResponseSchemaType = openSchemaType.IsAssignableTo(typeof(DataInResponse<>)); return isResponseSchemaType ? _relationshipTypeFactory.GetForResponse(relationship) : _relationshipTypeFactory.GetForRequest(relationship); } - private OpenApiSchema? GetReferenceSchemaForRelationship(Type relationshipSchemaType, SchemaRepository schemaRepository) + private OpenApiSchemaReference? GetReferenceSchemaForRelationship(Type relationshipSchemaType, SchemaRepository schemaRepository) { - return schemaRepository.TryLookupByType(relationshipSchemaType, out OpenApiSchema? referenceSchema) ? referenceSchema : null; + return schemaRepository.TryLookupByType(relationshipSchemaType, out var referenceSchema) ? referenceSchema : null; } - private OpenApiSchema CreateReferenceSchemaForRelationship(Type relationshipSchemaType, SchemaRepository schemaRepository) + private OpenApiSchemaReference CreateReferenceSchemaForRelationship(Type relationshipSchemaType, SchemaRepository schemaRepository) { - using ISchemaGenerationTraceScope traceScope = _schemaGenerationTracer.TraceStart(this, relationshipSchemaType); + using var traceScope = _schemaGenerationTracer.TraceStart(this, relationshipSchemaType); - OpenApiSchema referenceSchema = _defaultSchemaGenerator.GenerateSchema(relationshipSchemaType, schemaRepository); + var referenceSchema = (OpenApiSchemaReference)_defaultSchemaGenerator.GenerateSchema(relationshipSchemaType, schemaRepository); - OpenApiSchema fullSchema = schemaRepository.Schemas[referenceSchema.Reference.Id]; + var fullSchema = (OpenApiSchema)schemaRepository.Schemas[referenceSchema.Reference.Id]; if (JsonApiSchemaFacts.HasNullableDataProperty(relationshipSchemaType)) { - fullSchema.Properties[JsonApiPropertyName.Data].Nullable = true; + ((OpenApiSchema)fullSchema.Properties[JsonApiPropertyName.Data]).SetNullable(true); } if (JsonApiSchemaFacts.IsRelationshipInResponseType(relationshipSchemaType)) diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceSchemaType.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceSchemaType.cs index 148f0f4e2c..6eabd32947 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceSchemaType.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ResourceSchemaType.cs @@ -30,9 +30,9 @@ public static ResourceSchemaType Create(Type schemaConstructedType, IResourceGra ArgumentNullException.ThrowIfNull(schemaConstructedType); ArgumentNullException.ThrowIfNull(resourceGraph); - Type schemaOpenType = schemaConstructedType.GetGenericTypeDefinition(); - Type resourceClrType = schemaConstructedType.GenericTypeArguments[0]; - ResourceType resourceType = resourceGraph.GetResourceType(resourceClrType); + var schemaOpenType = schemaConstructedType.GetGenericTypeDefinition(); + var resourceClrType = schemaConstructedType.GenericTypeArguments[0]; + var resourceType = resourceGraph.GetResourceType(resourceClrType); return new ResourceSchemaType(schemaConstructedType, schemaOpenType, resourceType); } @@ -41,7 +41,7 @@ public ResourceSchemaType ChangeResourceType(ResourceType resourceType) { ArgumentNullException.ThrowIfNull(resourceType); - Type schemaConstructedType = SchemaOpenType.MakeGenericType(resourceType.ClrType); + var schemaConstructedType = SchemaOpenType.MakeGenericType(resourceType.ClrType); return new ResourceSchemaType(schemaConstructedType, SchemaOpenType, resourceType); } diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ServerDocumentFilter.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ServerDocumentFilter.cs index 723499d39c..cdc3c839cf 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ServerDocumentFilter.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/ServerDocumentFilter.cs @@ -19,9 +19,11 @@ public ServerDocumentFilter(IHttpContextAccessor httpContextAccessor) public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { + swaggerDoc.Servers ??= new List(); + if (swaggerDoc.Servers.Count == 0 && _httpContextAccessor.HttpContext != null) { - HttpRequest httpRequest = _httpContextAccessor.HttpContext.Request; + var httpRequest = _httpContextAccessor.HttpContext.Request; swaggerDoc.Servers.Add(new OpenApiServer { diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/StringEnumOrderingFilter.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/StringEnumOrderingFilter.cs index dec10db97b..fe22865e34 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/StringEnumOrderingFilter.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/SwaggerComponents/StringEnumOrderingFilter.cs @@ -1,7 +1,10 @@ +using System.Text.Json; +using System.Text.Json.Nodes; using JetBrains.Annotations; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Services; using Swashbuckle.AspNetCore.SwaggerGen; @@ -24,13 +27,13 @@ public void Apply(OpenApiDocument document, DocumentFilterContext context) private sealed class OpenApiEnumVisitor : OpenApiVisitorBase { - public override void Visit(OpenApiSchema schema) + public override void Visit(IOpenApiSchema schema) { - if (HasSortAnnotation(schema)) + if (schema is OpenApiSchema concreteSchema && HasSortAnnotation(concreteSchema)) { if (schema.Enum.Count > 1) { - OrderEnumMembers(schema); + OrderEnumMembers(concreteSchema); } } @@ -40,12 +43,12 @@ public override void Visit(OpenApiSchema schema) private static bool HasSortAnnotation(OpenApiSchema schema) { // Order our own enums, but don't touch enums from user-defined resource attributes. - return schema.Extensions.TryGetValue(RequiresSortKey, out IOpenApiExtension? extension) && extension is OpenApiBoolean { Value: true }; + return schema.Extensions.TryGetValue(RequiresSortKey, out var extension) && extension is OpenApiAny any && any.Node is JsonValue value && value.GetValueKind() == JsonValueKind.True; } private static void OrderEnumMembers(OpenApiSchema schema) { - List ordered = schema.Enum.OfType().OrderBy(openApiString => openApiString.Value).Cast().ToList(); + var ordered = schema.Enum.OrderBy(node => node.ToString()).ToList(); ConsistencyGuard.ThrowIf(ordered.Count != schema.Enum.Count); schema.Enum = ordered; diff --git a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/UnusedComponentSchemaCleaner.cs b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/UnusedComponentSchemaCleaner.cs index 4e2addabb3..0e763c1bd2 100644 --- a/src/JsonApiDotNetCore.OpenApi.Swashbuckle/UnusedComponentSchemaCleaner.cs +++ b/src/JsonApiDotNetCore.OpenApi.Swashbuckle/UnusedComponentSchemaCleaner.cs @@ -3,6 +3,8 @@ using JsonApiDotNetCore.OpenApi.Swashbuckle.SchemaGenerators; using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; +using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Services; using Swashbuckle.AspNetCore.SwaggerGen; @@ -21,9 +23,11 @@ public void Apply(OpenApiDocument document, DocumentFilterContext context) ArgumentNullException.ThrowIfNull(document); ArgumentNullException.ThrowIfNull(context); + document.Components ??= new OpenApiComponents(); + document.Components.Schemas ??= new Dictionary(); document.Components.Schemas.Remove(GenerationCacheSchemaGenerator.SchemaId); - HashSet unusedSchemaIds = GetUnusedSchemaIds(document); + var unusedSchemaIds = GetUnusedSchemaIds(document); AssertNoUnknownSchemasFound(unusedSchemaIds); RemoveUnusedComponentSchemas(document, unusedSchemaIds); @@ -31,7 +35,7 @@ public void Apply(OpenApiDocument document, DocumentFilterContext context) private static HashSet GetUnusedSchemaIds(OpenApiDocument document) { - HashSet reachableSchemaIds = ReachableRootsCollector.Instance.CollectReachableSchemaIds(document); + var reachableSchemaIds = ReachableRootsCollector.Instance.CollectReachableSchemaIds(document); ComponentSchemaUsageCollector collector = new(document); return collector.CollectUnusedSchemaIds(reachableSchemaIds); @@ -48,8 +52,10 @@ private static void AssertNoUnknownSchemasFound(HashSet unusedSchemaIds) private static void RemoveUnusedComponentSchemas(OpenApiDocument document, HashSet unusedSchemaIds) { - foreach (string schemaId in unusedSchemaIds) + foreach (var schemaId in unusedSchemaIds) { + document.Components ??= new OpenApiComponents(); + document.Components.Schemas ??= new Dictionary(); document.Components.Schemas.Remove(schemaId); } } @@ -78,11 +84,11 @@ private sealed class ComponentSchemaReferenceVisitor : OpenApiVisitorBase { public HashSet ReachableSchemaIds { get; } = []; - public override void Visit(IOpenApiReferenceable referenceable) + public override void Visit(IOpenApiReferenceHolder referenceHolder) { if (!PathString.StartsWith(ComponentSchemaPrefix, StringComparison.Ordinal)) { - if (referenceable is OpenApiSchema schema) + if (referenceHolder is OpenApiSchemaReference schema) { ReachableSchemaIds.Add(schema.Reference.Id); } @@ -93,13 +99,15 @@ public override void Visit(IOpenApiReferenceable referenceable) private sealed class ComponentSchemaUsageCollector { - private readonly IDictionary _componentSchemas; + private readonly IDictionary _componentSchemas; private readonly HashSet _schemaIdsInUse = []; public ComponentSchemaUsageCollector(OpenApiDocument document) { ArgumentNullException.ThrowIfNull(document); + document.Components ??= new OpenApiComponents(); + document.Components.Schemas ??= new Dictionary(); _componentSchemas = document.Components.Schemas; } @@ -107,12 +115,12 @@ public HashSet CollectUnusedSchemaIds(ICollection reachableSchem { _schemaIdsInUse.Clear(); - foreach (string schemaId in reachableSchemaIds) + foreach (var schemaId in reachableSchemaIds) { WalkSchemaId(schemaId); } - HashSet unusedSchemaIds = _componentSchemas.Keys.ToHashSet(); + var unusedSchemaIds = _componentSchemas.Keys.ToHashSet(); unusedSchemaIds.ExceptWith(_schemaIdsInUse); return unusedSchemaIds; } @@ -121,14 +129,14 @@ private void WalkSchemaId(string schemaId) { if (_schemaIdsInUse.Add(schemaId)) { - if (_componentSchemas.TryGetValue(schemaId, out OpenApiSchema? schema)) + if (_componentSchemas.TryGetValue(schemaId, out var schema)) { WalkSchema(schema); } } } - private void WalkSchema(OpenApiSchema? schema) + private void WalkSchema(IOpenApiSchema? schema) { if (schema != null) { @@ -137,45 +145,45 @@ private void WalkSchema(OpenApiSchema? schema) WalkSchema(schema.Items); WalkSchema(schema.Not); - foreach (OpenApiSchema? subSchema in schema.AllOf) + foreach (var subSchema in schema?.AllOf ?? []) { WalkSchema(subSchema); } - foreach (OpenApiSchema? subSchema in schema.AnyOf) + foreach (var subSchema in schema?.AnyOf ?? []) { WalkSchema(subSchema); } - foreach (OpenApiSchema? subSchema in schema.OneOf) + foreach (var subSchema in schema?.OneOf ?? []) { WalkSchema(subSchema); } - foreach (OpenApiSchema? subSchema in schema.Properties.Values) + foreach (var subSchema in schema?.Properties?.Values ?? []) { WalkSchema(subSchema); } // ReSharper disable once TailRecursiveCall - WalkSchema(schema.AdditionalProperties); + WalkSchema(schema?.AdditionalProperties); } } - private void VisitSchema(OpenApiSchema schema) + private void VisitSchema(IOpenApiSchema schema) { - if (schema.Reference is { Type: ReferenceType.Schema, IsExternal: false }) + if (schema is OpenApiSchemaReference refSchema && refSchema.Reference is { Type: ReferenceType.Schema, IsExternal: false }) { - WalkSchemaId(schema.Reference.Id); + WalkSchemaId(refSchema.Reference.Id); } if (schema.Discriminator != null) { - foreach (string mappingValue in schema.Discriminator.Mapping.Values) + foreach (var mappingValue in schema.Discriminator.Mapping.Values) { if (mappingValue.StartsWith(ComponentSchemaPrefix, StringComparison.Ordinal)) { - string schemaId = mappingValue[ComponentSchemaPrefix.Length..]; + var schemaId = mappingValue[ComponentSchemaPrefix.Length..]; WalkSchemaId(schemaId); } } diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index d36600e878..009c7d8656 100644 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,6 +1,6 @@ - net8.0 + net10.0;net8.0 true true diff --git a/test/AnnotationTests/AnnotationTests.csproj b/test/AnnotationTests/AnnotationTests.csproj index 885e9f769c..6d2bfff1e6 100644 --- a/test/AnnotationTests/AnnotationTests.csproj +++ b/test/AnnotationTests/AnnotationTests.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0;netstandard2.0 + net10.0;net9.0;net8.0;netstandard2.0 diff --git a/test/DapperTests/DapperTests.csproj b/test/DapperTests/DapperTests.csproj index 7d41d78911..3aca3d377c 100644 --- a/test/DapperTests/DapperTests.csproj +++ b/test/DapperTests/DapperTests.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0;net9.0;net8.0 diff --git a/test/DiscoveryTests/DiscoveryTests.csproj b/test/DiscoveryTests/DiscoveryTests.csproj index 825056684e..5520a1c03a 100644 --- a/test/DiscoveryTests/DiscoveryTests.csproj +++ b/test/DiscoveryTests/DiscoveryTests.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0 diff --git a/test/JsonApiDotNetCoreTests/JsonApiDotNetCoreTests.csproj b/test/JsonApiDotNetCoreTests/JsonApiDotNetCoreTests.csproj index 6bc5a666a1..c00be8a13c 100644 --- a/test/JsonApiDotNetCoreTests/JsonApiDotNetCoreTests.csproj +++ b/test/JsonApiDotNetCoreTests/JsonApiDotNetCoreTests.csproj @@ -1,6 +1,6 @@ - + - net9.0;net8.0 + net10.0;net9.0;net8.0 @@ -18,6 +18,6 @@ - + diff --git a/test/MultiDbContextTests/MultiDbContextTests.csproj b/test/MultiDbContextTests/MultiDbContextTests.csproj index e80f03c69e..524270f7e2 100644 --- a/test/MultiDbContextTests/MultiDbContextTests.csproj +++ b/test/MultiDbContextTests/MultiDbContextTests.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0;net9.0;net8.0 diff --git a/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj b/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj index 4deb6b21cd..9ff82322ba 100644 --- a/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj +++ b/test/NoEntityFrameworkTests/NoEntityFrameworkTests.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0;net9.0;net8.0 diff --git a/test/OpenApiKiotaEndToEndTests/OpenApiKiotaEndToEndTests.csproj b/test/OpenApiKiotaEndToEndTests/OpenApiKiotaEndToEndTests.csproj index ca0db62217..43742e6311 100644 --- a/test/OpenApiKiotaEndToEndTests/OpenApiKiotaEndToEndTests.csproj +++ b/test/OpenApiKiotaEndToEndTests/OpenApiKiotaEndToEndTests.csproj @@ -1,6 +1,6 @@ - net9.0 + net10.0 diff --git a/test/OpenApiNSwagClientTests/OpenApiNSwagClientTests.csproj b/test/OpenApiNSwagClientTests/OpenApiNSwagClientTests.csproj index 35a6ae73ff..eb8adc2586 100644 --- a/test/OpenApiNSwagClientTests/OpenApiNSwagClientTests.csproj +++ b/test/OpenApiNSwagClientTests/OpenApiNSwagClientTests.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 diff --git a/test/OpenApiNSwagEndToEndTests/OpenApiNSwagEndToEndTests.csproj b/test/OpenApiNSwagEndToEndTests/OpenApiNSwagEndToEndTests.csproj index 2fc34289fa..a28de8288c 100644 --- a/test/OpenApiNSwagEndToEndTests/OpenApiNSwagEndToEndTests.csproj +++ b/test/OpenApiNSwagEndToEndTests/OpenApiNSwagEndToEndTests.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index ed2a75b5f4..771616b8fd 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0 True false $(NoWarn);1591 diff --git a/test/SourceGeneratorTests/SourceGeneratorTests.csproj b/test/SourceGeneratorTests/SourceGeneratorTests.csproj index 4f487fa168..61946fbc1a 100644 --- a/test/SourceGeneratorTests/SourceGeneratorTests.csproj +++ b/test/SourceGeneratorTests/SourceGeneratorTests.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0;net9.0;net8.0 diff --git a/test/TestBuildingBlocks/TestBuildingBlocks.csproj b/test/TestBuildingBlocks/TestBuildingBlocks.csproj index 3f16e3818e..c27c3d22b8 100644 --- a/test/TestBuildingBlocks/TestBuildingBlocks.csproj +++ b/test/TestBuildingBlocks/TestBuildingBlocks.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0;net9.0;net8.0 diff --git a/test/UnitTests/UnitTests.csproj b/test/UnitTests/UnitTests.csproj index 68076a51e1..503547d0c5 100644 --- a/test/UnitTests/UnitTests.csproj +++ b/test/UnitTests/UnitTests.csproj @@ -1,6 +1,6 @@ - net9.0;net8.0 + net10.0;net9.0;net8.0