diff --git a/.editorconfig b/.editorconfig index fc328cb5e..d650df54f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,3 +3,6 @@ # IDE0009: Member access should be qualified. dotnet_diagnostic.IDE0009.severity = none dotnet_diagnostic.CA2016.severity = warning + +[*.cs] +dotnet_public_api_analyzer.require_api_files = true \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/CryptographyExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Common/CryptographyExtensions.cs index de93a5cba..249db5591 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/CryptographyExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/CryptographyExtensions.cs @@ -22,7 +22,7 @@ public static string GetHashSHA256(this string input) Utils.CheckArgumentNull(input, nameof(input)); var inputBytes = Encoding.UTF8.GetBytes(input); - var hashBytes = hasher.Value.ComputeHash(inputBytes); + if (hasher.Value?.ComputeHash(inputBytes) is not {} hashBytes) return string.Empty; var hash = new StringBuilder(); foreach (var b in hashBytes) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs b/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs index b3cdf8ed4..1603761c7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/EdmModelHelper.cs @@ -23,7 +23,7 @@ internal static class EdmModelHelper /// Adds the derived types references together with their base type reference in the OneOf property of an OpenAPI schema. /// /// The OpenAPI schema with the list of derived types references and their base type references set in the OneOf property. - internal static OpenApiSchema GetDerivedTypesReferenceSchema(IEdmStructuredType structuredType, IEdmModel edmModel, OpenApiDocument document) + internal static OpenApiSchema? GetDerivedTypesReferenceSchema(IEdmStructuredType structuredType, IEdmModel edmModel, OpenApiDocument document) { Utils.CheckArgumentNull(structuredType, nameof(structuredType)); Utils.CheckArgumentNull(edmModel, nameof(edmModel)); @@ -38,7 +38,7 @@ internal static OpenApiSchema GetDerivedTypesReferenceSchema(IEdmStructuredType OpenApiSchema schema = new() { - OneOf = new List() + OneOf = [] }; var baseTypeSchema = new OpenApiSchemaReference(schemaElement.FullName(), document); @@ -48,7 +48,7 @@ internal static OpenApiSchema GetDerivedTypesReferenceSchema(IEdmStructuredType { var derivedTypeSchema = new OpenApiSchemaReference(derivedType.FullName(), document); schema.OneOf.Add(derivedTypeSchema); - }; + } return schema; } @@ -60,8 +60,8 @@ internal static OpenApiSchema GetDerivedTypesReferenceSchema(IEdmStructuredType /// The . /// true, if navigability is allowed, otherwise false. internal static bool NavigationRestrictionsAllowsNavigability( - NavigationRestrictionsType restrictionType, - NavigationPropertyRestriction restrictionProperty) + NavigationRestrictionsType? restrictionType, + NavigationPropertyRestriction? restrictionProperty) { // Verify using individual navigation restriction first if (restrictionProperty?.Navigability != null && restrictionProperty.Navigability.Value == NavigationType.None) @@ -82,7 +82,7 @@ internal static bool NavigationRestrictionsAllowsNavigability( /// The OData context. /// Optional: Identifier indicating whether it is a collection-valued non-indexed or single-valued navigation property. /// The operation id generated from the given navigation property path. - internal static string GenerateNavigationPropertyPathOperationId(ODataPath path, ODataContext context, string prefix = null) + internal static string? GenerateNavigationPropertyPathOperationId(ODataPath path, ODataContext context, string? prefix = null) { IList items = RetrieveNavigationPropertyPathsOperationIdSegments(path, context); @@ -95,9 +95,9 @@ internal static string GenerateNavigationPropertyPathOperationId(ODataPath path, { items[lastItemIndex] = prefix + Utils.UpperFirstChar(items[lastItemIndex]); } - else + else if (Utils.UpperFirstChar(items[lastItemIndex]) is string lastIdentifier) { - items[lastItemIndex] = Utils.UpperFirstChar(items[lastItemIndex]); + items[lastItemIndex] = lastIdentifier; } return GenerateNavigationPropertyPathOperationId(items); @@ -110,24 +110,22 @@ internal static string GenerateNavigationPropertyPathOperationId(ODataPath path, /// The OData context. /// Optional: Identifier indicating whether it is a collection-valued or single-valued complex property. /// The operation id generated from the given complex property path. - internal static string GenerateComplexPropertyPathOperationId(ODataPath path, ODataContext context, string prefix = null) + internal static string? GenerateComplexPropertyPathOperationId(ODataPath path, ODataContext context, string? prefix = null) { IList items = RetrieveNavigationPropertyPathsOperationIdSegments(path, context); if (!items.Any()) return null; - ODataComplexPropertySegment lastSegment = path.Segments.Skip(1).OfType()?.Last(); - Utils.CheckArgumentNull(lastSegment, nameof(lastSegment)); - - if (!string.IsNullOrEmpty(prefix)) - { - items.Add(prefix + Utils.UpperFirstChar(lastSegment?.Identifier)); - } - else - { - items.Add(Utils.UpperFirstChar(lastSegment?.Identifier)); - } + if (path.Segments.Skip(1).OfType()?.Last()?.Identifier is string lastSegmentIdentifier) + if (!string.IsNullOrEmpty(prefix)) + { + items.Add(prefix + Utils.UpperFirstChar(lastSegmentIdentifier)); + } + else if (Utils.UpperFirstChar(lastSegmentIdentifier) is string lastIdentifier) + { + items.Add(lastIdentifier); + } return GenerateNavigationPropertyPathOperationId(items); } @@ -137,7 +135,7 @@ internal static string GenerateComplexPropertyPathOperationId(ODataPath path, OD /// /// The list of string values. /// The generated navigation property operation id. - private static string GenerateNavigationPropertyPathOperationId(IList items) + private static string? GenerateNavigationPropertyPathOperationId(IList items) { if (!items.Any()) return null; @@ -155,10 +153,10 @@ internal static IList RetrieveNavigationPropertyPathsOperationIdSegments { Utils.CheckArgumentNull(path, nameof(path)); - IEdmNavigationSource navigationSource = (path.FirstSegment as ODataNavigationSourceSegment)?.NavigationSource; - Utils.CheckArgumentNull(navigationSource, nameof(navigationSource)); + if (path.FirstSegment is not ODataNavigationSourceSegment {NavigationSource: IEdmNavigationSource navigationSource}) + throw new InvalidOperationException("The first segment of the path is not a navigation source segment."); - IList items = new List + var items = new List { navigationSource.Name }; @@ -174,7 +172,7 @@ s is ODataOperationSegment || s is ODataKeySegment); Utils.CheckArgumentNull(segments, nameof(segments)); - string previousTypeCastSegmentId = null; + string? previousTypeCastSegmentId = null; string pathHash = string.Empty; foreach (var segment in segments) @@ -185,15 +183,18 @@ s is ODataOperationSegment || } else if (segment is ODataTypeCastSegment typeCastSegment && path.Kind != ODataPathKind.TypeCast // ex: ~/NavSource/NavProp/TypeCast - && !(path.Kind == ODataPathKind.DollarCount && path.Segments.ElementAt(path.Segments.Count - 2)?.Kind == ODataSegmentKind.TypeCast)) // ex: ~/NavSource/NavProp/TypeCast/$count + && !(path.Kind == ODataPathKind.DollarCount && path.Segments[path.Segments.Count - 2]?.Kind == ODataSegmentKind.TypeCast)) // ex: ~/NavSource/NavProp/TypeCast/$count { // Only the last OData type cast segment identifier is added to the operation id - items.Remove(previousTypeCastSegmentId); - IEdmSchemaElement schemaElement = typeCastSegment.StructuredType as IEdmSchemaElement; - previousTypeCastSegmentId = "As" + Utils.UpperFirstChar(schemaElement.Name); - items.Add(previousTypeCastSegmentId); + if (!string.IsNullOrEmpty(previousTypeCastSegmentId)) + items.Remove(previousTypeCastSegmentId); + if (typeCastSegment.StructuredType is IEdmSchemaElement schemaElement) + { + previousTypeCastSegmentId = "As" + Utils.UpperFirstChar(schemaElement.Name); + items.Add(previousTypeCastSegmentId); + } } - else if (segment is ODataOperationSegment operationSegment) + else if (segment is ODataOperationSegment operationSegment && !string.IsNullOrEmpty(operationSegment.Identifier)) { // Navigation property generated via composable function if (operationSegment.Operation is IEdmFunction function && context.Model.IsOperationOverload(function)) @@ -239,19 +240,20 @@ internal static string GenerateNavigationPropertyPathTagName(ODataPath path, ODa Utils.CheckArgumentNull(path, nameof(path)); Utils.CheckArgumentNull(context, nameof(context)); - IEdmNavigationSource navigationSource = (path.FirstSegment as ODataNavigationSourceSegment)?.NavigationSource; + if (path.FirstSegment is not ODataNavigationSourceSegment {NavigationSource: IEdmNavigationSource navigationSource }) + throw new InvalidOperationException("The first segment of the path is not a navigation source segment."); - IList items = new List + var items = new List { navigationSource.Name }; - IEdmNavigationProperty navigationProperty = path.OfType()?.Last()?.NavigationProperty; - Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty)); + if (path.OfType()?.Last()?.NavigationProperty is not IEdmNavigationProperty navigationProperty) + throw new InvalidOperationException("The last segment of the path is not a navigation property segment."); - foreach (var segment in path.Segments.Skip(1).OfType()) + foreach (var segment in path.Segments.Skip(1).OfType().Select(static x => x.NavigationProperty)) { - if (segment.NavigationProperty == navigationProperty) + if (segment == navigationProperty) { items.Add(navigationProperty.ToEntityType().Name); break; @@ -260,12 +262,12 @@ internal static string GenerateNavigationPropertyPathTagName(ODataPath path, ODa { if (items.Count >= context.Settings.TagDepth - 1) { - items.Add(segment.NavigationProperty.ToEntityType().Name); + items.Add(segment.ToEntityType().Name); break; } else { - items.Add(segment.NavigationProperty.Name); + items.Add(segment.Name); } } } @@ -284,12 +286,12 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC Utils.CheckArgumentNull(path, nameof(path)); Utils.CheckArgumentNull(context, nameof(context)); - ODataComplexPropertySegment complexSegment = path.Segments.OfType()?.Last(); - Utils.CheckArgumentNull(complexSegment, nameof(complexSegment)); + if (path.Segments.OfType()?.Last() is not ODataComplexPropertySegment complexSegment) + throw new InvalidOperationException("The last segment of the path is not a complex property segment."); // Get the segment before the last complex type segment int complexSegmentIndex = path.Segments.IndexOf(complexSegment); - ODataSegment preComplexSegment = path.Segments.ElementAt(complexSegmentIndex - 1); + ODataSegment preComplexSegment = path.Segments[complexSegmentIndex - 1]; int preComplexSegmentIndex = path.Segments.IndexOf(preComplexSegment); while (preComplexSegment is ODataTypeCastSegment) @@ -297,10 +299,10 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC // Skip this segment, // Tag names don't include OData type cast segment identifiers preComplexSegmentIndex--; - preComplexSegment = path.Segments.ElementAt(preComplexSegmentIndex); + preComplexSegment = path.Segments[preComplexSegmentIndex]; } - string tagName = null; + string? tagName = null; if (preComplexSegment is ODataNavigationSourceSegment sourceSegment) { @@ -312,7 +314,7 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC } else if (preComplexSegment is ODataKeySegment) { - var prevKeySegment = path.Segments.ElementAt(preComplexSegmentIndex - 1); + var prevKeySegment = path.Segments[preComplexSegmentIndex - 1]; if (prevKeySegment is ODataNavigationPropertySegment) { tagName = GenerateNavigationPropertyPathTagName(path, context); @@ -323,9 +325,9 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC } } - List tagNameItems = tagName?.Split('.').ToList(); + List tagNameItems = tagName?.Split('.').ToList() ?? []; - if (tagNameItems.Count < context.Settings.TagDepth) + if (tagNameItems.Count < context.Settings.TagDepth && complexSegment.ComplexType is not null) { tagNameItems.Add(complexSegment.ComplexType.Name); } @@ -340,41 +342,41 @@ internal static string GenerateComplexPropertyPathTagName(ODataPath path, ODataC /// The OData context. /// Optional: Whether to include the List or Get prefix to the generated operation id. /// The operation id prefix generated from the OData type cast path. - internal static string GenerateODataTypeCastPathOperationIdPrefix(ODataPath path, ODataContext context, bool includeListOrGetPrefix = true) + internal static string? GenerateODataTypeCastPathOperationIdPrefix(ODataPath path, ODataContext context, bool includeListOrGetPrefix = true) { // Get the segment before the last OData type cast segment - ODataTypeCastSegment typeCastSegment = path.Segments.OfType()?.Last(); - Utils.CheckArgumentNull(typeCastSegment, nameof(typeCastSegment)); + if (path.Segments.OfType()?.Last() is not ODataTypeCastSegment typeCastSegment) + throw new InvalidOperationException("The last segment of the path is not a type cast segment."); int typeCastSegmentIndex = path.Segments.IndexOf(typeCastSegment); // The segment 1 place before the last OData type cast segment - ODataSegment secondLastSegment = path.Segments.ElementAt(typeCastSegmentIndex - 1); + ODataSegment secondLastSegment = path.Segments[typeCastSegmentIndex - 1]; bool isIndexedCollValuedNavProp = false; if (secondLastSegment is ODataKeySegment) { // The segment 2 places before the last OData type cast segment - ODataSegment thirdLastSegment = path.Segments.ElementAt(typeCastSegmentIndex - 2); + ODataSegment thirdLastSegment = path.Segments[typeCastSegmentIndex - 2]; if (thirdLastSegment is ODataNavigationPropertySegment) { isIndexedCollValuedNavProp = true; } } - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - IEdmSingleton singleton = navigationSourceSegment?.NavigationSource as IEdmSingleton; - IEdmEntitySet entitySet = navigationSourceSegment?.NavigationSource as IEdmEntitySet; + ODataNavigationSourceSegment? navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; + IEdmSingleton? singleton = navigationSourceSegment?.NavigationSource as IEdmSingleton; + IEdmEntitySet? entitySet = navigationSourceSegment?.NavigationSource as IEdmEntitySet; - string operationId = null; + string? operationId = null; if (secondLastSegment is ODataComplexPropertySegment complexSegment) { - string listOrGet = includeListOrGetPrefix ? (complexSegment.Property.Type.IsCollection() ? "List" : "Get") : null; + string? listOrGet = includeListOrGetPrefix ? (complexSegment.Property.Type.IsCollection() ? "List" : "Get") : null; operationId = GenerateComplexPropertyPathOperationId(path, context, listOrGet); } else if (secondLastSegment is ODataNavigationPropertySegment navPropSegment) { - string prefix = null; + string? prefix = null; if (includeListOrGetPrefix) { prefix = navPropSegment?.NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many ? "List" : "Get"; @@ -391,22 +393,34 @@ internal static string GenerateODataTypeCastPathOperationIdPrefix(ODataPath path else { string entityTypeName = keySegment.EntityType.Name; - string getPrefix = includeListOrGetPrefix ? "Get" : null; + string? getPrefix = includeListOrGetPrefix ? "Get" : null; string operationName = $"{getPrefix}{Utils.UpperFirstChar(entityTypeName)}"; if (keySegment.IsAlternateKey) { string alternateKeyName = string.Join("", keySegment.Identifier.Split(',').Select(static x => Utils.UpperFirstChar(x))); operationName = $"{operationName}By{alternateKeyName}"; } - operationId = (entitySet != null) ? entitySet.Name : singleton.Name; + if (entitySet != null) + { + operationId = entitySet.Name; + } + else if (singleton != null) + { + operationId = singleton.Name; + } operationId += $".{entityTypeName}.{operationName}"; } } else if (secondLastSegment is ODataNavigationSourceSegment) { - operationId = (entitySet != null) - ? entitySet.Name + "." + entitySet.EntityType.Name + $".{(includeListOrGetPrefix ? "List" : null)}" + Utils.UpperFirstChar(entitySet.EntityType.Name) - : singleton.Name + "." + singleton.EntityType.Name + $".{(includeListOrGetPrefix ? "Get" : null)}" + Utils.UpperFirstChar(singleton.EntityType.Name); + if (entitySet != null) + { + operationId = entitySet.Name + "." + entitySet.EntityType.Name + $".{(includeListOrGetPrefix ? "List" : null)}" + Utils.UpperFirstChar(entitySet.EntityType.Name); + } + else if (singleton != null) + { + operationId = singleton.Name + "." + singleton.EntityType.Name + $".{(includeListOrGetPrefix ? "Get" : null)}" + Utils.UpperFirstChar(singleton.EntityType.Name); + } } return operationId; @@ -419,7 +433,7 @@ internal static string GenerateODataTypeCastPathOperationIdPrefix(ODataPath path /// Optional: The Edm model. Used for searching for the namespace alias. /// The OpenAPI convert settings. /// The element name, alias-prefixed or namespace-stripped if applicable. - internal static string StripOrAliasNamespacePrefix(IEdmSchemaElement element, OpenApiConvertSettings settings, IEdmModel model = null) + internal static string StripOrAliasNamespacePrefix(IEdmSchemaElement element, OpenApiConvertSettings settings, IEdmModel? model = null) { Utils.CheckArgumentNull(element, nameof(element)); Utils.CheckArgumentNull(settings, nameof(settings)); diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs index 5d5e6ca7e..592100fe7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/OpenApiOperationExtensions.cs @@ -24,7 +24,7 @@ internal static class OpenApiOperationExtensions /// Optional: Whether to add a 204 no content response. /// Optional: The OpenAPI schema of the response. /// The OpenAPI document to lookup references. - public static void AddErrorResponses(this OpenApiOperation operation, OpenApiConvertSettings settings, OpenApiDocument document, bool addNoContent = false, IOpenApiSchema schema = null) + public static void AddErrorResponses(this OpenApiOperation operation, OpenApiConvertSettings settings, OpenApiDocument document, bool addNoContent = false, IOpenApiSchema? schema = null) { Utils.CheckArgumentNull(operation, nameof(operation)); Utils.CheckArgumentNull(settings, nameof(settings)); @@ -39,7 +39,7 @@ public static void AddErrorResponses(this OpenApiOperation operation, OpenApiCon { if (settings.UseSuccessStatusCodeRange) { - OpenApiResponse response = null; + OpenApiResponse? response = null; if (schema != null) { response = new() @@ -57,22 +57,25 @@ public static void AddErrorResponses(this OpenApiOperation operation, OpenApiCon } }; } - operation.Responses.Add(Constants.StatusCodeClass2XX, response ?? Constants.StatusCodeClass2XX.GetResponse(document)); + if ((response ?? Constants.StatusCodeClass2XX.GetResponse(document)) is {} x2xxResponse) + operation.Responses.Add(Constants.StatusCodeClass2XX, x2xxResponse); } - else + else if (Constants.StatusCode204.GetResponse(document) is {} x204Response) { - operation.Responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse(document)); + operation.Responses.Add(Constants.StatusCode204, x204Response); } } - if (settings.ErrorResponsesAsDefault) + if (settings.ErrorResponsesAsDefault && Constants.StatusCodeDefault.GetResponse(document) is {} defaultResponse) { - operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse(document)); + operation.Responses.Add(Constants.StatusCodeDefault, defaultResponse); } else { - operation.Responses.Add(Constants.StatusCodeClass4XX, Constants.StatusCodeClass4XX.GetResponse(document)); - operation.Responses.Add(Constants.StatusCodeClass5XX, Constants.StatusCodeClass5XX.GetResponse(document)); + if (Constants.StatusCodeClass4XX.GetResponse(document) is {} x4xxResponse) + operation.Responses.Add(Constants.StatusCodeClass4XX, x4xxResponse); + if (Constants.StatusCodeClass5XX.GetResponse(document) is {} x5xxResponse) + operation.Responses.Add(Constants.StatusCodeClass5XX, x5xxResponse); } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs b/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs index d5db7aa58..8f27b9d7b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Common/Utils.cs @@ -28,10 +28,10 @@ public static class Utils /// /// The type of the term. /// The qualified name. - public static string GetTermQualifiedName() + public static string? GetTermQualifiedName() { object[] attributes = typeof(T).GetCustomAttributes(typeof(TermAttribute), false); - if (attributes == null && attributes.Length == 0) + if (attributes == null || attributes.Length == 0) { return null; } @@ -45,7 +45,7 @@ public static string GetTermQualifiedName() /// /// The input string. /// The changed string. - public static string UpperFirstChar(string input) + public static string? UpperFirstChar(string? input) { if (input == null) { @@ -129,7 +129,7 @@ internal static string ToFirstCharacterLowerCase(this string input) /// /// The . /// Optional: The navigation property name. - internal static string NavigationPropertyPath(this ODataPath path, string navigationPropertyName = null) + internal static string NavigationPropertyPath(this ODataPath path, string? navigationPropertyName = null) { string value = string.Join("/", path.Segments.OfType().Select(e => e.Identifier)); @@ -176,7 +176,7 @@ private static Dictionary GetCustomXMLAttributesValueMapping(IEd { Dictionary attributesValueMap = new(); - if ((!customXMLAttributesMapping?.Any() ?? true) || + if (customXMLAttributesMapping is not {Count:>0} || model == null || element == null) { @@ -187,10 +187,10 @@ private static Dictionary GetCustomXMLAttributesValueMapping(IEd { string attributeName = item.Key.Split(':').Last(); // example, 'ags:IsHidden' --> 'IsHidden' string extensionName = item.Value; - EdmStringConstant customXMLAttribute = model.DirectValueAnnotationsManager.GetDirectValueAnnotations(element)? + var customXMLAttribute = model.DirectValueAnnotationsManager.GetDirectValueAnnotations(element)? .Where(x => x.Name.Equals(attributeName, StringComparison.OrdinalIgnoreCase))? .FirstOrDefault()?.Value as EdmStringConstant; - string attributeValue = customXMLAttribute?.Value; + var attributeValue = customXMLAttribute?.Value; if (!string.IsNullOrEmpty(attributeValue)) { @@ -212,10 +212,10 @@ private static Dictionary GetCustomXMLAttributesValueMapping(IEd internal static bool IsBaseTypeReferencedAsTypeInModel( this IEdmModel model, IEdmStructuredType baseType, - IEnumerable structuredTypes = null, - IEnumerable actions = null) + IEnumerable? structuredTypes = null, + IEnumerable? actions = null) { - string baseTypeName = baseType?.FullTypeName(); + string baseTypeName = baseType.FullTypeName(); bool isBaseTypeEntity = Constants.EntityName.Equals(baseTypeName?.Split('.').Last(), StringComparison.OrdinalIgnoreCase); if (!string.IsNullOrEmpty(baseTypeName) && !isBaseTypeEntity) @@ -253,7 +253,7 @@ internal static bool IsBaseTypeReferencedAsTypeInModel( /// /// The target . /// The entity type of the target . - internal static IEdmEntityType EntityTypeFromPathSegment(this ODataSegment segment) + internal static IEdmEntityType? EntityTypeFromPathSegment(this ODataSegment segment) { CheckArgumentNull(segment, nameof(segment)); @@ -279,12 +279,12 @@ internal static IEdmEntityType EntityTypeFromPathSegment(this ODataSegment segme /// /// The target . /// The entity type of the target . - private static IEdmEntityType EntityTypeFromOperationSegment(this ODataSegment segment) + private static IEdmEntityType? EntityTypeFromOperationSegment(this ODataSegment segment) { CheckArgumentNull(segment, nameof(segment)); if (segment is ODataOperationSegment operationSegment && - operationSegment.Operation.Parameters.FirstOrDefault() is IEdmOperationParameter bindingParameter) + operationSegment.Operation?.Parameters.FirstOrDefault() is IEdmOperationParameter bindingParameter) { IEdmTypeReference bindingType = bindingParameter.Type; @@ -339,10 +339,10 @@ internal static bool TryAddPath(this IDictionary pathI } ODataSegment lastSecondSegment = path.Segments.ElementAt(path.Count - secondLastSegmentIndex); - IEdmEntityType boundEntityType = lastSecondSegment?.EntityTypeFromPathSegment(); + var boundEntityType = lastSecondSegment?.EntityTypeFromPathSegment(); - IEdmEntityType operationEntityType = lastSegment.EntityTypeFromOperationSegment(); - IEnumerable derivedTypes = (operationEntityType != null) + var operationEntityType = lastSegment.EntityTypeFromOperationSegment(); + var derivedTypes = (operationEntityType != null) ? context.Model.FindAllDerivedTypes(operationEntityType) : null; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs index 97ed1cb64..901079bef 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmAnnotationExtensions.cs @@ -21,9 +21,9 @@ namespace Microsoft.OpenApi.OData.Edm /// internal static class EdmVocabularyAnnotationExtensions { - private static IDictionary> _cachedAnnotations; - private static IEdmModel _savedModel = null; // if diffenent model, the cache will be cleaned. - private static object _objectLock = new object(); + private static IDictionary>? _cachedAnnotations; + private static IEdmModel? _savedModel = null; // if different model, the cache will be cleaned. + private static readonly object _objectLock = new object(); /// /// Gets the boolean term value for the given . @@ -54,8 +54,7 @@ internal static class EdmVocabularyAnnotationExtensions // Note: Graph has a lot of annotations applied to the type, not to the navigation source. // Here's a work around to retrieve these annotations from type if we can't find it from navigation source. // It's the same reason for belows - IEdmNavigationSource navigationSource = target as IEdmNavigationSource; - if (navigationSource != null) + if (target is IEdmNavigationSource navigationSource) { IEdmEntityType entityType = navigationSource.EntityType; value = model.GetBoolean(entityType, term); @@ -87,7 +86,7 @@ internal static class EdmVocabularyAnnotationExtensions /// The Edm target. /// The Term qualified name. /// Null or the string value for this annotation. - public static string GetString(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) + public static string? GetString(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(target, nameof(target)); @@ -95,7 +94,7 @@ public static string GetString(this IEdmModel model, IEdmVocabularyAnnotatable t return GetOrAddCached(model, target, qualifiedName, () => { - string value = null; + string? value = null; IEdmTerm term = model.FindTerm(qualifiedName); if (term != null) { @@ -106,8 +105,7 @@ public static string GetString(this IEdmModel model, IEdmVocabularyAnnotatable t } else { - IEdmNavigationSource navigationSource = target as IEdmNavigationSource; - if (navigationSource != null) + if (target is IEdmNavigationSource navigationSource) { IEdmEntityType entityType = navigationSource.EntityType; value = model.GetString(entityType, term); @@ -127,11 +125,10 @@ public static string GetString(this IEdmModel model, IEdmVocabularyAnnotatable t /// The Edm model. /// The target element. /// Null or the record value (a complex type) for this annotation. - public static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target) - where T : IRecord, new() + public static T? GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target) + where T : class, IRecord, new() { - string qualifiedName = Utils.GetTermQualifiedName(); - return model.GetRecord(target, qualifiedName); + return Utils.GetTermQualifiedName() is string qualifiedName ? model.GetRecord(target, qualifiedName) : null; } /// @@ -142,8 +139,8 @@ public static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable tar /// The Edm target. /// The Term qualified name. /// Null or the record value (a complex type) for this annotation. - public static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) - where T : IRecord, new() + public static T? GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) + where T : class, IRecord, new() { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(target, nameof(target)); @@ -151,7 +148,7 @@ public static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable tar return GetOrAddCached(model, target, qualifiedName, () => { - T value = default; + T? value = default; IEdmTerm term = model.FindTerm(qualifiedName); if (term != null) { @@ -162,8 +159,7 @@ public static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable tar } else { - IEdmNavigationSource navigationSource = target as IEdmNavigationSource; - if (navigationSource != null) + if (target is IEdmNavigationSource navigationSource) { IEdmEntityType entityType = navigationSource.EntityType; value = model.GetRecord(entityType, term); @@ -183,8 +179,8 @@ public static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable tar /// The string representation of the Edm target path. /// The Term qualified name. /// - public static T GetRecord(this IEdmModel model, string targetPath, string qualifiedName) - where T : IRecord, new() + public static T? GetRecord(this IEdmModel model, string targetPath, string qualifiedName) + where T : class, IRecord, new() { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -204,7 +200,7 @@ public static T GetRecord(this IEdmModel model, string targetPath, string qua /// The Edm target. /// The Term qualified name. /// Null or the collection of string value for this annotation. - public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) + public static IEnumerable? GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(target, nameof(target)); @@ -212,7 +208,7 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabu return GetOrAddCached(model, target, qualifiedName, () => { - IEnumerable value = null; + IEnumerable? value = null; IEdmTerm term = model.FindTerm(qualifiedName); if (term != null) { @@ -223,8 +219,7 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabu } else { - IEdmNavigationSource navigationSource = target as IEdmNavigationSource; - if (navigationSource != null) + if (target is IEdmNavigationSource navigationSource) { IEdmEntityType entityType = navigationSource.EntityType; value = model.GetCollection(entityType, term); @@ -244,11 +239,10 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabu /// The Edm model. /// The Edm target. /// Null or the colllection of record value (a complex type) for this annotation. - public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target) + public static IEnumerable? GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target) where T : IRecord, new() { - string qualifiedName = Utils.GetTermQualifiedName(); - return GetCollection(model, target, qualifiedName); + return Utils.GetTermQualifiedName() is string qualifiedName ? GetCollection(model, target, qualifiedName) : null; } /// @@ -259,7 +253,7 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabula /// The Edm target. /// The Term qualified name. /// Null or the colllection of record value (a complex type) for this annotation. - public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) + public static IEnumerable? GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName) where T : IRecord, new() { Utils.CheckArgumentNull(model, nameof(model)); @@ -268,7 +262,7 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabula return GetOrAddCached(model, target, qualifiedName, () => { - IEnumerable value = null; + IEnumerable? value = null; IEdmTerm term = model.FindTerm(qualifiedName); if (term != null) { @@ -279,8 +273,7 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabula } else { - IEdmNavigationSource navigationSource = target as IEdmNavigationSource; - if (navigationSource != null) + if (target is IEdmNavigationSource navigationSource) { IEdmEntityType entityType = navigationSource.EntityType; value = model.GetCollection(entityType, term); @@ -299,10 +292,11 @@ public static IEnumerable GetCollection(this IEdmModel model, IEdmVocabula /// The Edm target. /// The link relation type for path operation. /// Null or the links record value (a complex type) for this annotation. - public static LinkType GetLinkRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, string linkRel) + public static LinkType? GetLinkRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, string linkRel) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(target, nameof(target)); + Utils.CheckArgumentNull(linkRel, nameof(linkRel)); return model.GetCollection(target, CoreConstants.Links)?.FirstOrDefault(x => x.Rel == linkRel); } @@ -314,7 +308,7 @@ public static LinkType GetLinkRecord(this IEdmModel model, IEdmVocabularyAnnotat /// The string representation of the Edm target path. /// The link relation type for path operation. /// Null or the links record value (a complex type) for this annotation. - public static LinkType GetLinkRecord(this IEdmModel model, string targetPath, string linkRel) + public static LinkType? GetLinkRecord(this IEdmModel model, string targetPath, string linkRel) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -332,7 +326,7 @@ public static LinkType GetLinkRecord(this IEdmModel model, string targetPath, st /// The Edm model. /// The Edm target. /// The created object. - public static IEnumerable GetAuthorizations(this IEdmModel model, IEdmVocabularyAnnotatable target) + public static IEnumerable? GetAuthorizations(this IEdmModel model, IEdmVocabularyAnnotatable target) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(target, nameof(target)); @@ -342,7 +336,7 @@ public static IEnumerable GetAuthorizations(this IEdmModel model, IEdmTerm term = model.FindTerm(AuthorizationConstants.Authorizations); if (term != null) { - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); + IEdmVocabularyAnnotation? annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.Collection) { IEdmCollectionExpression collection = (IEdmCollectionExpression)annotation.Value; @@ -353,9 +347,8 @@ public static IEnumerable GetAuthorizations(this IEdmModel model, Debug.Assert(e.ExpressionKind == EdmExpressionKind.Record); IEdmRecordExpression recordExpression = (IEdmRecordExpression)e; - Authorization auth = Authorization.CreateAuthorization(recordExpression); - return auth; - }); + return Authorization.CreateAuthorization(recordExpression); + }).OfType(); } } } @@ -364,7 +357,7 @@ public static IEnumerable GetAuthorizations(this IEdmModel model, }); } - public static string GetDescriptionAnnotation(this IEdmModel model, string targetPath) + public static string? GetDescriptionAnnotation(this IEdmModel model, string targetPath) { Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -376,7 +369,7 @@ public static string GetDescriptionAnnotation(this IEdmModel model, string targe return model.GetDescriptionAnnotation(target); } - private static T GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName, Func createFunc) + private static T? GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName, Func createFunc) { if (model == null || target == null) { @@ -400,8 +393,8 @@ private static T GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatab _cachedAnnotations = new Dictionary>(); } - object restriction; - if (_cachedAnnotations.TryGetValue(target, out IDictionary value)) + object? restriction; + if (_cachedAnnotations.TryGetValue(target, out var value)) { // Here means we visited target before and we are sure that the value is not null. if (value.TryGetValue(qualifiedName, out restriction)) @@ -409,9 +402,8 @@ private static T GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatab T ret = (T)restriction; return ret; } - else + else if (createFunc() is T ret) { - T ret = createFunc(); value[qualifiedName] = ret; return ret; } @@ -420,9 +412,12 @@ private static T GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatab // It's first time to query this target, create new dictionary and restriction. value = new Dictionary(); _cachedAnnotations[target] = value; - T newAnnotation = createFunc(); - value[qualifiedName] = newAnnotation; - return newAnnotation; + if (createFunc() is T newAnnotation) + { + value[qualifiedName] = newAnnotation; + return newAnnotation; + } + return default; } } @@ -432,7 +427,7 @@ private static T GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatab Debug.Assert(target != null); Debug.Assert(term != null); - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); + IEdmVocabularyAnnotation? annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.BooleanConstant) { IEdmBooleanConstantExpression boolConstant = (IEdmBooleanConstantExpression)annotation.Value; @@ -445,13 +440,13 @@ private static T GetOrAddCached(this IEdmModel model, IEdmVocabularyAnnotatab return null; } - private static string GetString(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) + private static string? GetString(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) { Debug.Assert(model != null); Debug.Assert(target != null); Debug.Assert(term != null); - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); + IEdmVocabularyAnnotation? annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.StringConstant) { IEdmStringConstantExpression stringConstant = (IEdmStringConstantExpression)annotation.Value; @@ -461,13 +456,13 @@ private static string GetString(this IEdmModel model, IEdmVocabularyAnnotatable return null; } - private static IEnumerable GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) + private static IEnumerable? GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) { Debug.Assert(model != null); Debug.Assert(target != null); Debug.Assert(term != null); - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); + IEdmVocabularyAnnotation? annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.Collection) { IEdmCollectionExpression collection = (IEdmCollectionExpression)annotation.Value; @@ -480,14 +475,14 @@ private static IEnumerable GetCollection(this IEdmModel model, IEdmVocab return null; } - private static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) + private static T? GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) where T : IRecord, new() { Debug.Assert(model != null); Debug.Assert(target != null); Debug.Assert(term != null); - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); + IEdmVocabularyAnnotation? annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.Record) { IEdmRecordExpression recordExpression = (IEdmRecordExpression)annotation.Value; @@ -499,14 +494,14 @@ private static T GetRecord(this IEdmModel model, IEdmVocabularyAnnotatable ta return default; } - private static IEnumerable GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) + private static IEnumerable? GetCollection(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term) where T : IRecord, new() { Debug.Assert(model != null); Debug.Assert(target != null); Debug.Assert(term != null); - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); + IEdmVocabularyAnnotation? annotation = model.FindVocabularyAnnotations(target, term).FirstOrDefault(); if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.Collection) { IEdmCollectionExpression collection = (IEdmCollectionExpression)annotation.Value; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs index 3ece9f1f6..6c3650578 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs @@ -48,7 +48,7 @@ private static bool IsUrlEscapeFunction(this IEdmModel model, IEdmFunction funct Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(function, nameof(function)); - IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations(function, + var annotation = model.FindVocabularyAnnotations(function, CommunityVocabularyModel.UrlEscapeFunctionTerm).FirstOrDefault(); if (annotation != null) { @@ -58,12 +58,11 @@ private static bool IsUrlEscapeFunction(this IEdmModel model, IEdmFunction funct return true; } - IEdmBooleanConstantExpression tagConstant = annotation.Value as IEdmBooleanConstantExpression; - if (tagConstant != null) - { - return tagConstant.Value; - } - } + if (annotation.Value is IEdmBooleanConstantExpression tagConstant) + { + return tagConstant.Value; + } + } return false; } @@ -73,16 +72,16 @@ private static bool IsUrlEscapeFunction(this IEdmModel model, IEdmFunction funct /// /// The Edm model. /// The dictionary. - public static IDictionary> LoadAllNavigationSources(this IEdmModel model) + public static Dictionary> LoadAllNavigationSources(this IEdmModel model) { var navigationSourceDic = new Dictionary>(); if (model != null && model.EntityContainer != null) { Action>> action = (ns, dic) => { - if (!dic.TryGetValue(ns.EntityType, out IList value)) + if (!dic.TryGetValue(ns.EntityType, out var value)) { - value = new List(); + value = []; dic[ns.EntityType] = value; } @@ -96,9 +95,9 @@ public static IDictionary> LoadAllNa } // singleton - foreach (var singelton in model.EntityContainer.Singletons()) + foreach (var singleton in model.EntityContainer.Singletons()) { - action(singelton, navigationSourceDic); + action(singleton, navigationSourceDic); } } @@ -114,7 +113,7 @@ public static IEnumerable FindAllBaseTypes(this IEdmEntityType e { if (entityType == null) { - yield return null; + yield break; } IEdmEntityType current = entityType.BaseEntityType(); @@ -134,7 +133,7 @@ public static IEnumerable FindAllBaseTypes(this IEdmComplexType { if (complexType == null) { - yield return null; + yield break; } IEdmComplexType current = complexType.BaseComplexType(); diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmOperationProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmOperationProvider.cs index fd928476a..d62a24c24 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmOperationProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmOperationProvider.cs @@ -13,7 +13,7 @@ namespace Microsoft.OpenApi.OData.Edm { internal class EdmOperationProvider { - private Lazy>> _boundEdmOperations; + private readonly Lazy>> _boundEdmOperations; /// /// Gets the Edm model. @@ -31,7 +31,7 @@ public EdmOperationProvider(IEdmModel model) Model = model; _boundEdmOperations = new Lazy>>( - () => LoadEdmOperations(), isThreadSafe: false); + LoadEdmOperations, isThreadSafe: false); } public IDictionary> Operations => _boundEdmOperations.Value; @@ -42,20 +42,19 @@ public EdmOperationProvider(IEdmModel model) /// The binding entity type. /// The collection or not. /// The found Edm operations. - public IEnumerable FindOperations(IEdmEntityType entityType, bool collection) + public IEnumerable? FindOperations(IEdmEntityType entityType, bool collection) { Utils.CheckArgumentNull(entityType, nameof(entityType)); string fullTypeName = collection ? "Collection(" + entityType.FullName() + ")" : entityType.FullName(); - IList edmOperations; - _boundEdmOperations.Value.TryGetValue(fullTypeName, out edmOperations); + if (!_boundEdmOperations.Value.TryGetValue(fullTypeName, out var edmOperations)) return null; foreach (IEdmEntityType derived in Model.FindAllDerivedTypes(entityType).OfType()) { string subFullTypeName = collection ? "Collection(" + derived.FullName() + ")" : derived.FullName(); - if (_boundEdmOperations.Value.TryGetValue(subFullTypeName, out IList edmSubOperations)) + if (_boundEdmOperations.Value.TryGetValue(subFullTypeName, out var edmSubOperations)) { foreach(var edmOperation in edmSubOperations) { @@ -77,9 +76,9 @@ private IDictionary> LoadEdmOperations() string bindingTypeName = bindingParameter.Type.FullName(); - if (!edmOperationDict.TryGetValue(bindingTypeName, out IList value)) + if (!edmOperationDict.TryGetValue(bindingTypeName, out var value)) { - value = new List(); + value = []; edmOperationDict[bindingTypeName] = value; } value.Add(edmOperation); diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataComplexPropertySegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataComplexPropertySegment.cs index 5c74f5b1e..904935fdd 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataComplexPropertySegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataComplexPropertySegment.cs @@ -26,7 +26,7 @@ public ODataComplexPropertySegment(IEdmStructuralProperty property) } /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.ComplexProperty; @@ -42,13 +42,13 @@ public ODataComplexPropertySegment(IEdmStructuralProperty property) /// /// Gets the type definition of the property this segment was inserted for. /// - public IEdmComplexType ComplexType => + public IEdmComplexType? ComplexType => (Property.Type.IsCollection() ? Property.Type.Definition.AsElementType() : Property.Type.AsComplex().Definition) as IEdmComplexType; /// public override IEnumerable GetAnnotables() { - return new IEdmVocabularyAnnotatable[] { Property, ComplexType }.Union(ComplexType.FindAllBaseTypes()); + return new IEdmVocabularyAnnotatable[] { Property }.Union(ComplexType is null ? [] : [ComplexType]).Union(ComplexType?.FindAllBaseTypes() ?? []); } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs index 300accc9f..1441a32fd 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataContext.cs @@ -9,6 +9,7 @@ using Microsoft.OData.Edm; using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Generator; @@ -24,7 +25,7 @@ namespace Microsoft.OpenApi.OData.Edm /// internal class ODataContext { - private IEnumerable _allPaths; + private IEnumerable? _allPaths; private readonly IODataPathProvider _pathProvider; /// @@ -135,7 +136,7 @@ public IEnumerable AllPaths /// /// Gets all tags. /// - public ISet Tags { get; private set; } + public ISet? Tags { get; private set; } /// /// Append tag. @@ -145,7 +146,7 @@ internal void AppendTag(OpenApiTag tagItem) { Tags ??= new HashSet(); - if (FindTagByName(tagItem.Name) is not null) + if (tagItem.Name is not null && FindTagByName(tagItem.Name) is not null) { return; } @@ -158,7 +159,7 @@ internal void AppendTag(OpenApiTag tagItem) /// /// The name to lookup the tag. /// - internal OpenApiTag FindTagByName(string name) + internal OpenApiTag? FindTagByName(string name) { Utils.CheckArgumentNullOrEmpty(name, nameof(name)); return Tags?.FirstOrDefault(t => StringComparer.Ordinal.Equals(t.Name, name)); @@ -180,11 +181,13 @@ internal void AddExtensionToTag(string tagName, string extensionName, OpenApiAny if (FindTagByName(tagName) is {} foundTag) { + foundTag.Extensions ??= new Dictionary(); foundTag.Extensions.TryAdd(extensionName, extensionValue); } else { var tag = initialValueFactory(); + tag.Extensions ??= new Dictionary(); tag.Extensions.TryAdd(extensionName, extensionValue); AppendTag(tag); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs index ac0a04d27..841df8cd3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataDollarCountSegment.cs @@ -17,10 +17,10 @@ public class ODataDollarCountSegment : ODataSegment /// /// Get the static instance of $count segment. /// - internal static ODataDollarCountSegment Instance = new(); + internal static readonly ODataDollarCountSegment Instance = new(); /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.DollarCount; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs index 3af32c2fa..748b5b811 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataKeySegment.cs @@ -45,7 +45,7 @@ public ODataKeySegment(IEdmEntityType entityType, IDictionary ke /// /// Gets the key/template mappings. /// - public IDictionary KeyMappings { get; } + public IDictionary? KeyMappings { get; } /// public override IEdmEntityType EntityType { get; } @@ -59,7 +59,7 @@ public override string Identifier get { IList keys = IsAlternateKey ? - KeyMappings.Values.ToList() : + KeyMappings?.Values.ToList() ?? [] : EntityType.Key().Select(static x => x.Name).ToList(); return string.Join(",", keys); diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataMetadataSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataMetadataSegment.cs index 859c30dec..ab28b7668 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataMetadataSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataMetadataSegment.cs @@ -16,7 +16,7 @@ namespace Microsoft.OpenApi.OData.Edm public class ODataMetadataSegment : ODataSegment { /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.Metadata; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationPropertySegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationPropertySegment.cs index 69ea6f562..6c725f58f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationPropertySegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationPropertySegment.cs @@ -42,7 +42,7 @@ public ODataNavigationPropertySegment(IEdmNavigationProperty navigationProperty) /// public override IEnumerable GetAnnotables() { - return new IEdmVocabularyAnnotatable[] { NavigationProperty, EntityType }.Union(EntityType.FindAllBaseTypes()); + return new IEdmVocabularyAnnotatable[] { NavigationProperty, EntityType }.Union(EntityType.FindAllBaseTypes() ?? []); } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationSourceSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationSourceSegment.cs index 8981af686..a4143d504 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationSourceSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataNavigationSourceSegment.cs @@ -42,7 +42,9 @@ public ODataNavigationSourceSegment(IEdmNavigationSource navigationSource) /// public override IEnumerable GetAnnotables() { - return new IEdmVocabularyAnnotatable[] { NavigationSource as IEdmVocabularyAnnotatable, EntityType }.Union(EntityType.FindAllBaseTypes()); + return (NavigationSource is IEdmVocabularyAnnotatable source ? new IEdmVocabularyAnnotatable[]{source} : []) + .Union([EntityType]) + .Union(EntityType.FindAllBaseTypes()); } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationImportSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationImportSegment.cs index 4a8ebd51f..ee2b70df0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationImportSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationImportSegment.cs @@ -41,7 +41,7 @@ public ODataOperationImportSegment(IEdmOperationImport operationImport, IDiction /// /// Gets the parameter mappings. /// - public IDictionary ParameterMappings { get; } + public IDictionary? ParameterMappings { get; } /// /// Gets the operation import. @@ -49,7 +49,7 @@ public ODataOperationImportSegment(IEdmOperationImport operationImport, IDiction public IEdmOperationImport OperationImport { get; } /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.OperationImport; @@ -60,7 +60,7 @@ public ODataOperationImportSegment(IEdmOperationImport operationImport, IDiction /// public override IEnumerable GetAnnotables() { - return new IEdmVocabularyAnnotatable[] { OperationImport }; + return [OperationImport]; } /// @@ -68,15 +68,15 @@ public override string GetPathItemName(OpenApiConvertSettings settings, HashSet< { Utils.CheckArgumentNull(settings, nameof(settings)); - if (OperationImport.IsFunctionImport()) + if (OperationImport.IsFunctionImport() && OperationImport is IEdmFunctionImport edmFunctionImport) { - return FunctionImportName(OperationImport as IEdmFunctionImport, settings, parameters); + return FunctionImportName(edmFunctionImport, settings, parameters); } return OperationImport.Name; } - private string FunctionImportName(IEdmFunctionImport functionImport, OpenApiConvertSettings settings, HashSet parameters) + private static string FunctionImportName(IEdmFunctionImport functionImport, OpenApiConvertSettings settings, HashSet parameters) { StringBuilder functionName = new StringBuilder(functionImport.Name); functionName.Append("("); diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs index 6ad4a2b5b..fabee69ce 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataOperationSegment.cs @@ -72,17 +72,17 @@ public ODataOperationSegment(IEdmOperation operation, bool isEscapedFunction, IE _model = model ?? throw Error.ArgumentNull(nameof(model)); } - private readonly IEdmModel _model; + private readonly IEdmModel? _model; /// /// Gets the parameter mappings. /// - public IDictionary ParameterMappings { get; } + public IDictionary? ParameterMappings { get; } /// /// Gets the operation. /// - public IEdmOperation Operation { get; } + public IEdmOperation? Operation { get; } /// /// Gets the is escaped function. @@ -93,31 +93,30 @@ public ODataOperationSegment(IEdmOperation operation, bool isEscapedFunction, IE public override ODataSegmentKind Kind => ODataSegmentKind.Operation; /// - public override string Identifier { get => Operation.Name; } + public override string? Identifier { get => Operation?.Name; } /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// - public override string GetPathItemName(OpenApiConvertSettings settings, HashSet parameters) + public override string? GetPathItemName(OpenApiConvertSettings settings, HashSet parameters) { Utils.CheckArgumentNull(settings, nameof(settings)); - if (Operation.IsFunction()) + if (Operation is IEdmFunction function) { - return FunctionName(Operation as IEdmFunction, settings, parameters); + return FunctionName(function, settings, parameters); } - return OperationName(Operation, settings); + return Operation is null ? null : OperationName(Operation, settings); } internal IDictionary GetNameMapping(OpenApiConvertSettings settings, HashSet parameters) { IDictionary parameterNamesMapping = new Dictionary(); - if (Operation.IsFunction()) + if (Operation is IEdmFunction function) { - IEdmFunction function = Operation as IEdmFunction; if (settings.EnableUriEscapeFunctionCall && IsEscapedFunction) { string parameterName = function.Parameters.Last().Name; @@ -156,8 +155,6 @@ private string FunctionName(IEdmFunction function, OpenApiConvertSettings settin { if (settings.EnableUriEscapeFunctionCall && IsEscapedFunction) { - // Debug.Assert(function.Parameters.Count == 2); It should be verify at Edm model. - // Debug.Assert(function.IsBound == true); string parameterName = function.Parameters.Last().Name; string uniqueName = Utils.GetUniqueName(parameterName, parameters); if (function.IsComposable) @@ -172,7 +169,7 @@ private string FunctionName(IEdmFunction function, OpenApiConvertSettings settin StringBuilder functionName = new(); functionName.Append(OperationName(function, settings)); - functionName.Append("("); + functionName.Append('('); int skip = function.IsBound ? 1 : 0; functionName.Append(string.Join(",", function.Parameters.Skip(skip).Select(p => @@ -184,7 +181,7 @@ private string FunctionName(IEdmFunction function, OpenApiConvertSettings settin : p.Name + $"={quote}{{{uniqueName}}}{quote}"; }))); - functionName.Append(")"); + functionName.Append(')'); return functionName.ToString(); } @@ -192,7 +189,7 @@ private string FunctionName(IEdmFunction function, OpenApiConvertSettings settin /// public override IEnumerable GetAnnotables() { - return new IEdmVocabularyAnnotatable[] { Operation }; + return Operation is null ? [] : [Operation]; } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs index e3a28619c..5ae52b2fa 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPath.cs @@ -20,7 +20,7 @@ namespace Microsoft.OpenApi.OData.Edm public class ODataPath : IEnumerable, IComparable { private ODataPathKind? _pathKind; - private string _defaultPathItemName; + private string? _defaultPathItemName; /// /// Initializes a new instance of class. @@ -54,7 +54,7 @@ public ODataPath(params ODataSegment[] segments) /// Gets/Sets the path template for this path. /// If it is set, it will be used to generate the path item. /// - public string PathTemplate { get; set; } + public string? PathTemplate { get; set; } /// /// Gets the segments. @@ -80,12 +80,12 @@ public virtual ODataPathKind Kind /// /// Gets the first segment in the path. Returns null if the path is empty. /// - public ODataSegment FirstSegment => Segments.Count == 0 ? null : Segments[0]; + public ODataSegment? FirstSegment => Segments is null || Segments.Count == 0 ? null : Segments[0]; /// /// Get the last segment in the path. Returns null if the path is empty. /// - public ODataSegment LastSegment => Segments.Count == 0 ? null : this.Segments[Segments.Count - 1]; + public ODataSegment? LastSegment => Segments is null || Segments.Count == 0 ? null : this.Segments[Segments.Count - 1]; /// /// Get the number of segments in this path. @@ -150,35 +150,34 @@ public string GetPathItemName(OpenApiConvertSettings settings) if (!string.IsNullOrWhiteSpace(settings.PathPrefix)) { - sb.Append("/"); + sb.Append('/'); sb.Append(settings.PathPrefix); } foreach (var segment in Segments) { - string pathItemName = segment.GetPathItemName(settings, parameters); + var pathItemName = segment.GetPathItemName(settings, parameters); if (segment is ODataKeySegment keySegment && (settings.EnableKeyAsSegment == null || !settings.EnableKeyAsSegment.Value || keySegment.IsAlternateKey)) { - sb.Append("("); + sb.Append('('); sb.Append(pathItemName); - sb.Append(")"); + sb.Append(')'); } else // other segments { - if (segment.Kind == ODataSegmentKind.Operation) + if (segment.Kind == ODataSegmentKind.Operation && + segment is ODataOperationSegment operation && + operation.IsEscapedFunction && + settings.EnableUriEscapeFunctionCall) { - ODataOperationSegment operation = (ODataOperationSegment)segment; - if (operation.IsEscapedFunction && settings.EnableUriEscapeFunctionCall) - { - sb.Append(":/"); - sb.Append(pathItemName); - continue; - } + sb.Append(":/"); + sb.Append(pathItemName); + continue; } - sb.Append("/"); + sb.Append('/'); sb.Append(pathItemName); } } @@ -204,10 +203,7 @@ internal bool SupportHttpMethod(string method) /// The whole path object. internal ODataPath Push(ODataSegment segment) { - if (Segments == null) - { - Segments = new List(); - } + Segments ??= []; _pathKind = null; _defaultPathItemName = null; @@ -290,7 +286,7 @@ public override string ToString() return PathTemplate; } - return "/" + String.Join("/", Segments.Select(e => e.Kind)); + return "/" + string.Join("/", Segments.Select(e => e.Kind)); } /// @@ -298,9 +294,9 @@ public override string ToString() /// /// The compare to ODataPath. /// true/false - public int CompareTo(ODataPath other) + public int CompareTo(ODataPath? other) { - return GetPathItemName().CompareTo(other.GetPathItemName()); + return GetPathItemName().CompareTo(other?.GetPathItemName()); } private ODataPathKind CalcPathType() @@ -365,7 +361,7 @@ private ODataPathKind CalcPathType() /// /// The settings. ///The suffix. - public string GetPathHash(OpenApiConvertSettings settings) => - LastSegment.GetPathHash(settings, this); + public string? GetPathHash(OpenApiConvertSettings settings) => + LastSegment?.GetPathHash(settings, this); } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs index d9275aebc..c2d5c79d9 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs @@ -19,17 +19,17 @@ namespace Microsoft.OpenApi.OData.Edm /// public class ODataPathProvider : IODataPathProvider { - private IDictionary> _allNavigationSources; + private Dictionary>? _allNavigationSources; - private IDictionary> _allNavigationSourcePaths = + private readonly IDictionary> _allNavigationSourcePaths = new Dictionary>(); - private IDictionary> _allNavigationPropertyPaths = + private readonly IDictionary> _allNavigationPropertyPaths = new Dictionary>(); - private IList _allOperationPaths = new List(); + private readonly List _allOperationPaths = []; - private IEdmModel _model; + private IEdmModel? _model; private readonly IDictionary> _dollarCountPaths = new Dictionary>(); @@ -52,39 +52,45 @@ public virtual IEnumerable GetPaths(IEdmModel model, OpenApiConvertSe { if (model == null || model.EntityContainer == null) { - return Enumerable.Empty(); + return []; } Initialize(model); - // entity set - foreach (IEdmEntitySet entitySet in _model.EntityContainer.EntitySets()) + if (_model is not null) { - if (CanFilter(entitySet)) - { - RetrieveNavigationSourcePaths(entitySet, settings); - } - } + // entity set + foreach (var entitySet in _model.EntityContainer.EntitySets()) + { + if (CanFilter(entitySet)) + { + RetrieveNavigationSourcePaths(entitySet, settings); + } + } - // singleton - foreach (IEdmSingleton singleton in _model.EntityContainer.Singletons()) - { - if (CanFilter(singleton)) - { - RetrieveNavigationSourcePaths(singleton, settings); - } + // singleton + foreach (var singleton in _model.EntityContainer.Singletons()) + { + if (CanFilter(singleton)) + { + RetrieveNavigationSourcePaths(singleton, settings); + } + } } // bound operations RetrieveBoundOperationPaths(settings); - // unbound operations - foreach (IEdmOperationImport import in _model.EntityContainer.OperationImports()) + if (_model is not null) { - if (CanFilter(import)) - { - AppendPath(new ODataPath(new ODataOperationImportSegment(import))); - } + // unbound operations + foreach (IEdmOperationImport import in _model.EntityContainer.OperationImports()) + { + if (CanFilter(import)) + { + AppendPath(new ODataPath(new ODataOperationImportSegment(import))); + } + } } return MergePaths(); @@ -142,9 +148,9 @@ private void AppendPath(ODataPath path) case ODataPathKind.MediaEntity: if (path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment) { - if(!_allNavigationSourcePaths.TryGetValue(navigationSourceSegment.EntityType, out IList nsList)) + if(!_allNavigationSourcePaths.TryGetValue(navigationSourceSegment.EntityType, out var nsList)) { - nsList = new List(); + nsList = []; _allNavigationSourcePaths[navigationSourceSegment.EntityType] = nsList; } @@ -157,9 +163,9 @@ private void AppendPath(ODataPath path) } else { - if (!_dollarCountPaths.TryGetValue(navigationSourceSegment.EntityType, out IList dollarPathList)) + if (!_dollarCountPaths.TryGetValue(navigationSourceSegment.EntityType, out var dollarPathList)) { - dollarPathList = new List(); + dollarPathList = []; _dollarCountPaths[navigationSourceSegment.EntityType] = dollarPathList; } dollarPathList.Add(path); @@ -174,9 +180,9 @@ private void AppendPath(ODataPath path) case ODataPathKind.Ref: ODataNavigationPropertySegment navigationPropertySegment = path.OfType().Last(); - if (!_allNavigationPropertyPaths.TryGetValue(navigationPropertySegment.EntityType, out IList npList)) + if (!_allNavigationPropertyPaths.TryGetValue(navigationPropertySegment.EntityType, out var npList)) { - npList = new List(); + npList = []; _allNavigationPropertyPaths[navigationPropertySegment.EntityType] = npList; } @@ -190,7 +196,7 @@ private void AppendPath(ODataPath path) foreach (var kvp in _dollarCountPaths) { if (kvp.Value.FirstOrDefault(p => DollarCountAndOperationPathsSimilar(p, path)) is ODataPath dollarCountPath && - _allNavigationSourcePaths.TryGetValue(kvp.Key, out IList dollarPathList)) + _allNavigationSourcePaths.TryGetValue(kvp.Key, out var dollarPathList)) { dollarPathList.Remove(dollarCountPath); break; @@ -208,9 +214,9 @@ private void AppendPath(ODataPath path) bool DollarCountAndOperationPathsSimilar(ODataPath path1, ODataPath path2) { if ((path1.Kind == ODataPathKind.DollarCount && - path2.Kind == ODataPathKind.Operation && path2.LastSegment.Identifier.Equals(Constants.CountSegmentIdentifier, StringComparison.OrdinalIgnoreCase)) || + path2.Kind == ODataPathKind.Operation && Constants.CountSegmentIdentifier.Equals(path2.LastSegment?.Identifier, StringComparison.OrdinalIgnoreCase)) || (path2.Kind == ODataPathKind.DollarCount && - path1.Kind == ODataPathKind.Operation && path1.LastSegment.Identifier.Equals(Constants.CountSegmentIdentifier, StringComparison.OrdinalIgnoreCase))) + path1.Kind == ODataPathKind.Operation && Constants.CountSegmentIdentifier.Equals(path1.LastSegment?.Identifier, StringComparison.OrdinalIgnoreCase))) { return GetModifiedPathItemName(path1)?.Equals(GetModifiedPathItemName(path2), StringComparison.OrdinalIgnoreCase) ?? false; } @@ -218,9 +224,9 @@ bool DollarCountAndOperationPathsSimilar(ODataPath path1, ODataPath path2) return false; } - string GetModifiedPathItemName(ODataPath path) + string? GetModifiedPathItemName(ODataPath path) { - if (!path.Any()) return null; + if (path.Count == 0) return null; IEnumerable modifiedSegments = path.Take(path.Count - 1); ODataPath modifiedPath = new(modifiedSegments); @@ -242,14 +248,15 @@ private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource ODataPath path = new(new ODataNavigationSourceSegment(navigationSource)); AppendPath(path.Clone()); - IEdmEntitySet entitySet = navigationSource as IEdmEntitySet; IEdmEntityType entityType = navigationSource.EntityType; - CountRestrictionsType count = null; + CountRestrictionsType? count = null; bool? indexableByKey = false; + var entitySetIsNull = true; // for entity set, create a path with key and a $count path - if (entitySet != null) + if (navigationSource is IEdmEntitySet entitySet && _model is not null) { + entitySetIsNull = false; string targetPath = path.GetTargetPath(_model); count = _model.GetRecord(targetPath, CapabilitiesConstants.CountRestrictions) ?? _model.GetRecord(entitySet, CapabilitiesConstants.CountRestrictions); @@ -291,13 +298,13 @@ private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource } } - if (entitySet != null && (indexableByKey ?? true)) + if (!entitySetIsNull && (indexableByKey ?? true)) { path.Pop(); // end of entity } path.Pop(); // end of navigation source. - Debug.Assert(path.Any() == false); + Debug.Assert(path.Count == 0); } /// @@ -312,7 +319,7 @@ private void RetrieveComplexPropertyPaths(IEdmEntityType entityType, ODataPath c Utils.CheckArgumentNull(currentPath, nameof(currentPath)); Utils.CheckArgumentNull(convertSettings, nameof(convertSettings)); - if (!convertSettings.EnableNavigationPropertyPath) return; + if (!convertSettings.EnableNavigationPropertyPath || _model is null) return; foreach (IEdmStructuralProperty sp in entityType.StructuralProperties() .Where(x => x.Type.IsComplex() || @@ -327,9 +334,9 @@ private void RetrieveComplexPropertyPaths(IEdmEntityType entityType, ODataPath c } AppendPath(currentPath.Clone()); - if (sp.Type.IsCollection()) + if (sp.Type.IsCollection() && sp.Type.Definition.AsElementType() is IEdmComplexType elemType) { - CreateTypeCastPaths(currentPath, convertSettings, sp.Type.Definition.AsElementType() as IEdmComplexType, sp, true); + CreateTypeCastPaths(currentPath, convertSettings, elemType, sp, true); var isCountable = _model.GetRecord(targetPath, CapabilitiesConstants.CountRestrictions)?.IsCountable ?? _model.GetRecord(sp, CapabilitiesConstants.CountRestrictions)?.IsCountable ?? true; @@ -345,7 +352,7 @@ private void RetrieveComplexPropertyPaths(IEdmEntityType entityType, ODataPath c // Append navigation property paths for this complex property RetrieveComplexTypeNavigationPropertyPaths(complexType, currentPath, convertSettings); - // Traverse this complex property to rerieve nested navigation property paths + // Traverse this complex property to retrieve nested navigation property paths TraverseComplexProperty(sp, currentPath, convertSettings); } @@ -373,7 +380,7 @@ private bool RetrieveComplexTypeNavigationPropertyPaths(IEdmComplexType complexT .Distinct() .Where(CanFilter); - if (!navigationProperties.Any()) return false; + if (!navigationProperties.Any() || _model is null) return false; foreach (var np in navigationProperties) { @@ -434,14 +441,14 @@ private bool ShouldCreateComplexPropertyPaths(IEdmStructuralProperty complexProp if (!convertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) return true; - bool isReadable = _model.GetRecord(targetPath, CapabilitiesConstants.ReadRestrictions)?.Readable - ?? _model.GetRecord(complexProperty, CapabilitiesConstants.ReadRestrictions)?.Readable + bool isReadable = _model?.GetRecord(targetPath, CapabilitiesConstants.ReadRestrictions)?.Readable + ?? _model?.GetRecord(complexProperty, CapabilitiesConstants.ReadRestrictions)?.Readable ?? false; - bool isUpdatable = _model.GetRecord(targetPath, CapabilitiesConstants.UpdateRestrictions)?.Updatable - ??_model.GetRecord(complexProperty, CapabilitiesConstants.UpdateRestrictions)?.Updatable + bool isUpdatable = _model?.GetRecord(targetPath, CapabilitiesConstants.UpdateRestrictions)?.Updatable + ??_model?.GetRecord(complexProperty, CapabilitiesConstants.UpdateRestrictions)?.Updatable ?? false; - bool isInsertable = _model.GetRecord(targetPath, CapabilitiesConstants.InsertRestrictions)?.Insertable - ?? _model.GetRecord(complexProperty, CapabilitiesConstants.InsertRestrictions)?.Insertable + bool isInsertable = _model?.GetRecord(targetPath, CapabilitiesConstants.InsertRestrictions)?.Insertable + ?? _model?.GetRecord(complexProperty, CapabilitiesConstants.InsertRestrictions)?.Insertable ?? false; return isReadable || isUpdatable || isInsertable; @@ -494,10 +501,10 @@ private void RetrieveMediaEntityStreamPaths(IEdmEntityType entityType, ODataPath /// A stack that holds the visited navigation properties in the . private void RetrieveNavigationPropertyPaths( IEdmNavigationProperty navigationProperty, - CountRestrictionsType count, + CountRestrictionsType? count, ODataPath currentPath, OpenApiConvertSettings convertSettings, - Stack visitedNavigationProperties = null) + Stack? visitedNavigationProperties = null) { Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty)); Utils.CheckArgumentNull(currentPath, nameof(currentPath)); @@ -518,18 +525,17 @@ private void RetrieveNavigationPropertyPaths( } // Get the annotatable navigation source for this navigation property. - IEdmVocabularyAnnotatable annotatableNavigationSource = (currentPath.FirstSegment as ODataNavigationSourceSegment)?.NavigationSource as IEdmVocabularyAnnotatable; - NavigationRestrictionsType navSourceRestrictionType = null; - NavigationRestrictionsType navPropRestrictionType = null; + NavigationRestrictionsType? navSourceRestrictionType = null; + NavigationRestrictionsType? navPropRestrictionType = null; // Get the NavigationRestrictions referenced by this navigation property: Can be defined in the navigation source or in-lined in the navigation property. - if (annotatableNavigationSource != null) + if (currentPath.FirstSegment is ODataNavigationSourceSegment { NavigationSource: IEdmVocabularyAnnotatable annotatableNavigationSource } && _model is not null) { navSourceRestrictionType = _model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.NavigationRestrictions); navPropRestrictionType = _model.GetRecord(navigationProperty, CapabilitiesConstants.NavigationRestrictions); } - NavigationPropertyRestriction restriction = navSourceRestrictionType?.RestrictedProperties? + NavigationPropertyRestriction? restriction = navSourceRestrictionType?.RestrictedProperties? .FirstOrDefault(r => r.NavigationProperty == currentPath.NavigationPropertyPath(navigationProperty.Name)) ?? navPropRestrictionType?.RestrictedProperties?.FirstOrDefault(); @@ -549,22 +555,13 @@ private void RetrieveNavigationPropertyPaths( visitedNavigationProperties.Push(navPropFullyQualifiedName); // For fetching annotations - var targetPath = currentPath.GetTargetPath(_model); + var targetPath = _model is null ? null : currentPath.GetTargetPath(_model); // Check whether a collection-valued navigation property should be indexed by key value(s). // Find indexability annotation annotated directly via NavigationPropertyRestriction. - bool? annotatedIndexability = _model.GetBoolean(targetPath, CapabilitiesConstants.IndexableByKey) - ?? _model.GetBoolean(navigationProperty, CapabilitiesConstants.IndexableByKey); - bool indexableByKey = true; - - if (restriction?.IndexableByKey != null) - { - indexableByKey = (bool)restriction.IndexableByKey; - } - else if (annotatedIndexability != null) - { - indexableByKey = annotatedIndexability.Value; - } + bool? annotatedIndexability = (string.IsNullOrEmpty(targetPath) ? null : _model?.GetBoolean(targetPath, CapabilitiesConstants.IndexableByKey)) + ?? _model?.GetBoolean(navigationProperty, CapabilitiesConstants.IndexableByKey); + bool indexableByKey = restriction?.IndexableByKey ?? annotatedIndexability ?? true; if (indexableByKey) { @@ -577,8 +574,8 @@ private void RetrieveNavigationPropertyPaths( if (count == null) { // First, get the directly annotated restriction annotation of the navigation property - count = _model.GetRecord(targetPath, CapabilitiesConstants.CountRestrictions) - ?? _model.GetRecord(navigationProperty, CapabilitiesConstants.CountRestrictions); + count = (string.IsNullOrEmpty(targetPath) ? null : _model?.GetRecord(targetPath, CapabilitiesConstants.CountRestrictions)) + ?? _model?.GetRecord(navigationProperty, CapabilitiesConstants.CountRestrictions); createCountPath = count?.Countable; } @@ -735,13 +732,11 @@ private void CreateTypeCastPaths(ODataPath currentPath, OpenApiConvertSettings c if(!convertSettings.EnableODataTypeCast) return; - var annotedTypeNames = GetDerivedTypeConstaintTypeNames(annotable); + var annotedTypeNames = GetDerivedTypeConstraintTypeNames(annotable); if(!annotedTypeNames.Any() && convertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments) return; // we don't want to generate any downcast path item if there is no type cast annotation. - var annotedTypeNamesSet = new HashSet(annotedTypeNames, StringComparer.OrdinalIgnoreCase); - bool filter(IEdmStructuredType x) => convertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments && annotedTypeNames.Contains(x.FullTypeName()) || !convertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments && ( @@ -750,16 +745,18 @@ bool filter(IEdmStructuredType x) => ); var targetTypes = _model - .FindAllDerivedTypes(structuredType) + ?.FindAllDerivedTypes(structuredType) .Where(x => (x.TypeKind == EdmTypeKind.Entity || x.TypeKind == EdmTypeKind.Complex) && filter(x)) .OfType() .ToArray(); + if (targetTypes is not { Length: > 0} || _model is null) return; + foreach (var targetType in targetTypes) { var targetTypeSegment = new ODataTypeCastSegment(targetType, _model); - if (currentPath.Segments.Any(x => x.Identifier.Equals(targetTypeSegment.Identifier))) + if (currentPath.Segments.Any(x => x.Identifier?.Equals(targetTypeSegment.Identifier) ?? false)) { // In case we have expanded a derived type's navigation property // and we are in a cyclic loop where the expanded navigation property @@ -802,7 +799,7 @@ bool filter(IEdmStructuredType x) => /// private void RetrieveBoundOperationPaths(OpenApiConvertSettings convertSettings) { - var edmOperations = _model.GetAllElements().OfType().Where(x => x.IsBound).ToArray(); + var edmOperations = _model?.GetAllElements().OfType().Where(x => x.IsBound).ToArray() ?? []; foreach (var edmOperation in edmOperations) { if (!CanFilter(edmOperation)) @@ -876,7 +873,7 @@ private void RetrieveBoundOperationPaths(OpenApiConvertSettings convertSettings) && operationSegment.Operation is IEdmFunction edmFunction && edmFunction.IsComposable && edmFunction.ReturnType != null - && edmFunction.ReturnType.Definition is IEdmEntityType returnBindingEntityType); + && edmFunction.ReturnType.Definition is IEdmEntityType); foreach( var functionPath in functionPaths) { @@ -902,11 +899,11 @@ functionPath.LastSegment is ODataOperationSegment && { /* Get number of segments already appended after the first composable function segment */ - int composableFuncSegIndex = functionPath.Segments.IndexOf( - functionPath.Segments.FirstOrDefault( - x => x is ODataOperationSegment operationSegment && - operationSegment.Operation is IEdmFunction edmFunction && - edmFunction.IsComposable)); + int composableFuncSegIndex = functionPath + .Segments + .OfType() + .FirstOrDefault(x => x.Operation is IEdmFunction {IsComposable: true}) is {} firstOperationSegment ? + functionPath.Segments.IndexOf(firstOperationSegment) : -1; int currentDepth = functionPath.Count - composableFuncSegIndex - 1; if (currentDepth < convertSettings.ComposableFunctionsExpansionDepth) @@ -928,10 +925,10 @@ bool filter(IEdmNavigationSource z) => z.EntityType.FindAllBaseTypes().Contains(firstEntityType); return new IEdmEntityType[] { firstEntityType } - .Union(_model.EntityContainer.EntitySets() - .Where(filter).Select(x => x.EntityType)) //Search all EntitySets - .Union(_model.EntityContainer.Singletons() - .Where(filter).Select(x => x.EntityType)) //Search all singletons + .Union(_model?.EntityContainer.EntitySets() + .Where(filter).Select(x => x.EntityType) ?? []) //Search all EntitySets + .Union(_model?.EntityContainer.Singletons() + .Where(filter).Select(x => x.EntityType) ?? []) //Search all singletons .Distinct() .ToList(); } @@ -944,9 +941,9 @@ bool filter(IEdmNavigationSource z) => }; private void AppendBoundOperationOnNavigationSourcePath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType, OpenApiConvertSettings convertSettings) { - if (_allNavigationSourcePaths.TryGetValue(bindingEntityType, out IList value)) + if (_allNavigationSourcePaths.TryGetValue(bindingEntityType, out var value)) { - bool isEscapedFunction = _model.IsUrlEscapeFunction(edmOperation); + bool isEscapedFunction = _model?.IsUrlEscapeFunction(edmOperation) ?? false; foreach (var subPath in value) { @@ -973,7 +970,7 @@ secondLastPathSegment is not ODataKeySegment && var annotatable = (lastPathSegment as ODataNavigationSourceSegment)?.NavigationSource as IEdmVocabularyAnnotatable; annotatable ??= (lastPathSegment as ODataKeySegment)?.EntityType; - if (annotatable != null && !EdmModelHelper.IsOperationAllowed(_model, edmOperation, annotatable)) + if (annotatable != null && _model is not null && !EdmModelHelper.IsOperationAllowed(_model, edmOperation, annotatable)) { // Check whether the navigation source is allowed to have an operation on the entity type annotatable = (secondLastPathSegment as ODataNavigationSourceSegment)?.NavigationSource as IEdmVocabularyAnnotatable; @@ -983,9 +980,12 @@ secondLastPathSegment is not ODataKeySegment && } } - ODataPath newPath = subPath.Clone(); - newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); - AppendPath(newPath); + if (_model is not null) + { + ODataPath newPath = subPath.Clone(); + newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); + AppendPath(newPath); + } } } } @@ -995,15 +995,15 @@ secondLastPathSegment is not ODataKeySegment && }; private void AppendBoundOperationOnNavigationPropertyPath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType) { - bool isEscapedFunction = _model.IsUrlEscapeFunction(edmOperation); + bool isEscapedFunction = _model?.IsUrlEscapeFunction(edmOperation) ?? false; - if (_allNavigationPropertyPaths.TryGetValue(bindingEntityType, out IList value)) + if (_allNavigationPropertyPaths.TryGetValue(bindingEntityType, out var value)) { foreach (var path in value.Where(x => !_pathKindToSkipForNavigationProperties.Contains(x.Kind))) { - ODataNavigationPropertySegment npSegment = path.Segments.Last(s => s is ODataNavigationPropertySegment) as ODataNavigationPropertySegment; + ODataNavigationPropertySegment npSegment = path.Segments.OfType().Last(); - if (!EdmModelHelper.IsOperationAllowed(_model, edmOperation, npSegment.NavigationProperty, npSegment.NavigationProperty.ContainsTarget)) + if (_model is not null && !EdmModelHelper.IsOperationAllowed(_model, edmOperation, npSegment.NavigationProperty, npSegment.NavigationProperty.ContainsTarget)) { continue; } @@ -1030,9 +1030,12 @@ private void AppendBoundOperationOnNavigationPropertyPath(IEdmOperation edmOpera } } - ODataPath newPath = path.Clone(); - newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); - AppendPath(newPath); + if (_model is not null) + { + ODataPath newPath = path.Clone(); + newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); + AppendPath(newPath); + } } } } @@ -1044,22 +1047,24 @@ private void AppendBoundOperationOnDerived( OpenApiConvertSettings convertSettings) { if (!convertSettings.AppendBoundOperationsOnDerivedTypeCastSegments) return; - bool isEscapedFunction = _model.IsUrlEscapeFunction(edmOperation); + bool isEscapedFunction = _model?.IsUrlEscapeFunction(edmOperation) ?? false; + if (_allNavigationSources is null) return; foreach (var baseType in bindingEntityType.FindAllBaseTypes()) { - if (_allNavigationSources.TryGetValue(baseType, out IList baseNavigationSource)) + if (_allNavigationSources.TryGetValue(baseType, out var baseNavigationSource)) { foreach (var ns in baseNavigationSource) { - if (HasUnsatisfiedDerivedTypeConstraint( - ns as IEdmVocabularyAnnotatable, + if (ns is not IEdmVocabularyAnnotatable nsAnnotatable || + HasUnsatisfiedDerivedTypeConstraint( + nsAnnotatable, baseType, convertSettings)) { continue; } - if (!EdmModelHelper.IsOperationAllowed(_model, edmOperation, ns as IEdmVocabularyAnnotatable)) + if (_model is null || !EdmModelHelper.IsOperationAllowed(_model, edmOperation, nsAnnotatable)) { continue; } @@ -1100,11 +1105,11 @@ private bool HasUnsatisfiedDerivedTypeConstraint( OpenApiConvertSettings convertSettings) { return convertSettings.RequireDerivedTypesConstraintForBoundOperations && - !GetDerivedTypeConstaintTypeNames(annotatable) + !GetDerivedTypeConstraintTypeNames(annotatable) .Any(c => c.Equals(baseType.FullName(), StringComparison.OrdinalIgnoreCase)); } - private IEnumerable GetDerivedTypeConstaintTypeNames(IEdmVocabularyAnnotatable annotatable) => - _model.GetCollection(annotatable, "Org.OData.Validation.V1.DerivedTypeConstraint") ?? Enumerable.Empty(); + private IEnumerable GetDerivedTypeConstraintTypeNames(IEdmVocabularyAnnotatable annotatable) => + _model?.GetCollection(annotatable, "Org.OData.Validation.V1.DerivedTypeConstraint") ?? []; private void AppendBoundOperationOnDerivedNavigationPropertyPath( IEdmOperation edmOperation, @@ -1113,11 +1118,11 @@ private void AppendBoundOperationOnDerivedNavigationPropertyPath( OpenApiConvertSettings convertSettings) { if (!convertSettings.AppendBoundOperationsOnDerivedTypeCastSegments) return; - bool isEscapedFunction = _model.IsUrlEscapeFunction(edmOperation); + bool isEscapedFunction = _model?.IsUrlEscapeFunction(edmOperation) ?? false; foreach (var baseType in bindingEntityType.FindAllBaseTypes()) { - if (_allNavigationPropertyPaths.TryGetValue(baseType, out IList paths)) + if (_allNavigationPropertyPaths.TryGetValue(baseType, out var paths)) { foreach (var path in paths.Where(x => !_pathKindToSkipForNavigationProperties.Contains(x.Kind))) { @@ -1127,7 +1132,7 @@ private void AppendBoundOperationOnDerivedNavigationPropertyPath( continue; } - if (!EdmModelHelper.IsOperationAllowed(_model, edmOperation, npSegment.NavigationProperty, npSegment.NavigationProperty.ContainsTarget)) + if (_model is not null && !EdmModelHelper.IsOperationAllowed(_model, edmOperation, npSegment.NavigationProperty, npSegment.NavigationProperty.ContainsTarget)) { continue; } @@ -1163,10 +1168,13 @@ private void AppendBoundOperationOnDerivedNavigationPropertyPath( continue; } - ODataPath newPath = path.Clone(); - newPath.Push(new ODataTypeCastSegment(bindingEntityType, _model)); - newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); - AppendPath(newPath); + if (_model is not null) + { + ODataPath newPath = path.Clone(); + newPath.Push(new ODataTypeCastSegment(bindingEntityType, _model)); + newPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); + AppendPath(newPath); + } } } } @@ -1174,7 +1182,7 @@ private void AppendBoundOperationOnDerivedNavigationPropertyPath( private void AppendBoundOperationOnOperationPath(IEdmOperation edmOperation, bool isCollection, IEdmEntityType bindingEntityType) { - bool isEscapedFunction = _model.IsUrlEscapeFunction(edmOperation); + bool isEscapedFunction = _model?.IsUrlEscapeFunction(edmOperation) ?? false; // only composable functions var paths = _allOperationPaths.Where(x => x.LastSegment is ODataOperationSegment operationSegment @@ -1188,7 +1196,7 @@ private void AppendBoundOperationOnOperationPath(IEdmOperation edmOperation, boo || operationSegment.Operation is not IEdmFunction edmFunction || !edmFunction.IsComposable || edmFunction.ReturnType == null || !edmFunction.ReturnType.Definition.Equals(bindingEntityType) || isCollection - || !EdmModelHelper.IsOperationAllowed(_model, edmOperation, operationSegment.Operation, true)) + || _model is not null && !EdmModelHelper.IsOperationAllowed(_model, edmOperation, operationSegment.Operation, true)) { continue; } @@ -1200,7 +1208,10 @@ private void AppendBoundOperationOnOperationPath(IEdmOperation edmOperation, boo } ODataPath newOperationPath = path.Clone(); - newOperationPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); + if (_model is not null) + { + newOperationPath.Push(new ODataOperationSegment(edmOperation, isEscapedFunction, _model)); + } AppendPath(newOperationPath); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataRefSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataRefSegment.cs index a1047d724..471e5ed63 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataRefSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataRefSegment.cs @@ -28,7 +28,7 @@ private ODataRefSegment() } /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.Ref; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs index 7a262d10b..b9eeb31a4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataSegment.cs @@ -86,7 +86,7 @@ public abstract class ODataSegment /// /// Gets the entity type of current segment. /// - public virtual IEdmEntityType EntityType => throw new NotImplementedException(); + public virtual IEdmEntityType? EntityType => throw new NotImplementedException(); /// /// Gets the kind of this segment. @@ -96,16 +96,16 @@ public abstract class ODataSegment /// /// Gets the identifier of this segment. /// - public abstract string Identifier { get; } + public abstract string? Identifier { get; } /// /// Gets the path item name for this segment. /// /// The settings. /// The path item name. - public string GetPathItemName(OpenApiConvertSettings settings) + public string? GetPathItemName(OpenApiConvertSettings settings) { - return GetPathItemName(settings, new HashSet()); + return GetPathItemName(settings, []); } /// /// Provides a suffix for the operation id based on the operation path. @@ -113,7 +113,7 @@ public string GetPathItemName(OpenApiConvertSettings settings) /// Path to use to deduplicate. /// The settings. ///The suffix. - public string GetPathHash(OpenApiConvertSettings settings, ODataPath path = default) + public string GetPathHash(OpenApiConvertSettings settings, ODataPath? path = default) { var suffix = string.Join("/", path?.Segments.Select(x => x.Identifier).Distinct() ?? Enumerable.Empty()); return (GetPathItemName(settings) + suffix).GetHashSHA256().Substring(0, 4); @@ -125,7 +125,7 @@ public string GetPathHash(OpenApiConvertSettings settings, ODataPath path = defa /// The settings. /// The existing parameters. /// The path item name. - public abstract string GetPathItemName(OpenApiConvertSettings settings, HashSet parameters); + public abstract string? GetPathItemName(OpenApiConvertSettings settings, HashSet parameters); /// /// Returns the list of this segment refers to. diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamContentSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamContentSegment.cs index 02101a887..01cd11425 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamContentSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamContentSegment.cs @@ -16,7 +16,7 @@ namespace Microsoft.OpenApi.OData.Edm public class ODataStreamContentSegment : ODataSegment { /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.StreamContent; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamPropertySegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamPropertySegment.cs index 06d52c365..0ee79bb6b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamPropertySegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataStreamPropertySegment.cs @@ -26,7 +26,7 @@ public ODataStreamPropertySegment(string streamPropertyName) } /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.StreamProperty; diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataTypeCastSegment.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataTypeCastSegment.cs index 47da7fd4f..e7a3ff3c0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataTypeCastSegment.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataTypeCastSegment.cs @@ -27,7 +27,7 @@ public ODataTypeCastSegment(IEdmStructuredType structuredType, IEdmModel model) private readonly IEdmModel _model; /// - public override IEdmEntityType EntityType => null; + public override IEdmEntityType? EntityType => null; /// public override ODataSegmentKind Kind => ODataSegmentKind.TypeCast; @@ -43,7 +43,7 @@ public ODataTypeCastSegment(IEdmStructuredType structuredType, IEdmModel model) /// public override IEnumerable GetAnnotables() { - return [StructuredType as IEdmVocabularyAnnotatable]; + return StructuredType is IEdmVocabularyAnnotatable annotable ? [annotable] : []; } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs index 5d8dc6d4a..3010a06c9 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Edm/RecordExpressionExtensions.cs @@ -41,7 +41,7 @@ internal static class RecordExpressionExtensions /// The given record. /// The property name. /// The property string value. - public static string GetString(this IEdmRecordExpression record, string propertyName) + public static string? GetString(this IEdmRecordExpression record, string propertyName) { Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); @@ -127,7 +127,7 @@ property.Value is IEdmEnumMemberExpression value && /// The record expression. /// The property name. /// The collection or null. - public static T GetRecord(this IEdmRecordExpression record, string propertyName) + public static T? GetRecord(this IEdmRecordExpression record, string propertyName) where T : IRecord, new() { Utils.CheckArgumentNull(record, nameof(record)); @@ -150,7 +150,7 @@ public static T GetRecord(this IEdmRecordExpression record, string propertyNa /// The record expression. /// The property name. /// The property path or null. - public static string GetPropertyPath(this IEdmRecordExpression record, string propertyName) + public static string? GetPropertyPath(this IEdmRecordExpression record, string propertyName) { Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); @@ -167,7 +167,7 @@ public static string GetPropertyPath(this IEdmRecordExpression record, string pr /// The record expression. /// The property name. /// The collection of property path or null. - public static IList GetCollectionPropertyPath(this IEdmRecordExpression record, string propertyName) + public static IList? GetCollectionPropertyPath(this IEdmRecordExpression record, string propertyName) { Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); @@ -196,7 +196,7 @@ public static IList GetCollectionPropertyPath(this IEdmRecordExpression /// The record expression. /// The property name. /// The collection of string or null. - public static IList GetCollection(this IEdmRecordExpression record, string propertyName) + public static IList? GetCollection(this IEdmRecordExpression record, string propertyName) { Utils.CheckArgumentNull(record, nameof(record)); Utils.CheckArgumentNull(propertyName, nameof(propertyName)); @@ -221,7 +221,7 @@ public static IList GetCollection(this IEdmRecordExpression record, stri /// The record expression. /// The property name. /// The collection or null. - public static IList GetCollection(this IEdmRecordExpression record, string propertyName) + public static IList? GetCollection(this IEdmRecordExpression record, string propertyName) where T : IRecord, new() { Utils.CheckArgumentNull(record, nameof(record)); diff --git a/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs index 5fe3f4b07..a1af2a25e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/EdmModelOpenApiExtensions.cs @@ -3,9 +3,11 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Validation; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -39,22 +41,20 @@ public static OpenApiDocument ConvertToOpenApi(this IEdmModel model, OpenApiConv Utils.CheckArgumentNull(model, nameof(model)); Utils.CheckArgumentNull(settings, nameof(settings)); - if (settings.VerifyEdmModel) - { - if (!model.Validate(out var errors)) + if (settings.VerifyEdmModel && !model.Validate(out var errors)) + { + OpenApiDocument document = new(); + int index = 1; + document.Extensions ??= new Dictionary(); + foreach (var error in errors) { - OpenApiDocument document = new(); - int index = 1; - foreach (var error in errors) - { - document.Extensions.Add(Constants.xMsEdmModelError + index++, new OpenApiAny(error.ToString())); - } - - return document; + document.Extensions.Add(Constants.xMsEdmModelError + index++, new OpenApiAny(error.ToString())); } + + return document; } - ODataContext context = new(model, settings); + ODataContext context = new(model, settings); return context.CreateDocument(); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Extensions/IODataRoutePathPrefixProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Extensions/IODataRoutePathPrefixProvider.cs index 22b33398f..edff4e306 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Extensions/IODataRoutePathPrefixProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Extensions/IODataRoutePathPrefixProvider.cs @@ -16,11 +16,11 @@ public interface IODataRoutePathPrefixProvider /// /// The route prefix. /// - public string PathPrefix { get; } + public string? PathPrefix { get; } /// /// The route prefix parameters. /// - public IEnumerable Parameters { get; } + public IEnumerable? Parameters { get; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Extensions/ODataRoutePathPrefixProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Extensions/ODataRoutePathPrefixProvider.cs index 61b409269..5a9d864c3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Extensions/ODataRoutePathPrefixProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Extensions/ODataRoutePathPrefixProvider.cs @@ -16,11 +16,11 @@ public class ODataRoutePathPrefixProvider : IODataRoutePathPrefixProvider /// /// Gets/sets the path prefix. /// - public string PathPrefix { get; set; } + public string? PathPrefix { get; set; } /// /// Gets/sets the associated parameters for the path prefix. /// - public IEnumerable Parameters { get; set; } + public IEnumerable? Parameters { get; set; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiComponentsGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiComponentsGenerator.cs index 64fe4417a..5d5ff3997 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiComponentsGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiComponentsGenerator.cs @@ -32,9 +32,12 @@ public static void AddComponentsToDocument(this ODataContext context, OpenApiDoc context.AddRequestBodiesToDocument(document); context.AddExamplesToDocument(document); context.AddSecuritySchemesToDocument(document); - document.Components.Links = null; - document.Components.Callbacks = null; - document.Components.Extensions = null; + if (document.Components is not null) + { + document.Components.Links = null; + document.Components.Callbacks = null; + document.Components.Extensions = null; + } } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs index fc315fdcb..1315f99e3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs @@ -47,7 +47,7 @@ public static void AddExamplesToDocument(this ODataContext context, OpenApiDocum } } - private static OpenApiExample CreateExample(this ODataContext context, IEdmType edmType, OpenApiDocument document) + private static OpenApiExample? CreateExample(this ODataContext context, IEdmType edmType, OpenApiDocument document) { Debug.Assert(context != null); Debug.Assert(edmType != null); diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiInfoGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiInfoGenerator.cs index 085cb5bb8..195893ef8 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiInfoGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiInfoGenerator.cs @@ -61,7 +61,7 @@ private static string GetTitle(this ODataContext context) } // If no Core.Description is present, a default title has to be provided as this is a required OpenAPI field. - string namespaceName = context.Model.EntityContainer != null ? + var namespaceName = context.Model.EntityContainer != null ? context.Model.EntityContainer.Namespace : context.Model.DeclaredNamespaces.FirstOrDefault(); @@ -100,7 +100,7 @@ private static string GetDescription(this ODataContext context) return "This OData service is located at " + context.Settings.ServiceRoot.OriginalString; } - private static Dictionary GetExtensions(this ODataContext context) + private static Dictionary? GetExtensions(this ODataContext context) { Debug.Assert(context != null); @@ -113,7 +113,7 @@ private static Dictionary GetExtensions(this ODataCon new OpenApiAny(new JsonObject { { "toolName", "Microsoft.OpenApi.OData" }, - { "toolVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString() } + { "toolVersion", Assembly.GetExecutingAssembly().GetName().Version?.ToString() } }) } }; diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs index 5fb7804ea..b852e2e43 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiLinkGenerator.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.OData.Edm; using System.Linq; using Microsoft.OpenApi.Models.Interfaces; +using System; namespace Microsoft.OpenApi.OData.Generator { @@ -31,7 +32,7 @@ internal static class OpenApiLinkGenerator /// The created dictionary of object. public static IDictionary CreateLinks(this ODataContext context, IEdmEntityType entityType, string entityName, string entityKind, ODataPath path, - IList parameters = null, string navPropOperationId = null) + IList? parameters = null, string? navPropOperationId = null) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(entityType, nameof(entityType)); @@ -47,7 +48,8 @@ public static IDictionary CreateLinks(this ODataContext co foreach (var parameter in parameters) { if (!string.IsNullOrEmpty(parameter.Description) && - parameter.Description.ToLower().Contains("key")) + parameter.Description.Contains("key", StringComparison.OrdinalIgnoreCase) && + !string.IsNullOrEmpty(parameter.Name)) { pathKeyNames.Add(parameter.Name); } @@ -68,7 +70,7 @@ public static IDictionary CreateLinks(this ODataContext co switch (entityKind) { - case "Navigation": // just for contained navigations + case "Navigation" when !string.IsNullOrEmpty(navPropOperationId): // just for contained navigations operationPrefix = navPropOperationId; break; default: // EntitySet, Entity, Singleton @@ -115,11 +117,12 @@ public static IDictionary CreateLinks(this ODataContext co { foreach (var operationPath in operationPaths) { + if (operationPath.LastSegment?.Identifier is null) continue; OpenApiLink link = new() { OperationId = string.Join(".", operationPath.Segments.Select(x => { - return x.Kind.Equals(ODataSegmentKind.Key) ? x.EntityType.Name : x.Identifier; + return x.Kind.Equals(ODataSegmentKind.Key) && x.EntityType is not null ? x.EntityType.Name : x.Identifier; })) }; diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs index dad145a3d..8c986e22b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiParameterGenerator.cs @@ -17,6 +17,7 @@ using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.Models.Interfaces; +using Microsoft.OpenApi.Interfaces; namespace Microsoft.OpenApi.OData.Generator { @@ -71,7 +72,7 @@ public static IList CreateParameters(this ODataContext contex /// The created list of . public static IList CreateParameters(this ODataContext context, IEdmFunction function, OpenApiDocument document, - IDictionary parameterNameMapping = null) + IDictionary? parameterNameMapping = null) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(function, nameof(function)); @@ -160,7 +161,7 @@ public static IList CreateParameters(this ODataContext contex /// The created list of . public static IList CreateKeyParameters(this ODataContext context, ODataKeySegment keySegment, OpenApiDocument document, - IDictionary parameterNameMapping = null) + IDictionary? parameterNameMapping = null) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(keySegment, nameof(keySegment)); @@ -193,6 +194,7 @@ public static IList CreateKeyParameters(this ODataContext cont Schema = context.CreateEdmTypeSchemaForParameter(keys[0].Type, document) }; + parameter.Extensions ??= new Dictionary(); parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiAny(entityType.Name)); parameters.Add(parameter); } @@ -218,6 +220,7 @@ public static IList CreateKeyParameters(this ODataContext cont parameter.Description += $", {keyProperty.Name}={quote}{{{parameter.Name}}}{quote}"; } + parameter.Extensions ??= new Dictionary(); parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiAny(entityType.Name)); parameters.Add(parameter); } @@ -341,21 +344,21 @@ public static List CreatePathParameters(this ODataPath path, /// The new OpenApiParameter to be appended public static void AppendParameter(this IList parameters, IOpenApiParameter parameter) { - HashSet parametersSet = new(parameters.Select(p => p.Name)); + HashSet parametersSet = new(parameters.Select(p => p.Name).OfType()); - string parameterName = parameter.Name; - int index = 1; - while (parametersSet.Contains(parameterName)) - { - parameterName += index.ToString(); - index++; - } - - if (parameter is OpenApiParameter openApiParameter) + if (parameter.Name is not string parameterName && + parameter is OpenApiParameter openApiParameter) { + parameterName = string.Empty; + int index = 1; + while (parametersSet.Contains(parameterName)) + { + parameterName += index.ToString(); + index++; + } openApiParameter.Name = parameterName; } - parametersSet.Add(parameterName); + parameters.Add(parameter); } @@ -366,7 +369,7 @@ public static void AppendParameter(this IList parameters, IOp /// The Edm annotation target. /// The Open API document. /// The created or null. - public static IOpenApiParameter CreateTop(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) + public static IOpenApiParameter? CreateTop(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); @@ -388,7 +391,7 @@ public static IOpenApiParameter CreateTop(this ODataContext context, IEdmVocabul /// The string representation of the Edm target path. /// The Open API document to use to build references. /// - public static IOpenApiParameter CreateTop(this ODataContext context, string targetPath, OpenApiDocument document) + public static IOpenApiParameter? CreateTop(this ODataContext context, string targetPath, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -408,7 +411,7 @@ public static IOpenApiParameter CreateTop(this ODataContext context, string targ /// The Edm annotation target. /// The Open API document to use to build references. /// The created or null. - public static IOpenApiParameter CreateSkip(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) + public static IOpenApiParameter? CreateSkip(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); @@ -430,7 +433,7 @@ public static IOpenApiParameter CreateSkip(this ODataContext context, IEdmVocabu /// The string representation of the Edm target path. /// The Open API document to use to build references. /// - public static IOpenApiParameter CreateSkip(this ODataContext context, string targetPath, OpenApiDocument document) + public static IOpenApiParameter? CreateSkip(this ODataContext context, string targetPath, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -450,14 +453,13 @@ public static IOpenApiParameter CreateSkip(this ODataContext context, string tar /// The Edm annotation target. /// The Open API document to use to build references. /// The created or null. - public static IOpenApiParameter CreateSearch(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) + public static IOpenApiParameter? CreateSearch(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(document, nameof(document)); - SearchRestrictionsType search = context.Model.GetRecord(target, CapabilitiesConstants.SearchRestrictions); - if (search == null || search.IsSearchable) + if (context.Model.GetRecord(target, CapabilitiesConstants.SearchRestrictions) is not {} search || search.IsSearchable) { return new OpenApiParameterReference("search", document); } @@ -471,7 +473,7 @@ public static IOpenApiParameter CreateSearch(this ODataContext context, IEdmVoca /// The string representation of the Edm target path. /// The Open API document to use to build references. /// - public static IOpenApiParameter CreateSearch(this ODataContext context, string targetPath, OpenApiDocument document) + public static IOpenApiParameter? CreateSearch(this ODataContext context, string targetPath, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -491,14 +493,13 @@ public static IOpenApiParameter CreateSearch(this ODataContext context, string t /// The Edm annotation target. /// The Open API document to use to build references. /// The created or null. - public static IOpenApiParameter CreateCount(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) + public static IOpenApiParameter? CreateCount(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(document, nameof(document)); - CountRestrictionsType count = context.Model.GetRecord(target, CapabilitiesConstants.CountRestrictions); - if (count == null || count.IsCountable) + if (context.Model.GetRecord(target, CapabilitiesConstants.CountRestrictions) is not {} count || count.IsCountable) { return new OpenApiParameterReference("count", document); } @@ -513,7 +514,7 @@ public static IOpenApiParameter CreateCount(this ODataContext context, IEdmVocab /// The string representation of the Edm target path. /// The Open API document to use to build references. /// - public static IOpenApiParameter CreateCount(this ODataContext context, string targetPath, OpenApiDocument document) + public static IOpenApiParameter? CreateCount(this ODataContext context, string targetPath, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -533,14 +534,13 @@ public static IOpenApiParameter CreateCount(this ODataContext context, string ta /// The Edm annotation target. /// The Open API document to use to build references. /// The created or null. - public static IOpenApiParameter CreateFilter(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) + public static IOpenApiParameter? CreateFilter(this ODataContext context, IEdmVocabularyAnnotatable target, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(document, nameof(document)); - FilterRestrictionsType filter = context.Model.GetRecord(target, CapabilitiesConstants.FilterRestrictions); - if (filter == null || filter.IsFilterable) + if (context.Model.GetRecord(target, CapabilitiesConstants.FilterRestrictions) is not {} filter || filter.IsFilterable) { return new OpenApiParameterReference("filter", document); } @@ -555,7 +555,7 @@ public static IOpenApiParameter CreateFilter(this ODataContext context, IEdmVoca /// The string representation of the Edm target path. /// The Open API document to use to build references. /// - public static IOpenApiParameter CreateFilter(this ODataContext context, string targetPath, OpenApiDocument document) + public static IOpenApiParameter? CreateFilter(this ODataContext context, string targetPath, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -567,7 +567,7 @@ public static IOpenApiParameter CreateFilter(this ODataContext context, string t return context.CreateFilter(target, document); } - public static OpenApiParameter CreateOrderBy(this ODataContext context, string targetPath, IEdmEntityType entityType) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, string targetPath, IEdmEntityType entityType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -579,7 +579,7 @@ public static OpenApiParameter CreateOrderBy(this ODataContext context, string t return context.CreateOrderBy(target, entityType); } - public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmEntitySet entitySet) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, IEdmEntitySet entitySet) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(entitySet, nameof(entitySet)); @@ -587,7 +587,7 @@ public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmEnti return context.CreateOrderBy(entitySet, entitySet.EntityType); } - public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmSingleton singleton) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, IEdmSingleton singleton) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(singleton, nameof(singleton)); @@ -595,7 +595,7 @@ public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmSing return context.CreateOrderBy(singleton, singleton.EntityType); } - public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmNavigationProperty navigationProperty) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, IEdmNavigationProperty navigationProperty) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty)); @@ -610,12 +610,12 @@ public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmNavi /// The Edm annotation target. /// The Edm Entity type. /// The created or null. - public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) {// patchwork to avoid breaking changes return context.CreateOrderBy(target, entityType as IEdmStructuredType); } - public static OpenApiParameter CreateOrderBy(this ODataContext context, string targetPath, IEdmStructuredType structuredType) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, string targetPath, IEdmStructuredType structuredType) { IEdmTargetPath target = context.Model.GetTargetPath(targetPath); if (target == null) @@ -624,13 +624,13 @@ public static OpenApiParameter CreateOrderBy(this ODataContext context, string t return context.CreateOrderBy(target, structuredType); } - public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmStructuredType structuredType) + public static OpenApiParameter? CreateOrderBy(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmStructuredType structuredType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(structuredType, nameof(structuredType)); - SortRestrictionsType sort = context.Model.GetRecord(target, CapabilitiesConstants.SortRestrictions); + var sort = context.Model.GetRecord(target, CapabilitiesConstants.SortRestrictions); if (sort != null && !sort.IsSortable) { return null; @@ -684,19 +684,18 @@ public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmVoca }; } - public static OpenApiParameter CreateSelect(this ODataContext context, string targetPath, IEdmEntityType entityType) + public static OpenApiParameter? CreateSelect(this ODataContext context, string targetPath, IEdmEntityType entityType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); - IEdmTargetPath target = context.Model.GetTargetPath(targetPath); - if (target == null) + if (context.Model.GetTargetPath(targetPath) is not {} target) return null; return context.CreateSelect(target, entityType); } - public static OpenApiParameter CreateSelect(this ODataContext context, IEdmEntitySet entitySet) + public static OpenApiParameter? CreateSelect(this ODataContext context, IEdmEntitySet entitySet) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(entitySet, nameof(entitySet)); @@ -704,7 +703,7 @@ public static OpenApiParameter CreateSelect(this ODataContext context, IEdmEntit return context.CreateSelect(entitySet, entitySet.EntityType); } - public static OpenApiParameter CreateSelect(this ODataContext context, IEdmSingleton singleton) + public static OpenApiParameter? CreateSelect(this ODataContext context, IEdmSingleton singleton) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(singleton, nameof(singleton)); @@ -712,7 +711,7 @@ public static OpenApiParameter CreateSelect(this ODataContext context, IEdmSingl return context.CreateSelect(singleton, singleton.EntityType); } - public static OpenApiParameter CreateSelect(this ODataContext context, IEdmNavigationProperty navigationProperty) + public static OpenApiParameter? CreateSelect(this ODataContext context, IEdmNavigationProperty navigationProperty) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty)); @@ -727,12 +726,12 @@ public static OpenApiParameter CreateSelect(this ODataContext context, IEdmNavig /// The Edm target. /// The Edm entity type. /// The created or null. - public static OpenApiParameter CreateSelect(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) + public static OpenApiParameter? CreateSelect(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) { // patchwork to avoid breaking changes return context.CreateSelect(target, entityType as IEdmStructuredType); } - public static OpenApiParameter CreateSelect(this ODataContext context, string targetPath, IEdmStructuredType structuredType) + public static OpenApiParameter? CreateSelect(this ODataContext context, string targetPath, IEdmStructuredType structuredType) { IEdmTargetPath target = context.Model.GetTargetPath(targetPath); if (target == null) @@ -741,13 +740,13 @@ public static OpenApiParameter CreateSelect(this ODataContext context, string ta return context.CreateSelect(target, structuredType); } - public static OpenApiParameter CreateSelect(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmStructuredType structuredType) + public static OpenApiParameter? CreateSelect(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmStructuredType structuredType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(structuredType, nameof(structuredType)); - NavigationRestrictionsType navigation = context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); + var navigation = context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); if (navigation != null && !navigation.IsNavigable) { return null; @@ -790,7 +789,7 @@ public static OpenApiParameter CreateSelect(this ODataContext context, IEdmVocab }; } - public static OpenApiParameter CreateExpand(this ODataContext context, string targetPath, IEdmEntityType entityType) + public static OpenApiParameter? CreateExpand(this ODataContext context, string targetPath, IEdmEntityType entityType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(targetPath, nameof(targetPath)); @@ -802,7 +801,7 @@ public static OpenApiParameter CreateExpand(this ODataContext context, string ta return context.CreateExpand(target, entityType); } - public static OpenApiParameter CreateExpand(this ODataContext context, IEdmEntitySet entitySet) + public static OpenApiParameter? CreateExpand(this ODataContext context, IEdmEntitySet entitySet) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(entitySet, nameof(entitySet)); @@ -810,7 +809,7 @@ public static OpenApiParameter CreateExpand(this ODataContext context, IEdmEntit return context.CreateExpand(entitySet, entitySet.EntityType); } - public static OpenApiParameter CreateExpand(this ODataContext context, IEdmSingleton singleton) + public static OpenApiParameter? CreateExpand(this ODataContext context, IEdmSingleton singleton) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(singleton, nameof(singleton)); @@ -818,7 +817,7 @@ public static OpenApiParameter CreateExpand(this ODataContext context, IEdmSingl return context.CreateExpand(singleton, singleton.EntityType); } - public static OpenApiParameter CreateExpand(this ODataContext context, IEdmNavigationProperty navigationProperty) + public static OpenApiParameter? CreateExpand(this ODataContext context, IEdmNavigationProperty navigationProperty) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty)); @@ -833,12 +832,12 @@ public static OpenApiParameter CreateExpand(this ODataContext context, IEdmNavig /// The edm entity path. /// The edm entity path. /// The created or null. - public static OpenApiParameter CreateExpand(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) + public static OpenApiParameter? CreateExpand(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) { // patchwork to avoid breaking changes return context.CreateExpand(target, entityType as IEdmStructuredType); } - public static OpenApiParameter CreateExpand(this ODataContext context, string targetPath, IEdmStructuredType structuredType) + public static OpenApiParameter? CreateExpand(this ODataContext context, string targetPath, IEdmStructuredType structuredType) { IEdmTargetPath target = context.Model.GetTargetPath(targetPath); if (target == null) @@ -847,13 +846,13 @@ public static OpenApiParameter CreateExpand(this ODataContext context, string ta return context.CreateExpand(target, structuredType); } - public static OpenApiParameter CreateExpand(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmStructuredType structuredType) + public static OpenApiParameter? CreateExpand(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmStructuredType structuredType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(structuredType, nameof(structuredType)); - ExpandRestrictionsType expand = context.Model.GetRecord(target, CapabilitiesConstants.ExpandRestrictions); + var expand = context.Model.GetRecord(target, CapabilitiesConstants.ExpandRestrictions); if (expand != null && !expand.IsExpandable) { return null; diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs index 5aa19ad11..69f824475 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiPathItemGenerator.cs @@ -4,7 +4,6 @@ // ------------------------------------------------------------ using System.Collections.Generic; -using System.Linq; using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; @@ -40,14 +39,13 @@ public static void AddPathItemsToDocument(this ODataContext context, OpenApiDocu settings.EnableKeyAsSegment = context.KeyAsSegment; foreach (ODataPath path in context.AllPaths) { - IPathItemHandler handler = context.PathItemHandlerProvider.GetHandler(path.Kind, document); + var handler = context.PathItemHandlerProvider.GetHandler(path.Kind, document); if (handler == null) { continue; } - OpenApiPathItem pathItem = handler.CreatePathItem(context, path); - if (!pathItem.Operations.Any()) + if (handler.CreatePathItem(context, path) is not {Operations.Count: > 0} pathItem) { continue; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs index ffb8f0c10..2e23c398a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiRequestBodyGenerator.cs @@ -26,7 +26,7 @@ internal static class OpenApiRequestBodyGenerator /// The Edm action import. /// The OpenApi document to lookup references. /// The created or null. - public static OpenApiRequestBody CreateRequestBody(this ODataContext context, IEdmActionImport actionImport, OpenApiDocument document) + public static OpenApiRequestBody? CreateRequestBody(this ODataContext context, IEdmActionImport actionImport, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(actionImport, nameof(actionImport)); @@ -42,7 +42,7 @@ public static OpenApiRequestBody CreateRequestBody(this ODataContext context, IE /// The Edm action. /// The OpenApi document to lookup references. /// The created or null. - public static OpenApiRequestBody CreateRequestBody(this ODataContext context, IEdmAction action, OpenApiDocument document) + public static OpenApiRequestBody? CreateRequestBody(this ODataContext context, IEdmAction action, OpenApiDocument document) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(action, nameof(action)); diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs index c0cfa4f01..25ec6f75c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiResponseGenerator.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using Microsoft.OData.Edm; using Microsoft.OpenApi.Models; @@ -28,7 +27,7 @@ internal static class OpenApiResponseGenerator /// The status code. /// The OpenApi document to lookup references. /// The created . - public static IOpenApiResponse GetResponse(this string statusCode, OpenApiDocument document) + public static IOpenApiResponse? GetResponse(this string statusCode, OpenApiDocument document) { return statusCode switch { Constants.StatusCodeDefault => new OpenApiResponseReference(Constants.Error, document), @@ -82,8 +81,7 @@ public static void AddResponsesToDocument(this ODataContext context, OpenApiDocu foreach (IEdmOperation operation in context.Model.SchemaElements.OfType() .Where(op => context.Model.OperationTargetsMultiplePaths(op))) { - OpenApiResponse response = context.CreateOperationResponse(operation, document); - if (response != null) + if (context.CreateOperationResponse(operation, document) is {} response) responses[$"{operation.Name}Response"] = response; } @@ -123,9 +121,9 @@ public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOp OpenApiResponses responses = new(); - if (operation.IsAction() && operation.ReturnType == null) + if (operation.IsAction() && operation.ReturnType == null && Constants.StatusCode204.GetResponse(document) is {} x204Response) { - responses.Add(Constants.StatusCode204, Constants.StatusCode204.GetResponse(document)); + responses.Add(Constants.StatusCode204, x204Response); } else if (context.Model.OperationTargetsMultiplePaths(operation)) { @@ -134,26 +132,27 @@ public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOp new OpenApiResponseReference($"{operation.Name}Response", document) ); } - else + else if (context.CreateOperationResponse(operation, document) is {} successResponse) { - OpenApiResponse response = context.CreateOperationResponse(operation, document); - responses.Add(context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, response); + responses.Add(context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, successResponse); } - if (context.Settings.ErrorResponsesAsDefault) + if (context.Settings.ErrorResponsesAsDefault && Constants.StatusCodeDefault.GetResponse(document) is {} defaultResponse) { - responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse(document)); + responses.Add(Constants.StatusCodeDefault, defaultResponse); } else { - responses.Add(Constants.StatusCodeClass4XX, Constants.StatusCodeClass4XX.GetResponse(document)); - responses.Add(Constants.StatusCodeClass5XX, Constants.StatusCodeClass5XX.GetResponse(document)); + if (Constants.StatusCodeClass4XX.GetResponse(document) is {} x4Response) + responses.Add(Constants.StatusCodeClass4XX, x4Response); + if (Constants.StatusCodeClass5XX.GetResponse(document) is {} x5Response) + responses.Add(Constants.StatusCodeClass5XX, x5Response); } return responses; } - public static OpenApiResponse CreateOperationResponse(this ODataContext context, IEdmOperation operation, OpenApiDocument document) + public static OpenApiResponse? CreateOperationResponse(this ODataContext context, IEdmOperation operation, OpenApiDocument document) { if (operation.ReturnType == null) return null; @@ -232,7 +231,7 @@ public static OpenApiResponse CreateOperationResponse(this ODataContext context, schema = context.CreateEdmTypeSchema(operation.ReturnType, document); } - string mediaType = Constants.ApplicationJsonMediaType; + string? mediaType = Constants.ApplicationJsonMediaType; if (operation.ReturnType.AsPrimitive()?.PrimitiveKind() == EdmPrimitiveTypeKind.Stream) { mediaType = context.Model.GetString(operation, CoreConstants.MediaType); diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs index 91648b010..1cb0941da 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs @@ -106,6 +106,7 @@ public static void AddSchemasToDocument(this ODataContext context, OpenApiDocume }; document.AddComponent(Constants.BaseCollectionPaginationCountResponse, responseSchema); + responseSchema.Properties ??= new Dictionary(); if (context.Settings.EnableCount) responseSchema.Properties.Add(ODataConstants.OdataCount); if (context.Settings.EnablePagination) @@ -210,7 +211,7 @@ internal static IEnumerable GetAllCollectionEntityTypes(this private static OpenApiSchema CreateCollectionSchema(ODataContext context, IEdmStructuredType structuredType, OpenApiDocument document) { - IOpenApiSchema schema = null; + IOpenApiSchema? schema = null; var entityType = structuredType as IEdmEntityType; if (context.Settings.EnableDerivedTypesReferencesForResponses && entityType != null) @@ -315,6 +316,7 @@ public static OpenApiSchema CreateEnumTypeSchema(this ODataContext context, IEdm { IsFlags = true, }; + schema.Extensions ??= new Dictionary(); schema.Extensions.Add(OpenApiEnumFlagsExtension.Name, enumFlagsExtension); } @@ -334,12 +336,15 @@ public static OpenApiSchema CreateEnumTypeSchema(this ODataContext context, IEdm AddEnumDescription(member, extension, context); } - if(extension?.ValuesDescriptions.Any() ?? false) + if(extension is {ValuesDescriptions.Count:> 0}) + { + schema.Extensions ??= new Dictionary(); schema.Extensions.Add(OpenApiEnumValuesDescriptionExtension.Name, extension); + } schema.Title = enumType.Name; return schema; } - private static void AddEnumDescription(IEdmEnumMember member, OpenApiEnumValuesDescriptionExtension target, ODataContext context) + private static void AddEnumDescription(IEdmEnumMember member, OpenApiEnumValuesDescriptionExtension? target, ODataContext context) { if (target == null) return; @@ -485,12 +490,12 @@ internal static IOpenApiSchema CreateSchemaTypeSchema(this ODataContext context, private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType, bool processBase, bool processExample, OpenApiDocument document, - IEnumerable derivedTypes = null) + IEnumerable? derivedTypes = null) { Debug.Assert(context != null); Debug.Assert(structuredType != null); - JsonNode example = null; + JsonNode? example = null; if (context.Settings.ShowSchemaExamples) { example = CreateStructuredTypePropertiesExample(context, structuredType, document); @@ -504,8 +509,8 @@ private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext contex if (processBase && structuredType.BaseType != null) { // The x-ms-discriminator-value extension is added to structured types which are derived types. - Dictionary extension = null; - if (context.Settings.EnableDiscriminatorValue && !derivedTypes.Any()) + Dictionary? extension = null; + if (context.Settings.EnableDiscriminatorValue && (derivedTypes is null || !derivedTypes.Any())) { extension = new Dictionary { @@ -537,11 +542,13 @@ private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext contex else { // The discriminator object is added to structured types which have derived types. - OpenApiDiscriminator discriminator = null; - if (context.Settings.EnableDiscriminatorValue && derivedTypes.Any()) + OpenApiDiscriminator? discriminator = null; + if (context.Settings.EnableDiscriminatorValue && derivedTypes is not null && derivedTypes.Any()) { Dictionary mapping = derivedTypes - .ToDictionary(x => $"#{x.FullTypeName()}", x => new OpenApiSchemaReference(x.FullTypeName(), document).Reference.ReferenceV3); + .Select(x => ($"#{x.FullTypeName()}", new OpenApiSchemaReference(x.FullTypeName(), document).Reference.ReferenceV3)) + .Where(x => x.Item2 != null) + .ToDictionary(x => x.Item1, x => x.Item2!); discriminator = new OpenApiDiscriminator { @@ -571,13 +578,13 @@ private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext contex if (context.Settings.EnableDiscriminatorValue) { - JsonNode defaultValue = null; + JsonNode? defaultValue = null; bool isBaseTypeEntity = Constants.EntityName.Equals(structuredType.BaseType?.FullTypeName().Split('.').Last(), StringComparison.OrdinalIgnoreCase); bool isBaseTypeAbstractNonEntity = (structuredType.BaseType?.IsAbstract ?? false) && !isBaseTypeEntity; if (!context.Settings.EnableTypeDisambiguationForDefaultValueOfOdataTypeProperty || isBaseTypeAbstractNonEntity || - context.Model.IsBaseTypeReferencedAsTypeInModel(structuredType.BaseType)) + structuredType.BaseType is not null && context.Model.IsBaseTypeReferencedAsTypeInModel(structuredType.BaseType)) { defaultValue = "#" + structuredType.FullTypeName(); } @@ -591,6 +598,7 @@ private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext contex throw new InvalidOperationException( $"Property {Constants.OdataType} is already present in schema {structuredType.FullTypeName()}; verify CSDL."); } + schema.Required ??= new HashSet(); schema.Required.Add(Constants.OdataType); } @@ -629,7 +637,7 @@ internal static JsonObject CreateStructuredTypePropertiesExample(ODataContext co if (propertyType.TypeKind() == EdmTypeKind.Primitive && item is JsonValue jsonValue && - jsonValue.TryGetValue(out string stringAny) && + jsonValue.TryGetValue(out var stringAny) && structuredType is IEdmEntityType entityType && entityType.Key().Any(k => StringComparer.Ordinal.Equals(k.Name, property.Name))) { @@ -642,7 +650,7 @@ structuredType is IEdmEntityType entityType && return example; } - private static JsonNode GetTypeNameForPrimitive(ODataContext context, IEdmTypeReference edmTypeReference, OpenApiDocument document) + private static JsonNode? GetTypeNameForPrimitive(ODataContext context, IEdmTypeReference edmTypeReference, OpenApiDocument document) { IEdmPrimitiveType primitiveType = edmTypeReference.AsPrimitive().PrimitiveDefinition(); IOpenApiSchema schema = context.CreateSchema(primitiveType, document); @@ -685,7 +693,7 @@ EdmTypeKind.Primitive when edmTypeReference.IsInt16() || edmTypeReference.IsInt64() || edmTypeReference.IsFloating() || edmTypeReference.IsDouble() => 0, - EdmTypeKind.Primitive => GetTypeNameForPrimitive(context, edmTypeReference, document), + EdmTypeKind.Primitive when GetTypeNameForPrimitive(context, edmTypeReference, document) is JsonNode primitiveType => primitiveType, EdmTypeKind.Entity or EdmTypeKind.Complex => new JsonObject() { @@ -700,7 +708,7 @@ EdmTypeKind.Primitive when edmTypeReference.IsInt16() || }; } - private static JsonNode CreateDefault(this IEdmStructuralProperty property) + private static JsonNode? CreateDefault(this IEdmStructuralProperty property) { if (property == null || property.DefaultValueString == null) diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecurityRequirementGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecurityRequirementGenerator.cs index 3aa231f98..5a6c39257 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecurityRequirementGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecurityRequirementGenerator.cs @@ -8,7 +8,6 @@ using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; -using Microsoft.OpenApi.OData.Vocabulary.Authorization; using Microsoft.OpenApi.OData.Vocabulary.Capabilities; using Microsoft.OpenApi.Models.References; @@ -36,12 +35,16 @@ public static IEnumerable CreateSecurityRequirements { foreach (PermissionType permission in permissions) { + if (string.IsNullOrEmpty(permission.SchemeName)) + { + continue; + } yield return new OpenApiSecurityRequirement { [ new OpenApiSecuritySchemeReference(permission.SchemeName, document) - ] = new List(permission.Scopes?.Select(c => c.Scope) ?? new List()) - }; + ] = [.. permission.Scopes?.Select(c => c.Scope).OfType() ?? []] + }; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecuritySchemeGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecuritySchemeGenerator.cs index e5156a837..5c3469351 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecuritySchemeGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSecuritySchemeGenerator.cs @@ -4,7 +4,6 @@ // ------------------------------------------------------------ using System; -using System.Collections.Generic; using System.Diagnostics; using System.Linq; using Microsoft.OpenApi.Models; @@ -37,6 +36,10 @@ public static void AddSecuritySchemesToDocument(this ODataContext context, OpenA foreach (var authorization in authorizations) { + if (string.IsNullOrEmpty(authorization.Name)) + { + continue; + } OpenApiSecurityScheme scheme = new OpenApiSecurityScheme { Type = authorization.SchemeType, @@ -104,7 +107,8 @@ private static void AppendOpenIdConnect(OpenApiSecurityScheme scheme, OpenIDConn Debug.Assert(scheme != null); Debug.Assert(openIdConnect != null); - scheme.OpenIdConnectUrl = new Uri(openIdConnect.IssuerUrl); + if (!string.IsNullOrEmpty(openIdConnect.IssuerUrl)) + scheme.OpenIdConnectUrl = new Uri(openIdConnect.IssuerUrl); } private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorization oAuth2) @@ -113,11 +117,11 @@ private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorizatio Debug.Assert(oAuth2 != null); scheme.Flows = new OpenApiOAuthFlows(); - OpenApiOAuthFlow flow = null; + OpenApiOAuthFlow? flow = null; switch (oAuth2.OAuth2Type) { - case OAuth2Type.AuthCode: // AuthCode - OAuth2AuthCode authCode = (OAuth2AuthCode)oAuth2; + case OAuth2Type.AuthCode when oAuth2 is OAuth2AuthCode {AuthorizationUrl: not null, TokenUrl: not null} authCode: + // AuthCode flow = new OpenApiOAuthFlow { AuthorizationUrl = new Uri(authCode.AuthorizationUrl), @@ -126,8 +130,8 @@ private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorizatio scheme.Flows.AuthorizationCode = flow; break; - case OAuth2Type.Pasword: // Password - OAuth2Password password = (OAuth2Password)oAuth2; + case OAuth2Type.Password when oAuth2 is OAuth2Password { TokenUrl: not null} password: + // Password flow = new OpenApiOAuthFlow { TokenUrl = new Uri(password.TokenUrl) @@ -135,8 +139,8 @@ private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorizatio scheme.Flows.Password = flow; break; - case OAuth2Type.Implicit: // Implicit - OAuth2Implicit @implicit = (OAuth2Implicit)oAuth2; + case OAuth2Type.Implicit when oAuth2 is OAuth2Implicit {AuthorizationUrl: not null} @implicit: + // Implicit flow = new OpenApiOAuthFlow { AuthorizationUrl = new Uri(@implicit.AuthorizationUrl) @@ -144,8 +148,8 @@ private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorizatio scheme.Flows.Implicit = flow; break; - case OAuth2Type.ClientCredentials: // ClientCredentials - OAuth2ClientCredentials credentials = (OAuth2ClientCredentials)oAuth2; + case OAuth2Type.ClientCredentials when oAuth2 is OAuth2ClientCredentials {TokenUrl: not null} credentials: + // ClientCredentials flow = new OpenApiOAuthFlow { TokenUrl = new Uri(credentials.TokenUrl) @@ -155,11 +159,14 @@ private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorizatio } Debug.Assert(flow != null); - flow.RefreshUrl = new Uri(oAuth2.RefreshUrl); + if (!string.IsNullOrEmpty(oAuth2.RefreshUrl)) + flow.RefreshUrl = new Uri(oAuth2.RefreshUrl); if (oAuth2.Scopes != null) { - flow.Scopes = oAuth2.Scopes.ToDictionary(s => s.Scope, s => s.Description); + flow.Scopes = oAuth2.Scopes + .Where(static x => !string.IsNullOrEmpty(x.Scope) && !string.IsNullOrEmpty(x.Description)) + .ToDictionary(s => s.Scope!, s => s.Description!); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiTagGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiTagGenerator.cs index c96d76952..192d2fc18 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiTagGenerator.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiTagGenerator.cs @@ -66,7 +66,7 @@ public static ISet CreateTags(this ODataContext context) // The tags array can contain additional Tag Objects for other logical groups, // e.g. for action imports or function imports that are not associated with an entity set. case EdmContainerElementKind.ActionImport: // Action Import - OpenApiTag actionImportTag = context.CreateOperationImportTag((IEdmActionImport)element); + var actionImportTag = context.CreateOperationImportTag((IEdmActionImport)element); if (actionImportTag != null) { tags.Add(actionImportTag); @@ -74,7 +74,7 @@ public static ISet CreateTags(this ODataContext context) break; case EdmContainerElementKind.FunctionImport: // Function Import - OpenApiTag functionImportTag = context.CreateOperationImportTag((IEdmFunctionImport)element); + var functionImportTag = context.CreateOperationImportTag((IEdmFunctionImport)element); if (functionImportTag != null) { tags.Add(functionImportTag); @@ -87,7 +87,7 @@ public static ISet CreateTags(this ODataContext context) return tags; } - private static OpenApiTag CreateOperationImportTag(this ODataContext context, IEdmOperationImport operationImport) + private static OpenApiTag? CreateOperationImportTag(this ODataContext context, IEdmOperationImport operationImport) { Debug.Assert(context != null); diff --git a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj index 7e979d2b1..f07b7c5e8 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj +++ b/src/Microsoft.OpenApi.OData.Reader/Microsoft.OpenAPI.OData.Reader.csproj @@ -18,6 +18,7 @@ ..\..\bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml true + enable README.md @@ -30,11 +31,11 @@ - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/src/Microsoft.OpenApi.OData.Reader/OData/IEdmExpressionExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/OData/IEdmExpressionExtensions.cs index 679a0bdfb..64b6878ab 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OData/IEdmExpressionExtensions.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OData/IEdmExpressionExtensions.cs @@ -21,7 +21,7 @@ internal static class IEdmExpressionExtensions /// /// The . /// The null or . - public static ODataValue Convert(this IEdmExpression expression) + public static ODataValue? Convert(this IEdmExpression expression) { if (expression == null) { @@ -112,7 +112,7 @@ public static ODataValue Convert(this IEdmExpression expression) return new ODataResourceValue { TypeReference = recordExpression.DeclaredType, - Properties = recordExpression.Properties.ToDictionary(p => p.Name, p => p.Value.Convert()) + Properties = recordExpression.Properties.Select(p => (p.Name, p.Value.Convert())).Where(p => p.Item2 is not null).ToDictionary(p => p.Item1, p => p.Item2!) }; case EdmExpressionKind.Collection: @@ -122,7 +122,7 @@ public static ODataValue Convert(this IEdmExpression expression) TypeReference = collectionExpression.DeclaredType }; - collectionValue.Elements = collectionExpression.Elements.Select(e => e.Convert()).ToList(); + collectionValue.Elements = collectionExpression.Elements.Select(e => e.Convert()).OfType().ToList(); return collectionValue; case EdmExpressionKind.Path: diff --git a/src/Microsoft.OpenApi.OData.Reader/OData/ODataCollectValue.cs b/src/Microsoft.OpenApi.OData.Reader/OData/ODataCollectValue.cs index a0c27e8d9..c78378286 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OData/ODataCollectValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OData/ODataCollectValue.cs @@ -12,6 +12,6 @@ namespace Microsoft.OpenApi.OData /// internal class ODataCollectValue : ODataValue { - public IList Elements { get; set; } + public IList? Elements { get; set; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/OData/ODataPrimitiveValue.cs b/src/Microsoft.OpenApi.OData.Reader/OData/ODataPrimitiveValue.cs index 4bab519d5..24a616723 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OData/ODataPrimitiveValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OData/ODataPrimitiveValue.cs @@ -20,7 +20,7 @@ public ODataPrimitiveValue(object value) /// public object Value { get; private set; } - public override string ToString() + public override string? ToString() { return Value.ToString(); } diff --git a/src/Microsoft.OpenApi.OData.Reader/OData/ODataResourceValue.cs b/src/Microsoft.OpenApi.OData.Reader/OData/ODataResourceValue.cs index c0990e097..c22f731e6 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OData/ODataResourceValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OData/ODataResourceValue.cs @@ -15,6 +15,6 @@ internal class ODataResourceValue : ODataValue /// /// Gets or sets the properties. /// - public IDictionary Properties { get; set; } + public IDictionary? Properties { get; set; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/OData/ODataValue.cs b/src/Microsoft.OpenApi.OData.Reader/OData/ODataValue.cs index d51c0173a..ee8e6bf93 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OData/ODataValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OData/ODataValue.cs @@ -15,6 +15,6 @@ internal abstract class ODataValue /// /// Gets or set the type reference of this value. /// - public IEdmTypeReference TypeReference { get; set; } + public IEdmTypeReference? TypeReference { get; set; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs b/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs index ecb73a7d4..5615f3ff0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs +++ b/src/Microsoft.OpenApi.OData.Reader/OpenApiConvertSettings.cs @@ -138,7 +138,7 @@ public class OpenApiConvertSettings /// /// Gets/sets a value that specifies a prefix to be prepended to all generated paths. /// - public string PathPrefix + public string? PathPrefix { get { @@ -166,7 +166,7 @@ public string PathPrefix /// /// Gets/sets a route path prefix provider. /// - public IODataRoutePathPrefixProvider RoutePathPrefixProvider { get; set; } + public IODataRoutePathPrefixProvider? RoutePathPrefixProvider { get; set; } /// /// Gets/Sets a value indicating whether or not to show the OpenAPI links in the responses. @@ -203,7 +203,7 @@ public string PathPrefix /// /// Gets/sets a the path provider. /// - public IODataPathProvider PathProvider { get; set; } + public IODataPathProvider? PathProvider { get; set; } /// /// Gets/sets a value indicating whether or not add OData $count segments in the description for collections. @@ -315,7 +315,7 @@ public string PathPrefix /// /// The namespace prefix to be stripped from the in method paths. /// - public string NamespacePrefixToStripForInMethodPaths { get; set; } + public string? NamespacePrefixToStripForInMethodPaths { get; set; } /// /// Enables the use of aliases for the type cast segments to shorten the url path. diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyBaseOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyBaseOperationHandler.cs index 79843b934..57dc7accc 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyBaseOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyBaseOperationHandler.cs @@ -23,7 +23,7 @@ protected ComplexPropertyBaseOperationHandler(OpenApiDocument document) : base(d { } - protected ODataComplexPropertySegment ComplexPropertySegment; + protected ODataComplexPropertySegment? ComplexPropertySegment; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -35,15 +35,18 @@ protected override void Initialize(ODataContext context, ODataPath path) /// protected override void SetTags(OpenApiOperation operation) { - string tagName = EdmModelHelper.GenerateComplexPropertyPathTagName(Path, Context); - operation.Tags ??= new HashSet(); - if (!string.IsNullOrEmpty(tagName)) + if (Context is not null && Path is not null) { - Context.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() - { - Name = tagName - }); - operation.Tags.Add(new OpenApiTagReference(tagName, _document)); + string tagName = EdmModelHelper.GenerateComplexPropertyPathTagName(Path, Context); + operation.Tags ??= new HashSet(); + if (!string.IsNullOrEmpty(tagName)) + { + Context.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() + { + Name = tagName + }); + operation.Tags.Add(new OpenApiTagReference(tagName, _document)); + } } base.SetTags(operation); @@ -52,10 +55,10 @@ protected override void SetTags(OpenApiOperation operation) /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs) + if (Context is {Settings.ShowExternalDocs: true} && CustomLinkRel is not null) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(ComplexPropertySegment.Property, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetLinkRecord(TargetPath, CustomLinkRel)) ?? + (ComplexPropertySegment is null ? null : Context.Model.GetLinkRecord(ComplexPropertySegment.Property, CustomLinkRel)); if (externalDocs != null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs index 6e873c83c..51db8e26c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyGetOperationHandler.cs @@ -3,11 +3,13 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -31,32 +33,37 @@ public ComplexPropertyGetOperationHandler(OpenApiDocument document):base(documen /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestrictions; + private ReadRestrictionsType? _readRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - var complexPropertyReadRestrictions = Context.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.ReadRestrictions); - _readRestrictions?.MergePropertiesIfNull(complexPropertyReadRestrictions); - _readRestrictions ??= complexPropertyReadRestrictions; + _readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + + if (ComplexPropertySegment is not null) + { + var complexPropertyReadRestrictions = Context?.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.ReadRestrictions); + _readRestrictions?.MergePropertiesIfNull(complexPropertyReadRestrictions); + _readRestrictions ??= complexPropertyReadRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Path is not null) { - string prefix = ComplexPropertySegment.Property.Type.IsCollection() ? "List" : "Get"; + string prefix = ComplexPropertySegment is not null && ComplexPropertySegment.Property.Type.IsCollection() ? "List" : "Get"; operation.OperationId = EdmModelHelper.GenerateComplexPropertyPathOperationId(Path, Context, prefix); } // Summary and Description - string placeHolder = $"Get {ComplexPropertySegment.Property.Name} property value"; + string placeHolder = $"Get {ComplexPropertySegment?.Property.Name} property value"; operation.Summary = _readRestrictions?.Description ?? placeHolder; - operation.Description = _readRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(ComplexPropertySegment.Property); + operation.Description = _readRestrictions?.LongDescription ?? + (ComplexPropertySegment is null ? null : Context?.Model.GetDescriptionAnnotation(ComplexPropertySegment.Property)); base.SetBasicInfo(operation); } @@ -65,7 +72,10 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); - IOpenApiParameter parameter; + if (Context is null || ComplexPropertySegment is null) return; + + IOpenApiParameter? parameter; + operation.Parameters ??= []; if(ComplexPropertySegment.Property.Type.IsCollection()) { // The parameters array contains Parameter Objects for all system query options allowed for this collection, @@ -73,35 +83,35 @@ protected override void SetParameters(OpenApiOperation operation) // Capabilities.TopSupported, Capabilities.SkipSupported, Capabilities.SearchRestrictions, // Capabilities.FilterRestrictions, and Capabilities.CountRestrictions // $top - parameter = Context.CreateTop(TargetPath, _document) ?? Context.CreateTop(ComplexPropertySegment.Property, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateTop(TargetPath, _document)) ?? Context.CreateTop(ComplexPropertySegment.Property, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $skip - parameter = Context.CreateSkip(TargetPath, _document) ?? Context.CreateSkip(ComplexPropertySegment.Property, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSkip(TargetPath, _document)) ?? Context.CreateSkip(ComplexPropertySegment.Property, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $search - parameter = Context.CreateSearch(TargetPath, _document) ?? Context.CreateSearch(ComplexPropertySegment.Property, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSearch(TargetPath, _document)) ?? Context.CreateSearch(ComplexPropertySegment.Property, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $filter - parameter = Context.CreateFilter(TargetPath, _document) ?? Context.CreateFilter(ComplexPropertySegment.Property, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateFilter(TargetPath, _document)) ?? Context.CreateFilter(ComplexPropertySegment.Property, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $count - parameter = Context.CreateCount(TargetPath, _document) ?? Context.CreateCount(ComplexPropertySegment.Property, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateCount(TargetPath, _document)) ?? Context.CreateCount(ComplexPropertySegment.Property, _document); if (parameter != null) { operation.Parameters.Add(parameter); @@ -112,40 +122,49 @@ protected override void SetParameters(OpenApiOperation operation) // of just providing a comma-separated list of properties can be expressed via an array-valued // parameter with an enum constraint // $order - parameter = Context.CreateOrderBy(TargetPath, ComplexPropertySegment.ComplexType) - ?? Context.CreateOrderBy(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); - if (parameter != null) + if (ComplexPropertySegment.ComplexType is not null) { - operation.Parameters.Add(parameter); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateOrderBy(TargetPath, ComplexPropertySegment.ComplexType)) + ?? Context.CreateOrderBy(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); + if (parameter != null) + { + operation.Parameters.Add(parameter); + } } } - // $select - parameter = Context.CreateSelect(TargetPath, ComplexPropertySegment.ComplexType) - ?? Context.CreateSelect(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); - if (parameter != null) + if (ComplexPropertySegment.ComplexType is not null) { - operation.Parameters.Add(parameter); - } + // $select + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, ComplexPropertySegment.ComplexType)) + ?? Context.CreateSelect(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); + if (parameter != null) + { + operation.Parameters.Add(parameter); + } - // $expand - parameter = Context.CreateExpand(TargetPath, ComplexPropertySegment.ComplexType) - ?? Context.CreateExpand(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); - if (parameter != null) - { - operation.Parameters.Add(parameter); + // $expand + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, ComplexPropertySegment.ComplexType)) + ?? Context.CreateExpand(ComplexPropertySegment.Property, ComplexPropertySegment.ComplexType); + if (parameter != null) + { + operation.Parameters.Add(parameter); + } } } protected override void SetExtensions(OpenApiOperation operation) { - if (Context.Settings.EnablePagination && ComplexPropertySegment.Property.Type.IsCollection()) + if (Context is {Settings.EnablePagination: true} && + ComplexPropertySegment is not null && + ComplexPropertySegment.Property.Type.IsCollection()) { JsonObject extension = new() { { "nextLinkName", "@odata.nextLink"}, { "operationName", Context.Settings.PageableOperationName} }; + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); base.SetExtensions(operation); @@ -154,18 +173,20 @@ protected override void SetExtensions(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - if (ComplexPropertySegment.Property.Type.IsCollection()) - { - SetCollectionResponse(operation, ComplexPropertySegment.ComplexType.FullName()); - } - else - { - var schema = new OpenApiSchemaReference(ComplexPropertySegment.ComplexType.FullName(), _document); + if (ComplexPropertySegment is not null) + if (ComplexPropertySegment.Property.Type.IsCollection()) + { + SetCollectionResponse(operation, ComplexPropertySegment.ComplexType.FullName()); + } + else + { + var schema = new OpenApiSchemaReference(ComplexPropertySegment.ComplexType.FullName(), _document); - SetSingleResponse(operation, schema); - } + SetSingleResponse(operation, schema); + } - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -176,7 +197,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_readRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_readRestrictions.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs index a6734b032..2bb2e2cf0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyPostOperationHandler.cs @@ -31,32 +31,36 @@ public ComplexPropertyPostOperationHandler(OpenApiDocument document):base(docume protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - if (!ComplexPropertySegment.Property.Type.IsCollection()) + if (ComplexPropertySegment is null || !ComplexPropertySegment.Property.Type.IsCollection()) { throw new InvalidOperationException("OData conventions do not support POSTing to a complex property that is not a collection."); } - _insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); - var complexPropertyInsertRestrictions = Context.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.InsertRestrictions); + if (!string.IsNullOrEmpty(TargetPath)) + { + _insertRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + } + + var complexPropertyInsertRestrictions = Context?.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.InsertRestrictions); _insertRestrictions?.MergePropertiesIfNull(complexPropertyInsertRestrictions); _insertRestrictions ??= complexPropertyInsertRestrictions; } /// public override HttpMethod OperationType => HttpMethod.Post; - private InsertRestrictionsType _insertRestrictions; + private InsertRestrictionsType? _insertRestrictions; /// protected override void SetBasicInfo(OpenApiOperation operation) { // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Path is not null) { operation.OperationId = EdmModelHelper.GenerateComplexPropertyPathOperationId(Path, Context, "Set"); } // Summary and Description - string placeHolder = $"Sets a new value for the collection of {ComplexPropertySegment.ComplexType.Name}."; + string placeHolder = $"Sets a new value for the collection of {ComplexPropertySegment?.ComplexType?.Name}."; operation.Summary = _insertRestrictions?.Description ?? placeHolder; operation.Description = _insertRestrictions?.LongDescription; @@ -68,6 +72,7 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + operation.Parameters ??= []; operation.Parameters.Add(new OpenApiParameter { Name = "If-Match", @@ -102,7 +107,8 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); base.SetResponses(operation); } @@ -113,7 +119,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_insertRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_insertRestrictions.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) @@ -134,8 +140,9 @@ protected override void AppendCustomParameters(OpenApiOperation operation) } } - private OpenApiSchema GetOpenApiSchema() + private OpenApiSchema? GetOpenApiSchema() { + if (ComplexPropertySegment is null) return null; return new() { Type = JsonSchemaType.Array, diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs index 1ac6ce8da..59532cf66 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ComplexPropertyUpdateOperationHandler.cs @@ -28,28 +28,33 @@ protected ComplexPropertyUpdateOperationHandler(OpenApiDocument document) : base } - private UpdateRestrictionsType _updateRestrictions; + private UpdateRestrictionsType? _updateRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - var complexPropertyUpdateRestrictions = Context.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions); - _updateRestrictions?.MergePropertiesIfNull(complexPropertyUpdateRestrictions); - _updateRestrictions ??= complexPropertyUpdateRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _updateRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + + if (ComplexPropertySegment is not null) + { + var complexPropertyUpdateRestrictions = Context?.Model.GetRecord(ComplexPropertySegment.Property, CapabilitiesConstants.UpdateRestrictions); + _updateRestrictions?.MergePropertiesIfNull(complexPropertyUpdateRestrictions); + _updateRestrictions ??= complexPropertyUpdateRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = $"Update property {ComplexPropertySegment.Property.Name} value."; + string placeHolder = $"Update property {ComplexPropertySegment?.Property.Name} value."; operation.Summary = _updateRestrictions?.Description ?? placeHolder; operation.Description = _updateRestrictions?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Path is not null) { string prefix = OperationType == HttpMethod.Patch ? "Update" : "Set"; operation.OperationId = EdmModelHelper.GenerateComplexPropertyPathOperationId(Path, Context, prefix); @@ -80,7 +85,8 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); base.SetResponses(operation); } protected override void SetSecurity(OpenApiOperation operation) @@ -90,7 +96,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_updateRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_updateRestrictions.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) @@ -111,8 +117,9 @@ protected override void AppendCustomParameters(OpenApiOperation operation) } } - private IOpenApiSchema GetOpenApiSchema() + private IOpenApiSchema? GetOpenApiSchema() { + if (ComplexPropertySegment is null) return null; var schema = new OpenApiSchemaReference(ComplexPropertySegment.ComplexType.FullName(), _document); if (ComplexPropertySegment.Property.Type.IsCollection()) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs index 0f7620d63..96b6e773d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/DollarCountGetOperationHandler.cs @@ -11,7 +11,6 @@ using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; -using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -40,8 +39,8 @@ public DollarCountGetOperationHandler(OpenApiDocument document) : base(document) /// Gets/sets the segment before $count. /// this segment could be "entity set", "Collection property", "Composable function whose return is collection",etc. /// - internal ODataSegment SecondLastSegment { get; set; } - private ODataSegment firstSegment; + internal ODataSegment? SecondLastSegment { get; set; } + private ODataSegment? firstSegment; private int pathCount; private const int SecondLastSegmentIndex = 2; private readonly List annotatables = []; @@ -61,19 +60,19 @@ protected override void Initialize(ODataContext context, ODataPath path) AddODataSegmentToAnnotables(SecondLastSegment, path.Segments.Count > SecondLastSegmentIndex ? path.Segments.SkipLast(SecondLastSegmentIndex).ToArray() : []); } - private void AddODataSegmentToAnnotables(ODataSegment oDataSegment, ODataSegment[] oDataSegments) + private void AddODataSegmentToAnnotables(ODataSegment? oDataSegment, ODataSegment[] oDataSegments) { - if (oDataSegment is ODataNavigationSourceSegment sourceSegment) + if (oDataSegment is ODataNavigationSourceSegment {NavigationSource: IEdmEntitySet sourceSet}) { - annotatables.Add(sourceSegment.NavigationSource as IEdmEntitySet); + annotatables.Add(sourceSet); } else if (oDataSegment is ODataNavigationPropertySegment navigationPropertySegment) { annotatables.Add(navigationPropertySegment.NavigationProperty); } - else if (oDataSegment is ODataTypeCastSegment odataTypeCastSegment) + else if (oDataSegment is ODataTypeCastSegment {StructuredType: IEdmVocabularyAnnotatable annotable}) { - annotatables.Add(odataTypeCastSegment.StructuredType as IEdmVocabularyAnnotatable); + annotatables.Add(annotable); if (annotatables.Count == 1 && oDataSegments.Length > 0) {// we want to look at the parent navigation property or entity set AddODataSegmentToAnnotables(oDataSegments[oDataSegments.Length - 1], oDataSegments.SkipLast(1).ToArray()); @@ -84,7 +83,7 @@ private void AddODataSegmentToAnnotables(ODataSegment oDataSegment, ODataSegment /// protected override void SetTags(OpenApiOperation operation) { - string tagName = null; + string? tagName = null; operation.Tags ??= new HashSet(); if (SecondLastSegment is ODataNavigationSourceSegment sourceSegment) @@ -95,7 +94,7 @@ protected override void SetTags(OpenApiOperation operation) { tagName = TagNameFromNavigationPropertySegment(); } - else if (SecondLastSegment is ODataTypeCastSegment) + else if (SecondLastSegment is ODataTypeCastSegment && Path is not null) { ODataSegment lastThirdSegment = Path.Segments[pathCount - 3]; if (lastThirdSegment is ODataNavigationSourceSegment sourceSegment2) @@ -107,12 +106,12 @@ protected override void SetTags(OpenApiOperation operation) tagName = TagNameFromNavigationPropertySegment(); } } - else if (SecondLastSegment is ODataComplexPropertySegment) + else if (SecondLastSegment is ODataComplexPropertySegment && Path is not null && Context is not null) { tagName = EdmModelHelper.GenerateComplexPropertyPathTagName(Path, Context); } - if (tagName != null) + if (tagName != null && Context is not null) { Context.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() { @@ -127,9 +126,9 @@ string TagNameFromNavigationSourceSegment(ODataNavigationSourceSegment sourceSeg return $"{sourceSegment.NavigationSource.Name}.{sourceSegment.NavigationSource.EntityType.Name}"; } - string TagNameFromNavigationPropertySegment() + string? TagNameFromNavigationPropertySegment() { - return EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context); + return Path is null || Context is null ? null : EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context); } base.SetTags(operation); @@ -142,9 +141,9 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Summary = $"Get the number of the resource"; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Path is not null) { - if (SecondLastSegment is ODataNavigationSourceSegment) + if (SecondLastSegment is ODataNavigationSourceSegment && firstSegment is not null) { operation.OperationId = $"{firstSegment.Identifier}.GetCount-{Path.GetPathHash(Context.Settings)}"; } @@ -153,9 +152,8 @@ protected override void SetBasicInfo(OpenApiOperation operation) var navPropOpId = string.Join(".", EdmModelHelper.RetrieveNavigationPropertyPathsOperationIdSegments(Path, Context)); operation.OperationId = $"{navPropOpId}.GetCount-{Path.GetPathHash(Context.Settings)}"; } - else if (SecondLastSegment is ODataTypeCastSegment odataTypeCastSegment) + else if (SecondLastSegment is ODataTypeCastSegment { StructuredType: IEdmNamedElement targetStructuredType}) { - IEdmNamedElement targetStructuredType = odataTypeCastSegment.StructuredType as IEdmNamedElement; operation.OperationId = $"{EdmModelHelper.GenerateODataTypeCastPathOperationIdPrefix(Path, Context, false)}.GetCount.As{Utils.UpperFirstChar(targetStructuredType.Name)}-{Path.GetPathHash(Context.Settings)}"; } else if (SecondLastSegment is ODataComplexPropertySegment) @@ -173,11 +171,12 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponseReference(Constants.DollarCountSchemaName, _document) } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -187,27 +186,30 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); - IOpenApiParameter parameter; - parameter = Context.CreateSearch(TargetPath, _document) ?? (annotatables.Count == 0 ? null : annotatables.Select(x => Context.CreateSearch(x, _document)).FirstOrDefault(static x => x is not null)); + var parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context?.CreateSearch(TargetPath, _document)) ?? + (annotatables.Count == 0 ? null : annotatables.Select(x => Context?.CreateSearch(x, _document)).FirstOrDefault(static x => x is not null)); if (parameter != null) { + operation.Parameters ??= []; operation.Parameters.Add(parameter); } - parameter = Context.CreateFilter(TargetPath, _document) ?? (annotatables.Count == 0 ? null : annotatables.Select(x => Context.CreateFilter(x, _document)).FirstOrDefault(static x => x is not null)); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context?.CreateFilter(TargetPath, _document)) ?? + (annotatables.Count == 0 ? null : annotatables.Select(x => Context?.CreateFilter(x, _document)).FirstOrDefault(static x => x is not null)); if (parameter != null) { + operation.Parameters ??= []; operation.Parameters.Add(parameter); } } protected override void AppendCustomParameters(OpenApiOperation operation) { - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - if (annotatables.Count > 0) + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (annotatables.Count > 0 && Context is not null) { - ReadRestrictionsType annotatableReadRestrictions = annotatables.Select(x => Context.Model.GetRecord(x, CapabilitiesConstants.ReadRestrictions)).FirstOrDefault(static x => x is not null); + var annotatableReadRestrictions = annotatables.Select(x => Context.Model.GetRecord(x, CapabilitiesConstants.ReadRestrictions)).FirstOrDefault(static x => x is not null); readRestrictions?.MergePropertiesIfNull(annotatableReadRestrictions); readRestrictions ??= annotatableReadRestrictions; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionImportOperationHandler.cs index 4111f9ddf..f5b94190f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionImportOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionImportOperationHandler.cs @@ -3,9 +3,11 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Generator; @@ -30,11 +32,10 @@ public EdmActionImportOperationHandler(OpenApiDocument document):base(document) protected override void SetRequestBody(OpenApiOperation operation) { - IEdmActionImport actionImport = EdmOperationImport as IEdmActionImport; - // The requestBody field contains a Request Body Object describing the structure of the request body. // Its schema value follows the rules for Schema Objects for complex types, with one property per action parameter. - operation.RequestBody = Context.CreateRequestBody(actionImport, _document); + if (EdmOperationImport is IEdmActionImport actionImport) + operation.RequestBody = Context?.CreateRequestBody(actionImport, _document); base.SetRequestBody(operation); } @@ -42,6 +43,7 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("actionImport")); base.SetExtensions(operation); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs index 057147b30..0aed94706 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmActionOperationHandler.cs @@ -3,9 +3,11 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -36,10 +38,14 @@ protected override void SetBasicInfo(OpenApiOperation operation) { base.SetBasicInfo(operation); - InsertRestrictionsType insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); - InsertRestrictionsType operationReadRestrictions = Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.InsertRestrictions); - insertRestrictions?.MergePropertiesIfNull(operationReadRestrictions); - insertRestrictions ??= operationReadRestrictions; + var insertRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + + if (Context is not null && EdmOperation is not null) + { + var operationReadRestrictions = Context?.Model.GetRecord(EdmOperation, CapabilitiesConstants.InsertRestrictions); + insertRestrictions?.MergePropertiesIfNull(operationReadRestrictions); + insertRestrictions ??= operationReadRestrictions; + } // Description if (!string.IsNullOrWhiteSpace(insertRestrictions?.LongDescription)) @@ -51,7 +57,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) /// protected override void SetRequestBody(OpenApiOperation operation) { - if (EdmOperation is IEdmAction action && Context.CreateRequestBody(action, _document) is OpenApiRequestBody requestBody) + if (EdmOperation is IEdmAction action && Context?.CreateRequestBody(action, _document) is OpenApiRequestBody requestBody) { if (Context.Model.OperationTargetsMultiplePaths(action)) { @@ -69,6 +75,7 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("action")); base.SetExtensions(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs index 50ec9a9f5..5c6e6c6a0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionImportOperationHandler.cs @@ -3,9 +3,11 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Generator; @@ -38,18 +40,21 @@ protected override void SetParameters(OpenApiOperation operation) return; } - if (OperationImportSegment.ParameterMappings != null) + if (OperationImportSegment?.ParameterMappings != null && + Context?.CreateParameters(functionImport.Function, _document, OperationImportSegment.ParameterMappings) is {} functionParamMappings) { - foreach (var param in Context.CreateParameters(functionImport.Function, _document, OperationImportSegment.ParameterMappings)) + operation.Parameters ??= []; + foreach (var param in functionParamMappings) { operation.Parameters.AppendParameter(param); } } - else + else if (Context?.CreateParameters(functionImport, _document) is {} functionParams) { + operation.Parameters ??= []; //The parameters array contains a Parameter Object for each parameter of the function overload, // and it contains specific Parameter Objects for the allowed system query options. - foreach (var param in Context.CreateParameters(functionImport, _document)) + foreach (var param in functionParams) { operation.Parameters.AppendParameter(param); } @@ -59,6 +64,7 @@ protected override void SetParameters(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("functionImport")); base.SetExtensions(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs index 802ccbbf4..bbe0c4bb5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmFunctionOperationHandler.cs @@ -3,9 +3,11 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -32,17 +34,21 @@ public EdmFunctionOperationHandler(OpenApiDocument document):base(document) /// /// Gets the Edm Function. /// - public IEdmFunction Function => EdmOperation as IEdmFunction; + public IEdmFunction? Function => EdmOperation as IEdmFunction; /// protected override void SetBasicInfo(OpenApiOperation operation) { base.SetBasicInfo(operation); - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType operationReadRestrictions = Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(operationReadRestrictions); - readRestrictions ??= operationReadRestrictions; + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + + if (Context is not null && EdmOperation is not null) + { + var operationReadRestrictions = Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(operationReadRestrictions); + readRestrictions ??= operationReadRestrictions; + } // Description if (!string.IsNullOrWhiteSpace(readRestrictions?.LongDescription)) @@ -54,6 +60,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("function")); base.SetExtensions(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs index d158e0654..b537b0b62 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationImportOperationHandler.cs @@ -8,6 +8,7 @@ using System.Linq; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -31,17 +32,17 @@ protected EdmOperationImportOperationHandler(OpenApiDocument document):base(docu { } - private OperationRestrictionsType _operationRestriction; + private OperationRestrictionsType? _operationRestriction; /// /// Gets the . /// - protected IEdmOperationImport EdmOperationImport { get; private set; } + protected IEdmOperationImport? EdmOperationImport { get; private set; } /// /// Gets the . /// - protected ODataOperationImportSegment OperationImportSegment { get; private set; } + protected ODataOperationImportSegment? OperationImportSegment { get; private set; } /// protected override void Initialize(ODataContext context, ODataPath path) @@ -49,29 +50,34 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); OperationImportSegment = path.LastSegment as ODataOperationImportSegment; - EdmOperationImport = OperationImportSegment.OperationImport; + EdmOperationImport = OperationImportSegment?.OperationImport; - _operationRestriction = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.OperationRestrictions); - var operationRestrictions = Context.Model.GetRecord(EdmOperationImport, CapabilitiesConstants.OperationRestrictions); - - if (_operationRestriction == null) - { - _operationRestriction = operationRestrictions; - } - else + _operationRestriction = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.OperationRestrictions); + + + if (EdmOperationImport is not null && Context?.Model.GetRecord(EdmOperationImport, CapabilitiesConstants.OperationRestrictions) is {} operationRestrictions) { - _operationRestriction.MergePropertiesIfNull(operationRestrictions); + if (_operationRestriction == null) + { + _operationRestriction = operationRestrictions; + } + else + { + _operationRestriction.MergePropertiesIfNull(operationRestrictions); + } } } /// protected override void SetBasicInfo(OpenApiOperation operation) { - operation.Summary = "Invoke " + (EdmOperationImport.IsActionImport() ? "actionImport " : "functionImport ") + EdmOperationImport.Name; + operation.Summary = "Invoke " + (EdmOperationImport.IsActionImport() ? "actionImport " : "functionImport ") + EdmOperationImport?.Name; - operation.Description = Context.Model.GetDescriptionAnnotation(TargetPath) ?? Context.Model.GetDescriptionAnnotation(EdmOperationImport); + if (Context is not null) + operation.Description = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetDescriptionAnnotation(TargetPath)) ?? + Context.Model.GetDescriptionAnnotation(EdmOperationImport); - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && EdmOperationImport is not null ) { if (EdmOperationImport.IsActionImport()) { @@ -81,7 +87,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) { if (Context.Model.IsOperationImportOverload(EdmOperationImport)) { - operation.OperationId = "FunctionImport." + EdmOperationImport.Name + "-" + Path.LastSegment.GetPathHash(Context.Settings); + operation.OperationId = "FunctionImport." + EdmOperationImport.Name + "-" + Path?.LastSegment?.GetPathHash(Context.Settings); } else { @@ -100,7 +106,9 @@ protected override void SetResponses(OpenApiOperation operation) // describing the structure of the success response by referencing an appropriate schema // in the global schemas. In addition, it contains a default name/value pair for // the OData error response referencing the global responses. - operation.Responses = Context.CreateResponses(EdmOperationImport, _document); + + if (Context is not null && EdmOperationImport is not null) + operation.Responses = Context.CreateResponses(EdmOperationImport, _document); base.SetResponses(operation); } @@ -113,7 +121,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_operationRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_operationRestriction.Permissions, _document).ToList(); } /// @@ -138,12 +146,16 @@ protected override void AppendCustomParameters(OpenApiOperation operation) /// protected override void SetTags(OpenApiOperation operation) { - var tag = CreateTag(EdmOperationImport); - tag.Extensions.Add(Constants.xMsTocType, new OpenApiAny("container")); - Context.AppendTag(tag); + if (EdmOperationImport is not null) + { + var tag = CreateTag(EdmOperationImport); + tag.Extensions ??= new Dictionary(); + tag.Extensions.Add(Constants.xMsTocType, new OpenApiAny("container")); + Context?.AppendTag(tag); - operation.Tags ??= new HashSet(); - operation.Tags.Add(new OpenApiTagReference(tag.Name, _document)); + operation.Tags ??= new HashSet(); + operation.Tags.Add(new OpenApiTagReference(tag.Name!, _document)); + } base.SetTags(operation); } @@ -172,10 +184,10 @@ internal static string PathAsString(IEnumerable path) /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs) + if (Context is {Settings.ShowExternalDocs: true} && CustomLinkRel is not null) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(EdmOperationImport, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetLinkRecord(TargetPath, CustomLinkRel)) ?? + (EdmOperationImport is null ? null : Context.Model.GetLinkRecord(EdmOperationImport, CustomLinkRel)); if (externalDocs != null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs index cfc186195..bcc644713 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EdmOperationOperationHandler.cs @@ -3,11 +3,13 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System; using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -31,22 +33,22 @@ protected EdmOperationOperationHandler(OpenApiDocument document) : base(document { } - private OperationRestrictionsType _operationRestriction; + private OperationRestrictionsType? _operationRestriction; /// /// Gets the navigation source. /// - protected IEdmNavigationSource NavigationSource { get; private set; } + protected IEdmNavigationSource? NavigationSource { get; private set; } /// /// Gets the Edm operation. /// - protected IEdmOperation EdmOperation { get; private set; } + protected IEdmOperation? EdmOperation { get; private set; } /// /// Gets the OData operation segment. /// - protected ODataOperationSegment OperationSegment { get; private set; } + protected ODataOperationSegment? OperationSegment { get; private set; } /// /// Gets a value indicating whether the path has type cast segment or not. @@ -59,31 +61,38 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); // It's bound operation, the first segment must be the navigaiton source. - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - NavigationSource = navigationSourceSegment.NavigationSource; + if (path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment) + NavigationSource = navigationSourceSegment.NavigationSource; - OperationSegment = path.LastSegment as ODataOperationSegment; - EdmOperation = OperationSegment.Operation; + if (path.LastSegment is ODataOperationSegment opSegment) + { + OperationSegment = opSegment; + EdmOperation = opSegment.Operation; + } HasTypeCast = path.Segments.Any(s => s is ODataTypeCastSegment); - _operationRestriction = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.OperationRestrictions); - var operationRestrictions = Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.OperationRestrictions); - _operationRestriction?.MergePropertiesIfNull(operationRestrictions); - _operationRestriction ??= operationRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _operationRestriction = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.OperationRestrictions); + if (Context is not null && EdmOperation is not null && + Context.Model.GetRecord(EdmOperation, CapabilitiesConstants.OperationRestrictions) is { } operationRestrictions) + { + _operationRestriction?.MergePropertiesIfNull(operationRestrictions); + _operationRestriction ??= operationRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { // Summary - operation.Summary = "Invoke " + (EdmOperation.IsAction() ? "action " : "function ") + EdmOperation.Name; + operation.Summary = "Invoke " + (EdmOperation?.IsAction() ?? false ? "action " : "function ") + EdmOperation?.Name; // Description - operation.Description = Context.Model.GetDescriptionAnnotation(TargetPath) ?? Context.Model.GetDescriptionAnnotation(EdmOperation); + operation.Description = (string.IsNullOrEmpty(TargetPath) ? null :Context?.Model.GetDescriptionAnnotation(TargetPath)) ?? Context?.Model.GetDescriptionAnnotation(EdmOperation); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Path is not null) { // When the key segment is available, // its EntityType name will be used @@ -96,7 +105,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) { if (segment is ODataKeySegment keySegment) { - if (!keySegment.IsAlternateKey) + if (!keySegment.IsAlternateKey && segment is {EntityType: not null}) { identifiers.Add(segment.EntityType.Name); continue; @@ -112,7 +121,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) identifiers.Add(keySegment.Identifier); } } - else if (segment is ODataOperationSegment opSegment) + else if (segment is ODataOperationSegment {Identifier: not null} opSegment) { if (opSegment.Operation is IEdmFunction function && Context.Model.IsOperationOverload(function)) { @@ -122,9 +131,9 @@ protected override void SetBasicInfo(OpenApiOperation operation) : (pathHash + opSegment.GetPathHash(Context.Settings)).GetHashSHA256()[..4]; } - identifiers.Add(segment.Identifier); + identifiers.Add(opSegment.Identifier); } - else + else if (!string.IsNullOrEmpty(segment.Identifier)) { identifiers.Add(segment.Identifier); } @@ -153,11 +162,12 @@ protected override void SetTags(OpenApiOperation operation) { Name = tagName, }; + tag.Extensions ??= new Dictionary(); tag.Extensions.Add(Constants.xMsTocType, new OpenApiAny("container")); operation.Tags ??= new HashSet(); operation.Tags.Add(new OpenApiTagReference(tag.Name, _document)); - Context.AppendTag(tag); + Context?.AppendTag(tag); base.SetTags(operation); } @@ -168,12 +178,13 @@ protected override void SetTags(OpenApiOperation operation) /// The generated tag name. /// The number of segments to skip. private void GenerateTagName(out string tagName, int skip = 1) - { + { + if (Path is null) throw new InvalidOperationException("Path is null."); var targetSegment = Path.Segments.Reverse().Skip(skip).FirstOrDefault(); switch (targetSegment) { - case ODataNavigationPropertySegment: + case ODataNavigationPropertySegment when Context is not null: tagName = EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context); break; case ODataOperationImportSegment: @@ -183,7 +194,7 @@ private void GenerateTagName(out string tagName, int skip = 1) GenerateTagName(out tagName, skip); break; default: - tagName = NavigationSource.Name + "." + NavigationSource.EntityType.Name; + tagName = NavigationSource?.Name + "." + NavigationSource?.EntityType.Name; if (EdmOperation.IsAction()) { tagName += ".Actions"; @@ -201,9 +212,8 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); - if (EdmOperation.IsFunction()) + if (EdmOperation.IsFunction() && EdmOperation is IEdmFunction function) { - IEdmFunction function = (IEdmFunction)EdmOperation; AppendSystemQueryOptions(function, operation); } } @@ -211,7 +221,8 @@ protected override void SetParameters(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - operation.Responses = Context.CreateResponses(EdmOperation, _document); + if (EdmOperation is not null && Context is not null) + operation.Responses = Context.CreateResponses(EdmOperation, _document); base.SetResponses(operation); } @@ -223,7 +234,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_operationRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_operationRestriction.Permissions, _document).ToList(); } /// @@ -247,8 +258,9 @@ protected override void AppendCustomParameters(OpenApiOperation operation) private void AppendSystemQueryOptions(IEdmFunction function, OpenApiOperation operation) { - if (function.ReturnType.IsCollection()) + if (function.ReturnType.IsCollection() && Context is not null) { + operation.Parameters ??= []; // $top if (Context.CreateTop(function, _document) is {} topParameter) { @@ -305,10 +317,10 @@ private void AppendSystemQueryOptions(IEdmFunction function, OpenApiOperation op /// protected override void SetCustomLinkRelType() { - if (Context.Settings.CustomHttpMethodLinkRelMapping != null && EdmOperation != null) + if (Context is {Settings.CustomHttpMethodLinkRelMapping: not null} && EdmOperation != null) { LinkRelKey key = EdmOperation.IsAction() ? LinkRelKey.Action : LinkRelKey.Function; - Context.Settings.CustomHttpMethodLinkRelMapping.TryGetValue(key, out string linkRelValue); + Context.Settings.CustomHttpMethodLinkRelMapping.TryGetValue(key, out var linkRelValue); CustomLinkRel = linkRelValue; } } @@ -316,10 +328,14 @@ protected override void SetCustomLinkRelType() /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs) + if (Context is { Settings.ShowExternalDocs: true }) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(EdmOperation, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath), string.IsNullOrEmpty(CustomLinkRel)) switch + { + (false, false) => Context.Model.GetLinkRecord(TargetPath!, CustomLinkRel!), + (true, false) when EdmOperation is not null => Context.Model.GetLinkRecord(EdmOperation, CustomLinkRel!), + (_, _) => null, + }; if (externalDocs != null) { @@ -335,14 +351,15 @@ protected override void SetExternalDocs(OpenApiOperation operation) // protected override void SetExtensions(OpenApiOperation operation) { - if (Context.Settings.EnablePagination && EdmOperation.ReturnType?.TypeKind() == EdmTypeKind.Collection) + if (Context is { Settings.EnablePagination: true } && EdmOperation?.ReturnType?.TypeKind() == EdmTypeKind.Collection) { - JsonObject extension = new JsonObject + var extension = new JsonObject { { "nextLinkName", "@odata.nextLink"}, { "operationName", Context.Settings.PageableOperationName} }; - + + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); } base.SetExtensions(operation); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs index 8b2091f05..16f8f7f3b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityDeleteOperationHandler.cs @@ -32,27 +32,29 @@ public EntityDeleteOperationHandler(OpenApiDocument document) : base(document) /// public override HttpMethod OperationType => HttpMethod.Delete; - private DeleteRestrictionsType _deleteRestrictions; + private DeleteRestrictionsType? _deleteRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); - var entityDeleteRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.DeleteRestrictions); - _deleteRestrictions?.MergePropertiesIfNull(entityDeleteRestrictions); - _deleteRestrictions ??= entityDeleteRestrictions; + if (Context is null) return; + if (!string.IsNullOrEmpty(TargetPath)) + _deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + if (EntitySet is not null) + { + var entityDeleteRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.DeleteRestrictions); + _deleteRestrictions?.MergePropertiesIfNull(entityDeleteRestrictions); + _deleteRestrictions ??= entityDeleteRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { - IEdmEntityType entityType = EntitySet.EntityType; - ODataKeySegment keySegment = Path.LastSegment as ODataKeySegment; - // Description - string placeHolder = $"Delete entity from {EntitySet.Name}"; - if (keySegment.IsAlternateKey) + string placeHolder = $"Delete entity from {EntitySet?.Name}"; + if (Path is {LastSegment: ODataKeySegment {IsAlternateKey: true} keySegment}) { placeHolder = $"{placeHolder} by {keySegment.Identifier}"; } @@ -60,13 +62,13 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Description = _deleteRestrictions?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is { Settings.EnableOperationId: true} && EntitySet?.EntityType is IEdmEntityType entityType) { string typeName = entityType.Name; string operationName =$"Delete{Utils.UpperFirstChar(typeName)}"; - if (keySegment.IsAlternateKey) + if (Path is {LastSegment: ODataKeySegment {IsAlternateKey: true} keySegment2}) { - string alternateKeyName = string.Join("", keySegment.Identifier.Split(',').Select(static x => Utils.UpperFirstChar(x))); + string alternateKeyName = string.Join("", keySegment2.Identifier.Split(',').Select(static x => Utils.UpperFirstChar(x))); operationName = $"{operationName}By{alternateKeyName}"; } operation.OperationId = $"{EntitySet.Name}.{typeName}.{operationName}"; @@ -78,6 +80,7 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + operation.Parameters ??= []; operation.Parameters.Add(new OpenApiParameter { Name = "If-Match", @@ -94,7 +97,7 @@ protected override void SetParameters(OpenApiOperation operation) protected override void SetResponses(OpenApiOperation operation) { // Response for Delete methods should be 204 No Content - OpenApiConvertSettings settings = Context.Settings.Clone(); + OpenApiConvertSettings settings = Context?.Settings.Clone() ?? new(); settings.UseSuccessStatusCodeRange = false; operation.AddErrorResponses(settings, _document, true); @@ -108,7 +111,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_deleteRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_deleteRestrictions.Permissions, _document).ToList() ?? []; } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs index 224c38333..b02d38abf 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityGetOperationHandler.cs @@ -35,39 +35,43 @@ public EntityGetOperationHandler(OpenApiDocument document) : base(document) /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestrictions; + private ReadRestrictionsType? _readRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); - _readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); - _readRestrictions ??= entityReadRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _readRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (Context is not null && EntitySet is not null) + { + var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); + _readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); + _readRestrictions ??= entityReadRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { - IEdmEntityType entityType = EntitySet.EntityType; - ODataKeySegment keySegment = Path.LastSegment as ODataKeySegment; + var keySegment = Path?.LastSegment as ODataKeySegment; // Description - string placeHolder = "Get entity from " + EntitySet.Name + " by key"; - if (keySegment.IsAlternateKey) + string placeHolder = "Get entity from " + EntitySet?.Name + " by key"; + if (keySegment?.IsAlternateKey ?? false) { placeHolder = $"{placeHolder} ({keySegment.Identifier})"; } operation.Summary = _readRestrictions?.ReadByKeyRestrictions?.Description ?? placeHolder; - operation.Description = _readRestrictions?.ReadByKeyRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(entityType); + operation.Description = _readRestrictions?.ReadByKeyRestrictions?.LongDescription ?? + (EntitySet is null ? null : Context?.Model.GetDescriptionAnnotation(EntitySet.EntityType)); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && EntitySet?.EntityType.Name is string entityTypeName) { - string typeName = entityType.Name; + string typeName = entityTypeName; string operationName = $"Get{Utils.UpperFirstChar(typeName)}"; - if (keySegment.IsAlternateKey) + if (keySegment?.IsAlternateKey ?? false) { string alternateKeyName = string.Join("", keySegment.Identifier.Split(',').Select(static x => Utils.UpperFirstChar(x))); operationName = $"{operationName}By{alternateKeyName}"; @@ -81,47 +85,49 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + if (Context is null || EntitySet is null) return; + // $select - OpenApiParameter parameter = Context.CreateSelect(EntitySet); - if (parameter != null) + if (Context.CreateSelect(EntitySet) is {} sParameter) { - operation.Parameters.Add(parameter); + operation.Parameters ??= []; + operation.Parameters.Add(sParameter); } // $expand - parameter = Context.CreateExpand(EntitySet); - if (parameter != null) + if (Context.CreateExpand(EntitySet) is {} eParameter) { - operation.Parameters.Add(parameter); + operation.Parameters ??= []; + operation.Parameters.Add(eParameter); } } /// protected override void SetResponses(OpenApiOperation operation) { - IOpenApiSchema schema = null; - IDictionary links = null; + IOpenApiSchema? schema = null; + IDictionary? links = null; - if (Context.Settings.EnableDerivedTypesReferencesForResponses) + if (EntitySet is not null) { - schema = EdmModelHelper.GetDerivedTypesReferenceSchema(EntitySet.EntityType, Context.Model, _document); - } + if (Context is {Settings.EnableDerivedTypesReferencesForResponses: true}) + { + schema = EdmModelHelper.GetDerivedTypesReferenceSchema(EntitySet.EntityType, Context.Model, _document); + } - if (Context.Settings.ShowLinks) - { - links = Context.CreateLinks(entityType: EntitySet.EntityType, entityName: EntitySet.Name, - entityKind: EntitySet.ContainerElementKind.ToString(), path: Path, parameters: PathParameters); - } + if (Context is {Settings.ShowLinks: true} && Path is not null) + { + links = Context.CreateLinks(entityType: EntitySet.EntityType, entityName: EntitySet.Name, + entityKind: EntitySet.ContainerElementKind.ToString(), path: Path, parameters: PathParameters); + } - if (schema == null) - { - schema = new OpenApiSchemaReference(EntitySet.EntityType.FullName(), _document); + schema ??= new OpenApiSchemaReference(EntitySet.EntityType.FullName(), _document); } operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Retrieved entity", @@ -139,7 +145,8 @@ protected override void SetResponses(OpenApiOperation operation) } } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -157,12 +164,12 @@ protected override void SetSecurity(OpenApiOperation operation) readBase = _readRestrictions.ReadByKeyRestrictions; } - if (readBase == null && readBase.Permissions == null) + if (readBase == null || readBase.Permissions == null) { return; } - operation.Security = Context.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs index 9dba9d979..e4b36f8ef 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetGetOperationHandler.cs @@ -3,11 +3,14 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System; +using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -36,28 +39,32 @@ public EntitySetGetOperationHandler(OpenApiDocument document) : base(document) /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestrictions; + private ReadRestrictionsType? _readRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); - _readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); - _readRestrictions ??= entityReadRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _readRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (Context is not null && EntitySet is not null) + { + var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); + _readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); + _readRestrictions ??= entityReadRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Descriptions - string placeHolder = "Get entities from " + EntitySet.Name; + string placeHolder = "Get entities from " + EntitySet?.Name; operation.Summary = _readRestrictions?.Description ?? placeHolder; - operation.Description = _readRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(EntitySet); + operation.Description = _readRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(EntitySet); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && EntitySet is not null) { string typeName = EntitySet.EntityType.Name; operation.OperationId = EntitySet.Name + "." + typeName + ".List" + Utils.UpperFirstChar(typeName); @@ -66,13 +73,14 @@ protected override void SetBasicInfo(OpenApiOperation operation) protected override void SetExtensions(OpenApiOperation operation) { - if (Context.Settings.EnablePagination) + if (Context is {Settings.EnablePagination: true}) { - JsonObject extension = new JsonObject + var extension = new JsonObject { { "nextLinkName", "@odata.nextLink"}, { "operationName", Context.Settings.PageableOperationName} }; + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); base.SetExtensions(operation); @@ -83,41 +91,43 @@ protected override void SetExtensions(OpenApiOperation operation) protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + if (Context is null || EntitySet is null) return; // The parameters array contains Parameter Objects for all system query options allowed for this collection, // and it does not list system query options not allowed for this collection, see terms // Capabilities.TopSupported, Capabilities.SkipSupported, Capabilities.SearchRestrictions, // Capabilities.FilterRestrictions, and Capabilities.CountRestrictions // $top - var parameter = Context.CreateTop(TargetPath, _document) ?? Context.CreateTop(EntitySet, _document); + operation.Parameters ??= []; + var parameter = (TargetPath is null ? null : Context.CreateTop(TargetPath, _document)) ?? Context.CreateTop(EntitySet, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $skip - parameter = Context.CreateSkip(TargetPath, _document) ?? Context.CreateSkip(EntitySet, _document); + parameter = (TargetPath is null ? null : Context.CreateSkip(TargetPath, _document)) ?? Context.CreateSkip(EntitySet, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $search - parameter = Context.CreateSearch(TargetPath, _document) ?? Context.CreateSearch(EntitySet, _document); + parameter = (TargetPath is null ? null : Context.CreateSearch(TargetPath, _document)) ?? Context.CreateSearch(EntitySet, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $filter - parameter = Context.CreateFilter(TargetPath, _document) ?? Context.CreateFilter(EntitySet, _document); + parameter = (TargetPath is null ? null : Context.CreateFilter(TargetPath, _document)) ?? Context.CreateFilter(EntitySet, _document); if (parameter != null) { operation.Parameters.Add(parameter); } // $count - parameter = Context.CreateCount(TargetPath, _document) ?? Context.CreateCount(EntitySet, _document); + parameter = (TargetPath is null ? null : Context.CreateCount(TargetPath, _document)) ?? Context.CreateCount(EntitySet, _document); if (parameter != null) { operation.Parameters.Add(parameter); @@ -128,21 +138,21 @@ protected override void SetParameters(OpenApiOperation operation) // of just providing a comma-separated list of properties can be expressed via an array-valued // parameter with an enum constraint // $order - parameter = Context.CreateOrderBy(TargetPath, EntitySet.EntityType) ?? Context.CreateOrderBy(EntitySet); + parameter = (TargetPath is null ? null : Context.CreateOrderBy(TargetPath, EntitySet.EntityType)) ?? Context.CreateOrderBy(EntitySet); if (parameter != null) { operation.Parameters.Add(parameter); } // $select - parameter = Context.CreateSelect(TargetPath, EntitySet.EntityType) ?? Context.CreateSelect(EntitySet); + parameter = (TargetPath is null ? null : Context.CreateSelect(TargetPath, EntitySet.EntityType)) ?? Context.CreateSelect(EntitySet); if (parameter != null) { operation.Parameters.Add(parameter); } // $expand - parameter = Context.CreateExpand(TargetPath, EntitySet.EntityType) ?? Context.CreateExpand(EntitySet); + parameter = (TargetPath is null ? null : Context.CreateExpand(TargetPath, EntitySet.EntityType)) ?? Context.CreateExpand(EntitySet); if (parameter != null) { operation.Parameters.Add(parameter); @@ -155,12 +165,13 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, - new OpenApiResponseReference($"{EntitySet.EntityType.FullName()}{Constants.CollectionSchemaSuffix}", _document) + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + new OpenApiResponseReference($"{EntitySet?.EntityType.FullName()}{Constants.CollectionSchemaSuffix}", _document) } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -172,7 +183,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_readRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_readRestrictions.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetOperationHandler.cs index 4719ddee7..e3a79902c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetOperationHandler.cs @@ -5,6 +5,7 @@ using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -30,7 +31,7 @@ protected EntitySetOperationHandler(OpenApiDocument document) : base(document) /// /// Gets/sets the . /// - protected IEdmEntitySet EntitySet { get; private set; } + protected IEdmEntitySet? EntitySet { get; private set; } /// protected override void Initialize(ODataContext context, ODataPath path) @@ -38,19 +39,18 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); // get the entity set. - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - - EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmEntitySet navigationSource}) + EntitySet = navigationSource; } /// protected override void SetTags(OpenApiOperation operation) { - var tagName = EntitySet.Name + "." + EntitySet.EntityType.Name; + var tagName = EntitySet?.Name + "." + EntitySet?.EntityType.Name; operation.Tags ??= new HashSet(); operation.Tags.Add(new OpenApiTagReference(tagName, _document)); - Context.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() + Context?.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() { Name = tagName }); @@ -61,6 +61,7 @@ protected override void SetTags(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("operation")); base.SetExtensions(operation); @@ -69,10 +70,10 @@ protected override void SetExtensions(OpenApiOperation operation) /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs) + if (Context is {Settings.ShowExternalDocs: true} && CustomLinkRel is not null) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(EntitySet, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetLinkRecord(TargetPath, CustomLinkRel)) ?? + (EntitySet is null ? null : Context.Model.GetLinkRecord(EntitySet, CustomLinkRel)); if (externalDocs != null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs index 046ba8380..235b8fd2e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntitySetPostOperationHandler.cs @@ -36,28 +36,32 @@ public EntitySetPostOperationHandler(OpenApiDocument document) : base(document) /// public override HttpMethod OperationType => HttpMethod.Post; - private InsertRestrictionsType _insertRestrictions; + private InsertRestrictionsType? _insertRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); - var entityInsertRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.InsertRestrictions); - _insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); - _insertRestrictions ??= entityInsertRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _insertRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + if (Context is not null && EntitySet is not null) + { + var entityInsertRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.InsertRestrictions); + _insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); + _insertRestrictions ??= entityInsertRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Add new entity to " + EntitySet.Name; + string placeHolder = "Add new entity to " + EntitySet?.Name; operation.Summary = _insertRestrictions?.Description ?? placeHolder; operation.Description = _insertRestrictions?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && EntitySet is not null) { string typeName = EntitySet.EntityType.Name; operation.OperationId = EntitySet.Name + "." + typeName + ".Create" + Utils.UpperFirstChar(typeName); @@ -85,7 +89,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode201, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode201, new OpenApiResponse { Description = "Created entity", @@ -94,7 +98,8 @@ protected override void SetResponses(OpenApiOperation operation) } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -106,7 +111,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_insertRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_insertRestrictions.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) @@ -136,16 +141,14 @@ private IDictionary GetContentDescription() var schema = GetEntitySchema(); var content = new Dictionary(); - if (EntitySet.EntityType.HasStream) + if (EntitySet is {EntityType.HasStream: true}) { - IEnumerable mediaTypes = Context.Model.GetCollection(EntitySet.EntityType, - CoreConstants.AcceptableMediaTypes); - - if (mediaTypes != null) + if (Context?.Model.GetCollection(EntitySet.EntityType, + CoreConstants.AcceptableMediaTypes) is {} mediaTypes) { foreach (string item in mediaTypes) { - content.Add(item, null); + content.Add(item, new()); } } else @@ -164,8 +167,7 @@ private IDictionary GetContentDescription() else { // Add the annotated request content media types - IEnumerable mediaTypes = _insertRestrictions?.RequestContentTypes; - if (mediaTypes != null) + if (_insertRestrictions?.RequestContentTypes is {} mediaTypes) { foreach (string mediaType in mediaTypes) { @@ -192,9 +194,10 @@ private IDictionary GetContentDescription() /// Get the entity schema. /// /// The entity schema. - private IOpenApiSchema GetEntitySchema() + private IOpenApiSchema? GetEntitySchema() { - return Context.Settings.EnableDerivedTypesReferencesForRequestBody ? + if (EntitySet is null) return null; + return Context?.Settings.EnableDerivedTypesReferencesForRequestBody ?? false ? EdmModelHelper.GetDerivedTypesReferenceSchema(EntitySet.EntityType, Context.Model, _document) : new OpenApiSchemaReference(EntitySet.EntityType.FullName(), _document); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityUpdateOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityUpdateOperationHandler.cs index a34d6d9f2..81be9e2bd 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/EntityUpdateOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/EntityUpdateOperationHandler.cs @@ -30,27 +30,30 @@ protected EntityUpdateOperationHandler(OpenApiDocument document):base(document) { } - private UpdateRestrictionsType _updateRestrictions; + private UpdateRestrictionsType? _updateRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - var entityUpdateRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.UpdateRestrictions); - _updateRestrictions?.MergePropertiesIfNull(entityUpdateRestrictions); - _updateRestrictions ??= entityUpdateRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _updateRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + if (Context is not null && EntitySet is not null) + { + var entityUpdateRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.UpdateRestrictions); + _updateRestrictions?.MergePropertiesIfNull(entityUpdateRestrictions); + _updateRestrictions ??= entityUpdateRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { - IEdmEntityType entityType = EntitySet.EntityType; - ODataKeySegment keySegment = Path.LastSegment as ODataKeySegment; + var keySegment = Path?.LastSegment as ODataKeySegment; // Summary and Description - string placeHolder = "Update entity in " + EntitySet.Name; - if (keySegment.IsAlternateKey) + string placeHolder = "Update entity in " + EntitySet?.Name; + if (keySegment is {IsAlternateKey: true}) { placeHolder = $"{placeHolder} by {keySegment.Identifier}"; } @@ -58,12 +61,12 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Description = _updateRestrictions?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && EntitySet?.EntityType is {} entityType) { string typeName = entityType.Name; string prefix = OperationType == HttpMethod.Patch ? "Update" : "Set"; string operationName = $"{prefix}{ Utils.UpperFirstChar(typeName)}"; - if (keySegment.IsAlternateKey) + if (keySegment is {IsAlternateKey: true}) { string alternateKeyName = string.Join("", keySegment.Identifier.Split(',').Select(static x => Utils.UpperFirstChar(x))); operationName = $"{operationName}By{alternateKeyName}"; @@ -89,10 +92,9 @@ protected IDictionary GetContent() { var schema = GetOpenApiSchema(); var content = new Dictionary(); - IEnumerable mediaTypes = _updateRestrictions?.RequestContentTypes; // Add the annotated request content media types - if (mediaTypes != null) + if (_updateRestrictions?.RequestContentTypes is {} mediaTypes) { foreach (string mediaType in mediaTypes) { @@ -109,7 +111,7 @@ protected IDictionary GetContent() { Schema = schema }); - }; + } return content; } @@ -117,7 +119,8 @@ protected IDictionary GetContent() /// protected override void SetResponses(OpenApiOperation operation) { - operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); + if (GetOpenApiSchema() is {} schema) + operation.AddErrorResponses(Context?.Settings ?? new(), _document, true, schema); base.SetResponses(operation); } @@ -128,7 +131,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_updateRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_updateRestrictions.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) @@ -149,11 +152,13 @@ protected override void AppendCustomParameters(OpenApiOperation operation) } } - private IOpenApiSchema GetOpenApiSchema() + private IOpenApiSchema? GetOpenApiSchema() { - if (Context.Settings.EnableDerivedTypesReferencesForRequestBody) + if (EntitySet is null) return null; + if (Context is {Settings.EnableDerivedTypesReferencesForRequestBody: true} && + EdmModelHelper.GetDerivedTypesReferenceSchema(EntitySet.EntityType, Context.Model, _document) is {} schema) { - return EdmModelHelper.GetDerivedTypesReferenceSchema(EntitySet.EntityType, Context.Model, _document); + return schema; } return new OpenApiSchemaReference(EntitySet.EntityType.FullName(), _document); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandlerProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandlerProvider.cs index be07c065f..4d812c1c7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandlerProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/IOperationHandlerProvider.cs @@ -21,6 +21,6 @@ internal interface IOperationHandlerProvider /// The operation type. /// The Open API document to use to lookup references. /// The corresponding . - IOperationHandler GetHandler(ODataPathKind pathKind, HttpMethod operationType, OpenApiDocument document); + IOperationHandler? GetHandler(ODataPathKind pathKind, HttpMethod operationType, OpenApiDocument document); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs index af94ff02c..bacd851e2 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityDeleteOperationHandler.cs @@ -22,7 +22,7 @@ public MediaEntityDeleteOperationHandler(OpenApiDocument document) : base(docume /// public override HttpMethod OperationType => HttpMethod.Delete; - private DeleteRestrictionsType _deleteRestrictions; + private DeleteRestrictionsType? _deleteRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { @@ -30,17 +30,18 @@ protected override void Initialize(ODataContext context, ODataPath path) if (Property != null) { - _deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + if (!string.IsNullOrEmpty(TargetPath)) + _deleteRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); if (Property is IEdmNavigationProperty) { - var navigationDeleteRestrictions = Context.Model.GetRecord(Property, CapabilitiesConstants.NavigationRestrictions)? + var navigationDeleteRestrictions = Context?.Model.GetRecord(Property, CapabilitiesConstants.NavigationRestrictions)? .RestrictedProperties?.FirstOrDefault()?.DeleteRestrictions; _deleteRestrictions?.MergePropertiesIfNull(navigationDeleteRestrictions); _deleteRestrictions ??= navigationDeleteRestrictions; } else { - var propertyDeleteRestrictions = Context.Model.GetRecord(Property, CapabilitiesConstants.DeleteRestrictions); + var propertyDeleteRestrictions = Context?.Model.GetRecord(Property, CapabilitiesConstants.DeleteRestrictions); _deleteRestrictions?.MergePropertiesIfNull(propertyDeleteRestrictions); _deleteRestrictions ??= propertyDeleteRestrictions; } @@ -51,19 +52,19 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary - string placeholderValue = LastSegmentIsStreamPropertySegment ? Path.LastSegment.Identifier : "media content"; + string placeholderValue = LastSegmentIsStreamPropertySegment && Path is {LastSegment.Identifier: not null} ? Path.LastSegment.Identifier : "media content"; operation.Summary = _deleteRestrictions?.Description; operation.Summary ??= IsNavigationPropertyPath - ? $"Delete {placeholderValue} for the navigation property {NavigationProperty.Name} in {NavigationSourceSegment.NavigationSource.Name}" - : $"Delete {placeholderValue} for {NavigationSourceSegment.EntityType.Name} in {NavigationSourceSegment.Identifier}"; + ? $"Delete {placeholderValue} for the navigation property {NavigationProperty?.Name} in {NavigationSourceSegment?.NavigationSource.Name}" + : $"Delete {placeholderValue} for {NavigationSourceSegment?.EntityType.Name} in {NavigationSourceSegment?.Identifier}"; // Description - operation.Description = _deleteRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(Property); + operation.Description = _deleteRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(Property); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { - string identifier = LastSegmentIsStreamPropertySegment ? Path.LastSegment.Identifier : "Content"; + string identifier = LastSegmentIsStreamPropertySegment && Path is {LastSegment.Identifier: not null} ? Path.LastSegment.Identifier : "Content"; operation.OperationId = GetOperationId("Delete", identifier); } @@ -75,6 +76,7 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + operation.Parameters ??= []; operation.Parameters.Add(new OpenApiParameter { Name = "If-Match", @@ -91,7 +93,7 @@ protected override void SetParameters(OpenApiOperation operation) protected override void SetResponses(OpenApiOperation operation) { // Response for Delete methods should be 204 No Content - OpenApiConvertSettings settings = Context.Settings.Clone(); + OpenApiConvertSettings settings = Context?.Settings.Clone() ?? new(); settings.UseSuccessStatusCodeRange = false; operation.AddErrorResponses(settings, _document, true); @@ -105,7 +107,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_deleteRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_deleteRestrictions.Permissions, _document).ToList() ?? []; } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs index 1f6a695b7..e44471ed4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityGetOperationHandler.cs @@ -30,7 +30,7 @@ public MediaEntityGetOperationHandler(OpenApiDocument document) : base(document) } /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestrictions = null; + private ReadRestrictionsType? _readRestrictions = null; protected override void Initialize(ODataContext context, ODataPath path) { @@ -38,17 +38,18 @@ protected override void Initialize(ODataContext context, ODataPath path) if (Property != null) { - _readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (!string.IsNullOrEmpty(TargetPath)) + _readRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); if (Property is IEdmNavigationProperty) { - var navigationReadRestrictions = Context.Model.GetRecord(Property, CapabilitiesConstants.NavigationRestrictions)? + var navigationReadRestrictions = Context?.Model.GetRecord(Property, CapabilitiesConstants.NavigationRestrictions)? .RestrictedProperties?.FirstOrDefault()?.ReadRestrictions; _readRestrictions?.MergePropertiesIfNull(navigationReadRestrictions); _readRestrictions ??= navigationReadRestrictions; } else { - var propertyReadRestrictions = Context.Model.GetRecord(Property, CapabilitiesConstants.ReadRestrictions); + var propertyReadRestrictions = Context?.Model.GetRecord(Property, CapabilitiesConstants.ReadRestrictions); _readRestrictions?.MergePropertiesIfNull(propertyReadRestrictions); _readRestrictions ??= propertyReadRestrictions; } @@ -59,34 +60,35 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary - string placeholderValue = LastSegmentIsStreamPropertySegment ? Path.LastSegment.Identifier : "media content"; + var placeholderValue = LastSegmentIsStreamPropertySegment ? Path?.LastSegment?.Identifier : "media content"; operation.Summary = _readRestrictions?.Description; operation.Summary ??= IsNavigationPropertyPath - ? $"Get {placeholderValue} for the navigation property {NavigationProperty.Name} from {NavigationSourceSegment.NavigationSource.Name}" - : $"Get {placeholderValue} for {NavigationSourceSegment.EntityType.Name} from {NavigationSourceSegment.Identifier}"; + ? $"Get {placeholderValue} for the navigation property {NavigationProperty?.Name} from {NavigationSourceSegment?.NavigationSource.Name}" + : $"Get {placeholderValue} for {NavigationSourceSegment?.EntityType.Name} from {NavigationSourceSegment?.Identifier}"; // Description - string description; + string? description; if (Property is IEdmNavigationProperty) { description = LastSegmentIsKeySegment ? _readRestrictions?.ReadByKeyRestrictions?.LongDescription : _readRestrictions?.LongDescription - ?? Context.Model.GetDescriptionAnnotation(Property); + ?? Context?.Model.GetDescriptionAnnotation(Property); } else { // Structural property - description = _readRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(Property); + description = _readRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(Property); } - operation.Description = description; + if (!string.IsNullOrEmpty(description)) + operation.Description = description; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && + (LastSegmentIsStreamPropertySegment ? Path?.LastSegment?.Identifier : "Content") is string identifier) { - string identifier = LastSegmentIsStreamPropertySegment ? Path.LastSegment.Identifier : "Content"; operation.OperationId = GetOperationId("Get", identifier); } } @@ -97,7 +99,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Retrieved media content", @@ -105,7 +107,8 @@ protected override void SetResponses(OpenApiOperation operation) } } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -113,9 +116,8 @@ protected override void SetResponses(OpenApiOperation operation) /// protected override void SetSecurity(OpenApiOperation operation) { - IEdmVocabularyAnnotatable annotatableNavigationSource = (IEdmVocabularyAnnotatable)NavigationSourceSegment.NavigationSource; - ReadRestrictionsType read = Context.Model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.ReadRestrictions); - if (read == null) + if (NavigationSourceSegment?.NavigationSource is not IEdmVocabularyAnnotatable annotatableNavigationSource || + Context?.Model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.ReadRestrictions) is not {} read) { return; } @@ -126,7 +128,7 @@ protected override void SetSecurity(OpenApiOperation operation) readBase = read.ReadByKeyRestrictions; } - if (readBase == null && readBase.Permissions == null) + if (readBase == null || readBase.Permissions == null) { return; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs index 488046d6c..cc954648c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityOperationalHandler.cs @@ -10,6 +10,7 @@ using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.OData.Vocabulary.Core; +using System; using System.Collections.Generic; using System.Linq; @@ -31,7 +32,7 @@ protected MediaEntityOperationalHandler(OpenApiDocument document) : base(documen /// /// Gets/Sets the NavigationSource segment /// - protected ODataNavigationSourceSegment NavigationSourceSegment { get; private set; } + protected ODataNavigationSourceSegment? NavigationSourceSegment { get; private set; } /// /// Gets/Sets flag indicating whether path is navigation property path @@ -50,12 +51,12 @@ protected MediaEntityOperationalHandler(OpenApiDocument document) : base(documen /// /// Gets the media entity property. /// - protected IEdmProperty Property { get; private set; } + protected IEdmProperty? Property { get; private set; } /// /// Gets the navigation property. /// - protected IEdmNavigationProperty NavigationProperty { get; private set; } + protected IEdmNavigationProperty? NavigationProperty { get; private set; } /// protected override void Initialize(ODataContext context, ODataPath path) @@ -64,12 +65,13 @@ protected override void Initialize(ODataContext context, ODataPath path) NavigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; // Check whether path is a navigation property path - IsNavigationPropertyPath = Path.Segments.Contains( - Path.Segments.FirstOrDefault(segment => segment is ODataNavigationPropertySegment)); + IsNavigationPropertyPath = Path is not null && + Path.Segments.OfType().FirstOrDefault() is {} firstPropSegment && + Path.Segments.Contains(firstPropSegment); - LastSegmentIsStreamPropertySegment = Path.LastSegment.Kind == ODataSegmentKind.StreamProperty; + LastSegmentIsStreamPropertySegment = Path?.LastSegment?.Kind == ODataSegmentKind.StreamProperty; - LastSegmentIsStreamContentSegment = Path.LastSegment.Kind == ODataSegmentKind.StreamContent; + LastSegmentIsStreamContentSegment = Path?.LastSegment?.Kind == ODataSegmentKind.StreamContent; LastSegmentIsKeySegment = path.LastSegment is ODataKeySegment; @@ -87,12 +89,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetTags(OpenApiOperation operation) { - string tagIdentifier = IsNavigationPropertyPath + string tagIdentifier = IsNavigationPropertyPath && Path is not null && Context is not null ? EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context) - : NavigationSourceSegment.Identifier + "." + NavigationSourceSegment.EntityType.Name; + : NavigationSourceSegment?.Identifier + "." + NavigationSourceSegment?.EntityType.Name; - Context.AddExtensionToTag(tagIdentifier, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() + Context?.AddExtensionToTag(tagIdentifier, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() { Name = tagIdentifier }); @@ -118,17 +120,19 @@ protected string GetOperationId(string prefix, string identifier) Utils.CheckArgumentNullOrEmpty(prefix, nameof(prefix)); Utils.CheckArgumentNullOrEmpty(identifier, nameof(identifier)); - var items = new List + var items = NavigationSourceSegment is null ? [] : new List { NavigationSourceSegment.Identifier }; + if (Path is null) throw new InvalidOperationException("Path is null."); + ODataSegment lastSegment = Path.Segments.Last(c => c is ODataStreamContentSegment || c is ODataStreamPropertySegment); foreach (ODataSegment segment in Path.Segments.Skip(1)) { if (segment == lastSegment) { - if (!IsNavigationPropertyPath) + if (!IsNavigationPropertyPath && NavigationSourceSegment is not null) { string typeName = NavigationSourceSegment.EntityType.Name; items.Add(typeName); @@ -138,8 +142,11 @@ protected string GetOperationId(string prefix, string identifier) { // Remove the last navigation property segment for navigation property paths, // as this will be included within the prefixed name of the operation id - items.Remove(NavigationProperty.Name); - items.Add(prefix + Utils.UpperFirstChar(NavigationProperty.Name) + Utils.UpperFirstChar(identifier)); + if (NavigationProperty is not null) + { + items.Remove(NavigationProperty.Name); + items.Add(prefix + Utils.UpperFirstChar(NavigationProperty.Name) + Utils.UpperFirstChar(identifier)); + } } break; } @@ -152,7 +159,7 @@ protected string GetOperationId(string prefix, string identifier) } } - return $"{string.Join(".", items)}-{Path.GetPathHash(Context.Settings)}"; + return $"{string.Join(".", items)}-{Path.GetPathHash(Context?.Settings ?? new())}"; } /// @@ -163,12 +170,6 @@ protected IDictionary GetContentDescription() { // Fetch the respective AcceptableMediaTypes (_, var property) = GetStreamElements(); - IEnumerable mediaTypes = null; - if (property != null) - { - mediaTypes = Context.Model.GetCollection(property, - CoreConstants.AcceptableMediaTypes); - } OpenApiSchema schema = new() { @@ -177,7 +178,9 @@ protected IDictionary GetContentDescription() }; var content = new Dictionary(); - if (mediaTypes != null) + if (property is not null && + Context?.Model.GetCollection(property, + CoreConstants.AcceptableMediaTypes) is {} mediaTypes) { foreach (string item in mediaTypes) { @@ -203,35 +206,44 @@ protected IDictionary GetContentDescription() /// Gets the stream property and entity type declaring the stream property. /// /// The stream property and entity type declaring the stream property. - protected (IEdmEntityType entityType, IEdmProperty property) GetStreamElements() + protected (IEdmEntityType? entityType, IEdmProperty? property) GetStreamElements() { // Only ODataStreamPropertySegment is annotatable - if (!LastSegmentIsStreamPropertySegment && !LastSegmentIsStreamContentSegment) return (null, null); + if (!LastSegmentIsStreamPropertySegment && !LastSegmentIsStreamContentSegment || Path is null) return (null, null); // Retrieve the entity type of the segment before the stream property segment var entityType = LastSegmentIsStreamContentSegment - ? Path.Segments.ElementAtOrDefault(Path.Segments.Count - 3).EntityType - : Path.Segments.ElementAtOrDefault(Path.Segments.Count - 2).EntityType; + ? Path.Segments.ElementAtOrDefault(Path.Segments.Count - 3)?.EntityType + : Path.Segments.ElementAtOrDefault(Path.Segments.Count - 2)?.EntityType; + + if (entityType is null) return (null, null); // The stream property can either be a structural type or a navigation property type - ODataSegment lastSegmentProp = LastSegmentIsStreamContentSegment + var lastSegmentProp = LastSegmentIsStreamContentSegment ? Path.Segments.Reverse().Skip(1).FirstOrDefault() - : Path.Segments.LastOrDefault(c => c is ODataStreamPropertySegment); - IEdmProperty property = GetStructuralProperty(entityType, lastSegmentProp.Identifier); - if (property == null) + : Path.Segments.OfType().LastOrDefault(); + + if (lastSegmentProp?.Identifier is not string lastIdentifier) return (null, null); + + if (GetStructuralProperty(entityType, lastIdentifier) is IEdmProperty property) { - property = GetNavigationProperty(entityType, lastSegmentProp.Identifier); + return (entityType, property); } - return (entityType, property); + if (GetNavigationProperty(entityType, lastIdentifier) is IEdmProperty navigationProperty) + { + return (entityType, navigationProperty); + } + + return (null, null); } - private IEdmStructuralProperty GetStructuralProperty(IEdmEntityType entityType, string identifier) + private static IEdmStructuralProperty? GetStructuralProperty(IEdmEntityType entityType, string identifier) { return entityType.StructuralProperties().FirstOrDefault(x => x.Name.Equals(identifier)); } - private IEdmNavigationProperty GetNavigationProperty(IEdmEntityType entityType, string identifier) + private static IEdmNavigationProperty? GetNavigationProperty(IEdmEntityType entityType, string identifier) { return entityType.DeclaredNavigationProperties().FirstOrDefault(x => x.Name.Equals(identifier)); } @@ -239,10 +251,14 @@ private IEdmNavigationProperty GetNavigationProperty(IEdmEntityType entityType, /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs && Property != null) + if (Context is { Settings.ShowExternalDocs: true } && Property != null) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(Property, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath), string.IsNullOrEmpty(CustomLinkRel)) switch + { + (_, true) => null, + (false, false) => Context.Model.GetLinkRecord(TargetPath!, CustomLinkRel!), + (_, false) => Context.Model.GetLinkRecord(Property, CustomLinkRel!), + }; if (externalDocs != null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs index 0fde994a4..66db24322 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MediaEntityPutOperationHandler.cs @@ -33,7 +33,7 @@ public MediaEntityPutOperationHandler(OpenApiDocument document):base(document) /// public override HttpMethod OperationType => HttpMethod.Put; - private UpdateRestrictionsType _updateRestrictions = null; + private UpdateRestrictionsType? _updateRestrictions = null; protected override void Initialize(ODataContext context, ODataPath path) { @@ -41,17 +41,18 @@ protected override void Initialize(ODataContext context, ODataPath path) if (Property != null) { - _updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + if (!string.IsNullOrEmpty(TargetPath)) + _updateRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); if (Property is IEdmNavigationProperty) { - var navigationUpdateRestrictions = Context.Model.GetRecord(Property, CapabilitiesConstants.NavigationRestrictions)? + var navigationUpdateRestrictions = Context?.Model.GetRecord(Property, CapabilitiesConstants.NavigationRestrictions)? .RestrictedProperties?.FirstOrDefault()?.UpdateRestrictions; _updateRestrictions?.MergePropertiesIfNull(navigationUpdateRestrictions); _updateRestrictions ??= navigationUpdateRestrictions; } else { - var propertyUpdateRestrictions = Context.Model.GetRecord(Property, CapabilitiesConstants.UpdateRestrictions); + var propertyUpdateRestrictions = Context?.Model.GetRecord(Property, CapabilitiesConstants.UpdateRestrictions); _updateRestrictions?.MergePropertiesIfNull(propertyUpdateRestrictions); _updateRestrictions ??= propertyUpdateRestrictions; } @@ -62,19 +63,19 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary - string placeholderValue = LastSegmentIsStreamPropertySegment ? Path.LastSegment.Identifier : "media content"; + var placeholderValue = LastSegmentIsStreamPropertySegment ? Path?.LastSegment?.Identifier : "media content"; operation.Summary = _updateRestrictions?.Description; operation.Summary ??= IsNavigationPropertyPath - ? $"Update {placeholderValue} for the navigation property {NavigationProperty.Name} in {NavigationSourceSegment.NavigationSource.Name}" - : $"Update {placeholderValue} for {NavigationSourceSegment.EntityType.Name} in {NavigationSourceSegment.Identifier}"; + ? $"Update {placeholderValue} for the navigation property {NavigationProperty?.Name} in {NavigationSourceSegment?.NavigationSource.Name}" + : $"Update {placeholderValue} for {NavigationSourceSegment?.EntityType.Name} in {NavigationSourceSegment?.Identifier}"; // Description - operation.Description = _updateRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(Property); + operation.Description = _updateRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(Property); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { - string identifier = LastSegmentIsStreamPropertySegment ? Path.LastSegment.Identifier : "Content"; + var identifier = LastSegmentIsStreamPropertySegment && Path?.LastSegment?.Identifier is string lastIdentifier ? lastIdentifier : "Content"; operation.OperationId = GetOperationId("Update", identifier); } } @@ -95,18 +96,18 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - if (LastSegmentIsStreamPropertySegment && Path.LastSegment.Identifier.Equals(Constants.Content, StringComparison.OrdinalIgnoreCase)) + if (LastSegmentIsStreamPropertySegment && Constants.Content.Equals(Path?.LastSegment?.Identifier, StringComparison.OrdinalIgnoreCase)) { // Get the entity type declaring this stream property. (var entityType, _) = GetStreamElements(); var schema = new OpenApiSchemaReference(entityType.FullName(), _document); - operation.AddErrorResponses(Context.Settings, _document, addNoContent: true, schema: schema); + operation.AddErrorResponses(Context?.Settings ?? new(), _document, addNoContent: true, schema: schema); } else { - operation.AddErrorResponses(Context.Settings, _document, true); + operation.AddErrorResponses(Context?.Settings ?? new(), _document, true); } base.SetResponses(operation); @@ -115,9 +116,9 @@ protected override void SetResponses(OpenApiOperation operation) /// protected override void SetSecurity(OpenApiOperation operation) { - IEdmVocabularyAnnotatable annotatableNavigationSource = (IEdmVocabularyAnnotatable)NavigationSourceSegment.NavigationSource; - UpdateRestrictionsType update = Context.Model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.UpdateRestrictions); - if (update == null || update.Permissions == null) + if (NavigationSourceSegment?.NavigationSource is not IEdmVocabularyAnnotatable annotatableNavigationSource || + Context?.Model.GetRecord(annotatableNavigationSource, CapabilitiesConstants.UpdateRestrictions) is not {} update || + update.Permissions == null) { return; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs index 4ec24a1ee..f3114b698 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/MetadataGetOperationHandler.cs @@ -33,7 +33,7 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Summary = $"Get OData metadata (CSDL) document"; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string routePrefix = Context.Settings.PathPrefix ?? ""; if (Context.Settings.PathPrefix != null) @@ -60,7 +60,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Retrieved metadata document", @@ -77,7 +77,8 @@ protected override void SetResponses(OpenApiOperation operation) } } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs index 2bedd562a..51f2cb085 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyDeleteOperationHandler.cs @@ -31,7 +31,7 @@ public NavigationPropertyDeleteOperationHandler(OpenApiDocument document):base(d /// public override HttpMethod OperationType => HttpMethod.Delete; - private DeleteRestrictionsType _deleteRestriction; + private DeleteRestrictionsType? _deleteRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -44,12 +44,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Delete navigation property " + NavigationProperty.Name + " for " + NavigationSource.Name; + string placeHolder = "Delete navigation property " + NavigationProperty?.Name + " for " + NavigationSource?.Name; operation.Summary = _deleteRestriction?.Description ?? placeHolder; operation.Description = _deleteRestriction?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is { Settings.EnableOperationId: true}) { string prefix = "Delete"; operation.OperationId = GetOperationId(prefix); @@ -63,6 +63,7 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + operation.Parameters ??= []; operation.Parameters.Add(new OpenApiParameter { Name = "If-Match", @@ -78,19 +79,19 @@ protected override void SetParameters(OpenApiOperation operation) /// protected override void SetSecurity(OpenApiOperation operation) { - if (_deleteRestriction == null) + if (_deleteRestriction?.Permissions == null) { return; } - operation.Security = Context.CreateSecurityRequirements(_deleteRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_deleteRestriction.Permissions, _document).ToList() ?? []; } /// protected override void SetResponses(OpenApiOperation operation) { // Response for Delete methods should be 204 No Content - OpenApiConvertSettings settings = Context.Settings.Clone(); + OpenApiConvertSettings settings = Context?.Settings.Clone() ?? new(); settings.UseSuccessStatusCodeRange = false; operation.AddErrorResponses(settings, _document, true); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs index 0d01c013d..49a271198 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyGetOperationHandler.cs @@ -3,12 +3,14 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -37,7 +39,7 @@ public NavigationPropertyGetOperationHandler(OpenApiDocument document) : base(do /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestriction; + private ReadRestrictionsType? _readRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -50,13 +52,13 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Get " + NavigationProperty.Name + " from " + NavigationSource.Name; + string placeHolder = "Get " + NavigationProperty?.Name + " from " + NavigationSource?.Name; operation.Summary = (LastSegmentIsKeySegment ? _readRestriction?.ReadByKeyRestrictions?.Description : _readRestriction?.Description) ?? placeHolder; operation.Description = (LastSegmentIsKeySegment ? _readRestriction?.ReadByKeyRestrictions?.LongDescription : _readRestriction?.LongDescription) - ?? Context.Model.GetDescriptionAnnotation(NavigationProperty); + ?? Context?.Model.GetDescriptionAnnotation(NavigationProperty); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is { Settings.EnableOperationId: true }) { string prefix = "Get"; if (!LastSegmentIsKeySegment && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) @@ -72,18 +74,16 @@ protected override void SetBasicInfo(OpenApiOperation operation) protected override void SetExtensions(OpenApiOperation operation) { - if (Context.Settings.EnablePagination) + if (Context is { Settings.EnablePagination: true } && !LastSegmentIsKeySegment && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) { - if (!LastSegmentIsKeySegment && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) + var extension = new JsonObject { - JsonObject extension = new JsonObject - { - { "nextLinkName", "@odata.nextLink"}, - { "operationName", Context.Settings.PageableOperationName} - }; + { "nextLinkName", "@odata.nextLink"}, + { "operationName", Context.Settings.PageableOperationName} + }; - operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); - } + operation.Extensions ??= new Dictionary(); + operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); } base.SetExtensions(operation); @@ -92,10 +92,10 @@ protected override void SetExtensions(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - IDictionary links = null; - if (Context.Settings.ShowLinks) + IDictionary? links = null; + if (Context is { Settings.ShowLinks: true } && NavigationProperty is not null && Path is not null) { - string operationId = GetOperationId(); + var operationId = GetOperationId(); links = Context.CreateLinks(entityType: NavigationProperty.ToEntityType(), entityName: NavigationProperty.Name, entityKind: NavigationProperty.PropertyKind.ToString(), path: Path, parameters: PathParameters, @@ -107,17 +107,17 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponseReference($"{NavigationProperty.ToEntityType().FullName()}{Constants.CollectionSchemaSuffix}", _document) } }; } else { - IOpenApiSchema schema = null; + IOpenApiSchema? schema = null; var entityType = NavigationProperty.ToEntityType(); - if (Context.Settings.EnableDerivedTypesReferencesForResponses) + if (Context is { Settings.EnableDerivedTypesReferencesForResponses: true }) { schema = EdmModelHelper.GetDerivedTypesReferenceSchema(entityType, Context.Model, _document); } @@ -127,7 +127,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Retrieved navigation property", @@ -147,7 +147,8 @@ protected override void SetResponses(OpenApiOperation operation) }; } - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -157,73 +158,71 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); - OpenApiParameter selectParameter = Context.CreateSelect(TargetPath, NavigationProperty.ToEntityType()) - ?? Context.CreateSelect(NavigationProperty); - - OpenApiParameter expandParameter = Context.CreateExpand(TargetPath, NavigationProperty.ToEntityType()) - ?? Context.CreateExpand(NavigationProperty); + if (Context is null) + { + return; + } - if (!LastSegmentIsKeySegment && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) + var (selectParameter, expandParameter) = (string.IsNullOrEmpty(TargetPath), NavigationProperty) switch + { + (false, not null) when NavigationProperty.ToEntityType() is {} entityType => + (Context.CreateSelect(TargetPath!, entityType) ?? Context.CreateSelect(NavigationProperty), + Context.CreateExpand(TargetPath!, entityType) ?? Context.CreateExpand(NavigationProperty)), + (true, not null) => (Context.CreateSelect(NavigationProperty), Context.CreateExpand(NavigationProperty)), + _ => (null, null), + }; + + var parametersToAdd = new List(); + if (!LastSegmentIsKeySegment && NavigationProperty?.TargetMultiplicity() == EdmMultiplicity.Many) { // Need to verify that TopSupported or others should be applied to navigation source. // So, how about for the navigation property. - var parameter = Context.CreateTop(TargetPath, _document) ?? Context.CreateTop(NavigationProperty, _document); - if (parameter != null) - { - operation.Parameters.Add(parameter); - } - - parameter = Context.CreateSkip(TargetPath, _document) ?? Context.CreateSkip(NavigationProperty, _document); - if (parameter != null) - { - operation.Parameters.Add(parameter); - } - - parameter = Context.CreateSearch(TargetPath, _document) ?? Context.CreateSearch(NavigationProperty, _document); - if (parameter != null) - { - operation.Parameters.Add(parameter); - } - - parameter = Context.CreateFilter(TargetPath, _document) ?? Context.CreateFilter(NavigationProperty, _document); - if (parameter != null) - { - operation.Parameters.Add(parameter); - } - - parameter = Context.CreateCount(TargetPath, _document) ?? Context.CreateCount(NavigationProperty, _document); - if (parameter != null) + AddParameterIfExists(parametersToAdd, Context.CreateTop, Context.CreateTop); + AddParameterIfExists(parametersToAdd, Context.CreateSkip, Context.CreateSkip); + AddParameterIfExists(parametersToAdd, Context.CreateSearch, Context.CreateSearch); + AddParameterIfExists(parametersToAdd, Context.CreateFilter, Context.CreateFilter); + AddParameterIfExists(parametersToAdd, Context.CreateCount, Context.CreateCount); + + var orderByParameter = (string.IsNullOrEmpty(TargetPath), NavigationProperty) switch + { + (false, not null) when NavigationProperty.ToEntityType() is {} entityType => + Context.CreateOrderBy(TargetPath!, entityType), + (true, not null) => Context.CreateOrderBy(NavigationProperty), + _ => null, + }; + if (orderByParameter != null) { - operation.Parameters.Add(parameter); + parametersToAdd.Add(orderByParameter); } + } - parameter = Context.CreateOrderBy(TargetPath, NavigationProperty.ToEntityType()) ?? Context.CreateOrderBy(NavigationProperty); - if (parameter != null) - { - operation.Parameters.Add(parameter); - } + if (selectParameter != null) + { + parametersToAdd.Add(selectParameter); + } - if (selectParameter != null) - { - operation.Parameters.Add(selectParameter); - } + if (expandParameter != null) + { + parametersToAdd.Add(expandParameter); + } - if (expandParameter != null) - { - operation.Parameters.Add(expandParameter); - } + if (parametersToAdd.Count > 0) + { + if (operation.Parameters is null) operation.Parameters = parametersToAdd; + else parametersToAdd.ForEach(p => operation.Parameters.Add(p)); } - else + } + private void AddParameterIfExists(List parameters, + Func createParameterFromPath, + Func createParameterFromProperty) + { + if (!string.IsNullOrEmpty(TargetPath) && createParameterFromPath(TargetPath, _document) is {} parameterFromPath) { - if (selectParameter != null) - { - operation.Parameters.Add(selectParameter); - } - - if (expandParameter != null) - { - operation.Parameters.Add(expandParameter); - } + parameters.Add(parameterFromPath); + } + else if (NavigationProperty is not null && createParameterFromProperty(NavigationProperty, _document) is {} parameterFromProperty) + { + parameters.Add(parameterFromProperty); } } @@ -240,7 +239,8 @@ protected override void SetSecurity(OpenApiOperation operation) readBase = _readRestriction.ReadByKeyRestrictions; } - operation.Security = Context.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); + if (readBase.Permissions is not null) + operation.Security = Context?.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs index 445dd4074..d55a0ec2c 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyOperationHandler.cs @@ -5,6 +5,7 @@ using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -34,17 +35,17 @@ protected NavigationPropertyOperationHandler(OpenApiDocument document):base(docu /// /// Gets the navigation property. /// - protected IEdmNavigationProperty NavigationProperty { get; private set; } + protected IEdmNavigationProperty? NavigationProperty { get; private set; } /// /// Gets the navigation source. /// - protected IEdmNavigationSource NavigationSource { get; private set; } + protected IEdmNavigationSource? NavigationSource { get; private set; } /// /// Gets the navigation restriction. /// - protected NavigationPropertyRestriction Restriction { get; private set; } + protected NavigationPropertyRestriction? Restriction { get; private set; } /// /// Gets a bool value indicating whether the last segment is a key segment. @@ -66,41 +67,39 @@ protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - NavigationSource = navigationSourceSegment.NavigationSource; + ODataNavigationSourceSegment? navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; + NavigationSource = navigationSourceSegment?.NavigationSource; LastSegmentIsKeySegment = path.LastSegment is ODataKeySegment; LastSegmentIsRefSegment = path.LastSegment is ODataRefSegment; - SecondLastSegmentIsKeySegment = Path.Segments.Reverse().Skip(1).Take(1).Single().Kind == ODataSegmentKind.Key; + SecondLastSegmentIsKeySegment = Path?.Segments.Reverse().Skip(1).Take(1).Single().Kind == ODataSegmentKind.Key; NavigationProperty = path.OfType().Last().NavigationProperty; - IEdmEntitySet entitySet = NavigationSource as IEdmEntitySet; - IEdmSingleton singleton = NavigationSource as IEdmSingleton; + var navigation = NavigationSource switch { + IEdmEntitySet entitySet => Context?.Model.GetRecord(entitySet, CapabilitiesConstants.NavigationRestrictions), + IEdmSingleton singleton => Context?.Model.GetRecord(singleton, CapabilitiesConstants.NavigationRestrictions), + _ => null + }; - NavigationRestrictionsType navigation; - if (entitySet != null) - { - navigation = Context.Model.GetRecord(entitySet, CapabilitiesConstants.NavigationRestrictions); - } - else - { - navigation = Context.Model.GetRecord(singleton, CapabilitiesConstants.NavigationRestrictions); - } + var navPropertyPath = Path?.NavigationPropertyPath(); - Restriction = navigation?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty != null && r.NavigationProperty == Path.NavigationPropertyPath()) - ?? Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.NavigationRestrictions)?.RestrictedProperties?.FirstOrDefault(); + Restriction = navigation?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty != null && r.NavigationProperty == navPropertyPath) + ?? Context?.Model.GetRecord(NavigationProperty, CapabilitiesConstants.NavigationRestrictions)?.RestrictedProperties?.FirstOrDefault(); } /// protected override void SetTags(OpenApiOperation operation) { - string name = EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context); - Context.AddExtensionToTag(name, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() - { - Name = name - }); - operation.Tags ??= new HashSet(); - operation.Tags.Add(new OpenApiTagReference(name, _document)); + if (Context is not null && Path is not null) + { + string name = EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context); + Context.AddExtensionToTag(name, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() + { + Name = name + }); + operation.Tags ??= new HashSet(); + operation.Tags.Add(new OpenApiTagReference(name, _document)); + } base.SetTags(operation); } @@ -108,23 +107,28 @@ protected override void SetTags(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("operation")); base.SetExtensions(operation); } - internal string GetOperationId(string prefix = null) - { + internal string? GetOperationId(string? prefix = null) + { + if (Context is null || Path is null) + { + return null; + } return EdmModelHelper.GenerateNavigationPropertyPathOperationId(Path, Context, prefix); } /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs) + if (Context is {Settings.ShowExternalDocs: true} && !string.IsNullOrEmpty(CustomLinkRel)) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(NavigationProperty, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetLinkRecord(TargetPath, CustomLinkRel)) ?? + (NavigationProperty is null ? null : Context.Model.GetLinkRecord(NavigationProperty, CustomLinkRel)); if (externalDocs != null) { @@ -143,48 +147,61 @@ protected override void SetExternalDocs(OpenApiOperation operation) /// /// The fully qualified restriction annotation term. /// The restriction annotation, or null if not available. - protected IRecord GetRestrictionAnnotation(string annotationTerm) + protected IRecord? GetRestrictionAnnotation(string annotationTerm) { + if (Context is null) return null; switch (annotationTerm) { case CapabilitiesConstants.ReadRestrictions: - var readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); readRestrictions?.MergePropertiesIfNull(Restriction?.ReadRestrictions); readRestrictions ??= Restriction?.ReadRestrictions; - var navPropReadRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(navPropReadRestrictions); - readRestrictions ??= navPropReadRestrictions; + if (NavigationProperty is not null) + { + var navPropReadRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(navPropReadRestrictions); + readRestrictions ??= navPropReadRestrictions; + } return readRestrictions; case CapabilitiesConstants.UpdateRestrictions: - var updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + var updateRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); updateRestrictions?.MergePropertiesIfNull(Restriction?.UpdateRestrictions); updateRestrictions ??= Restriction?.UpdateRestrictions; - var navPropUpdateRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.UpdateRestrictions); - updateRestrictions?.MergePropertiesIfNull(navPropUpdateRestrictions); - updateRestrictions ??= navPropUpdateRestrictions; + if (NavigationProperty is not null) + { + var navPropUpdateRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.UpdateRestrictions); + updateRestrictions?.MergePropertiesIfNull(navPropUpdateRestrictions); + updateRestrictions ??= navPropUpdateRestrictions; + } return updateRestrictions; case CapabilitiesConstants.InsertRestrictions: - var insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + var insertRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); insertRestrictions?.MergePropertiesIfNull(Restriction?.InsertRestrictions); insertRestrictions ??= Restriction?.InsertRestrictions; - var navPropInsertRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.InsertRestrictions); - insertRestrictions?.MergePropertiesIfNull(navPropInsertRestrictions); - insertRestrictions ??= navPropInsertRestrictions; + if (NavigationProperty is not null) + { + var navPropInsertRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.InsertRestrictions); + insertRestrictions?.MergePropertiesIfNull(navPropInsertRestrictions); + insertRestrictions ??= navPropInsertRestrictions; + } return insertRestrictions; case CapabilitiesConstants.DeleteRestrictions: - var deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + var deleteRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); deleteRestrictions?.MergePropertiesIfNull(Restriction?.DeleteRestrictions); deleteRestrictions ??= Restriction?.DeleteRestrictions; - var navPropDeleteRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.DeleteRestrictions); - deleteRestrictions?.MergePropertiesIfNull(navPropDeleteRestrictions); - deleteRestrictions ??= navPropDeleteRestrictions; + if (NavigationProperty is not null) + { + var navPropDeleteRestrictions = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.DeleteRestrictions); + deleteRestrictions?.MergePropertiesIfNull(navPropDeleteRestrictions); + deleteRestrictions ??= navPropDeleteRestrictions; + } return deleteRestrictions; default: @@ -193,7 +210,7 @@ protected IRecord GetRestrictionAnnotation(string annotationTerm) } } - protected IDictionary GetContent(IOpenApiSchema schema = null, IEnumerable mediaTypes = null) + protected Dictionary GetContent(IOpenApiSchema? schema = null, IEnumerable? mediaTypes = null) { schema ??= GetOpenApiSchema(); var content = new Dictionary(); @@ -215,7 +232,7 @@ protected IDictionary GetContent(IOpenApiSchema schema { Schema = schema }); - }; + } return content; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs index 065fcfe44..de3e656bb 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyPostOperationHandler.cs @@ -32,7 +32,7 @@ public NavigationPropertyPostOperationHandler(OpenApiDocument document):base(doc /// public override HttpMethod OperationType => HttpMethod.Post; - private InsertRestrictionsType _insertRestriction; + private InsertRestrictionsType? _insertRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -45,12 +45,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Create new navigation property to " + NavigationProperty.Name + " for " + NavigationSource.Name; + string placeHolder = "Create new navigation property to " + NavigationProperty?.Name + " for " + NavigationSource?.Name; operation.Summary = _insertRestriction?.Description ?? placeHolder; operation.Description = _insertRestriction?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string prefix = "Create"; operation.OperationId = GetOperationId(prefix); @@ -62,12 +62,9 @@ protected override void SetBasicInfo(OpenApiOperation operation) /// protected override void SetRequestBody(OpenApiOperation operation) { - OpenApiSchema schema = null; - - if (Context.Settings.EnableDerivedTypesReferencesForRequestBody) - { - schema = EdmModelHelper.GetDerivedTypesReferenceSchema(NavigationProperty.ToEntityType(), Context.Model, _document); - } + var schema = Context is {Settings.EnableDerivedTypesReferencesForRequestBody: true} ? + EdmModelHelper.GetDerivedTypesReferenceSchema(NavigationProperty.ToEntityType(), Context.Model, _document) : + null; operation.RequestBody = new OpenApiRequestBody { @@ -82,17 +79,14 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - OpenApiSchema schema = null; - - if (Context.Settings.EnableDerivedTypesReferencesForResponses) - { - schema = EdmModelHelper.GetDerivedTypesReferenceSchema(NavigationProperty.ToEntityType(), Context.Model, _document); - } + var schema = Context is {Settings.EnableDerivedTypesReferencesForResponses: true} ? + EdmModelHelper.GetDerivedTypesReferenceSchema(NavigationProperty.ToEntityType(), Context.Model, _document) : + null; operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode201, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode201, new OpenApiResponse { Description = "Created navigation property.", @@ -100,7 +94,8 @@ protected override void SetResponses(OpenApiOperation operation) } } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -112,7 +107,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_insertRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_insertRestriction.Permissions ?? [], _document).ToList() ?? []; } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs index 3549480a6..566196258 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/NavigationPropertyUpdateOperationHandler.cs @@ -30,7 +30,7 @@ protected NavigationPropertyUpdateOperationHandler(OpenApiDocument document):bas { } - private UpdateRestrictionsType _updateRestriction; + private UpdateRestrictionsType? _updateRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -43,12 +43,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Update the navigation property " + NavigationProperty.Name + " in " + NavigationSource.Name; + string placeHolder = "Update the navigation property " + NavigationProperty?.Name + " in " + NavigationSource?.Name; operation.Summary = _updateRestriction?.Description ?? placeHolder; operation.Description = _updateRestriction?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string prefix = OperationType == HttpMethod.Patch ? "Update" : "Set"; operation.OperationId = GetOperationId(prefix); @@ -60,11 +60,9 @@ protected override void SetBasicInfo(OpenApiOperation operation) /// protected override void SetRequestBody(OpenApiOperation operation) { - OpenApiSchema schema = null; - if (Context.Settings.EnableDerivedTypesReferencesForRequestBody) - { - schema = EdmModelHelper.GetDerivedTypesReferenceSchema(NavigationProperty.ToEntityType(), Context.Model, _document); - } + var schema = Context is { Settings.EnableDerivedTypesReferencesForRequestBody: true } ? + EdmModelHelper.GetDerivedTypesReferenceSchema(NavigationProperty.ToEntityType(), Context.Model, _document) : + null; operation.RequestBody = new OpenApiRequestBody { @@ -79,18 +77,19 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); base.SetResponses(operation); } protected override void SetSecurity(OpenApiOperation operation) { - if (_updateRestriction == null) + if (_updateRestriction?.Permissions == null) { return; } - operation.Security = Context.CreateSecurityRequirements(_updateRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_updateRestriction.Permissions, _document).ToList() ?? []; } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs index 4b6555087..bff2cf5f0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/ODataTypeCastGetOperationHandler.cs @@ -11,6 +11,7 @@ using Microsoft.OData.Edm; using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -42,7 +43,7 @@ public ODataTypeCastGetOperationHandler(OpenApiDocument document):base(document) /// Gets/sets the segment before cast. /// this segment could be "entity set", "Collection property", etc. /// - internal ODataSegment SecondLastSegment { get; set; } + internal ODataSegment? SecondLastSegment { get; set; } private bool isKeySegment; @@ -58,18 +59,18 @@ private bool IsSingleElement entitySet == null); } - private NavigationPropertyRestriction restriction; - private IEdmSingleton singleton; - private IEdmEntitySet entitySet; - private IEdmNavigationProperty navigationProperty; - private IEdmStructuredType parentStructuredType; - private IEdmSchemaElement ParentSchemaElement => parentStructuredType as IEdmSchemaElement; - private IEdmStructuredType targetStructuredType; - private IEdmSchemaElement TargetSchemaElement => targetStructuredType as IEdmSchemaElement; + private NavigationPropertyRestriction? restriction; + private IEdmSingleton? singleton; + private IEdmEntitySet? entitySet; + private IEdmNavigationProperty? navigationProperty; + private IEdmStructuredType? parentStructuredType; + private IEdmSchemaElement? ParentSchemaElement => parentStructuredType as IEdmSchemaElement; + private IEdmStructuredType? targetStructuredType; + private IEdmSchemaElement? TargetSchemaElement => targetStructuredType as IEdmSchemaElement; private const int SecondLastSegmentIndex = 2; private bool isIndexedCollValuedNavProp = false; - private IEdmNavigationSource navigationSource; - private IEdmVocabularyAnnotatable annotatable; + private IEdmNavigationSource? navigationSource; + private IEdmVocabularyAnnotatable? annotatable; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -90,11 +91,13 @@ protected override void Initialize(ODataContext context, ODataPath path) // get the last second segment int count = path.Segments.Count; if(count >= SecondLastSegmentIndex) - SecondLastSegment = path.Segments.ElementAt(count - SecondLastSegmentIndex); + SecondLastSegment = path.Segments[count - SecondLastSegmentIndex]; - parentStructuredType = SecondLastSegment is ODataComplexPropertySegment complexSegment ? complexSegment.ComplexType : SecondLastSegment.EntityType; - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - navigationSource = navigationSourceSegment.NavigationSource; + parentStructuredType = SecondLastSegment is ODataComplexPropertySegment complexSegment ? complexSegment.ComplexType : SecondLastSegment?.EntityType; + if (path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment) + { + navigationSource = navigationSourceSegment.NavigationSource; + } if (SecondLastSegment is ODataNavigationPropertySegment navigationPropertySegment) { @@ -107,7 +110,7 @@ protected override void Initialize(ODataContext context, ODataPath path) else if (SecondLastSegment is ODataKeySegment) { isKeySegment = true; - var thirdLastSegment = path.Segments.ElementAt(count - SecondLastSegmentIndex - 1); + var thirdLastSegment = path.Segments[count - SecondLastSegmentIndex - 1]; if (thirdLastSegment is ODataNavigationPropertySegment navigationPropertySegment1) { isIndexedCollValuedNavProp = true; @@ -137,20 +140,21 @@ private void SetNavigationPropertyAndRestrictionFromNavigationSegment(ODataNavig { navigationProperty = navigationPropertySegment.NavigationProperty; annotatable = navigationProperty; - var navigationPropertyPath = string.Join("/", - Path.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment - || s is ODataStreamContentSegment || s is ODataStreamPropertySegment)).Select(e => e.Identifier)); - if(path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment) + if(path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment && + Context is not null) { - NavigationRestrictionsType navigation = navigationSourceSegment.NavigationSource switch { + NavigationRestrictionsType? navigation = navigationSourceSegment.NavigationSource switch { IEdmEntitySet eSet => Context.Model.GetRecord(eSet, CapabilitiesConstants.NavigationRestrictions), IEdmSingleton single => Context.Model.GetRecord(single, CapabilitiesConstants.NavigationRestrictions), _ => null }; - if (navigation?.RestrictedProperties != null) + if (navigation?.RestrictedProperties != null && Path is not null) { + var navigationPropertyPath = string.Join("/", + Path.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment + || s is ODataStreamContentSegment || s is ODataStreamPropertySegment)).Select(e => e.Identifier)); restriction = navigation.RestrictedProperties.FirstOrDefault(r => r.NavigationProperty != null && r.NavigationProperty == navigationPropertyPath); } } @@ -170,16 +174,16 @@ private void SetAnnotatableRestrictionFromNavigationSourceSegment(ODataNavigatio singleton = sTon; } - SetRestrictionFromAnnotatable(annotatable); + SetRestrictionFromAnnotatable(); } - private void SetRestrictionFromAnnotatable(IEdmVocabularyAnnotatable annotatable) + private void SetRestrictionFromAnnotatable() { - if (this.annotatable == null) + if (annotatable == null) return; - NavigationRestrictionsType navigation = Context.Model.GetRecord(annotatable, CapabilitiesConstants.NavigationRestrictions); + var navigation = Context?.Model.GetRecord(annotatable, CapabilitiesConstants.NavigationRestrictions); if (navigation?.RestrictedProperties != null) { restriction = navigation.RestrictedProperties.FirstOrDefault(r => r.NavigationProperty == null); @@ -189,7 +193,7 @@ private void SetRestrictionFromAnnotatable(IEdmVocabularyAnnotatable annotatable /// protected override void SetBasicInfo(OpenApiOperation operation) { - ReadRestrictionsType _readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var _readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); // Summary string placeHolder = IsSingleElement @@ -199,7 +203,9 @@ protected override void SetBasicInfo(OpenApiOperation operation) operation.Description = _readRestrictions?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is { Settings.EnableOperationId: true } && + Path is not null && + TargetSchemaElement is not null) operation.OperationId = EdmModelHelper.GenerateODataTypeCastPathOperationIdPrefix(Path, Context) + $".As{Utils.UpperFirstChar(TargetSchemaElement.Name)}-{Path.GetPathHash(Context.Settings)}"; base.SetBasicInfo(operation); @@ -210,9 +216,9 @@ protected override void SetResponses(OpenApiOperation operation) { if (IsSingleElement) { - IOpenApiSchema schema = null; + IOpenApiSchema? schema = null; - if (Context.Settings.EnableDerivedTypesReferencesForResponses) + if (Context is { Settings.EnableDerivedTypesReferencesForResponses: true } && targetStructuredType is not null) { schema = EdmModelHelper.GetDerivedTypesReferenceSchema(targetStructuredType, Context.Model, _document); } @@ -229,7 +235,8 @@ protected override void SetResponses(OpenApiOperation operation) SetCollectionResponse(operation, TargetSchemaElement.FullName()); } - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -237,23 +244,26 @@ protected override void SetResponses(OpenApiOperation operation) /// protected override void SetTags(OpenApiOperation operation) { - string tagName = null; + if (Context is null) + return; + string? tagName = null; operation.Tags ??= new HashSet(); - if (SecondLastSegment is ODataNavigationPropertySegment || isIndexedCollValuedNavProp) + if ((SecondLastSegment is ODataNavigationPropertySegment || isIndexedCollValuedNavProp) && + Path is not null) { tagName = EdmModelHelper.GenerateNavigationPropertyPathTagName(Path, Context); } else if ((SecondLastSegment is ODataKeySegment && !isIndexedCollValuedNavProp) || (SecondLastSegment is ODataNavigationSourceSegment)) { - var singletonNavigationSource = navigationSource as IEdmSingleton; - - tagName = navigationSource is IEdmEntitySet entitySetNavigationSource - ? entitySetNavigationSource.Name + "." + entitySetNavigationSource.EntityType.Name - : singletonNavigationSource.Name + "." + singletonNavigationSource.EntityType.Name; + tagName = navigationSource switch { + IEdmEntitySet entitySetNavigationSource => entitySetNavigationSource.Name + "." + entitySetNavigationSource.EntityType.Name, + IEdmSingleton singletonNavigationSource => singletonNavigationSource.Name + "." + singletonNavigationSource.EntityType.Name, + _ => null + }; } - else if (SecondLastSegment is ODataComplexPropertySegment) + else if (SecondLastSegment is ODataComplexPropertySegment && Path is not null) { tagName = EdmModelHelper.GenerateComplexPropertyPathTagName(Path, Context); } @@ -277,14 +287,19 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + if (Context is null) + return; + + operation.Parameters ??= []; + if(navigationProperty != null) { if (IsSingleElement) { - new OpenApiParameter[] { - Context.CreateSelect(TargetPath, navigationProperty.ToEntityType()) ?? Context.CreateSelect(navigationProperty), - Context.CreateExpand(TargetPath, navigationProperty.ToEntityType()) ?? Context.CreateExpand(navigationProperty), + new IOpenApiParameter?[] { + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, navigationProperty.ToEntityType())) ?? Context.CreateSelect(navigationProperty), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, navigationProperty.ToEntityType())) ?? Context.CreateExpand(navigationProperty), } - .Where(x => x != null) + .OfType() .ToList() .ForEach(p => operation.Parameters.Add(p)); } @@ -292,12 +307,12 @@ protected override void SetParameters(OpenApiOperation operation) { GetParametersForAnnotableOfMany(navigationProperty) .Union( - new OpenApiParameter[] { - Context.CreateOrderBy(TargetPath, navigationProperty.ToEntityType()) ?? Context.CreateOrderBy(navigationProperty), - Context.CreateSelect(TargetPath, navigationProperty.ToEntityType()) ?? Context.CreateSelect(navigationProperty), - Context.CreateExpand(TargetPath, navigationProperty.ToEntityType()) ?? Context.CreateExpand(navigationProperty), - }) - .Where(x => x != null) + [ + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateOrderBy(TargetPath, navigationProperty.ToEntityType())) ?? Context.CreateOrderBy(navigationProperty), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, navigationProperty.ToEntityType())) ?? Context.CreateSelect(navigationProperty), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, navigationProperty.ToEntityType())) ?? Context.CreateExpand(navigationProperty), + ]) + .OfType() .ToList() .ForEach(p => operation.Parameters.Add(p)); } @@ -306,11 +321,11 @@ protected override void SetParameters(OpenApiOperation operation) { if(IsSingleElement) { - new IOpenApiParameter[] { - Context.CreateSelect(TargetPath, entitySet.EntityType) ?? Context.CreateSelect(entitySet), - Context.CreateExpand(TargetPath, entitySet.EntityType) ?? Context.CreateExpand(entitySet), + new IOpenApiParameter?[] { + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, entitySet.EntityType)) ?? Context.CreateSelect(entitySet), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, entitySet.EntityType)) ?? Context.CreateExpand(entitySet), } - .Where(x => x != null) + .OfType() .ToList() .ForEach(operation.Parameters.Add); } @@ -319,28 +334,30 @@ protected override void SetParameters(OpenApiOperation operation) GetParametersForAnnotableOfMany(entitySet) .Union( [ - Context.CreateOrderBy(TargetPath, entitySet.EntityType) ?? Context.CreateOrderBy(entitySet), - Context.CreateSelect(TargetPath, entitySet.EntityType) ?? Context.CreateSelect(entitySet), - Context.CreateExpand(TargetPath, entitySet.EntityType) ?? Context.CreateExpand(entitySet), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateOrderBy(TargetPath, entitySet.EntityType)) ?? Context.CreateOrderBy(entitySet), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, entitySet.EntityType)) ?? Context.CreateSelect(entitySet), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, entitySet.EntityType)) ?? Context.CreateExpand(entitySet), ]) - .Where(x => x != null) + .OfType() .ToList() .ForEach(p => operation.Parameters.Add(p)); } } else if(singleton != null) { - new OpenApiParameter[] { - Context.CreateSelect(TargetPath, singleton.EntityType) ?? Context.CreateSelect(singleton), - Context.CreateExpand(TargetPath, singleton.EntityType) ?? Context.CreateExpand(singleton), + new IOpenApiParameter?[] { + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSelect(TargetPath, singleton.EntityType)) ?? Context.CreateSelect(singleton), + (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateExpand(TargetPath, singleton.EntityType)) ?? Context.CreateExpand(singleton), } - .Where(x => x != null) + .OfType() .ToList() .ForEach(p => operation.Parameters.Add(p)); } } - private IEnumerable GetParametersForAnnotableOfMany(IEdmVocabularyAnnotatable annotable) + private IEnumerable GetParametersForAnnotableOfMany(IEdmVocabularyAnnotatable annotable) { + if (Context is null) + return []; // Need to verify that TopSupported or others should be applied to navigation source. // So, how about for the navigation property. return [ @@ -354,19 +371,17 @@ private IEnumerable GetParametersForAnnotableOfMany(IEdmVocab protected override void SetSecurity(OpenApiOperation operation) { - if (restriction == null || restriction.ReadRestrictions == null) + if (restriction is not {ReadRestrictions.Permissions: not null}) { return; } - ReadRestrictionsBase readBase = restriction.ReadRestrictions; - - operation.Security = Context.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(restriction.ReadRestrictions.Permissions, _document).ToList(); } protected override void SetExtensions(OpenApiOperation operation) { - if (Context.Settings.EnablePagination && !IsSingleElement) + if (Context is { Settings.EnablePagination: true } && !IsSingleElement) { JsonObject extension = new() { @@ -374,6 +389,7 @@ protected override void SetExtensions(OpenApiOperation operation) { "operationName", Context.Settings.PageableOperationName} }; + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); } @@ -385,10 +401,15 @@ protected override void AppendCustomParameters(OpenApiOperation operation) if (annotatable == null) return; - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - var annotatableReadRestrictions = Context.Model.GetRecord(annotatable, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(annotatableReadRestrictions); - readRestrictions ??= annotatableReadRestrictions; + if (Context is null) + return; + + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (Context.Model.GetRecord(annotatable, CapabilitiesConstants.ReadRestrictions) is {} annotatableReadRestrictions) + { + readRestrictions?.MergePropertiesIfNull(annotatableReadRestrictions); + readRestrictions ??= annotatableReadRestrictions; + } if (readRestrictions == null) { @@ -408,7 +429,10 @@ protected override void AppendCustomParameters(OpenApiOperation operation) protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs && Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) is LinkType externalDocs) + if (Context is { Settings.ShowExternalDocs: true } && + !string.IsNullOrEmpty(CustomLinkRel) && + !string.IsNullOrEmpty(TargetPath) && + Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) is LinkType externalDocs) { operation.ExternalDocs = new OpenApiExternalDocs() { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs index 4f27692c6..f09ff552b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandler.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.MicrosoftExtensions; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; @@ -37,17 +38,17 @@ protected OperationHandler(OpenApiDocument document) /// public abstract HttpMethod OperationType { get; } - protected IDictionary> ParameterMappings; + protected IDictionary>? ParameterMappings; /// /// The path parameters in the path /// - protected IList PathParameters; + protected IList? PathParameters; /// /// The string representation of the Edm target path for annotations. /// - protected string TargetPath; + protected string? TargetPath; /// public virtual OpenApiOperation CreateOperation(ODataContext context, ODataPath path) @@ -96,38 +97,43 @@ will be used in the Responses when creating Links. private void SetDeprecation(OpenApiOperation operation) { - if (operation != null && Context.Settings.EnableDeprecationInformation) + if (operation is null || + Context is null || + !Context.Settings.EnableDeprecationInformation || + Path is null) { - var deprecationInfo = Path.SelectMany(x => x.GetAnnotables()) - .SelectMany(x => Context.GetDeprecationInformations(x)) - .Where(x => x != null) - .OrderByDescending(x => x.Date) - .ThenByDescending(x => x.RemovalDate) - .FirstOrDefault(); - - if (deprecationInfo != null) - { - operation.Deprecated = true; - var deprecationDetails = deprecationInfo.GetOpenApiExtension(); - operation.Extensions.Add(OpenApiDeprecationExtension.Name, deprecationDetails); - } + return; + } + var deprecationInfo = Path.SelectMany(x => x.GetAnnotables()) + .SelectMany(x => Context.GetDeprecationInformations(x)) + .Where(x => x != null) + .OrderByDescending(x => x.Date) + .ThenByDescending(x => x.RemovalDate) + .FirstOrDefault(); + + if (deprecationInfo != null) + { + operation.Deprecated = true; + var deprecationDetails = deprecationInfo.GetOpenApiExtension(); + operation.Extensions ??= new Dictionary(); + operation.Extensions.Add(OpenApiDeprecationExtension.Name, deprecationDetails); } } /// /// Gets the OData context. /// - protected ODataContext Context { get; private set; } + protected ODataContext? Context { get; private set; } /// /// Gets the OData path. /// - protected ODataPath Path { get; private set; } + protected ODataPath? Path { get; private set; } /// /// Gets the custom link relation type for path based on operation type /// - protected string CustomLinkRel { get; set; } + protected string? CustomLinkRel { get; set; } /// /// Initialize the handler. @@ -175,12 +181,16 @@ protected virtual void SetRequestBody(OpenApiOperation operation) /// The . protected virtual void SetParameters(OpenApiOperation operation) { - PathParameters = Path.CreatePathParameters(Context, _document); - if (!Context.Settings.DeclarePathParametersOnPathItem) + if (Context is not null && Path is not null) { - foreach (var parameter in PathParameters) + PathParameters = Path.CreatePathParameters(Context, _document); + if (!Context.Settings.DeclarePathParametersOnPathItem) { - operation.Parameters.AppendParameter(parameter); + operation.Parameters ??= []; + foreach (var parameter in PathParameters) + { + operation.Parameters.AppendParameter(parameter); + } } } @@ -239,7 +249,7 @@ protected static void AppendCustomParameters(OpenApiOperation operation, IList protected virtual void SetCustomLinkRelType() { - if (Context.Settings.CustomHttpMethodLinkRelMapping != null) + if (Context?.Settings.CustomHttpMethodLinkRelMapping is not null && + Path is not null) { LinkRelKey? key = OperationType.ToString().ToLowerInvariant() switch { @@ -300,9 +312,8 @@ protected virtual void SetCustomLinkRelType() _ => null, }; - if (key != null) + if (key != null && key.HasValue && Context.Settings.CustomHttpMethodLinkRelMapping.TryGetValue(key.Value, out var linkRelValue)) { - Context.Settings.CustomHttpMethodLinkRelMapping.TryGetValue((LinkRelKey)key, out string linkRelValue); CustomLinkRel = linkRelValue; } } @@ -316,7 +327,7 @@ internal void SetCollectionResponse(OpenApiOperation operation, string targetEle operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + (Context?.Settings.UseSuccessStatusCodeRange ?? false) ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponseReference($"{targetElementFullName}{Constants.CollectionSchemaSuffix}", _document) } }; @@ -330,7 +341,7 @@ internal void SetSingleResponse(OpenApiOperation operation, IOpenApiSchema schem operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + (Context?.Settings.UseSuccessStatusCodeRange ?? false) ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Entity result.", diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs index 9f65fedf8..ebb420d37 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/OperationHandlerProvider.cs @@ -16,7 +16,7 @@ namespace Microsoft.OpenApi.OData.Operation internal class OperationHandlerProvider : IOperationHandlerProvider { /// - public IOperationHandler GetHandler(ODataPathKind pathKind, HttpMethod operationType, OpenApiDocument document) + public IOperationHandler? GetHandler(ODataPathKind pathKind, HttpMethod operationType, OpenApiDocument document) { return (pathKind, operationType.ToString().ToLowerInvariant()) switch { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs index 5211b8657..dab9aadb0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefDeleteOperationHandler.cs @@ -29,7 +29,7 @@ public RefDeleteOperationHandler(OpenApiDocument document) : base(document) } /// public override HttpMethod OperationType => HttpMethod.Delete; - private DeleteRestrictionsType _deleteRestriction; + private DeleteRestrictionsType? _deleteRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -42,15 +42,15 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Delete ref of navigation property " + NavigationProperty.Name + " for " + NavigationSource.Name; + string placeHolder = "Delete ref of navigation property " + NavigationProperty?.Name + " for " + NavigationSource?.Name; operation.Summary = _deleteRestriction?.Description ?? placeHolder; operation.Description = _deleteRestriction?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string prefix = "DeleteRef"; - var segments = GetOperationId().Split('.').ToList(); + var segments = GetOperationId()?.Split('.').ToList() ?? []; if (SecondLastSegmentIsKeySegment) { @@ -73,6 +73,7 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + operation.Parameters ??= []; operation.Parameters.Add(new OpenApiParameter { Name = "If-Match", @@ -86,7 +87,7 @@ protected override void SetParameters(OpenApiOperation operation) // for collection, we should have @id in query if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many && - Path.Segments.Reverse().Skip(1).First() is ODataNavigationPropertySegment) + Path?.Segments.Reverse().Skip(1).First() is ODataNavigationPropertySegment) { operation.Parameters.Add(new OpenApiParameter { @@ -105,19 +106,19 @@ protected override void SetParameters(OpenApiOperation operation) /// protected override void SetSecurity(OpenApiOperation operation) { - if (_deleteRestriction == null) + if (_deleteRestriction?.Permissions == null) { return; } - operation.Security = Context.CreateSecurityRequirements(_deleteRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_deleteRestriction.Permissions, _document).ToList(); } /// protected override void SetResponses(OpenApiOperation operation) { // Response for Delete methods should be 204 No Content - OpenApiConvertSettings settings = Context.Settings.Clone(); + var settings = Context?.Settings.Clone() ?? new(); settings.UseSuccessStatusCodeRange = false; operation.AddErrorResponses(settings, _document, true); diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs index 6f4138194..a70765b21 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefGetOperationHandler.cs @@ -9,6 +9,7 @@ using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.Interfaces; using Microsoft.OpenApi.Models.References; @@ -34,7 +35,7 @@ public RefGetOperationHandler(OpenApiDocument document) : base(document) } /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestriction; + private ReadRestrictionsType? _readRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -47,13 +48,13 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Get ref of " + NavigationProperty.Name + " from " + NavigationSource.Name; + string placeHolder = "Get ref of " + NavigationProperty?.Name + " from " + NavigationSource?.Name; operation.Summary = (LastSegmentIsKeySegment ? _readRestriction?.ReadByKeyRestrictions?.Description : _readRestriction?.Description) ?? placeHolder; operation.Description = (LastSegmentIsKeySegment ? _readRestriction?.ReadByKeyRestrictions?.LongDescription : _readRestriction?.LongDescription) - ?? Context.Model.GetDescriptionAnnotation(NavigationProperty); + ?? Context?.Model.GetDescriptionAnnotation(NavigationProperty); // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string prefix = "GetRef"; if (!LastSegmentIsKeySegment && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) @@ -67,18 +68,16 @@ protected override void SetBasicInfo(OpenApiOperation operation) protected override void SetExtensions(OpenApiOperation operation) { - if (Context.Settings.EnablePagination) + if (Context is { Settings.EnablePagination: true } && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) { - if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) - { - JsonObject extension = new JsonObject + JsonObject extension = new JsonObject { { "nextLinkName", "@odata.nextLink"}, { "operationName", Context.Settings.PageableOperationName} }; - operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); - } + operation.Extensions ??= new Dictionary(); + operation.Extensions.Add(Constants.xMsPageable, new OpenApiAny(extension)); } base.SetExtensions(operation); @@ -92,7 +91,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponseReference($"String{Constants.CollectionSchemaSuffix}", _document) } }; @@ -104,10 +103,10 @@ protected override void SetResponses(OpenApiOperation operation) // $ref returns string for the Uri? Type = JsonSchemaType.String }; - IDictionary links = null; - if (Context.Settings.ShowLinks) + IDictionary? links = null; + if (Context is {Settings.ShowLinks: true} && NavigationProperty is not null && Path is not null) { - string operationId = GetOperationId(); + var operationId = GetOperationId(); links = Context.CreateLinks(entityType: NavigationProperty.ToEntityType(), entityName: NavigationProperty.Name, entityKind: NavigationProperty.PropertyKind.ToString(), parameters: PathParameters, path: Path, @@ -117,7 +116,7 @@ protected override void SetResponses(OpenApiOperation operation) operation.Responses = new OpenApiResponses { { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, new OpenApiResponse { Description = "Retrieved navigation property link", @@ -137,7 +136,8 @@ protected override void SetResponses(OpenApiOperation operation) }; } - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -147,41 +147,48 @@ protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); - if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) + if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many && Context is not null) { // Need to verify that TopSupported or others should be applied to navigaiton source. // So, how about for the navigation property. - var parameter = Context.CreateTop(TargetPath, _document) ?? Context.CreateTop(NavigationProperty, _document); + var parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateTop(TargetPath, _document)) ?? + (NavigationProperty is null ? null : Context.CreateTop(NavigationProperty, _document)); + operation.Parameters ??= []; if (parameter != null) { operation.Parameters.Add(parameter); } - parameter = Context.CreateSkip(TargetPath, _document) ?? Context.CreateSkip(NavigationProperty, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSkip(TargetPath, _document)) ?? + (NavigationProperty is null ? null : Context.CreateSkip(NavigationProperty, _document)); if (parameter != null) { operation.Parameters.Add(parameter); } - parameter = Context.CreateSearch(TargetPath, _document) ?? Context.CreateSearch(NavigationProperty, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateSearch(TargetPath, _document)) ?? + (NavigationProperty is null ? null : Context.CreateSearch(NavigationProperty, _document)); if (parameter != null) { operation.Parameters.Add(parameter); } - parameter = Context.CreateFilter(TargetPath, _document) ?? Context.CreateFilter(NavigationProperty, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateFilter(TargetPath, _document)) ?? + (NavigationProperty is null ? null : Context.CreateFilter(NavigationProperty, _document)); if (parameter != null) { operation.Parameters.Add(parameter); } - parameter = Context.CreateCount(TargetPath, _document) ?? Context.CreateCount(NavigationProperty, _document); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateCount(TargetPath, _document)) ?? + (NavigationProperty is null ? null : Context.CreateCount(NavigationProperty, _document)); if (parameter != null) { operation.Parameters.Add(parameter); } - parameter = Context.CreateOrderBy(TargetPath, NavigationProperty.ToEntityType()) ?? Context.CreateOrderBy(NavigationProperty); + parameter = (string.IsNullOrEmpty(TargetPath) ? null : Context.CreateOrderBy(TargetPath, NavigationProperty.ToEntityType())) ?? + (NavigationProperty is null ? null : Context.CreateOrderBy(NavigationProperty)); if (parameter != null) { operation.Parameters.Add(parameter); @@ -191,13 +198,12 @@ protected override void SetParameters(OpenApiOperation operation) protected override void SetSecurity(OpenApiOperation operation) { - if (_readRestriction == null) + if (_readRestriction?.Permissions == null) { return; } - ReadRestrictionsBase readBase = _readRestriction; - operation.Security = Context.CreateSecurityRequirements(readBase.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_readRestriction.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs index 04c82e54b..228019c3a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPostOperationHandler.cs @@ -29,7 +29,7 @@ public RefPostOperationHandler(OpenApiDocument document) : base(document) } /// public override HttpMethod OperationType => HttpMethod.Post; - private InsertRestrictionsType _insertRestriction; + private InsertRestrictionsType? _insertRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -42,12 +42,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Create new navigation property ref to " + NavigationProperty.Name + " for " + NavigationSource.Name; + string placeHolder = "Create new navigation property ref to " + NavigationProperty?.Name + " for " + NavigationSource?.Name; operation.Summary = _insertRestriction?.Description ?? placeHolder; operation.Description = _insertRestriction?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string prefix = "CreateRef"; operation.OperationId = GetOperationId(prefix); @@ -73,19 +73,20 @@ protected override void SetResponses(OpenApiOperation operation) } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } protected override void SetSecurity(OpenApiOperation operation) { - if (_insertRestriction == null) + if (_insertRestriction?.Permissions is null) { return; } - operation.Security = Context.CreateSecurityRequirements(_insertRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_insertRestriction.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs index 984be2386..4d0e85cee 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/RefPutOperationHandler.cs @@ -29,7 +29,7 @@ public RefPutOperationHandler(OpenApiDocument document) : base(document) } /// public override HttpMethod OperationType => HttpMethod.Patch; - private UpdateRestrictionsType _updateRestriction; + private UpdateRestrictionsType? _updateRestriction; /// protected override void Initialize(ODataContext context, ODataPath path) @@ -42,12 +42,12 @@ protected override void Initialize(ODataContext context, ODataPath path) protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Description - string placeHolder = "Update the ref of navigation property " + NavigationProperty.Name + " in " + NavigationSource.Name; + string placeHolder = "Update the ref of navigation property " + NavigationProperty?.Name + " in " + NavigationSource?.Name; operation.Summary = _updateRestriction?.Description ?? placeHolder; operation.Description = _updateRestriction?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true}) { string prefix = "UpdateRef"; operation.OperationId = GetOperationId(prefix); @@ -73,18 +73,19 @@ protected override void SetResponses(OpenApiOperation operation) } }; - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } protected override void SetSecurity(OpenApiOperation operation) { - if (_updateRestriction == null) + if (_updateRestriction?.Permissions == null) { return; } - operation.Security = Context.CreateSecurityRequirements(_updateRestriction.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_updateRestriction.Permissions, _document).ToList(); } protected override void AppendCustomParameters(OpenApiOperation operation) diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs index 76e9232c4..d4f90bc31 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonGetOperationHandler.cs @@ -35,28 +35,33 @@ public SingletonGetOperationHandler(OpenApiDocument document) : base(document) /// public override HttpMethod OperationType => HttpMethod.Get; - private ReadRestrictionsType _readRestrictions; + private ReadRestrictionsType? _readRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - var singletonReadRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.ReadRestrictions); - _readRestrictions?.MergePropertiesIfNull(singletonReadRestrictions); - _readRestrictions ??= singletonReadRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _readRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + + if (Context is not null && Singleton is not null) + { + var singletonReadRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.ReadRestrictions); + _readRestrictions?.MergePropertiesIfNull(singletonReadRestrictions); + _readRestrictions ??= singletonReadRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Descriptions - string placeHolder = "Get " + Singleton.Name; + string placeHolder = "Get " + Singleton?.Name; operation.Summary = _readRestrictions?.Description ?? placeHolder; - operation.Description = _readRestrictions?.LongDescription ?? Context.Model.GetDescriptionAnnotation(Singleton); + operation.Description = _readRestrictions?.LongDescription ?? Context?.Model.GetDescriptionAnnotation(Singleton); // OperationId, it should be unique among all operations described in the API. - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Singleton is not null) { string typeName = Singleton.EntityType.Name; operation.OperationId = Singleton.Name + "." + typeName + ".Get" + Utils.UpperFirstChar(typeName); @@ -67,16 +72,19 @@ protected override void SetBasicInfo(OpenApiOperation operation) protected override void SetParameters(OpenApiOperation operation) { base.SetParameters(operation); + + if (Singleton is null) return; // $select - OpenApiParameter parameter = Context.CreateSelect(Singleton); + var parameter = Context?.CreateSelect(Singleton); + operation.Parameters ??= []; if (parameter != null) { operation.Parameters.Add(parameter); } // $expand - parameter = Context.CreateExpand(Singleton); + parameter = Context?.CreateExpand(Singleton); if (parameter != null) { operation.Parameters.Add(parameter); @@ -86,45 +94,49 @@ protected override void SetParameters(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - IOpenApiSchema schema = null; - IDictionary links = null; - - if (Context.Settings.EnableDerivedTypesReferencesForResponses) + if (Singleton is not null) { - schema = EdmModelHelper.GetDerivedTypesReferenceSchema(Singleton.EntityType, Context.Model, _document); - } + IOpenApiSchema? schema = null; + IDictionary? links = null; - if (Context.Settings.ShowLinks) - { - links = Context.CreateLinks(entityType: Singleton.EntityType, entityName: Singleton.Name, - entityKind: Singleton.ContainerElementKind.ToString(), path: Path, parameters: PathParameters); - } + if (Context is {Settings.EnableDerivedTypesReferencesForResponses: true}) + { + schema = EdmModelHelper.GetDerivedTypesReferenceSchema(Singleton.EntityType, Context.Model, _document); + } + + if (Context is {Settings.ShowLinks: true} && Path is not null) + { + links = Context.CreateLinks(entityType: Singleton.EntityType, entityName: Singleton.Name, + entityKind: Singleton.ContainerElementKind.ToString(), path: Path, parameters: PathParameters); + } - schema ??= new OpenApiSchemaReference(Singleton.EntityType.FullName(), _document); + schema ??= new OpenApiSchemaReference(Singleton.EntityType.FullName(), _document); - operation.Responses = new OpenApiResponses - { + operation.Responses = new OpenApiResponses { - Context.Settings.UseSuccessStatusCodeRange ? Constants.StatusCodeClass2XX : Constants.StatusCode200, - new OpenApiResponse { - Description = "Retrieved entity", - Content = new Dictionary + Context?.Settings.UseSuccessStatusCodeRange ?? false ? Constants.StatusCodeClass2XX : Constants.StatusCode200, + new OpenApiResponse { + Description = "Retrieved entity", + Content = new Dictionary { - Constants.ApplicationJsonMediaType, - new OpenApiMediaType { - Schema = schema + Constants.ApplicationJsonMediaType, + new OpenApiMediaType + { + Schema = schema + } } - } - }, - Links = links + }, + Links = links + } } - } - }; + }; + } - operation.AddErrorResponses(Context.Settings, _document, false); + if (Context is not null) + operation.AddErrorResponses(Context.Settings, _document, false); base.SetResponses(operation); } @@ -137,7 +149,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_readRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_readRestrictions.Permissions, _document).ToList(); } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonOperationHandler.cs index 7e8baa6b0..e49713ccf 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonOperationHandler.cs @@ -5,6 +5,7 @@ using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models.References; using Microsoft.OpenApi.OData.Common; @@ -30,7 +31,7 @@ protected SingletonOperationHandler(OpenApiDocument document):base(document) /// /// Gets the . /// - protected IEdmSingleton Singleton { get; private set; } + protected IEdmSingleton? Singleton { get; private set; } /// protected override void Initialize(ODataContext context, ODataPath path) @@ -38,9 +39,8 @@ protected override void Initialize(ODataContext context, ODataPath path) // Base Initialize should be called at top of this method. base.Initialize(context, path); - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - - Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmSingleton source}) + Singleton = source; } /// @@ -48,9 +48,9 @@ protected override void SetTags(OpenApiOperation operation) { // In this SDK, we use "[Singleton Name].[Singleton Entity Type Name] // For example: "Me.User" - var tagName = Singleton.Name + "." + Singleton.EntityType.Name; + var tagName = Singleton?.Name + "." + Singleton?.EntityType.Name; - Context.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() + Context?.AddExtensionToTag(tagName, Constants.xMsTocType, new OpenApiAny("page"), () => new OpenApiTag() { Name = tagName }); @@ -64,6 +64,7 @@ protected override void SetTags(OpenApiOperation operation) /// protected override void SetExtensions(OpenApiOperation operation) { + operation.Extensions ??= new Dictionary(); operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiAny("operation")); base.SetExtensions(operation); @@ -72,10 +73,10 @@ protected override void SetExtensions(OpenApiOperation operation) /// protected override void SetExternalDocs(OpenApiOperation operation) { - if (Context.Settings.ShowExternalDocs) + if (Context is {Settings.ShowExternalDocs: true} && CustomLinkRel is not null) { - var externalDocs = Context.Model.GetLinkRecord(TargetPath, CustomLinkRel) ?? - Context.Model.GetLinkRecord(Singleton, CustomLinkRel); + var externalDocs = (string.IsNullOrEmpty(TargetPath) ? null : Context.Model.GetLinkRecord(TargetPath, CustomLinkRel)) ?? + (Singleton is null ? null : Context.Model.GetLinkRecord(Singleton, CustomLinkRel)); if (externalDocs != null) { diff --git a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs index 4342f8f64..cd4f56dea 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Operation/SingletonPatchOperationHandler.cs @@ -35,28 +35,33 @@ public SingletonPatchOperationHandler(OpenApiDocument document) : base(document) /// public override HttpMethod OperationType => HttpMethod.Patch; - private UpdateRestrictionsType _updateRestrictions; + private UpdateRestrictionsType? _updateRestrictions; protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - _updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - var singletonUpdateRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.UpdateRestrictions); - _updateRestrictions?.MergePropertiesIfNull(singletonUpdateRestrictions); - _updateRestrictions ??= singletonUpdateRestrictions; + if (!string.IsNullOrEmpty(TargetPath)) + _updateRestrictions = Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + + if (Context is not null && Singleton is not null) + { + var singletonUpdateRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.UpdateRestrictions); + _updateRestrictions?.MergePropertiesIfNull(singletonUpdateRestrictions); + _updateRestrictions ??= singletonUpdateRestrictions; + } } /// protected override void SetBasicInfo(OpenApiOperation operation) { // Summary and Descriptions - string placeHolder = "Update " + Singleton.Name; + string placeHolder = "Update " + Singleton?.Name; operation.Summary = _updateRestrictions?.Description ?? placeHolder; operation.Description = _updateRestrictions?.LongDescription; // OperationId - if (Context.Settings.EnableOperationId) + if (Context is {Settings.EnableOperationId: true} && Singleton is not null) { string typeName = Singleton.EntityType.Name; operation.OperationId = Singleton.Name + "." + typeName + ".Update" + Utils.UpperFirstChar(typeName); @@ -87,7 +92,8 @@ protected override void SetRequestBody(OpenApiOperation operation) /// protected override void SetResponses(OpenApiOperation operation) { - operation.AddErrorResponses(Context.Settings, _document, true, GetOpenApiSchema()); + if (Context is not null && GetOpenApiSchema() is {} schema) + operation.AddErrorResponses(Context.Settings, _document, true, schema); base.SetResponses(operation); } @@ -99,7 +105,7 @@ protected override void SetSecurity(OpenApiOperation operation) return; } - operation.Security = Context.CreateSecurityRequirements(_updateRestrictions.Permissions, _document).ToList(); + operation.Security = Context?.CreateSecurityRequirements(_updateRestrictions.Permissions, _document).ToList(); } /// @@ -121,9 +127,10 @@ protected override void AppendCustomParameters(OpenApiOperation operation) } } - private IOpenApiSchema GetOpenApiSchema() + private IOpenApiSchema? GetOpenApiSchema() { - return Context.Settings.EnableDerivedTypesReferencesForRequestBody ? + if (Singleton is null) return null; + return Context is {Settings.EnableDerivedTypesReferencesForRequestBody: true} ? EdmModelHelper.GetDerivedTypesReferenceSchema(Singleton.EntityType, Context.Model, _document) : new OpenApiSchemaReference(Singleton.EntityType.FullName(), _document); } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs index f027d2f14..c83d881ef 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/ComplexPropertyItemHandler.cs @@ -3,8 +3,10 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -28,7 +30,7 @@ public ComplexPropertyItemHandler(OpenApiDocument document) : base(document) /// /// Gets the complex property /// - protected IEdmStructuralProperty ComplexProperty { get; private set; } + protected IEdmStructuralProperty? ComplexProperty { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) @@ -40,13 +42,16 @@ protected override void SetOperations(OpenApiPathItem item) public void AddReadOperation(OpenApiPathItem item) { - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType complexTypeReadRestrictions = Context.Model.GetRecord(ComplexProperty, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(complexTypeReadRestrictions); - readRestrictions ??= complexTypeReadRestrictions; + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (ComplexProperty is not null) + { + var complexTypeReadRestrictions = Context?.Model.GetRecord(ComplexProperty, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(complexTypeReadRestrictions); + readRestrictions ??= complexTypeReadRestrictions; + } bool isReadable = readRestrictions?.Readable ?? false; - if ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isReadable) || - !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) + if (Context is not null && ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isReadable) || + !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths)) { AddOperation(item, HttpMethod.Get); } @@ -54,15 +59,18 @@ public void AddReadOperation(OpenApiPathItem item) public void AddInsertOperation(OpenApiPathItem item) { - if (Path.LastSegment is ODataComplexPropertySegment segment && segment.Property.Type.IsCollection()) + if (Path?.LastSegment is ODataComplexPropertySegment segment && segment.Property.Type.IsCollection()) { - InsertRestrictionsType insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); - InsertRestrictionsType entityInsertRestrictions = Context.Model.GetRecord(ComplexProperty, CapabilitiesConstants.InsertRestrictions); - insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); - insertRestrictions ??= entityInsertRestrictions; + var insertRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + if (ComplexProperty is not null) + { + var entityInsertRestrictions = Context?.Model.GetRecord(ComplexProperty, CapabilitiesConstants.InsertRestrictions); + insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); + insertRestrictions ??= entityInsertRestrictions; + } bool isInsertable = insertRestrictions?.Insertable ?? false; - if ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isInsertable) || - !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) + if (Context is not null && ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isInsertable) || + !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths)) { AddOperation(item, HttpMethod.Post); } @@ -71,13 +79,16 @@ public void AddInsertOperation(OpenApiPathItem item) public void AddUpdateOperation(OpenApiPathItem item) { - UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - UpdateRestrictionsType complexTypeUpdateRestrictions = Context.Model.GetRecord(ComplexProperty, CapabilitiesConstants.UpdateRestrictions); - updateRestrictions?.MergePropertiesIfNull(complexTypeUpdateRestrictions); - updateRestrictions ??= complexTypeUpdateRestrictions; + var updateRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + if (ComplexProperty is not null) + { + var complexTypeUpdateRestrictions = Context?.Model.GetRecord(ComplexProperty, CapabilitiesConstants.UpdateRestrictions); + updateRestrictions?.MergePropertiesIfNull(complexTypeUpdateRestrictions); + updateRestrictions ??= complexTypeUpdateRestrictions; + } bool isUpdatable = updateRestrictions?.Updatable ?? false; - if ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isUpdatable) || - !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths) + if (Context is not null && ((Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths && isUpdatable) || + !Context.Settings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths)) { if (updateRestrictions?.IsUpdateMethodPutAndPatch == true) { @@ -101,13 +112,19 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); // The last segment should be the complex property segment. - ODataComplexPropertySegment navigationSourceSegment = path.LastSegment as ODataComplexPropertySegment; - ComplexProperty = navigationSourceSegment.Property; + if (path.LastSegment is ODataComplexPropertySegment {Property: {} property}) + ComplexProperty = property; } /// protected override void SetExtensions(OpenApiPathItem item) { - item.Extensions.AddCustomAttributesToExtensions(Context, ComplexProperty); + if (ComplexProperty is null) return; + + if (Context is not null) + { + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, ComplexProperty); + } } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs index 9b394158b..22f91287a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntityPathItemHandler.cs @@ -3,8 +3,10 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -31,10 +33,14 @@ public EntityPathItemHandler(OpenApiDocument document) : base(document) /// protected override void SetOperations(OpenApiPathItem item) { - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); - readRestrictions ??= entityReadRestrictions; + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + + if (Context is not null && EntitySet is not null) + { + var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); + readRestrictions ??= entityReadRestrictions; + } if (readRestrictions == null || (readRestrictions.ReadByKeyRestrictions == null && readRestrictions.IsReadable) || (readRestrictions.ReadByKeyRestrictions != null && readRestrictions.ReadByKeyRestrictions.IsReadable)) @@ -43,10 +49,14 @@ protected override void SetOperations(OpenApiPathItem item) AddOperation(item, HttpMethod.Get); } - UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - UpdateRestrictionsType entityUpdateRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.UpdateRestrictions); - updateRestrictions?.MergePropertiesIfNull(entityUpdateRestrictions); - updateRestrictions ??= entityUpdateRestrictions; + var updateRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + + if (Context is not null && EntitySet is not null) + { + var entityUpdateRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.UpdateRestrictions); + updateRestrictions?.MergePropertiesIfNull(entityUpdateRestrictions); + updateRestrictions ??= entityUpdateRestrictions; + } if (updateRestrictions?.IsUpdatable ?? true) { if (updateRestrictions?.IsUpdateMethodPutAndPatch == true) @@ -64,10 +74,14 @@ protected override void SetOperations(OpenApiPathItem item) } } - DeleteRestrictionsType deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); - DeleteRestrictionsType entityDeleteRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.DeleteRestrictions); - deleteRestrictions?.MergePropertiesIfNull(entityDeleteRestrictions); - deleteRestrictions ??= entityDeleteRestrictions; + var deleteRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + + if (Context is not null && EntitySet is not null) + { + var entityDeleteRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.DeleteRestrictions); + deleteRestrictions?.MergePropertiesIfNull(entityDeleteRestrictions); + deleteRestrictions ??= entityDeleteRestrictions; + } if (deleteRestrictions?.IsDeletable ?? true) { AddOperation(item, HttpMethod.Delete); @@ -75,10 +89,13 @@ protected override void SetOperations(OpenApiPathItem item) } /// - protected override void SetExtensions(OpenApiPathItem pathItem) + protected override void SetExtensions(OpenApiPathItem item) { - base.SetExtensions(pathItem); - pathItem.Extensions.AddCustomAttributesToExtensions(Context, EntitySet.EntityType); + base.SetExtensions(item); + if (EntitySet is null || Context is null) return; + + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, EntitySet.EntityType); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntitySetPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntitySetPathItemHandler.cs index 0240a0fea..403250959 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/EntitySetPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/EntitySetPathItemHandler.cs @@ -3,8 +3,10 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -31,24 +33,32 @@ public EntitySetPathItemHandler(OpenApiDocument document) : base(document) /// /// Gets the entity set. /// - protected IEdmEntitySet EntitySet { get; private set; } + protected IEdmEntitySet? EntitySet { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) { - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); - readRestrictions ??= entityReadRestrictions; + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + + if (Context is not null && EntitySet is not null) + { + var entityReadRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(entityReadRestrictions); + readRestrictions ??= entityReadRestrictions; + } if (readRestrictions?.IsReadable ?? true) { AddOperation(item, HttpMethod.Get); } - InsertRestrictionsType insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); - InsertRestrictionsType entityInsertRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.InsertRestrictions); - insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); - insertRestrictions ??= entityInsertRestrictions; + var insertRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + + if (Context is not null && EntitySet is not null) + { + var entityInsertRestrictions = Context.Model.GetRecord(EntitySet, CapabilitiesConstants.InsertRestrictions); + insertRestrictions?.MergePropertiesIfNull(entityInsertRestrictions); + insertRestrictions ??= entityInsertRestrictions; + } if (insertRestrictions?.IsInsertable ?? true) { AddOperation(item, HttpMethod.Post); @@ -61,21 +71,23 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); // The first segment should be the entity set segment. - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmEntitySet sourceSet}) + EntitySet = sourceSet; } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Provides operations to manage the collection of {EntitySet.EntityType.Name} entities."; + pathItem.Description = $"Provides operations to manage the collection of {EntitySet?.EntityType.Name} entities."; } /// - protected override void SetExtensions(OpenApiPathItem pathItem) + protected override void SetExtensions(OpenApiPathItem item) { - base.SetExtensions(pathItem); - pathItem.Extensions.AddCustomAttributesToExtensions(Context, EntitySet); + base.SetExtensions(item); + if (EntitySet is null || Context is null) return; + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, EntitySet); } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/IPathItemHandlerProvider.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/IPathItemHandlerProvider.cs index 5e6a39ffb..8a1aa0660 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/IPathItemHandlerProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/IPathItemHandlerProvider.cs @@ -19,6 +19,6 @@ internal interface IPathItemHandlerProvider /// The path kind. /// The Open API document to use to lookup references. /// The . - IPathItemHandler GetHandler(ODataPathKind pathKind, OpenApiDocument document); + IPathItemHandler? GetHandler(ODataPathKind pathKind, OpenApiDocument document); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs index 48bf11f03..7498243f3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/MediaEntityPathItemHandler.cs @@ -30,20 +30,20 @@ public MediaEntityPathItemHandler(OpenApiDocument document) : base(document) /// /// Gets the entity set. /// - protected IEdmEntitySet EntitySet { get; private set; } + protected IEdmEntitySet? EntitySet { get; private set; } /// /// Gets the singleton. /// - protected IEdmSingleton Singleton { get; private set; } + protected IEdmSingleton? Singleton { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) { - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType navSourceReadRestrictions = EntitySet != null - ? Context.Model.GetRecord(EntitySet) - : Context.Model.GetRecord(Singleton); + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null :Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var navSourceReadRestrictions = EntitySet != null + ? Context?.Model.GetRecord(EntitySet) + : (Singleton is null ? null : Context?.Model.GetRecord(Singleton)); readRestrictions ??= navSourceReadRestrictions; if (readRestrictions == null || (readRestrictions.ReadByKeyRestrictions == null && readRestrictions.IsReadable) || @@ -52,20 +52,20 @@ protected override void SetOperations(OpenApiPathItem item) AddOperation(item, HttpMethod.Get); } - UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - UpdateRestrictionsType navSourceUpdateRestrictions = EntitySet != null - ? Context.Model.GetRecord(EntitySet) - : Context.Model.GetRecord(Singleton); + var updateRestrictions = string.IsNullOrEmpty(TargetPath) ? null :Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + var navSourceUpdateRestrictions = EntitySet != null + ? Context?.Model.GetRecord(EntitySet) + : (Singleton is null ? null : Context?.Model.GetRecord(Singleton)); updateRestrictions ??= navSourceUpdateRestrictions; if (updateRestrictions?.IsUpdatable ?? true) { AddOperation(item, HttpMethod.Put); } - DeleteRestrictionsType deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); - DeleteRestrictionsType navSourceDeleteRestrictions = EntitySet != null - ? Context.Model.GetRecord(EntitySet) - : Context.Model.GetRecord(Singleton); + var deleteRestrictions = string.IsNullOrEmpty(TargetPath) ? null :Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + var navSourceDeleteRestrictions = EntitySet != null + ? Context?.Model.GetRecord(EntitySet) + : (Singleton is null ? null : Context?.Model.GetRecord(Singleton)); deleteRestrictions ??= navSourceDeleteRestrictions; if (deleteRestrictions?.IsDeletable ?? true) { @@ -79,19 +79,16 @@ protected override void Initialize(ODataContext context, ODataPath path) base.Initialize(context, path); // The first segment could be an entity set segment or a singleton segment. - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - - EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet; - if (EntitySet == null) - { - Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton; - } + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmEntitySet entitySet}) + EntitySet = entitySet; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmSingleton singleton}) + Singleton = singleton; } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Provides operations to manage the media for the {(EntitySet?.EntityType ?? Singleton?.EntityType).Name} entity."; + pathItem.Description = $"Provides operations to manage the media for the {(EntitySet?.EntityType ?? Singleton?.EntityType)?.Name} entity."; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs index 21306c0d7..f657944f5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/NavigationPropertyPathItemHandler.cs @@ -15,6 +15,7 @@ using Microsoft.OpenApi.OData.Vocabulary.Capabilities; using System.Text.Json.Nodes; using System.Net.Http; +using Microsoft.OpenApi.Interfaces; namespace Microsoft.OpenApi.OData.PathItem { @@ -37,12 +38,12 @@ public NavigationPropertyPathItemHandler(OpenApiDocument document) : base(docume /// /// Gets the navigation property. /// - public IEdmNavigationProperty NavigationProperty { get; private set; } + public IEdmNavigationProperty? NavigationProperty { get; private set; } /// /// Gets the navigation source. /// - public IEdmNavigationSource NavigationSource { get; private set; } + public IEdmNavigationSource? NavigationSource { get; private set; } /// /// Gets a bool value indicating whether the last segment is a key segment. @@ -57,26 +58,28 @@ public NavigationPropertyPathItemHandler(OpenApiDocument document) : base(docume /// /// The entity type targeted by the /// - private IEdmEntityType _navPropEntityType; + private IEdmEntityType? _navPropEntityType; /// protected override void SetOperations(OpenApiPathItem item) { - IEdmEntitySet entitySet = NavigationSource as IEdmEntitySet; - IEdmVocabularyAnnotatable target = entitySet; - target ??= NavigationSource as IEdmSingleton; - - NavigationRestrictionsType targetPathRestrictionType = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.NavigationRestrictions); - NavigationRestrictionsType navSourceRestrictionType = Context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); - NavigationRestrictionsType navPropRestrictionType = Context.Model.GetRecord(NavigationProperty, CapabilitiesConstants.NavigationRestrictions); + IEdmVocabularyAnnotatable? target = NavigationSource switch { + IEdmEntitySet es => es, + IEdmSingleton singleton => singleton, + _ => null + }; + + var targetPathRestrictionType = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.NavigationRestrictions); + var navSourceRestrictionType = target is null ? null : Context?.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); + var navPropRestrictionType = NavigationProperty is null ? null : Context?.Model.GetRecord(NavigationProperty, CapabilitiesConstants.NavigationRestrictions); - NavigationPropertyRestriction restriction = targetPathRestrictionType?.RestrictedProperties?.FirstOrDefault() - ?? navSourceRestrictionType?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty == Path.NavigationPropertyPath()) + var restriction = targetPathRestrictionType?.RestrictedProperties?.FirstOrDefault() + ?? (Path is null ? null : navSourceRestrictionType?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty == Path.NavigationPropertyPath())) ?? navPropRestrictionType?.RestrictedProperties?.FirstOrDefault(); // Check whether the navigation property should be part of the path - if (EdmModelHelper.NavigationRestrictionsAllowsNavigability(navSourceRestrictionType, restriction) == false || - EdmModelHelper.NavigationRestrictionsAllowsNavigability(navPropRestrictionType, restriction) == false) + if (!EdmModelHelper.NavigationRestrictionsAllowsNavigability(navSourceRestrictionType, restriction) || + !EdmModelHelper.NavigationRestrictionsAllowsNavigability(navPropRestrictionType, restriction)) { return; } @@ -84,28 +87,34 @@ protected override void SetOperations(OpenApiPathItem item) AddGetOperation(item, restriction); // Update restrictions - UpdateRestrictionsType navPropUpdateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + var navPropUpdateRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); navPropUpdateRestrictions?.MergePropertiesIfNull(restriction?.UpdateRestrictions); navPropUpdateRestrictions ??= restriction?.UpdateRestrictions; - UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(NavigationProperty); - navPropUpdateRestrictions?.MergePropertiesIfNull(updateRestrictions); - navPropUpdateRestrictions ??= updateRestrictions; + if (NavigationProperty is not null && Context is not null) + { + var updateRestrictions = Context.Model.GetRecord(NavigationProperty); + navPropUpdateRestrictions?.MergePropertiesIfNull(updateRestrictions); + navPropUpdateRestrictions ??= updateRestrictions; + } // Insert restrictions - InsertRestrictionsType navPropInsertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + var navPropInsertRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); navPropInsertRestrictions?.MergePropertiesIfNull(restriction?.InsertRestrictions); navPropInsertRestrictions ??= restriction?.InsertRestrictions; - InsertRestrictionsType insertRestrictions = Context.Model.GetRecord(NavigationProperty); - navPropInsertRestrictions?.MergePropertiesIfNull(insertRestrictions); - navPropInsertRestrictions ??= insertRestrictions; + if (NavigationProperty is not null && Context is not null) + { + var insertRestrictions = Context.Model.GetRecord(NavigationProperty); + navPropInsertRestrictions?.MergePropertiesIfNull(insertRestrictions); + navPropInsertRestrictions ??= insertRestrictions; + } // Entity insert restrictions - UpdateRestrictionsType entityUpdateRestrictions = Context.Model.GetRecord(_navPropEntityType); + var entityUpdateRestrictions = _navPropEntityType is null ? null : Context?.Model.GetRecord(_navPropEntityType); // containment: (Post - Collection | Patch/Put - Single) - if (NavigationProperty.ContainsTarget) + if (NavigationProperty?.ContainsTarget ?? false) { - UpdateRestrictionsType updateRestrictionType = navPropUpdateRestrictions ?? entityUpdateRestrictions; + var updateRestrictionType = navPropUpdateRestrictions ?? entityUpdateRestrictions; if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) { if (LastSegmentIsKeySegment) @@ -120,7 +129,7 @@ protected override void SetOperations(OpenApiPathItem item) } else { - InsertRestrictionsType entityInsertRestrictions = Context.Model.GetRecord(_navPropEntityType); + var entityInsertRestrictions = _navPropEntityType is null ? null : Context?.Model.GetRecord(_navPropEntityType); bool isInsertableDefault = navPropInsertRestrictions == null && entityInsertRestrictions == null; if (isInsertableDefault || @@ -169,16 +178,20 @@ protected override void SetOperations(OpenApiPathItem item) AddDeleteOperation(item, restriction); } - private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { - ReadRestrictionsType navPropReadRestriction = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var navPropReadRestriction = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); navPropReadRestriction?.MergePropertiesIfNull(restriction?.ReadRestrictions); navPropReadRestriction ??= restriction?.ReadRestrictions; - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(NavigationProperty); - navPropReadRestriction?.MergePropertiesIfNull(readRestrictions); - navPropReadRestriction ??= readRestrictions; - ReadRestrictionsType entityReadRestriction = Context.Model.GetRecord(_navPropEntityType); + if (NavigationProperty is not null && Context is not null) + { + var readRestrictions = Context.Model.GetRecord(NavigationProperty); + navPropReadRestriction?.MergePropertiesIfNull(readRestrictions); + navPropReadRestriction ??= readRestrictions; + } + + var entityReadRestriction = _navPropEntityType is null ? null : Context?.Model.GetRecord(_navPropEntityType); bool isReadableDefault = navPropReadRestriction == null && entityReadRestriction == null; if (isReadableDefault) { @@ -208,7 +221,7 @@ private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction } else { - Debug.Assert(LastSegmentIsKeySegment == false); + Debug.Assert(!LastSegmentIsKeySegment); if ((navPropReadRestriction?.IsReadable ?? true) && (entityReadRestriction?.IsReadable ?? true)) { @@ -217,27 +230,30 @@ private void AddGetOperation(OpenApiPathItem item, NavigationPropertyRestriction } } - private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { Debug.Assert(!LastSegmentIsRefSegment); - DeleteRestrictionsType navPropDeleteRestriction = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + var navPropDeleteRestriction = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); navPropDeleteRestriction?.MergePropertiesIfNull(restriction?.DeleteRestrictions); navPropDeleteRestriction ??= restriction?.DeleteRestrictions; - DeleteRestrictionsType insertRestrictions = Context.Model.GetRecord(NavigationProperty); - navPropDeleteRestriction?.MergePropertiesIfNull(insertRestrictions); - navPropDeleteRestriction ??= insertRestrictions; + if (NavigationProperty is not null && Context is not null) + { + var insertRestrictions = Context.Model.GetRecord(NavigationProperty); + navPropDeleteRestriction?.MergePropertiesIfNull(insertRestrictions); + navPropDeleteRestriction ??= insertRestrictions; + } if (!(NavigationProperty.TargetMultiplicity() != EdmMultiplicity.Many || LastSegmentIsKeySegment)) return; - DeleteRestrictionsType entityDeleteRestriction = Context.Model.GetRecord(_navPropEntityType); + var entityDeleteRestriction = _navPropEntityType is null ? null : Context?.Model.GetRecord(_navPropEntityType); bool isDeletable = (navPropDeleteRestriction == null && entityDeleteRestriction == null) || ((entityDeleteRestriction?.IsDeletable ?? true) && (navPropDeleteRestriction?.IsDeletable ?? true)); - if (NavigationProperty.ContainsTarget && isDeletable) + if ((NavigationProperty?.ContainsTarget ?? false) && isDeletable) { AddOperation(item, HttpMethod.Delete); } @@ -251,7 +267,7 @@ private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestrict return; } - private void AddUpdateOperation(OpenApiPathItem item, UpdateRestrictionsType updateRestrictionsType) + private void AddUpdateOperation(OpenApiPathItem item, UpdateRestrictionsType? updateRestrictionsType) { if (updateRestrictionsType?.IsUpdatable ?? true) { @@ -277,11 +293,11 @@ protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - NavigationSource = navigationSourceSegment.NavigationSource; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: {} source}) + NavigationSource = source; - LastSegmentIsKeySegment = path.LastSegment.Kind == ODataSegmentKind.Key; - LastSegmentIsRefSegment = path.LastSegment.Kind == ODataSegmentKind.Ref; + LastSegmentIsKeySegment = path.LastSegment?.Kind == ODataSegmentKind.Key; + LastSegmentIsRefSegment = path.LastSegment?.Kind == ODataSegmentKind.Ref; NavigationProperty = path.OfType().Last().NavigationProperty; _navPropEntityType = NavigationProperty.ToEntityType(); } @@ -289,12 +305,12 @@ protected override void Initialize(ODataContext context, ODataPath path) /// protected override void SetExtensions(OpenApiPathItem item) { - if (!Context.Settings.ShowMsDosGroupPath) + if (Context is null || !Context.Settings.ShowMsDosGroupPath) { return; } - IList samePaths = new List(); + var samePaths = new List(); foreach (var path in Context.AllPaths.Where(p => p.Kind == ODataPathKind.NavigationProperty && p != Path)) { bool lastIsKeySegment = path.LastSegment is ODataKeySegment; @@ -309,11 +325,12 @@ protected override void SetExtensions(OpenApiPathItem item) continue; } - if (path.LastSegment is not ODataNavigationPropertySegment npSegment) - { - npSegment = path.Segments[path.Count - 2] as ODataNavigationPropertySegment; - } - if (NavigationProperty != npSegment.NavigationProperty) + var npSegment = path.LastSegment is ODataNavigationPropertySegment npS ? + npS : + path.Segments[path.Count - 2] is ODataNavigationPropertySegment npSegmentFallback ? + npSegmentFallback : + null; + if (NavigationProperty != npSegment?.NavigationProperty) { continue; } @@ -331,17 +348,22 @@ protected override void SetExtensions(OpenApiPathItem item) array.Add(p.GetPathItemName(settings)); } + item.Extensions ??= new Dictionary(); item.Extensions.Add(Constants.xMsDosGroupPath, new OpenApiAny(array)); } base.SetExtensions(item); - item.Extensions.AddCustomAttributesToExtensions(Context, NavigationProperty); + if (NavigationProperty is not null) + { + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, NavigationProperty); + } } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Provides operations to manage the {NavigationProperty.Name} property of the {NavigationProperty.DeclaringType.FullTypeName()} entity."; + pathItem.Description = $"Provides operations to manage the {NavigationProperty?.Name} property of the {NavigationProperty?.DeclaringType.FullTypeName()} entity."; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs index 38e4e224e..36cdd7cd5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/ODataTypeCastPathItemHandler.cs @@ -3,8 +3,10 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -41,19 +43,22 @@ protected override void Initialize(ODataContext context, ODataPath path) StructuredType = castSegment.StructuredType; } } - private IEdmStructuredType StructuredType { get; set; } + private IEdmStructuredType? StructuredType { get; set; } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Casts the previous resource to {(StructuredType as IEdmNamedElement).Name}."; + if (StructuredType is IEdmNamedElement namedElement) + pathItem.Description = $"Casts the previous resource to {namedElement.Name}."; } /// - protected override void SetExtensions(OpenApiPathItem pathItem) + protected override void SetExtensions(OpenApiPathItem item) { - base.SetExtensions(pathItem); - pathItem.Extensions.AddCustomAttributesToExtensions(Context, StructuredType); + base.SetExtensions(item); + if (StructuredType is null || Context is null) return; + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, StructuredType); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationImportPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationImportPathItemHandler.cs index 2d3eab0a6..a7a53286d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationImportPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationImportPathItemHandler.cs @@ -3,8 +3,10 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -31,7 +33,7 @@ public OperationImportPathItemHandler(OpenApiDocument document) : base(document) /// /// Gets the operation import. /// - public IEdmOperationImport EdmOperationImport { get; private set; } + public IEdmOperationImport? EdmOperationImport { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) @@ -52,10 +54,13 @@ protected override void SetOperations(OpenApiPathItem item) // how to invoke the function import. // so far, - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType operationReadRestrictions = Context.Model.GetRecord(EdmOperationImport, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(operationReadRestrictions); - readRestrictions ??= operationReadRestrictions; + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + if (Context is not null && EdmOperationImport is not null) + { + var operationReadRestrictions = Context.Model.GetRecord(EdmOperationImport, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(operationReadRestrictions); + readRestrictions ??= operationReadRestrictions; + } if (readRestrictions?.IsReadable ?? true) { AddOperation(item, HttpMethod.Get); @@ -68,21 +73,23 @@ protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - ODataOperationImportSegment operationImportSegment = path.FirstSegment as ODataOperationImportSegment; - EdmOperationImport = operationImportSegment.OperationImport; + if (path.FirstSegment is ODataOperationImportSegment {OperationImport: {} import}) + EdmOperationImport = import; } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Provides operations to call the {EdmOperationImport.Name} method."; + pathItem.Description = $"Provides operations to call the {EdmOperationImport?.Name} method."; } /// protected override void SetExtensions(OpenApiPathItem item) { base.SetExtensions(item); + if (EdmOperationImport is null || Context is null) return; + item.Extensions ??= new Dictionary(); item.Extensions.AddCustomAttributesToExtensions(Context, EdmOperationImport); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationPathItemHandler.cs index 899271924..b2ea58dab 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/OperationPathItemHandler.cs @@ -9,6 +9,7 @@ using System.Text.Json.Nodes; using Microsoft.OData.Edm; using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -34,7 +35,7 @@ public OperationPathItemHandler(OpenApiDocument document) : base(document) /// /// Gets the Edm operation. /// - public IEdmOperation EdmOperation { get; private set; } + public IEdmOperation? EdmOperation { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) @@ -58,61 +59,65 @@ protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - ODataOperationSegment operationSegment = path.LastSegment as ODataOperationSegment; - EdmOperation = operationSegment.Operation; + if (path.LastSegment is ODataOperationSegment {Operation: {} operation}) + EdmOperation = operation; } /// protected override void SetExtensions(OpenApiPathItem item) { - if (!Context.Settings.ShowMsDosGroupPath) + if (Context is null || !Context.Settings.ShowMsDosGroupPath) { return; } - ODataNavigationSourceSegment navigationSourceSegment = Path.FirstSegment as ODataNavigationSourceSegment; - IEdmNavigationSource currentNavSource = navigationSourceSegment.NavigationSource; - - IList samePaths = new List(); - foreach (var path in Context.AllPaths.Where(p => p.Kind == ODataPathKind.Operation && p != Path)) + if (Path?.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmNavigationSource currentNavSource}) { - navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - if (currentNavSource != navigationSourceSegment.NavigationSource) - { - continue; - } - ODataOperationSegment operationSegment = path.LastSegment as ODataOperationSegment; - if (EdmOperation.FullName() != operationSegment.Operation.FullName()) + var samePaths = new List(); + foreach (var path in Context.AllPaths.Where(p => p.Kind == ODataPathKind.Operation && p != Path)) { - continue; - } + if (path.FirstSegment is ODataNavigationSourceSegment navigationSourceSegment && currentNavSource != navigationSourceSegment.NavigationSource) + { + continue; + } - samePaths.Add(path); - } + if (path.LastSegment is ODataOperationSegment operationSegment && EdmOperation.FullName() != operationSegment.Operation.FullName()) + { + continue; + } - if (samePaths.Any()) - { - JsonArray array = new JsonArray(); - OpenApiConvertSettings settings = Context.Settings.Clone(); - settings.EnableKeyAsSegment = Context.KeyAsSegment; - foreach (var p in samePaths) - { - array.Add(p.GetPathItemName(settings)); + samePaths.Add(path); } - item.Extensions.Add(Constants.xMsDosGroupPath, new OpenApiAny(array)); + if (samePaths.Any()) + { + JsonArray array = new JsonArray(); + OpenApiConvertSettings settings = Context.Settings.Clone(); + settings.EnableKeyAsSegment = Context.KeyAsSegment; + foreach (var p in samePaths) + { + array.Add(p.GetPathItemName(settings)); + } + + item.Extensions ??= new Dictionary(); + item.Extensions.Add(Constants.xMsDosGroupPath, new OpenApiAny(array)); + } } base.SetExtensions(item); - item.Extensions.AddCustomAttributesToExtensions(Context, EdmOperation); + if (EdmOperation is not null) + { + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, EdmOperation); + } } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Provides operations to call the {EdmOperation.Name} method."; + pathItem.Description = $"Provides operations to call the {EdmOperation?.Name} method."; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandler.cs index 97e9c8805..0d20abedc 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandler.cs @@ -7,7 +7,6 @@ using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; using Microsoft.OpenApi.OData.Generator; -using Microsoft.OpenApi.OData.Operation; using Microsoft.OpenApi.OData.Properties; using System; using System.Net.Http; @@ -37,17 +36,17 @@ protected PathItemHandler(OpenApiDocument document) /// /// Gets the OData Context. /// - protected ODataContext Context { get; private set; } + protected ODataContext? Context { get; private set; } /// /// Gets the OData Path. /// - protected ODataPath Path { get; private set; } + protected ODataPath? Path { get; private set; } /// /// Gets the string representation of the Edm target path for annotations. /// - protected string TargetPath; + protected string? TargetPath; /// public virtual OpenApiPathItem CreatePathItem(ODataContext context, ODataPath path) @@ -115,14 +114,14 @@ protected virtual void SetExtensions(OpenApiPathItem item) protected virtual void AddOperation(OpenApiPathItem item, HttpMethod operationType) { string httpMethod = operationType.ToString(); - if (!Path.SupportHttpMethod(httpMethod)) + if (Path is null || !Path.SupportHttpMethod(httpMethod)) { return; } - IOperationHandlerProvider provider = Context.OperationHandlerProvider; - IOperationHandler operationHandler = provider.GetHandler(Path.Kind, operationType, _document); - item.AddOperation(operationType, operationHandler.CreateOperation(Context, Path)); + if (Context?.OperationHandlerProvider is {} provider && + provider.GetHandler(Path.Kind, operationType, _document) is {} operationHandler) + item.AddOperation(operationType, operationHandler.CreateOperation(Context, Path)); } /// @@ -131,9 +130,13 @@ protected virtual void AddOperation(OpenApiPathItem item, HttpMethod operationTy /// The . protected virtual void SetParameters(OpenApiPathItem item) { - foreach (var parameter in Path.CreatePathParameters(Context, _document)) + if (Context is not null && Path?.CreatePathParameters(Context, _document) is { Count:> 0} parameters) { - item.Parameters.AppendParameter(parameter); + item.Parameters ??= []; + foreach (var parameter in parameters) + { + item.Parameters.AppendParameter(parameter); + } } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandlerProvider.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandlerProvider.cs index 90c82c47a..51fdd24fc 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandlerProvider.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/PathItemHandlerProvider.cs @@ -14,7 +14,7 @@ namespace Microsoft.OpenApi.OData.PathItem internal class PathItemHandlerProvider : IPathItemHandlerProvider { /// - public IPathItemHandler GetHandler(ODataPathKind pathKind, OpenApiDocument document) + public IPathItemHandler? GetHandler(ODataPathKind pathKind, OpenApiDocument document) { return pathKind switch { // EntitySet diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/RefPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/RefPathItemHandler.cs index fffef6015..f54a88702 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/RefPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/RefPathItemHandler.cs @@ -34,28 +34,32 @@ public RefPathItemHandler(OpenApiDocument document) : base(document) /// /// Gets the navigation property. /// - public IEdmNavigationProperty NavigationProperty { get; private set; } + public IEdmNavigationProperty? NavigationProperty { get; private set; } /// /// Gets the navigation source. /// - public IEdmNavigationSource NavigationSource { get; private set; } + public IEdmNavigationSource? NavigationSource { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) { - IEdmEntitySet entitySet = NavigationSource as IEdmEntitySet; - IEdmVocabularyAnnotatable target = entitySet; - target ??= NavigationSource as IEdmSingleton; + if (NavigationSource is not IEdmVocabularyAnnotatable target) + throw new InvalidOperationException($"The navigation source {NavigationSource?.Name} is not a vocabulary annotatable."); - string navigationPropertyPath = String.Join("/", - Path.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment)).Select(e => e.Identifier)); + string navigationPropertyPath = string.Join("/", + Path?.Segments.Where(s => !(s is ODataKeySegment || s is ODataNavigationSourceSegment)).Select(e => e.Identifier) ?? []); - NavigationRestrictionsType navigationRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.NavigationRestrictions); - NavigationRestrictionsType sourceNavigationRestrictions = Context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); - navigationRestrictions?.MergePropertiesIfNull(sourceNavigationRestrictions); - navigationRestrictions ??= sourceNavigationRestrictions; - NavigationPropertyRestriction restriction = navigationRestrictions?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty == navigationPropertyPath); + var navigationRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.NavigationRestrictions); + + if (Context is not null && target is not null) + { + var sourceNavigationRestrictions = Context.Model.GetRecord(target, CapabilitiesConstants.NavigationRestrictions); + navigationRestrictions?.MergePropertiesIfNull(sourceNavigationRestrictions); + navigationRestrictions ??= sourceNavigationRestrictions; + } + + var restriction = navigationRestrictions?.RestrictedProperties?.FirstOrDefault(r => r.NavigationProperty == navigationPropertyPath); // verify using individual first if (restriction?.Navigability != null && restriction.Navigability.Value == NavigationType.None) @@ -77,8 +81,7 @@ protected override void SetOperations(OpenApiPathItem item) // Create the ref if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many) { - ODataSegment penultimateSegment = Path.Segments.Reverse().Skip(1).First(); - if (penultimateSegment is ODataKeySegment) + if (Path?.Segments.Reverse().Skip(1).First() is ODataKeySegment) { // Collection-valued indexed: DELETE ~/entityset/{key}/collection-valued-Nav/{key}/$ref AddDeleteOperation(item, restriction); @@ -99,9 +102,9 @@ protected override void SetOperations(OpenApiPathItem item) } } - private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { - DeleteRestrictionsType deleteRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); + var deleteRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.DeleteRestrictions); deleteRestrictions?.MergePropertiesIfNull(restriction?.DeleteRestrictions); deleteRestrictions ??= restriction?.DeleteRestrictions; if (deleteRestrictions?.IsDeletable ?? true) @@ -110,9 +113,9 @@ private void AddDeleteOperation(OpenApiPathItem item, NavigationPropertyRestrict } } - private void AddReadOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + private void AddReadOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); readRestrictions?.MergePropertiesIfNull(restriction?.ReadRestrictions); readRestrictions ??= restriction?.ReadRestrictions; if (readRestrictions?.IsReadable ?? true) @@ -121,9 +124,9 @@ private void AddReadOperation(OpenApiPathItem item, NavigationPropertyRestrictio } } - private void AddInsertOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + private void AddInsertOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { - InsertRestrictionsType insertRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); + var insertRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.InsertRestrictions); insertRestrictions?.MergePropertiesIfNull(restriction?.InsertRestrictions); insertRestrictions ??= restriction?.InsertRestrictions; if (insertRestrictions?.IsInsertable ?? true) @@ -132,9 +135,9 @@ private void AddInsertOperation(OpenApiPathItem item, NavigationPropertyRestrict } } - private void AddUpdateOperation(OpenApiPathItem item, NavigationPropertyRestriction restriction) + private void AddUpdateOperation(OpenApiPathItem item, NavigationPropertyRestriction? restriction) { - UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + var updateRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); updateRestrictions?.MergePropertiesIfNull(restriction?.UpdateRestrictions); updateRestrictions ??= restriction?.UpdateRestrictions; if (updateRestrictions?.IsUpdatable ?? true) @@ -148,8 +151,10 @@ protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - NavigationSource = navigationSourceSegment.NavigationSource; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: {} source}) + { + NavigationSource = source; + } NavigationProperty = path.OfType().Last().NavigationProperty; } diff --git a/src/Microsoft.OpenApi.OData.Reader/PathItem/SingletonPathItemHandler.cs b/src/Microsoft.OpenApi.OData.Reader/PathItem/SingletonPathItemHandler.cs index e288e1bac..d3fb7937b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PathItem/SingletonPathItemHandler.cs +++ b/src/Microsoft.OpenApi.OData.Reader/PathItem/SingletonPathItemHandler.cs @@ -3,8 +3,10 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ +using System.Collections.Generic; using System.Net.Http; using Microsoft.OData.Edm; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.OData.Common; using Microsoft.OpenApi.OData.Edm; @@ -31,26 +33,33 @@ public SingletonPathItemHandler(OpenApiDocument document): base(document) /// /// Gets the singleton. /// - protected IEdmSingleton Singleton { get; private set; } + protected IEdmSingleton? Singleton { get; private set; } /// protected override void SetOperations(OpenApiPathItem item) { // Retrieve a singleton. - ReadRestrictionsType readRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); - ReadRestrictionsType singletonReadRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.ReadRestrictions); - readRestrictions?.MergePropertiesIfNull(singletonReadRestrictions); - readRestrictions ??= singletonReadRestrictions; + var readRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.ReadRestrictions); + + if (Context is not null && Singleton is not null) + { + var singletonReadRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.ReadRestrictions); + readRestrictions?.MergePropertiesIfNull(singletonReadRestrictions); + readRestrictions ??= singletonReadRestrictions; + } if (readRestrictions?.IsReadable ?? true) { AddOperation(item, HttpMethod.Get); } // Update a singleton - UpdateRestrictionsType updateRestrictions = Context.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); - UpdateRestrictionsType singletonUpdateRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.UpdateRestrictions); - updateRestrictions?.MergePropertiesIfNull(singletonUpdateRestrictions); - updateRestrictions ??= singletonUpdateRestrictions; + var updateRestrictions = string.IsNullOrEmpty(TargetPath) ? null : Context?.Model.GetRecord(TargetPath, CapabilitiesConstants.UpdateRestrictions); + if (Context is not null && Singleton is not null) + { + var singletonUpdateRestrictions = Context.Model.GetRecord(Singleton, CapabilitiesConstants.UpdateRestrictions); + updateRestrictions?.MergePropertiesIfNull(singletonUpdateRestrictions); + updateRestrictions ??= singletonUpdateRestrictions; + } if (updateRestrictions?.IsUpdatable ?? true) { AddOperation(item, HttpMethod.Patch); @@ -62,22 +71,27 @@ protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); - ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment; - Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton; + if (path.FirstSegment is ODataNavigationSourceSegment {NavigationSource: IEdmSingleton source}) + Singleton = source; } /// protected override void SetBasicInfo(OpenApiPathItem pathItem) { base.SetBasicInfo(pathItem); - pathItem.Description = $"Provides operations to manage the {Singleton.EntityType.Name} singleton."; + pathItem.Description = $"Provides operations to manage the {Singleton?.EntityType.Name} singleton."; } /// - protected override void SetExtensions(OpenApiPathItem pathItem) + protected override void SetExtensions(OpenApiPathItem item) { - base.SetExtensions(pathItem); - pathItem.Extensions.AddCustomAttributesToExtensions(Context, Singleton); + base.SetExtensions(item); + + if (Context is not null && Singleton is not null) + { + item.Extensions ??= new Dictionary(); + item.Extensions.AddCustomAttributesToExtensions(Context, Singleton); + } } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt index 96bcd04af..283e9f540 100644 --- a/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt +++ b/src/Microsoft.OpenApi.OData.Reader/PublicAPI.Unshipped.txt @@ -1,120 +1,67 @@ -abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -abstract Microsoft.OpenApi.OData.Edm.ODataSegment.Identifier.get -> string +#nullable enable +abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string? +abstract Microsoft.OpenApi.OData.Edm.ODataSegment.Identifier.get -> string? abstract Microsoft.OpenApi.OData.Edm.ODataSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -abstract Microsoft.OpenApi.OData.Edm.ODataSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable Microsoft.OpenApi.OData.Common.Utils Microsoft.OpenApi.OData.Edm.EdmModelExtensions Microsoft.OpenApi.OData.Edm.EdmTypeExtensions -Microsoft.OpenApi.OData.Edm.ODataKeySegment.IsAlternateKey.get -> bool -Microsoft.OpenApi.OData.Edm.ODataKeySegment.IsAlternateKey.set -> void -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation operation) -> void -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation operation, bool isEscapedFunction) -> void -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation operation, bool isEscapedFunction, Microsoft.OData.Edm.IEdmModel model) -> void -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation operation, Microsoft.OData.Edm.IEdmModel model) -> void -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation operation, System.Collections.Generic.IDictionary parameterMappings) -> void -Microsoft.OpenApi.OData.Edm.ODataPath.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> string -Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> string -Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.ODataTypeCastSegment(Microsoft.OData.Edm.IEdmStructuredType structuredType, Microsoft.OData.Edm.IEdmModel model) -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddAlternateKeyPaths.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddAlternateKeyPaths.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumFlagsExtension.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumFlagsExtension.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.AppendBoundOperationsOnDerivedTypeCastSegments.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.AppendBoundOperationsOnDerivedTypeCastSegments.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.ComposableFunctionsExpansionDepth.get -> int -Microsoft.OpenApi.OData.OpenApiConvertSettings.ComposableFunctionsExpansionDepth.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomHttpMethodLinkRelMapping.get -> System.Collections.Generic.Dictionary -Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomHttpMethodLinkRelMapping.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForOperationSegments.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForOperationSegments.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForTypeCastSegments.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForTypeCastSegments.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableCount.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableCount.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataAnnotationReferencesForResponses.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataAnnotationReferencesForResponses.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableTypeDisambiguationForDefaultValueOfOdataTypeProperty.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableTypeDisambiguationForDefaultValueOfOdataTypeProperty.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomXMLAttributesMapping.get -> System.Collections.Generic.Dictionary -Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomXMLAttributesMapping.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.GenerateDerivedTypesProperties.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.GenerateDerivedTypesProperties.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.IncludeAssemblyInfo.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.IncludeAssemblyInfo.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.NamespacePrefixToStripForInMethodPaths.get -> string -Microsoft.OpenApi.OData.OpenApiConvertSettings.NamespacePrefixToStripForInMethodPaths.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.SemVerVersion.get -> string -Microsoft.OpenApi.OData.OpenApiConvertSettings.SemVerVersion.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowExternalDocs.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowExternalDocs.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.UseStringArrayForQueryOptionsSchema.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.UseStringArrayForQueryOptionsSchema.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.UseSuccessStatusCodeRange.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.UseSuccessStatusCodeRange.set -> void -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Action = 6 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Create = 2 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Delete = 4 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Function = 5 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.List = 1 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.ReadByKey = 0 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Update = 3 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey -override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataRefSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.OperationTargetsMultiplePaths(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmOperation operation) -> bool -static Microsoft.OpenApi.OData.Edm.EdmTypeExtensions.ShouldPathParameterBeQuoted(this Microsoft.OData.Edm.IEdmType edmType, Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> bool Microsoft.OpenApi.OData.Edm.IODataPathProvider -Microsoft.OpenApi.OData.Edm.IODataPathProvider.CanFilter(Microsoft.OData.Edm.IEdmElement element) -> bool -Microsoft.OpenApi.OData.Edm.IODataPathProvider.GetPaths(Microsoft.OData.Edm.IEdmModel model, Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> System.Collections.Generic.IEnumerable +Microsoft.OpenApi.OData.Edm.IODataPathProvider.CanFilter(Microsoft.OData.Edm.IEdmElement! element) -> bool +Microsoft.OpenApi.OData.Edm.IODataPathProvider.GetPaths(Microsoft.OData.Edm.IEdmModel! model, Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> System.Collections.Generic.IEnumerable! +Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment +Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.ComplexType.get -> Microsoft.OData.Edm.IEdmComplexType? +Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.ODataComplexPropertySegment(Microsoft.OData.Edm.IEdmStructuralProperty! property) -> void +Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Property.get -> Microsoft.OData.Edm.IEdmStructuralProperty! Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.ODataDollarCountSegment() -> void Microsoft.OpenApi.OData.Edm.ODataKeySegment -Microsoft.OpenApi.OData.Edm.ODataKeySegment.KeyMappings.get -> System.Collections.Generic.IDictionary -Microsoft.OpenApi.OData.Edm.ODataKeySegment.ODataKeySegment(Microsoft.OData.Edm.IEdmEntityType entityType) -> void -Microsoft.OpenApi.OData.Edm.ODataKeySegment.ODataKeySegment(Microsoft.OData.Edm.IEdmEntityType entityType, System.Collections.Generic.IDictionary keyMappings) -> void +Microsoft.OpenApi.OData.Edm.ODataKeySegment.IsAlternateKey.get -> bool +Microsoft.OpenApi.OData.Edm.ODataKeySegment.IsAlternateKey.set -> void +Microsoft.OpenApi.OData.Edm.ODataKeySegment.KeyMappings.get -> System.Collections.Generic.IDictionary? +Microsoft.OpenApi.OData.Edm.ODataKeySegment.ODataKeySegment(Microsoft.OData.Edm.IEdmEntityType! entityType) -> void +Microsoft.OpenApi.OData.Edm.ODataKeySegment.ODataKeySegment(Microsoft.OData.Edm.IEdmEntityType! entityType, System.Collections.Generic.IDictionary! keyMappings) -> void Microsoft.OpenApi.OData.Edm.ODataMetadataSegment Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.ODataMetadataSegment() -> void Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment -Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.NavigationProperty.get -> Microsoft.OData.Edm.IEdmNavigationProperty -Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.ODataNavigationPropertySegment(Microsoft.OData.Edm.IEdmNavigationProperty navigationProperty) -> void +Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.NavigationProperty.get -> Microsoft.OData.Edm.IEdmNavigationProperty! +Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.ODataNavigationPropertySegment(Microsoft.OData.Edm.IEdmNavigationProperty! navigationProperty) -> void Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment -Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.NavigationSource.get -> Microsoft.OData.Edm.IEdmNavigationSource -Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.ODataNavigationSourceSegment(Microsoft.OData.Edm.IEdmNavigationSource navigationSource) -> void +Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.NavigationSource.get -> Microsoft.OData.Edm.IEdmNavigationSource! +Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.ODataNavigationSourceSegment(Microsoft.OData.Edm.IEdmNavigationSource! navigationSource) -> void Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment -Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ODataOperationImportSegment(Microsoft.OData.Edm.IEdmOperationImport operationImport) -> void -Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ODataOperationImportSegment(Microsoft.OData.Edm.IEdmOperationImport operationImport, System.Collections.Generic.IDictionary parameterMappings) -> void -Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.OperationImport.get -> Microsoft.OData.Edm.IEdmOperationImport -Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ParameterMappings.get -> System.Collections.Generic.IDictionary +Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ODataOperationImportSegment(Microsoft.OData.Edm.IEdmOperationImport! operationImport) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ODataOperationImportSegment(Microsoft.OData.Edm.IEdmOperationImport! operationImport, System.Collections.Generic.IDictionary! parameterMappings) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.OperationImport.get -> Microsoft.OData.Edm.IEdmOperationImport! +Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.ParameterMappings.get -> System.Collections.Generic.IDictionary? Microsoft.OpenApi.OData.Edm.ODataOperationSegment Microsoft.OpenApi.OData.Edm.ODataOperationSegment.IsEscapedFunction.get -> bool -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Operation.get -> Microsoft.OData.Edm.IEdmOperation -Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ParameterMappings.get -> System.Collections.Generic.IDictionary +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation! operation) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation! operation, bool isEscapedFunction) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation! operation, bool isEscapedFunction, Microsoft.OData.Edm.IEdmModel! model) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation! operation, Microsoft.OData.Edm.IEdmModel! model) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ODataOperationSegment(Microsoft.OData.Edm.IEdmOperation! operation, System.Collections.Generic.IDictionary! parameterMappings) -> void +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Operation.get -> Microsoft.OData.Edm.IEdmOperation? +Microsoft.OpenApi.OData.Edm.ODataOperationSegment.ParameterMappings.get -> System.Collections.Generic.IDictionary? Microsoft.OpenApi.OData.Edm.ODataPath -Microsoft.OpenApi.OData.Edm.ODataPath.Clone() -> Microsoft.OpenApi.OData.Edm.ODataPath -Microsoft.OpenApi.OData.Edm.ODataPath.GetPathHash(Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> string -Microsoft.OpenApi.OData.Edm.ODataPath.CompareTo(Microsoft.OpenApi.OData.Edm.ODataPath other) -> int +Microsoft.OpenApi.OData.Edm.ODataPath.Clone() -> Microsoft.OpenApi.OData.Edm.ODataPath! +Microsoft.OpenApi.OData.Edm.ODataPath.CompareTo(Microsoft.OpenApi.OData.Edm.ODataPath? other) -> int Microsoft.OpenApi.OData.Edm.ODataPath.Count.get -> int -Microsoft.OpenApi.OData.Edm.ODataPath.FirstSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment +Microsoft.OpenApi.OData.Edm.ODataPath.FirstSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment? Microsoft.OpenApi.OData.Edm.ODataPath.GetCount(bool keySegmentAsDepth) -> int -Microsoft.OpenApi.OData.Edm.ODataPath.GetEnumerator() -> System.Collections.Generic.IEnumerator -Microsoft.OpenApi.OData.Edm.ODataPath.GetPathItemName() -> string -Microsoft.OpenApi.OData.Edm.ODataPath.HttpMethods.get -> System.Collections.Generic.ISet -Microsoft.OpenApi.OData.Edm.ODataPath.LastSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment -Microsoft.OpenApi.OData.Edm.ODataPath.ODataPath(params Microsoft.OpenApi.OData.Edm.ODataSegment[] segments) -> void -Microsoft.OpenApi.OData.Edm.ODataPath.ODataPath(System.Collections.Generic.IEnumerable segments) -> void -Microsoft.OpenApi.OData.Edm.ODataPath.PathTemplate.get -> string +Microsoft.OpenApi.OData.Edm.ODataPath.GetEnumerator() -> System.Collections.Generic.IEnumerator! +Microsoft.OpenApi.OData.Edm.ODataPath.GetPathHash(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> string? +Microsoft.OpenApi.OData.Edm.ODataPath.GetPathItemName() -> string! +Microsoft.OpenApi.OData.Edm.ODataPath.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> string! +Microsoft.OpenApi.OData.Edm.ODataPath.HttpMethods.get -> System.Collections.Generic.ISet! +Microsoft.OpenApi.OData.Edm.ODataPath.LastSegment.get -> Microsoft.OpenApi.OData.Edm.ODataSegment? +Microsoft.OpenApi.OData.Edm.ODataPath.ODataPath(params Microsoft.OpenApi.OData.Edm.ODataSegment![]! segments) -> void +Microsoft.OpenApi.OData.Edm.ODataPath.ODataPath(System.Collections.Generic.IEnumerable! segments) -> void +Microsoft.OpenApi.OData.Edm.ODataPath.PathTemplate.get -> string? Microsoft.OpenApi.OData.Edm.ODataPath.PathTemplate.set -> void -Microsoft.OpenApi.OData.Edm.ODataPath.Segments.get -> System.Collections.Generic.IList +Microsoft.OpenApi.OData.Edm.ODataPath.Segments.get -> System.Collections.Generic.IList! Microsoft.OpenApi.OData.Edm.ODataPathKind +Microsoft.OpenApi.OData.Edm.ODataPathKind.ComplexProperty = 11 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathKind.DollarCount = 9 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathKind.Entity = 1 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathKind.EntitySet = 0 -> Microsoft.OpenApi.OData.Edm.ODataPathKind @@ -126,15 +73,16 @@ Microsoft.OpenApi.OData.Edm.ODataPathKind.OperationImport = 4 -> Microsoft.OpenA Microsoft.OpenApi.OData.Edm.ODataPathKind.Ref = 6 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathKind.Singleton = 2 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathKind.TypeCast = 10 -> Microsoft.OpenApi.OData.Edm.ODataPathKind -Microsoft.OpenApi.OData.Edm.ODataPathKind.ComplexProperty = 11 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathKind.Unknown = 12 -> Microsoft.OpenApi.OData.Edm.ODataPathKind Microsoft.OpenApi.OData.Edm.ODataPathProvider Microsoft.OpenApi.OData.Edm.ODataPathProvider.ODataPathProvider() -> void Microsoft.OpenApi.OData.Edm.ODataRefSegment Microsoft.OpenApi.OData.Edm.ODataSegment -Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathHash(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, Microsoft.OpenApi.OData.Edm.ODataPath path = null) -> string +Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathHash(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, Microsoft.OpenApi.OData.Edm.ODataPath? path = null) -> string! +Microsoft.OpenApi.OData.Edm.ODataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> string? Microsoft.OpenApi.OData.Edm.ODataSegment.ODataSegment() -> void Microsoft.OpenApi.OData.Edm.ODataSegmentKind +Microsoft.OpenApi.OData.Edm.ODataSegmentKind.ComplexProperty = 11 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataSegmentKind.DollarCount = 10 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataSegmentKind.Key = 5 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataSegmentKind.Metadata = 0 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind @@ -146,41 +94,66 @@ Microsoft.OpenApi.OData.Edm.ODataSegmentKind.Ref = 7 -> Microsoft.OpenApi.OData. Microsoft.OpenApi.OData.Edm.ODataSegmentKind.StreamContent = 8 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataSegmentKind.StreamProperty = 9 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataSegmentKind.TypeCast = 6 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -Microsoft.OpenApi.OData.Edm.ODataSegmentKind.ComplexProperty = 11 -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.ODataStreamContentSegment() -> void Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment -Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.ODataStreamPropertySegment(string streamPropertyName) -> void +Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.ODataStreamPropertySegment(string! streamPropertyName) -> void Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment -Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment -Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.ODataComplexPropertySegment(Microsoft.OData.Edm.IEdmStructuralProperty property) -> void -Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Property.get -> Microsoft.OData.Edm.IEdmStructuralProperty -override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType -override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Identifier.get -> string -Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.ComplexType.get -> Microsoft.OData.Edm.IEdmComplexType -override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable +Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.ODataTypeCastSegment(Microsoft.OData.Edm.IEdmStructuredType! structuredType, Microsoft.OData.Edm.IEdmModel! model) -> void +Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.StructuredType.get -> Microsoft.OData.Edm.IEdmStructuredType! Microsoft.OpenApi.OData.EdmModelOpenApiExtensions Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider -Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider.Parameters.get -> System.Collections.Generic.IEnumerable -Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider.PathPrefix.get -> string +Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider.Parameters.get -> System.Collections.Generic.IEnumerable? +Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider.PathPrefix.get -> string? Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.ODataRoutePathPrefixProvider() -> void -Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.Parameters.get -> System.Collections.Generic.IEnumerable +Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.Parameters.get -> System.Collections.Generic.IEnumerable? Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.Parameters.set -> void -Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.PathPrefix.get -> string +Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.PathPrefix.get -> string? Microsoft.OpenApi.OData.Extensions.ODataRoutePathPrefixProvider.PathPrefix.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddAlternateKeyPaths.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddAlternateKeyPaths.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumDescriptionExtension.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumDescriptionExtension.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumFlagsExtension.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumFlagsExtension.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddSingleQuotesForStringParameters.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.AddSingleQuotesForStringParameters.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.AppendBoundOperationsOnDerivedTypeCastSegments.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.AppendBoundOperationsOnDerivedTypeCastSegments.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.ComposableFunctionsExpansionDepth.get -> int +Microsoft.OpenApi.OData.OpenApiConvertSettings.ComposableFunctionsExpansionDepth.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomHttpMethodLinkRelMapping.get -> System.Collections.Generic.Dictionary! +Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomHttpMethodLinkRelMapping.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomXMLAttributesMapping.get -> System.Collections.Generic.Dictionary! +Microsoft.OpenApi.OData.OpenApiConvertSettings.CustomXMLAttributesMapping.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.DeclarePathParametersOnPathItem.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.DeclarePathParametersOnPathItem.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForOperationSegments.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForOperationSegments.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForTypeCastSegments.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableAliasForTypeCastSegments.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableCount.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableCount.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDeprecationInformation.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDeprecationInformation.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDerivedTypesReferencesForRequestBody.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDerivedTypesReferencesForRequestBody.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDerivedTypesReferencesForResponses.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDerivedTypesReferencesForResponses.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDiscriminatorValue.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDiscriminatorValue.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDollarCountPath.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDollarCountPath.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableKeyAsSegment.get -> bool? Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableKeyAsSegment.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableNavigationPropertyPath.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableNavigationPropertyPath.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataAnnotationReferencesForResponses.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataAnnotationReferencesForResponses.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataTypeCast.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataTypeCast.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableOperationId.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableOperationId.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableOperationImportPath.get -> bool @@ -189,37 +162,49 @@ Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableOperationPath.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableOperationPath.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnablePagination.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnablePagination.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableTypeDisambiguationForDefaultValueOfOdataTypeProperty.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableTypeDisambiguationForDefaultValueOfOdataTypeProperty.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableUnqualifiedCall.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableUnqualifiedCall.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableUriEscapeFunctionCall.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableUriEscapeFunctionCall.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.ErrorResponsesAsDefault.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.ErrorResponsesAsDefault.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.GenerateDerivedTypesProperties.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.GenerateDerivedTypesProperties.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.IEEE754Compatible.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.IEEE754Compatible.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.IncludeAssemblyInfo.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.IncludeAssemblyInfo.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.InnerErrorComplexTypeName.get -> string! +Microsoft.OpenApi.OData.OpenApiConvertSettings.InnerErrorComplexTypeName.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.NamespacePrefixToStripForInMethodPaths.get -> string? +Microsoft.OpenApi.OData.OpenApiConvertSettings.NamespacePrefixToStripForInMethodPaths.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.OpenApiConvertSettings() -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.OpenApiSpecVersion.get -> Microsoft.OpenApi.OpenApiSpecVersion Microsoft.OpenApi.OData.OpenApiConvertSettings.OpenApiSpecVersion.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.PageableOperationName.get -> string +Microsoft.OpenApi.OData.OpenApiConvertSettings.PageableOperationName.get -> string! Microsoft.OpenApi.OData.OpenApiConvertSettings.PageableOperationName.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.PathPrefix.get -> string +Microsoft.OpenApi.OData.OpenApiConvertSettings.PathPrefix.get -> string? Microsoft.OpenApi.OData.OpenApiConvertSettings.PathPrefix.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.PathProvider.get -> Microsoft.OpenApi.OData.Edm.IODataPathProvider +Microsoft.OpenApi.OData.OpenApiConvertSettings.PathProvider.get -> Microsoft.OpenApi.OData.Edm.IODataPathProvider? Microsoft.OpenApi.OData.OpenApiConvertSettings.PathProvider.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDollarCountPath.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDollarCountPath.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddSingleQuotesForStringParameters.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddSingleQuotesForStringParameters.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataTypeCast.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableODataTypeCast.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.PrefixEntityTypeNameBeforeKey.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.PrefixEntityTypeNameBeforeKey.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForBoundOperations.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForBoundOperations.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.RoutePathPrefixProvider.get -> Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider +Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireDerivedTypesConstraintForODataTypeCastSegments.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.RequireRestrictionAnnotationsToGenerateComplexPropertyPaths.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.RoutePathPrefixProvider.get -> Microsoft.OpenApi.OData.Extensions.IODataRoutePathPrefixProvider? Microsoft.OpenApi.OData.OpenApiConvertSettings.RoutePathPrefixProvider.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.ServiceRoot.get -> System.Uri +Microsoft.OpenApi.OData.OpenApiConvertSettings.SemVerVersion.get -> string! +Microsoft.OpenApi.OData.OpenApiConvertSettings.SemVerVersion.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.ServiceRoot.get -> System.Uri! Microsoft.OpenApi.OData.OpenApiConvertSettings.ServiceRoot.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowExternalDocs.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowExternalDocs.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowLinks.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowLinks.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.ShowMsDosGroupPath.get -> bool @@ -232,82 +217,98 @@ Microsoft.OpenApi.OData.OpenApiConvertSettings.TagDepth.get -> int Microsoft.OpenApi.OData.OpenApiConvertSettings.TagDepth.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.TopExample.get -> int Microsoft.OpenApi.OData.OpenApiConvertSettings.TopExample.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.UseStringArrayForQueryOptionsSchema.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.UseStringArrayForQueryOptionsSchema.set -> void +Microsoft.OpenApi.OData.OpenApiConvertSettings.UseSuccessStatusCodeRange.get -> bool +Microsoft.OpenApi.OData.OpenApiConvertSettings.UseSuccessStatusCodeRange.set -> void Microsoft.OpenApi.OData.OpenApiConvertSettings.VerifyEdmModel.get -> bool Microsoft.OpenApi.OData.OpenApiConvertSettings.VerifyEdmModel.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDeprecationInformation.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.EnableDeprecationInformation.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumDescriptionExtension.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.AddEnumDescriptionExtension.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.ErrorResponsesAsDefault.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.ErrorResponsesAsDefault.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.InnerErrorComplexTypeName.set -> void -Microsoft.OpenApi.OData.OpenApiConvertSettings.InnerErrorComplexTypeName.get -> string -Microsoft.OpenApi.OData.OpenApiConvertSettings.DeclarePathParametersOnPathItem.get -> bool -Microsoft.OpenApi.OData.OpenApiConvertSettings.DeclarePathParametersOnPathItem.set -> void -override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Action = 6 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Create = 2 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Delete = 4 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Function = 5 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.List = 1 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.ReadByKey = 0 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey.Update = 3 -> Microsoft.OpenApi.OData.Vocabulary.Core.LinkRelKey +override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? +override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Identifier.get -> string! +override Microsoft.OpenApi.OData.Edm.ODataComplexPropertySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind +override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? +override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataDollarCountSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataKeySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType -override Microsoft.OpenApi.OData.Edm.ODataKeySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataKeySegment.Identifier.get -> string +override Microsoft.OpenApi.OData.Edm.ODataKeySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataKeySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataKeySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataKeySegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataKeySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataKeySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? +override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataMetadataSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType -override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.Identifier.get -> string +override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataNavigationPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType -override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings settings, System.Collections.Generic.HashSet parameters) -> string -override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.Identifier.get -> string +override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType! +override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataNavigationSourceSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? +override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataOperationImportSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? +override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string? +override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Identifier.get -> string? override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataOperationSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataPath.ToString() -> string -override Microsoft.OpenApi.OData.Edm.ODataRefSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataRefSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataPath.ToString() -> string! +override Microsoft.OpenApi.OData.Edm.ODataRefSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? +override Microsoft.OpenApi.OData.Edm.ODataRefSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataRefSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataRefSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataRefSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataRefSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? +override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataStreamContentSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? +override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataStreamPropertySegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.StructuredType.get -> Microsoft.OData.Edm.IEdmStructuredType -override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.Identifier.get -> string -override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? +override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable! +override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.GetPathItemName(Microsoft.OpenApi.OData.OpenApiConvertSettings! settings, System.Collections.Generic.HashSet! parameters) -> string! +override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.Identifier.get -> string! override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataSegmentKind -override Microsoft.OpenApi.OData.Edm.ODataTypeCastSegment.GetAnnotables() -> System.Collections.Generic.IEnumerable -static Microsoft.OpenApi.OData.Common.Utils.GetTermQualifiedName() -> string -static Microsoft.OpenApi.OData.Common.Utils.GetUniqueName(string input, System.Collections.Generic.HashSet set) -> string -static Microsoft.OpenApi.OData.Common.Utils.UpperFirstChar(string input) -> string -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmEntityType entityType) -> System.Collections.Generic.IEnumerable -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmComplexType complexType) -> System.Collections.Generic.IEnumerable -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.GetAllElements(this Microsoft.OData.Edm.IEdmModel model) -> System.Collections.Generic.IEnumerable -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsOperationImportOverload(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmOperationImport operationImport) -> bool -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsOperationOverload(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmOperation operation) -> bool -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsUrlEscapeFunction(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OData.Edm.IEdmOperation operation) -> bool -static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.LoadAllNavigationSources(this Microsoft.OData.Edm.IEdmModel model) -> System.Collections.Generic.IDictionary> -static Microsoft.OpenApi.OData.Edm.ODataRefSegment.Instance -> Microsoft.OpenApi.OData.Edm.ODataRefSegment -static Microsoft.OpenApi.OData.EdmModelOpenApiExtensions.ConvertToOpenApi(this Microsoft.OData.Edm.IEdmModel model) -> Microsoft.OpenApi.Models.OpenApiDocument -static Microsoft.OpenApi.OData.EdmModelOpenApiExtensions.ConvertToOpenApi(this Microsoft.OData.Edm.IEdmModel model, Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> Microsoft.OpenApi.Models.OpenApiDocument +static Microsoft.OpenApi.OData.Common.Utils.GetTermQualifiedName() -> string? +static Microsoft.OpenApi.OData.Common.Utils.GetUniqueName(string! input, System.Collections.Generic.HashSet! set) -> string! +static Microsoft.OpenApi.OData.Common.Utils.UpperFirstChar(string? input) -> string? +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmComplexType! complexType) -> System.Collections.Generic.IEnumerable! +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.FindAllBaseTypes(this Microsoft.OData.Edm.IEdmEntityType! entityType) -> System.Collections.Generic.IEnumerable! +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.GetAllElements(this Microsoft.OData.Edm.IEdmModel! model) -> System.Collections.Generic.IEnumerable! +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsOperationImportOverload(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OData.Edm.IEdmOperationImport! operationImport) -> bool +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsOperationOverload(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OData.Edm.IEdmOperation! operation) -> bool +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.IsUrlEscapeFunction(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OData.Edm.IEdmOperation! operation) -> bool +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.LoadAllNavigationSources(this Microsoft.OData.Edm.IEdmModel! model) -> System.Collections.Generic.Dictionary!>! +static Microsoft.OpenApi.OData.Edm.EdmModelExtensions.OperationTargetsMultiplePaths(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OData.Edm.IEdmOperation! operation) -> bool +static Microsoft.OpenApi.OData.Edm.EdmTypeExtensions.ShouldPathParameterBeQuoted(this Microsoft.OData.Edm.IEdmType! edmType, Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> bool +static Microsoft.OpenApi.OData.Edm.ODataRefSegment.Instance -> Microsoft.OpenApi.OData.Edm.ODataRefSegment! +static Microsoft.OpenApi.OData.EdmModelOpenApiExtensions.ConvertToOpenApi(this Microsoft.OData.Edm.IEdmModel! model) -> Microsoft.OpenApi.Models.OpenApiDocument! +static Microsoft.OpenApi.OData.EdmModelOpenApiExtensions.ConvertToOpenApi(this Microsoft.OData.Edm.IEdmModel! model, Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> Microsoft.OpenApi.Models.OpenApiDocument! virtual Microsoft.OpenApi.OData.Edm.ODataPath.Kind.get -> Microsoft.OpenApi.OData.Edm.ODataPathKind -virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.CanFilter(Microsoft.OData.Edm.IEdmElement element) -> bool -virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.GetPaths(Microsoft.OData.Edm.IEdmModel model, Microsoft.OpenApi.OData.OpenApiConvertSettings settings) -> System.Collections.Generic.IEnumerable -virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.Initialize(Microsoft.OData.Edm.IEdmModel model) -> void -virtual Microsoft.OpenApi.OData.Edm.ODataSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType +virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.CanFilter(Microsoft.OData.Edm.IEdmElement! element) -> bool +virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.GetPaths(Microsoft.OData.Edm.IEdmModel! model, Microsoft.OpenApi.OData.OpenApiConvertSettings! settings) -> System.Collections.Generic.IEnumerable! +virtual Microsoft.OpenApi.OData.Edm.ODataPathProvider.Initialize(Microsoft.OData.Edm.IEdmModel! model) -> void +virtual Microsoft.OpenApi.OData.Edm.ODataSegment.EntityType.get -> Microsoft.OData.Edm.IEdmEntityType? diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/ApiKey.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/ApiKey.cs index bfdf14ed9..d41e96dcf 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/ApiKey.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/ApiKey.cs @@ -38,7 +38,7 @@ internal class ApiKey : Authorization /// /// The name of the header or query parameter. /// - public string KeyName { get; set; } + public string? KeyName { get; set; } /// /// Whether the API Key is passed in the header or as a query option. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Authorization.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Authorization.cs index 4c3bfb475..520c99732 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Authorization.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Authorization.cs @@ -23,12 +23,12 @@ internal abstract class Authorization : IRecord /// /// Name that can be used to reference the authorization flow. /// - public string Name { get; set; } + public string? Name { get; set; } /// /// Description of the authorization method. /// - public string Description { get; set; } + public string? Description { get; set; } /// /// Gets the security scheme type. @@ -55,20 +55,19 @@ public virtual void Initialize(IEdmRecordExpression record) /// /// The input record. /// The created object. - public static Authorization CreateAuthorization(IEdmRecordExpression record) + public static Authorization? CreateAuthorization(IEdmRecordExpression record) { if (record == null || record.DeclaredType == null) { return null; } - IEdmComplexType complexType = record.DeclaredType.Definition as IEdmComplexType; - if (complexType == null) - { - return null; - } + if (record.DeclaredType.Definition is not IEdmComplexType complexType) + { + return null; + } - Authorization auth; + Authorization auth; switch (complexType.FullTypeName()) { case AuthorizationConstants.OpenIDConnect: // OpenIDConnect @@ -104,10 +103,7 @@ public static Authorization CreateAuthorization(IEdmRecordExpression record) throw new OpenApiException(String.Format(SRResource.AuthorizationRecordTypeNameNotCorrect, complexType.FullTypeName())); } - if (auth != null) - { - auth.Initialize(record); - } + auth?.Initialize(record); return auth; } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/AuthorizationScope.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/AuthorizationScope.cs index b42721a8e..b59cb9bbf 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/AuthorizationScope.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/AuthorizationScope.cs @@ -17,18 +17,18 @@ internal class AuthorizationScope : IRecord /// /// Scope name. /// - public string Scope { get; set; } + public string? Scope { get; set; } /// /// Scope Grant. /// Identity that has access to the scope or can grant access to the scope. /// - public string Grant { get; set; } + public string? Grant { get; set; } /// /// Description of the scope. /// - public string Description { get; set; } + public string? Description { get; set; } /// /// Init the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Http.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Http.cs index 6234b48b6..8a44d4361 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Http.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/Http.cs @@ -17,12 +17,12 @@ internal class Http : Authorization /// /// HTTP Authorization scheme to be used in the Authorization header, as per RFC7235. /// - public string Scheme { get; set; } + public string? Scheme { get; set; } /// /// Format of the bearer token. /// - public string BearerFormat { get; set; } + public string? BearerFormat { get; set; } /// /// Gets the security scheme type. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2AuthCode.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2AuthCode.cs index 7cbf2fdb9..5e47755ad 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2AuthCode.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2AuthCode.cs @@ -16,12 +16,12 @@ internal class OAuth2AuthCode : OAuthAuthorization /// /// Authorization URL. /// - public string AuthorizationUrl { get; set; } + public string? AuthorizationUrl { get; set; } /// /// Token Url. /// - public string TokenUrl { get; set; } + public string? TokenUrl { get; set; } /// /// Gets the OAuth2 type. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2ClientCredentials.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2ClientCredentials.cs index 5cb38578f..74b8b8973 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2ClientCredentials.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2ClientCredentials.cs @@ -16,7 +16,7 @@ internal class OAuth2ClientCredentials : OAuthAuthorization /// /// Token Url. /// - public string TokenUrl { get; set; } + public string? TokenUrl { get; set; } /// /// Gets the OAuth2 type. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Implicit.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Implicit.cs index db02422b2..8b827047a 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Implicit.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Implicit.cs @@ -16,7 +16,7 @@ internal class OAuth2Implicit : OAuthAuthorization /// /// Authorization URL. /// - public string AuthorizationUrl { get; set; } + public string? AuthorizationUrl { get; set; } /// /// Gets the OAuth2 type. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Password.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Password.cs index 0305b74a2..e5d72a780 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Password.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuth2Password.cs @@ -16,12 +16,12 @@ internal class OAuth2Password : OAuthAuthorization /// /// Token Url. /// - public string TokenUrl { get; set; } + public string? TokenUrl { get; set; } /// /// Gets the OAuth2 type. /// - public override OAuth2Type OAuth2Type => OAuth2Type.Pasword; + public override OAuth2Type OAuth2Type => OAuth2Type.Password; /// /// Init . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuthAuthorization.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuthAuthorization.cs index 73df17002..79434342f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuthAuthorization.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OAuthAuthorization.cs @@ -26,9 +26,9 @@ internal enum OAuth2Type Implicit, /// - /// Pasword + /// Password /// - Pasword, + Password, /// /// AuthCode @@ -44,12 +44,12 @@ internal abstract class OAuthAuthorization : Authorization /// /// Available scopes. /// - public IList Scopes { get; set; } + public IList? Scopes { get; set; } /// /// Refresh Url /// - public string RefreshUrl { get; set; } + public string? RefreshUrl { get; set; } /// /// Gets the security scheme type. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OpenIDConnect.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OpenIDConnect.cs index 8ef4562fd..d444119db 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OpenIDConnect.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/OpenIDConnect.cs @@ -18,7 +18,7 @@ internal class OpenIDConnect : Authorization /// Issuer location for the OpenID Provider. /// Configuration information can be obtained by appending `/.well-known/openid-configuration` to this Url. /// - public string IssuerUrl { get; set; } + public string? IssuerUrl { get; set; } /// /// Gets the security scheme type. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/SecurityScheme.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/SecurityScheme.cs index 54aec311a..15ab64ae5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/SecurityScheme.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Authorization/SecurityScheme.cs @@ -19,12 +19,12 @@ internal class SecurityScheme : IRecord /// /// The name of a required authorization scheme. /// - public string Authorization { get; set; } + public string? Authorization { get; set; } /// /// The names of scopes required from this authorization scheme. /// - public IList RequiredScopes { get; set; } + public IList? RequiredScopes { get; set; } /// /// Init the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CollectionPropertyRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CollectionPropertyRestrictionsType.cs index d125e0046..c89ad5b2b 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CollectionPropertyRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CollectionPropertyRestrictionsType.cs @@ -19,27 +19,27 @@ internal class CollectionPropertyRestrictionsType : IRecord /// /// Gets the Restricted Collection-valued property. /// - public string CollectionProperty { get; private set; } + public string? CollectionProperty { get; private set; } /// /// Gets the List of functions and operators supported in filter expressions.. /// - public IList FilterFunctions { get; private set; } + public IList? FilterFunctions { get; private set; } /// /// Gets Restrictions on filter expressions. /// - public FilterRestrictionsType FilterRestrictions { get; private set; } + public FilterRestrictionsType? FilterRestrictions { get; private set; } /// /// Gets Restrictions on search expressions. /// - public SearchRestrictionsType SearchRestrictions { get; private set; } + public SearchRestrictionsType? SearchRestrictions { get; private set; } /// /// Gets Restrictions on orderby expressions. /// - public SortRestrictionsType SortRestrictions { get; private set; } + public SortRestrictionsType? SortRestrictions { get; private set; } /// /// Gets Supports $top. @@ -54,7 +54,7 @@ internal class CollectionPropertyRestrictionsType : IRecord /// /// Gets Support for $select. /// - public SelectSupportType SelectSupport { get; private set; } + public SelectSupportType? SelectSupport { get; private set; } /// /// Gets the collection supports positional inserts. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CountRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CountRestrictionsType.cs index 17447ca92..ad248cd9f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CountRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CountRestrictionsType.cs @@ -25,12 +25,12 @@ internal class CountRestrictionsType : IRecord /// /// Gets the properties which do not allow /$count segments. /// - public IList NonCountableProperties { get; private set; } + public IList? NonCountableProperties { get; private set; } /// /// Gets the navigation properties which do not allow /$count segments. /// - public IList NonCountableNavigationProperties { get; private set; } + public IList? NonCountableNavigationProperties { get; private set; } /// /// Test the target supports count. diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CustomParameter.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CustomParameter.cs index d4243260d..e390304e4 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CustomParameter.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/CustomParameter.cs @@ -21,17 +21,17 @@ internal class CustomParameter : IRecord /// /// Gets/sets the name of the custom parameter. /// - public string Name { get; set; } + public string? Name { get; set; } /// /// Gets/sets the description of the custom parameter. /// - public string Description { get; set; } + public string? Description { get; set; } /// /// Gets/sets the documentationURL of the custom parameter. /// - public string DocumentationURL { get; set; } + public string? DocumentationURL { get; set; } /// /// Gets/sets the reuired of the custom parameter. true: parameter is required, false or not specified: parameter is optional. @@ -41,7 +41,7 @@ internal class CustomParameter : IRecord /// /// Gets the list of scopes that can provide access to the resource. /// s - public IList ExampleValues { get; set; } + public IList? ExampleValues { get; set; } /// /// Init the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs index 9171681dd..f036983be 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/DeleteRestrictionsType.cs @@ -25,7 +25,7 @@ internal class DeleteRestrictionsType : IRecord /// /// Gets the navigation properties which do not allow DeleteLink requests. /// - public IList NonDeletableNavigationProperties { get; private set; } + public IList? NonDeletableNavigationProperties { get; private set; } /// /// Gets the maximum number of navigation properties that can be traversed. @@ -45,27 +45,27 @@ internal class DeleteRestrictionsType : IRecord /// /// Gets the required scopes to perform the insert. /// - public IList Permissions { get; private set; } + public IList? Permissions { get; private set; } /// /// Gets the Supported or required custom headers. /// - public IList CustomHeaders { get; private set; } + public IList? CustomHeaders { get; private set; } /// /// Gets the Supported or required custom query options. /// - public IList CustomQueryOptions { get; private set; } + public IList? CustomQueryOptions { get; private set; } /// /// Gets A brief description of the request. /// - public string Description { get; private set; } + public string? Description { get; private set; } /// /// Gets A lengthy description of the request. /// - public string LongDescription { get; private set; } + public string? LongDescription { get; private set; } /// /// Test the target supports delete. @@ -80,9 +80,7 @@ internal class DeleteRestrictionsType : IRecord /// True/False. public bool IsNonDeletableNavigationProperty(string navigationPropertyPath) { - return NonDeletableNavigationProperties != null ? - NonDeletableNavigationProperties.Any(a => a == navigationPropertyPath) : - false; + return NonDeletableNavigationProperties != null && NonDeletableNavigationProperties.Any(a => a == navigationPropertyPath); } /// @@ -128,7 +126,7 @@ public void Initialize(IEdmRecordExpression record) /// Merges properties of the specified object into this instance if they are null. /// /// The object containing properties to merge. - public void MergePropertiesIfNull(DeleteRestrictionsType source) + public void MergePropertiesIfNull(DeleteRestrictionsType? source) { if (source == null) return; diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ExpandRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ExpandRestrictionsType.cs index 60b797afa..df25b6624 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ExpandRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ExpandRestrictionsType.cs @@ -30,7 +30,7 @@ internal class ExpandRestrictionsType : IRecord /// /// Gets the properties which cannot be used in $expand expressions. /// - public IList NonExpandableProperties { get; private set; } + public IList? NonExpandableProperties { get; private set; } /// /// Gets the maximum number of levels that can be expanded in a expand expression. @@ -50,7 +50,7 @@ internal class ExpandRestrictionsType : IRecord /// True/False. public bool IsNonExpandableProperty(string navigationPropertyPath) { - return NonExpandableProperties != null ? NonExpandableProperties.Any(a => a == navigationPropertyPath) : false; + return NonExpandableProperties != null && NonExpandableProperties.Any(a => a == navigationPropertyPath); } public void Initialize(IEdmRecordExpression record) diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterExpressionRestrictionType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterExpressionRestrictionType.cs index 6ed387261..39377f3f3 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterExpressionRestrictionType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterExpressionRestrictionType.cs @@ -17,14 +17,14 @@ internal class FilterExpressionRestrictionType : IRecord /// /// Gets the Path to the restricted property. /// - public string Property { get; private set; } + public string? Property { get; private set; } /// /// Gets the RequiresFilter value. /// /// /// - public string AllowedExpressions { get; private set; } + public string? AllowedExpressions { get; private set; } /// /// Init the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterRestrictionsType.cs index 7cd05d444..8093b7e8d 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/FilterRestrictionsType.cs @@ -30,12 +30,12 @@ internal class FilterRestrictionsType : IRecord /// /// Gets the properties which must be specified in the $filter clause. /// - public IList RequiredProperties { get; private set; } + public IList? RequiredProperties { get; private set; } /// /// Gets the properties which cannot be used in $filter expressions. /// - public IList NonFilterableProperties { get; private set; } + public IList? NonFilterableProperties { get; private set; } /// /// Gets The maximum number of levels (including recursion) that can be traversed in a filter expression. A value of -1 indicates there is no restriction. @@ -46,7 +46,7 @@ internal class FilterRestrictionsType : IRecord /// Gets These properties only allow a subset of filter expressions. /// A valid filter expression for a single property can be enclosed in parentheses and combined by `and` with valid expressions for other properties. /// - public IList FilterExpressionRestrictions { get; private set; } + public IList? FilterExpressionRestrictions { get; private set; } /// /// Test the target supports filter. @@ -61,7 +61,7 @@ internal class FilterRestrictionsType : IRecord /// True/False. public bool IsRequiredProperty(string propertyPath) { - return RequiredProperties != null ? RequiredProperties.Any(a => a == propertyPath) : false; + return RequiredProperties != null && RequiredProperties.Any(a => a == propertyPath); } /// @@ -71,7 +71,7 @@ public bool IsRequiredProperty(string propertyPath) /// True/False. public bool IsNonFilterableProperty(string propertyPath) { - return NonFilterableProperties != null ? NonFilterableProperties.Any(a => a == propertyPath) : false; + return NonFilterableProperties != null && NonFilterableProperties.Any(a => a == propertyPath); } /// diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/InsertRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/InsertRestrictionsType.cs index 8652f7a72..7b1258a0e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/InsertRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/InsertRestrictionsType.cs @@ -25,12 +25,12 @@ internal class InsertRestrictionsType : IRecord /// /// Gets the structural properties cannot be specified on insert. /// - public IList NonInsertableProperties { get; private set; } + public IList? NonInsertableProperties { get; private set; } /// /// Gets the navigation properties which do not allow deep inserts. /// - public IList NonInsertableNavigationProperties { get; private set; } + public IList? NonInsertableNavigationProperties { get; private set; } /// /// Gets the maximum number of navigation properties that can be traversed. @@ -45,50 +45,50 @@ internal class InsertRestrictionsType : IRecord /// /// Gets the required scopes to perform the insert. /// - public IList Permissions { get; private set; } + public IList? Permissions { get; private set; } /// /// Gets the Support for query options with insert requests. /// - public ModificationQueryOptionsType QueryOptions { get; private set; } + public ModificationQueryOptionsType? QueryOptions { get; private set; } /// /// Gets the Supported or required custom headers. /// - public IList CustomHeaders { get; private set; } + public IList? CustomHeaders { get; private set; } /// /// Gets the Supported or required custom query options. /// - public IList CustomQueryOptions { get; private set; } + public IList? CustomQueryOptions { get; private set; } /// /// Gets A brief description of the request. /// - public string Description { get; private set; } + public string? Description { get; private set; } /// /// Gets A lengthy description of the request. /// - public string LongDescription { get; private set; } + public string? LongDescription { get; private set; } /// /// Test the target supports insert. /// /// True/false. - public bool IsInsertable => Insertable == null || Insertable.Value == true; + public bool IsInsertable => Insertable == null || Insertable.Value; /// /// Lists the media types acceptable for the request content /// /// This is not an official OASIS standard property. - public IList RequestContentTypes { get; private set; } + public IList? RequestContentTypes { get; private set; } /// /// Lists the media types acceptable for the response content /// /// This is not an official OASIS standard property. - public IList ResponseContentTypes { get; private set; } + public IList? ResponseContentTypes { get; private set; } /// /// Test the input navigation property do not allow deep insert. @@ -111,47 +111,47 @@ public void Initialize(IEdmRecordExpression record) Utils.CheckArgumentNull(record, nameof(record)); // Insertable - Insertable = record.GetBoolean("Insertable"); + Insertable = record.GetBoolean(nameof(Insertable)); // NonInsertableNavigationProperties - NonInsertableNavigationProperties = record.GetCollectionPropertyPath("NonInsertableNavigationProperties"); + NonInsertableNavigationProperties = record.GetCollectionPropertyPath(nameof(NonInsertableNavigationProperties)); // MaxLevels - MaxLevels = record.GetInteger("MaxLevels"); + MaxLevels = record.GetInteger(nameof(MaxLevels)); // TypecastSegmentSupported - TypecastSegmentSupported = record.GetBoolean("TypecastSegmentSupported"); + TypecastSegmentSupported = record.GetBoolean(nameof(TypecastSegmentSupported)); // Permissions - Permissions = record.GetCollection("Permissions"); + Permissions = record.GetCollection(nameof(Permissions)); // QueryOptions - QueryOptions = record.GetRecord("QueryOptions"); + QueryOptions = record.GetRecord(nameof(QueryOptions)); // CustomHeaders - CustomHeaders = record.GetCollection("CustomHeaders"); + CustomHeaders = record.GetCollection(nameof(CustomHeaders)); // CustomHeaders - CustomQueryOptions = record.GetCollection("CustomQueryOptions"); + CustomQueryOptions = record.GetCollection(nameof(CustomQueryOptions)); // Description - Description = record.GetString("Description"); + Description = record.GetString(nameof(Description)); // LongDescription - LongDescription = record.GetString("LongDescription"); + LongDescription = record.GetString(nameof(LongDescription)); // RequestContentTypes - RequestContentTypes = record.GetCollection("RequestContentTypes"); + RequestContentTypes = record.GetCollection(nameof(RequestContentTypes)); // ResponseContentTypes - ResponseContentTypes = record.GetCollection("ResponseContentTypes"); + ResponseContentTypes = record.GetCollection(nameof(ResponseContentTypes)); } /// /// Merges properties of the specified object into this instance if they are null. /// /// The object containing properties to merge. - public void MergePropertiesIfNull(InsertRestrictionsType source) + public void MergePropertiesIfNull(InsertRestrictionsType? source) { if (source == null) return; diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/NavigationRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/NavigationRestrictionsType.cs index e0ff6696a..9f4fea30f 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/NavigationRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/NavigationRestrictionsType.cs @@ -40,7 +40,7 @@ internal class NavigationPropertyRestriction : IRecord /// /// Navigation properties can be navigated /// - public string NavigationProperty { get; set; } + public string? NavigationProperty { get; set; } /// /// Navigation properties can be navigated to this level. @@ -50,22 +50,22 @@ internal class NavigationPropertyRestriction : IRecord /// /// List of functions and operators supported in filter expressions. /// - public IList FilterFunctions { get; set; } + public IList? FilterFunctions { get; set; } /// /// Restrictions on filter expressions. /// - public FilterRestrictionsType FilterRestrictions { get; set; } + public FilterRestrictionsType? FilterRestrictions { get; set; } /// /// Restrictions on search expressions. /// - public SearchRestrictionsType SearchRestrictions { get; set; } + public SearchRestrictionsType? SearchRestrictions { get; set; } /// /// Restrictions on orderby expressions. /// - public SortRestrictionsType SortRestrictions { get; set; } + public SortRestrictionsType? SortRestrictions { get; set; } /// /// Supports $top. @@ -80,7 +80,7 @@ internal class NavigationPropertyRestriction : IRecord /// /// Supports $select. /// - public SelectSupportType SelectSupport { get; set; } + public SelectSupportType? SelectSupport { get; set; } /// /// Supports key values according to OData URL conventions. @@ -90,27 +90,27 @@ internal class NavigationPropertyRestriction : IRecord /// /// Restrictions on insert operations. /// - public InsertRestrictionsType InsertRestrictions { get; set; } + public InsertRestrictionsType? InsertRestrictions { get; set; } /// /// Deep Insert Support of the annotated resource (the whole service, an entity set, or a collection-valued resource). /// - public DeepInsertSupportType DeepInsertSupport { get; set; } + public DeepInsertSupportType? DeepInsertSupport { get; set; } /// /// Restrictions on update operations. /// - public UpdateRestrictionsType UpdateRestrictions { get; set; } + public UpdateRestrictionsType? UpdateRestrictions { get; set; } /// /// Deep Update Support of the annotated resource (the whole service, an entity set, or a collection-valued resource). /// - public DeepUpdateSupportType DeepUpdateSupport { get; set; } + public DeepUpdateSupportType? DeepUpdateSupport { get; set; } /// /// Restrictions on delete operations. /// - public DeleteRestrictionsType DeleteRestrictions { get; set; } + public DeleteRestrictionsType? DeleteRestrictions { get; set; } /// /// Data modification (including insert) along this navigation property requires the use of ETags. @@ -120,7 +120,7 @@ internal class NavigationPropertyRestriction : IRecord /// /// Restrictions for retrieving entities. /// - public ReadRestrictionsType ReadRestrictions { get; set; } + public ReadRestrictionsType? ReadRestrictions { get; set; } /// /// Init the . @@ -197,7 +197,7 @@ internal class NavigationRestrictionsType : IRecord /// /// Gets the navigation properties which has navigation restrictions. /// - public IList RestrictedProperties { get; private set; } + public IList? RestrictedProperties { get; private set; } /// /// Gets the navigation property referenceable value. @@ -216,10 +216,8 @@ internal class NavigationRestrictionsType : IRecord /// True/False. public bool IsRestrictedProperty(string navigationPropertyPath) { - return RestrictedProperties != null ? - RestrictedProperties.Where(a => a.NavigationProperty == navigationPropertyPath) - .Any(b => b.Navigability != null && b.Navigability.Value == NavigationType.None) : - false; + return RestrictedProperties != null && RestrictedProperties.Where(a => a.NavigationProperty == navigationPropertyPath) + .Any(b => b.Navigability != null && b.Navigability.Value == NavigationType.None); } /// @@ -244,7 +242,7 @@ public void Initialize(IEdmRecordExpression record) /// Merges properties of the specified object into this instance if they are null. /// /// The object containing properties to merge. - public void MergePropertiesIfNull(NavigationRestrictionsType source) + public void MergePropertiesIfNull(NavigationRestrictionsType? source) { if (source == null) return; diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionsType.cs index c5613d2e7..b8caa1362 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/OperationRestrictionsType.cs @@ -24,17 +24,17 @@ internal class OperationRestrictionsType : IRecord /// /// Gets the List of required scopes to invoke an action or function. /// - public IList Permissions { get; private set; } + public IList? Permissions { get; private set; } /// /// Gets the Supported or required custom headers. /// - public IList CustomHeaders { get; private set; } + public IList? CustomHeaders { get; private set; } /// /// Gets the Supported or required custom query options. /// - public IList CustomQueryOptions { get; private set; } + public IList? CustomQueryOptions { get; private set; } /// /// Init the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/PermissionType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/PermissionType.cs index 16b3bcddf..edbeb66be 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/PermissionType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/PermissionType.cs @@ -3,7 +3,6 @@ // Licensed under the MIT License (MIT). See LICENSE in the repo root for license information. // ------------------------------------------------------------ -using System.Collections; using System.Collections.Generic; using Microsoft.OData.Edm.Vocabularies; using Microsoft.OpenApi.OData.Common; @@ -19,12 +18,12 @@ internal class PermissionType : IRecord /// /// Gets the Authorization flow scheme name. /// - public string SchemeName { get; private set; } + public string? SchemeName { get; private set; } /// /// Gets the list of scopes that can provide access to the resource. /// - public IList Scopes { get; private set; } + public IList? Scopes { get; private set; } /// /// Init the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ReadRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ReadRestrictionsType.cs index 7061b4b56..7b2d84487 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ReadRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ReadRestrictionsType.cs @@ -23,27 +23,27 @@ internal abstract class ReadRestrictionsBase : IRecord /// /// Gets the List of required scopes to invoke an action or function /// - public IList Permissions { get; private set; } + public IList? Permissions { get; private set; } /// /// Gets the Supported or required custom headers. /// - public IList CustomHeaders { get; private set; } + public IList? CustomHeaders { get; private set; } /// /// Gets the Supported or required custom query options. /// - public IList CustomQueryOptions { get; private set; } + public IList? CustomQueryOptions { get; private set; } /// /// Gets A brief description of the request. /// - public string Description { get; private set; } + public string? Description { get; private set; } /// /// Gets A lengthy description of the request. /// - public string LongDescription { get; private set; } + public string? LongDescription { get; private set; } /// /// Test the target supports read. @@ -83,7 +83,7 @@ public virtual void Initialize(IEdmRecordExpression record) /// Merges properties of the specified object into this instance if they are null. /// /// The object containing properties to merge. - public void MergePropertiesIfNull(ReadRestrictionsBase source) + public void MergePropertiesIfNull(ReadRestrictionsBase? source) { if (source == null) return; @@ -120,7 +120,7 @@ internal class ReadRestrictionsType : ReadRestrictionsBase /// /// Gets the Restrictions for retrieving an entity by key /// - public ReadByKeyRestrictions ReadByKeyRestrictions { get; set; } + public ReadByKeyRestrictions? ReadByKeyRestrictions { get; set; } /// /// Init the . @@ -139,7 +139,7 @@ public override void Initialize(IEdmRecordExpression record) /// Merges properties of the specified object into this instance if they are null. /// /// The object containing properties to merge. - public void MergePropertiesIfNull(ReadRestrictionsType source) + public void MergePropertiesIfNull(ReadRestrictionsType? source) { base.MergePropertiesIfNull(source); diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ScopeType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ScopeType.cs index 0a7d24236..c181a1459 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ScopeType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/ScopeType.cs @@ -17,14 +17,14 @@ internal class ScopeType : IRecord /// /// Gets the names of the scope. /// - public string Scope { get; private set; } + public string? Scope { get; private set; } /// /// Gets the restricted properties. /// Comma-separated string value of all properties that will be included or excluded when using the scope. /// Possible string value identifiers when specifying properties are '*', _PropertyName_, '-'_PropertyName_. /// - public string RestrictedProperties { get; private set; } + public string? RestrictedProperties { get; private set; } /// /// Init the . diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SearchRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SearchRestrictionsType.cs index e001f5273..dce043cc0 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SearchRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SearchRestrictionsType.cs @@ -102,29 +102,23 @@ public void Initialize(IEdmRecordExpression record) Searchable = record.GetBoolean("Searchable"); // read the "UnsupportedExpressions" - IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == "UnsupportedExpressions"); - if (property != null) + if (record.Properties.FirstOrDefault(e => e.Name == "UnsupportedExpressions") is {Value: IEdmEnumMemberExpression {EnumMembers: not null} value}) { - IEdmEnumMemberExpression value = property.Value as IEdmEnumMemberExpression; - if (value != null && value.EnumMembers != null) - { - SearchExpressions result; - foreach (var v in value.EnumMembers) - { - if (Enum.TryParse(v.Name, out result)) - { - if (UnsupportedExpressions == null) - { - UnsupportedExpressions = result; - } - else - { - UnsupportedExpressions = UnsupportedExpressions | result; - } - } - } - } - } + foreach (var v in value.EnumMembers) + { + if (Enum.TryParse(v.Name, out SearchExpressions result)) + { + if (UnsupportedExpressions == null) + { + UnsupportedExpressions = result; + } + else + { + UnsupportedExpressions |= result; + } + } + } + } } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SortRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SortRestrictionsType.cs index 3559341fb..8d38c583e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SortRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/SortRestrictionsType.cs @@ -25,17 +25,17 @@ internal class SortRestrictionsType : IRecord /// /// Gets the properties which can only be used for sorting in Ascending order. /// - public IList AscendingOnlyProperties { get; private set; } + public IList? AscendingOnlyProperties { get; private set; } /// /// Gets the properties which can only be used for sorting in Descending order. /// - public IList DescendingOnlyProperties { get; private set; } + public IList? DescendingOnlyProperties { get; private set; } /// /// Gets the properties which cannot be used in $orderby expressions. /// - public IList NonSortableProperties { get; private set; } + public IList? NonSortableProperties { get; private set; } /// /// Gets a boolean value indicating whether the target supports $orderby. @@ -89,7 +89,7 @@ public void Initialize(IEdmRecordExpression record) // DescendingOnlyProperties DescendingOnlyProperties = record.GetCollectionPropertyPath("DescendingOnlyProperties"); - // NonSortablePropeties + // NonSortableProperties NonSortableProperties = record.GetCollectionPropertyPath("NonSortableProperties"); } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs index 724d2ddc9..9484edbc5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Capabilities/UpdateRestrictionsType.cs @@ -69,7 +69,7 @@ internal class UpdateRestrictionsType : IRecord /// /// Gets the navigation properties which do not allow rebinding. /// - public IList NonUpdatableNavigationProperties { get; private set; } + public IList? NonUpdatableNavigationProperties { get; private set; } /// /// Gets the maximum number of navigation properties that can be traversed when addressing the collection or entity to update. @@ -80,32 +80,32 @@ internal class UpdateRestrictionsType : IRecord /// /// Gets the Required permissions. One of the specified sets of scopes is required to perform the update. /// - public IList Permissions { get; private set; } + public IList? Permissions { get; private set; } /// /// Gets/sets the support for query options with update requests. /// - public ModificationQueryOptionsType QueryOptions { get; private set; } + public ModificationQueryOptionsType? QueryOptions { get; private set; } /// /// Gets/sets the supported or required custom headers. /// - public IList CustomHeaders { get; private set; } + public IList? CustomHeaders { get; private set; } /// /// Gets/sets the supported or required custom query options. /// - public IList CustomQueryOptions { get; private set; } + public IList? CustomQueryOptions { get; private set; } /// /// Gets A brief description of the request. /// - public string Description { get; private set; } + public string? Description { get; private set; } /// /// Gets A lengthy description of the request. /// - public string LongDescription { get; private set; } + public string? LongDescription { get; private set; } /// /// Test the target supports update. @@ -120,9 +120,7 @@ internal class UpdateRestrictionsType : IRecord /// True/False. public bool IsNonUpdatableNavigationProperty(string navigationPropertyPath) { - return NonUpdatableNavigationProperties != null ? - NonUpdatableNavigationProperties.Any(a => a == navigationPropertyPath) : - false; + return NonUpdatableNavigationProperties != null && NonUpdatableNavigationProperties.Any(a => a == navigationPropertyPath); } /// @@ -140,13 +138,13 @@ public bool IsNonUpdatableNavigationProperty(string navigationPropertyPath) /// Lists the media types acceptable for the request content /// /// This is not an official OASIS standard property. - public IList RequestContentTypes { get; private set; } + public IList? RequestContentTypes { get; private set; } /// /// Lists the media types acceptable for the response content /// /// This is not an official OASIS standard property. - public IList ResponseContentTypes { get; private set; } + public IList? ResponseContentTypes { get; private set; } /// /// Init the . @@ -209,7 +207,7 @@ public void Initialize(IEdmRecordExpression record) /// Merges properties of the specified object into this instance if they are null. /// /// The object containing properties to merge. - public void MergePropertiesIfNull(UpdateRestrictionsType source) + public void MergePropertiesIfNull(UpdateRestrictionsType? source) { if (source == null) return; diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExampleValue.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExampleValue.cs index e0f7b2047..ba41116a5 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExampleValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExampleValue.cs @@ -17,7 +17,7 @@ internal class ExampleValue : IRecord /// /// Gets the description of the example value. /// - public string Description { get; private set; } + public string? Description { get; private set; } /// /// Init the diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExternalExampleValue.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExternalExampleValue.cs index 5afceefd5..97e2ee0e2 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExternalExampleValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ExternalExampleValue.cs @@ -16,7 +16,7 @@ internal class ExternalExampleValue : ExampleValue /// /// Gets the Url reference to the value in its literal format /// - public string ExternalValue { get; set; } + public string? ExternalValue { get; set; } /// /// Init the diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/LinkType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/LinkType.cs index cbec48e03..194186fc7 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/LinkType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/LinkType.cs @@ -19,12 +19,12 @@ internal class LinkType : IRecord /// /// The link relation type. /// - public string Rel { get; private set; } + public string? Rel { get; private set; } /// /// The link to the documentation. /// - public Uri Href { get; private set; } + public Uri? Href { get; private set; } /// /// Init the . @@ -34,7 +34,7 @@ public virtual void Initialize(IEdmRecordExpression record) { Utils.CheckArgumentNull(record, nameof(record)); Rel = record.GetString("rel"); - Href = new Uri(record.GetString("href")); + Href = record.GetString("href") is string href ? new Uri(href) : null; } } } diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/PrimitiveExampleValue.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/PrimitiveExampleValue.cs index c91a87c19..b90e1d883 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/PrimitiveExampleValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/PrimitiveExampleValue.cs @@ -17,7 +17,7 @@ internal class PrimitiveExampleValue : ExampleValue /// /// Gets the Example value for the custom parameter /// - public ODataPrimitiveValue Value { get; private set; } + public ODataPrimitiveValue? Value { get; private set; } /// /// Init the diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ResourceExampleValue.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ResourceExampleValue.cs index bc7c40da0..71ab995a6 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ResourceExampleValue.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/ResourceExampleValue.cs @@ -16,7 +16,7 @@ internal abstract class ResourceExampleValue : ExampleValue /// /// Gets the Example value for the custom parameter /// - public ODataResourceValue Value { get; private set; } + public ODataResourceValue? Value { get; private set; } /// /// Init the diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionRecord.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionRecord.cs index 27a36a45c..3252a1d15 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionRecord.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionRecord.cs @@ -39,8 +39,8 @@ internal OpenApiDeprecationExtension GetOpenApiExtension() { Date = Date.HasValue ? new DateTimeOffset(Date.Value, TimeSpan.Zero) : default, RemovalDate = RemovalDate.HasValue ? new DateTimeOffset(RemovalDate.Value, TimeSpan.Zero) : default, - Description = Description, - Version = Version, + Description = string.IsNullOrEmpty(Description) ? string.Empty : Description, + Version = string.IsNullOrEmpty(Version) ? string.Empty : Version, }; } } \ No newline at end of file diff --git a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionType.cs b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionType.cs index c530f8cdc..f8d09b25e 100644 --- a/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionType.cs +++ b/src/Microsoft.OpenApi.OData.Reader/Vocabulary/Core/RevisionType.cs @@ -14,7 +14,7 @@ internal class RevisionType : IRecord /// /// The version this revision was introduced. /// - public string Version { get; private set; } + public string? Version { get; private set; } /// /// The kind of the revision /// @@ -22,7 +22,7 @@ internal class RevisionType : IRecord /// /// The description of the revision. /// - public string Description { get; private set; } + public string? Description { get; private set; } /// /// Init the . /// diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Authorization/OAuth2PasswordTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Authorization/OAuth2PasswordTests.cs index d193f0794..166e364dc 100644 --- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Authorization/OAuth2PasswordTests.cs +++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Vocabulary/Authorization/OAuth2PasswordTests.cs @@ -25,7 +25,7 @@ public void SchemeTypeKindAndOAuthTypeSetCorrectly() // Act & Assert Assert.Equal(SecuritySchemeType.OAuth2, password.SchemeType); - Assert.Equal(OAuth2Type.Pasword, password.OAuth2Type); + Assert.Equal(OAuth2Type.Password, password.OAuth2Type); } [Fact]