/// <summary> /// Create the dictionary of <see cref="OpenApiSchema"/> object. /// The name of each pair is the namespace-qualified name of the type. It uses the namespace instead of the alias. /// The value of each pair is a <see cref="OpenApiSchema"/>. /// </summary> /// <param name="context">The OData to Open API context.</param> /// <returns>The string/schema dictionary.</returns> public static IDictionary <string, OpenApiSchema> CreateSchemas(this ODataContext context) { Utils.CheckArgumentNull(context, nameof(context)); IDictionary <string, OpenApiSchema> schemas = new Dictionary <string, OpenApiSchema>(); // Each entity type, complex type, enumeration type, and type definition directly // or indirectly used in the paths field is represented as a name / value pair of the schemas map. foreach (var element in context.Model.SchemaElements.Where(c => !c.Namespace.StartsWith("Org.OData."))) { switch (element.SchemaElementKind) { case EdmSchemaElementKind.TypeDefinition: // Type definition { IEdmType reference = (IEdmType)element; schemas.Add(reference.FullTypeName(), context.CreateSchemaTypeSchema(reference)); } break; } } // append the Edm.Spatial foreach (var schema in context.CreateSpatialSchemas()) { schemas[schema.Key] = schema.Value; } // append the OData errors foreach (var schema in context.CreateODataErrorSchemas()) { schemas[schema.Key] = schema.Value; } return(schemas); }
/// <summary> /// Creates the inner error schema definition. If an "InnerError" complex type is defined in the root namespace, then this type will be used as the inner error type. /// Otherwise, a default inner error type of object will be created. /// </summary> /// <param name="context">The OData to Open API context.</param> /// <returns>The inner error schema definition.</returns> public static OpenApiSchema CreateInnerErrorSchema(ODataContext context) { Utils.CheckArgumentNull(context, nameof(context)); var rootNamespace = context.Model.DeclaredNamespaces.OrderBy(n => n.Count(x => x == '.')).FirstOrDefault(); if (!string.IsNullOrEmpty(context.Settings.InnerErrorComplexTypeName) && !string.IsNullOrEmpty(rootNamespace) && context.Model.FindDeclaredType($"{rootNamespace}.{context.Settings.InnerErrorComplexTypeName}") is IEdmComplexType complexType) { return(context.CreateSchemaTypeSchema(complexType)); } return(new OpenApiSchema { Type = "object", Description = "The structure of this object is service-specific" }); }
/// <summary> /// Create the dictionary of <see cref="OpenApiSchema"/> object. /// The name of each pair is the namespace-qualified name of the type. It uses the namespace instead of the alias. /// The value of each pair is a <see cref="OpenApiSchema"/>. /// </summary> /// <param name="context">The OData to Open API context.</param> /// <returns>The string/schema dictionary.</returns> public static IDictionary <string, OpenApiSchema> CreateSchemas(this ODataContext context) { Utils.CheckArgumentNull(context, nameof(context)); IDictionary <string, OpenApiSchema> schemas = new Dictionary <string, OpenApiSchema>(); // Each entity type, complex type, enumeration type, and type definition directly // or indirectly used in the paths field is represented as a name / value pair of the schemas map. // Ideally this would be driven off the types used in the paths, but in practice, it is simply // all of the types present in the model. IEnumerable <IEdmSchemaElement> elements = context.Model.GetAllElements(); foreach (var element in elements) { switch (element.SchemaElementKind) { case EdmSchemaElementKind.TypeDefinition: // Type definition { IEdmType reference = (IEdmType)element; schemas.Add(reference.FullTypeName(), context.CreateSchemaTypeSchema(reference)); } break; } } // append the Edm.Spatial foreach (var schema in context.CreateSpatialSchemas()) { schemas[schema.Key] = schema.Value; } // append the OData errors foreach (var schema in context.CreateODataErrorSchemas()) { schemas[schema.Key] = schema.Value; } return(schemas); }
/// <summary> /// Create the dictionary of <see cref="OpenApiSchema"/> object. /// The name of each pair is the namespace-qualified name of the type. It uses the namespace instead of the alias. /// The value of each pair is a <see cref="OpenApiSchema"/>. /// </summary> /// <param name="context">The OData to Open API context.</param> /// <returns>The string/schema dictionary.</returns> public static IDictionary <string, OpenApiSchema> CreateSchemas(this ODataContext context) { Utils.CheckArgumentNull(context, nameof(context)); IDictionary <string, OpenApiSchema> schemas = new Dictionary <string, OpenApiSchema>(); // Each entity type, complex type, enumeration type, and type definition directly // or indirectly used in the paths field is represented as a name / value pair of the schemas map. // Ideally this would be driven off the types used in the paths, but in practice, it is simply // all of the types present in the model. IEnumerable <IEdmSchemaElement> elements = context.Model.GetAllElements(); foreach (var element in elements) { switch (element.SchemaElementKind) { case EdmSchemaElementKind.TypeDefinition: // Type definition { IEdmType reference = (IEdmType)element; var fullTypeName = reference.FullTypeName(); if (reference is IEdmComplexType && fullTypeName.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries) .Last() .Equals(context.Settings.InnerErrorComplexTypeName, StringComparison.Ordinal)) { continue; } schemas.Add(fullTypeName, context.CreateSchemaTypeSchema(reference)); } break; } } // append the Edm.Spatial foreach (var schema in context.CreateSpatialSchemas()) { schemas[schema.Key] = schema.Value; } // append the OData errors foreach (var schema in context.CreateODataErrorSchemas()) { schemas[schema.Key] = schema.Value; } if (context.Settings.EnableDollarCountPath) { schemas[Constants.DollarCountSchemaName] = new OpenApiSchema { Type = "integer", Format = "int32" } } ; schemas = schemas.Concat(context.GetAllCollectionEntityTypes() .Select(x => new KeyValuePair <string, OpenApiSchema>( $"{(x is IEdmEntityType eType ? eType.FullName() : x.FullTypeName())}{Constants.CollectionSchemaSuffix}", CreateCollectionSchema(context, x))) .Where(x => !schemas.ContainsKey(x.Key))) .Concat(context.GetAllCollectionComplexTypes() .Select(x => new KeyValuePair <string, OpenApiSchema>( $"{x.FullTypeName()}{Constants.CollectionSchemaSuffix}", CreateCollectionSchema(context, x))) .Where(x => !schemas.ContainsKey(x.Key))) .ToDictionary(x => x.Key, x => x.Value); if (context.HasAnyNonContainedCollections()) { schemas[$"String{Constants.CollectionSchemaSuffix}"] = CreateCollectionSchema(context, new OpenApiSchema { Type = "string" }, "string"); } schemas[Constants.ReferenceUpdateSchemaName] = new() { Type = "object", Properties = new Dictionary <string, OpenApiSchema> { { Constants.OdataId, new OpenApiSchema { Type = "string", Nullable = false } }, { Constants.OdataType, new OpenApiSchema { Type = "string", Nullable = true } }, } }; schemas[Constants.ReferenceCreateSchemaName] = new() { Type = "object", Properties = new Dictionary <string, OpenApiSchema> { { Constants.OdataId, new OpenApiSchema { Type = "string", Nullable = false } } }, AdditionalProperties = new OpenApiSchema { Type = "object" } }; return(schemas); } internal static bool HasAnyNonContainedCollections(this ODataContext context)