public void OperationRestrictionsTermWorksToCreateOperationForEdmFunctionImport(bool enableAnnotation) { string template = @"<?xml version=""1.0"" encoding=""utf-8""?> <edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx""> <edmx:DataServices> <Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm""> <Function Name=""GetNearestAirport""> <Parameter Name=""lat"" Type=""Edm.Double"" Nullable=""false"" /> <Parameter Name=""lon"" Type=""Edm.Double"" Nullable=""false"" /> <ReturnType Type=""Edm.String"" /> </Function> <EntityContainer Name=""GraphService""> <FunctionImport Name=""GetNearestAirport"" Function=""NS.GetNearestAirport"" > {0} </FunctionImport> </EntityContainer> </Schema> </edmx:DataServices> </edmx:Edmx> "; string annotation = @"<Annotation Term=""Org.OData.Capabilities.V1.OperationRestrictions""> <Record> <PropertyValue Property=""CustomHeaders""> <Collection> <Record> <PropertyValue Property=""Name"" String=""myhead1"" /> <PropertyValue Property=""Required"" Bool=""true"" /> </Record> </Collection> </PropertyValue> <PropertyValue Property=""Permissions""> <Collection> <Record> <PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" /> <PropertyValue Property=""Scopes""> <Collection> <Record> <PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""User.Read.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""Directory.Read.All"" /> </Record> </Collection> </PropertyValue> </Record> <Record> <PropertyValue Property=""SchemeName"" String=""Application"" /> <PropertyValue Property=""Scopes""> <Collection> <Record> <PropertyValue Property=""Scope"" String=""User.Read.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""Directory.Read.All"" /> </Record> </Collection> </PropertyValue> </Record> </Collection> </PropertyValue> </Record> </Annotation>"; // Arrange string csdl = string.Format(template, enableAnnotation ? annotation : ""); var edmModel = CsdlReader.Parse(XElement.Parse(csdl).CreateReader()); Assert.NotNull(edmModel); IEdmOperationImport operationImport = edmModel.EntityContainer.FindOperationImports("GetNearestAirport").FirstOrDefault(); Assert.NotNull(operationImport); ODataContext context = new ODataContext(edmModel); ODataPath path = new ODataPath(new ODataOperationImportSegment(operationImport)); // Act var operation = _operationHandler.CreateOperation(context, path); // Assert Assert.NotNull(operation); Assert.NotNull(operation.Security); if (enableAnnotation) { Assert.Equal(2, operation.Security.Count); string json = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); Assert.Contains(@" ""security"": [ { ""Delegated (work or school account)"": [ ""User.ReadBasic.All"", ""User.Read.All"", ""Directory.Read.All"" ] }, { ""Application"": [ ""User.Read.All"", ""Directory.Read.All"" ] } ],".ChangeLineBreaks(), json); Assert.Contains(@" { ""name"": ""myhead1"", ""in"": ""header"", ""required"": true, ""schema"": { ""type"": ""string"" } } ".ChangeLineBreaks(), json); } else { Assert.Empty(operation.Security); } }
/// <summary> /// Create the collection of <see cref="OpenApiTag"/> object. /// </summary> /// <param name="context">The OData context.</param> /// <returns>The created collection of <see cref="OpenApiTag"/> object.</returns> public static IList <OpenApiTag> CreateTags(this ODataContext context) { Utils.CheckArgumentNull(context, nameof(context)); // The value of tags is an array of Tag Objects. // For an OData service the natural groups are entity sets and singletons, // so the tags array contains one Tag Object per entity set and singleton in the entity container. // A Tag Object has to contain the field name, whose value is the name of the entity set or singleton, // and it optionally can contain the field description, whose value is the value of the unqualified annotation // Core.Description of the entity set or singleton. if (context.Tags != null) { return(context.Tags); } IList <OpenApiTag> tags = new List <OpenApiTag>(); if (context.EntityContainer != null) { foreach (IEdmEntityContainerElement element in context.Model.EntityContainer.Elements) { switch (element.ContainerElementKind) { case EdmContainerElementKind.EntitySet: // entity set IEdmEntitySet entitySet = (IEdmEntitySet)element; tags.Add(new OpenApiTag { Name = entitySet.Name, Description = context.Model.GetDescriptionAnnotation(entitySet) }); break; case EdmContainerElementKind.Singleton: // singleton IEdmSingleton singleton = (IEdmSingleton)element; tags.Add(new OpenApiTag { Name = singleton.Name, Description = context.Model.GetDescriptionAnnotation(singleton) }); break; // 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); if (actionImportTag != null) { tags.Add(actionImportTag); } break; case EdmContainerElementKind.FunctionImport: // Function Import OpenApiTag functionImportTag = context.CreateOperationImportTag((IEdmFunctionImport)element); if (functionImportTag != null) { tags.Add(functionImportTag); } break; } } } return(tags); }
private void VerifyMediaEntityPutOperation(string annotation, bool enableOperationId) { // Arrange IEdmModel model = MediaEntityGetOperationHandlerTests.GetEdmModel(annotation); OpenApiConvertSettings settings = new OpenApiConvertSettings { EnableOperationId = enableOperationId }; ODataContext context = new ODataContext(model, settings); IEdmEntitySet todos = model.EntityContainer.FindEntitySet("Todos"); IEdmSingleton me = model.EntityContainer.FindSingleton("me"); Assert.NotNull(todos); IEdmEntityType todo = model.SchemaElements.OfType <IEdmEntityType>().First(c => c.Name == "Todo"); IEdmStructuralProperty sp = todo.StructuralProperties().First(c => c.Name == "Logo"); ODataPath path = new ODataPath(new ODataNavigationSourceSegment(todos), new ODataKeySegment(todos.EntityType()), new ODataStreamPropertySegment(sp.Name)); IEdmEntityType user = model.SchemaElements.OfType <IEdmEntityType>().First(c => c.Name == "user"); IEdmNavigationProperty navProperty = user.NavigationProperties().First(c => c.Name == "photo"); ODataPath path2 = new ODataPath(new ODataNavigationSourceSegment(me), new ODataNavigationPropertySegment(navProperty), new ODataStreamContentSegment()); // Act var putOperation = _operationalHandler.CreateOperation(context, path); var putOperation2 = _operationalHandler.CreateOperation(context, path2); // Assert Assert.NotNull(putOperation); Assert.NotNull(putOperation2); Assert.Equal("Update Logo for Todo in Todos", putOperation.Summary); Assert.Equal("Update media content for the navigation property photo in me", putOperation2.Summary); Assert.NotNull(putOperation.Tags); Assert.NotNull(putOperation2.Tags); var tag = Assert.Single(putOperation.Tags); var tag2 = Assert.Single(putOperation2.Tags); Assert.Equal("Todos.Todo", tag.Name); Assert.Equal("me.profilePhoto", tag2.Name); Assert.NotNull(putOperation.Responses); Assert.NotNull(putOperation2.Responses); Assert.Equal(2, putOperation.Responses.Count); Assert.Equal(2, putOperation2.Responses.Count); Assert.Equal(new[] { "204", "default" }, putOperation.Responses.Select(r => r.Key)); Assert.Equal(new[] { "204", "default" }, putOperation2.Responses.Select(r => r.Key)); if (!string.IsNullOrEmpty(annotation)) { Assert.Equal(2, putOperation.RequestBody.Content.Keys.Count); Assert.True(putOperation.RequestBody.Content.ContainsKey("image/png")); Assert.True(putOperation.RequestBody.Content.ContainsKey("image/jpeg")); Assert.Equal("The logo image.", putOperation.Description); Assert.Equal(1, putOperation2.RequestBody.Content.Keys.Count); Assert.True(putOperation2.RequestBody.Content.ContainsKey(Constants.ApplicationOctetStreamMediaType)); } else { Assert.Equal(1, putOperation.RequestBody.Content.Keys.Count); Assert.Equal(1, putOperation2.RequestBody.Content.Keys.Count); Assert.True(putOperation.RequestBody.Content.ContainsKey(Constants.ApplicationOctetStreamMediaType)); Assert.True(putOperation2.RequestBody.Content.ContainsKey(Constants.ApplicationOctetStreamMediaType)); } if (enableOperationId) { Assert.Equal("Todos.Todo.UpdateLogo", putOperation.OperationId); Assert.Equal("me.UpdatePhotoContent", putOperation2.OperationId); } else { Assert.Null(putOperation.OperationId); Assert.Null(putOperation2.OperationId); } }
protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); _readRestrictions = Context.Model.GetRecord <ReadRestrictionsType>(EntitySet, CapabilitiesConstants.ReadRestrictions); }
public void CreateEntityTypeWithBaseSchemaReturnCorrectSchema() { // Arrange IEdmModel model = EdmModelHelper.MultipleInheritanceEdmModel; ODataContext context = new ODataContext(model); IEdmEntityType entity = model.SchemaElements.OfType <IEdmEntityType>().First(t => t.Name == "Human"); Assert.NotNull(entity); // Guard // Act var schema = context.CreateStructuredTypeSchema(entity); // Assert Assert.NotNull(schema); Assert.True(String.IsNullOrEmpty(schema.Type)); Assert.NotNull(schema.AllOf); Assert.Null(schema.AnyOf); Assert.Null(schema.OneOf); Assert.Null(schema.Properties); Assert.Equal(2, schema.AllOf.Count); var baseSchema = schema.AllOf.First(); Assert.NotNull(baseSchema.Reference); Assert.Equal(ReferenceType.Schema, baseSchema.Reference.Type); Assert.Equal("NS.Animal", baseSchema.Reference.Id); var declaredSchema = schema.AllOf.Last(); Assert.Equal("object", declaredSchema.Type); Assert.Null(declaredSchema.AllOf); Assert.Null(declaredSchema.AnyOf); Assert.Null(declaredSchema.OneOf); Assert.NotNull(declaredSchema.Properties); Assert.Equal(1, declaredSchema.Properties.Count); var property = Assert.Single(declaredSchema.Properties); Assert.Equal("Name", property.Key); Assert.Equal("string", property.Value.Type); Assert.Null(property.Value.OneOf); Assert.Equal("Entity type 'Human' description.", declaredSchema.Description); Assert.Equal("Human", declaredSchema.Title); // Act string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); _output.WriteLine(json); // Assert Assert.NotNull(json); Assert.Equal(@"{ ""allOf"": [ { ""$ref"": ""#/components/schemas/NS.Animal"" }, { ""title"": ""Human"", ""type"": ""object"", ""properties"": { ""Name"": { ""type"": ""string"" } }, ""description"": ""Entity type 'Human' description."" } ], ""example"": { ""Id"": ""integer (identifier)"", ""Age"": ""integer"", ""Name"": ""string"" } }" .ChangeLineBreaks(), json); }
public static OpenApiSchema CreateSchemaTypeDefinitionSchema(this ODataContext context, IEdmTypeDefinition typeDefinition) { return(context.CreateSchema(typeDefinition.UnderlyingType)); }
public BaseController(ODataContext context) { _Context = context; }
public void OperationRestrictionsTermWorksToCreateOperationForEdmActionImport(bool enableAnnotation) { string template = @"<?xml version=""1.0"" encoding=""utf-8""?> <edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx""> <edmx:DataServices> <Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm""> <Action Name=""ResetDataSource"" /> <EntityContainer Name=""GraphService""> <ActionImport Name=""ResetDataSource"" Action=""NS.ResetDataSource"" > {0} </ActionImport> </EntityContainer> </Schema> </edmx:DataServices> </edmx:Edmx> "; string annotation = @"<Annotation Term=""Org.OData.Capabilities.V1.OperationRestrictions""> <Record> <PropertyValue Property=""Permissions""> <Collection> <Record> <PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" /> <PropertyValue Property=""Scopes""> <Collection> <Record> <PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""User.Read.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""Directory.Read.All"" /> </Record> </Collection> </PropertyValue> </Record> <Record> <PropertyValue Property=""SchemeName"" String=""Application"" /> <PropertyValue Property=""Scopes""> <Collection> <Record> <PropertyValue Property=""Scope"" String=""User.Read.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""Directory.Read.All"" /> </Record> </Collection> </PropertyValue> </Record> </Collection> </PropertyValue> <PropertyValue Property=""CustomQueryOptions""> <Collection> <Record> <PropertyValue Property=""Name"" String=""odata-debug"" /> <PropertyValue Property=""Description"" String=""Debug support for OData services"" /> <PropertyValue Property=""Required"" Bool=""false"" /> <PropertyValue Property=""ExampleValues""> <Collection> <Record> <PropertyValue Property=""Value"" String=""html"" /> <PropertyValue Property=""Description"" String=""Service responds with self-contained..."" /> </Record> <Record> <PropertyValue Property=""Value"" String=""json"" /> <PropertyValue Property=""Description"" String=""Service responds with JSON document..."" /> </Record> </Collection> </PropertyValue> </Record> </Collection> </PropertyValue> </Record> </Annotation>"; // Arrange string csdl = string.Format(template, enableAnnotation ? annotation : ""); var edmModel = CsdlReader.Parse(XElement.Parse(csdl).CreateReader()); Assert.NotNull(edmModel); IEdmOperationImport operationImport = edmModel.EntityContainer.FindOperationImports("ResetDataSource").FirstOrDefault(); Assert.NotNull(operationImport); ODataContext context = new ODataContext(edmModel); ODataPath path = new ODataPath(new ODataOperationImportSegment(operationImport)); // Act var operation = _operationHandler.CreateOperation(context, path); // Assert Assert.NotNull(operation); Assert.NotNull(operation.Security); if (enableAnnotation) { Assert.Equal(2, operation.Security.Count); string json = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); Assert.Contains(@" ""security"": [ { ""Delegated (work or school account)"": [ ""User.ReadBasic.All"", ""User.Read.All"", ""Directory.Read.All"" ] }, { ""Application"": [ ""User.Read.All"", ""Directory.Read.All"" ] } ],".ChangeLineBreaks(), json); // with custom query options Assert.Contains(@" ""parameters"": [ { ""name"": ""odata-debug"", ""in"": ""query"", ""description"": ""Debug support for OData services"", ""schema"": { ""type"": ""string"" }, ""examples"": { ""example-1"": { ""description"": ""Service responds with self-contained..."", ""value"": ""html"" }, ""example-2"": { ""description"": ""Service responds with JSON document..."", ""value"": ""json"" } } } ],".ChangeLineBreaks(), json); } else { Assert.Empty(operation.Security); } }
/// <summary> /// Create the collection of <see cref="OpenApiLink"/> object for an entity or collection of entities. /// </summary> /// <param name="context">The OData context.</param> /// <param name="entityType">The Entity type.</param> /// <param name ="entityName">The name of the source of the <see cref="IEdmEntityType"/> object.</param> /// <param name="entityKind">"The kind of the source of the <see cref="IEdmEntityType"/> object.</param> /// <param name="path">The OData path of the operation the links are to be generated for.</param> /// <param name="parameters">"Optional: The list of parameters of the incoming operation.</param> /// <param name="navPropOperationId">Optional: The operation id of the source of the NavigationProperty object.</param> /// <returns>The created dictionary of <see cref="OpenApiLink"/> object.</returns> public static IDictionary <string, OpenApiLink> CreateLinks(this ODataContext context, IEdmEntityType entityType, string entityName, string entityKind, ODataPath path, IList <OpenApiParameter> parameters = null, string navPropOperationId = null) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(entityType, nameof(entityType)); Utils.CheckArgumentNullOrEmpty(entityName, nameof(entityName)); Utils.CheckArgumentNullOrEmpty(entityKind, nameof(entityKind)); Utils.CheckArgumentNull(path, nameof(path)); List <string> pathKeyNames = new(); // Fetch defined Id(s) from incoming parameters (if any) if (parameters != null) { foreach (var parameter in parameters) { if (!string.IsNullOrEmpty(parameter.Description) && parameter.Description.ToLower().Contains("key")) { pathKeyNames.Add(parameter.Name); } } } Dictionary <string, OpenApiLink> links = new(); bool lastSegmentIsColNavProp = (path.LastSegment as ODataNavigationPropertySegment)?.NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many; // Valid only for non collection-valued navigation properties if (!lastSegmentIsColNavProp) { foreach (IEdmNavigationProperty navProp in entityType.NavigationProperties()) { string navPropName = navProp.Name; string operationId; string operationPrefix; switch (entityKind) { case "Navigation": // just for contained navigations operationPrefix = navPropOperationId; break; default: // EntitySet, Entity, Singleton operationPrefix = entityName; break; } if (navProp.TargetMultiplicity() == EdmMultiplicity.Many) { operationId = operationPrefix + ".List" + Utils.UpperFirstChar(navPropName); } else { operationId = operationPrefix + ".Get" + Utils.UpperFirstChar(navPropName); } OpenApiLink link = new OpenApiLink { OperationId = operationId, Parameters = new Dictionary <string, RuntimeExpressionAnyWrapper>() }; if (pathKeyNames.Any()) { foreach (var pathKeyName in pathKeyNames) { link.Parameters[pathKeyName] = new RuntimeExpressionAnyWrapper { Any = new OpenApiString("$request.path." + pathKeyName) }; } } links[navProp.Name] = link; } } // Get the Operations and OperationImport paths bound to this (collection of) entity. IEnumerable <ODataPath> operationPaths = context.AllPaths.Where(p => (p.Kind.Equals(ODataPathKind.Operation) || p.Kind.Equals(ODataPathKind.OperationImport)) && path.GetPathItemName().Equals(p.Clone().Pop().GetPathItemName())); // Generate links to the Operations and OperationImport operations. if (operationPaths.Any()) { foreach (var operationPath in operationPaths) { OpenApiLink link = new() { OperationId = string.Join(".", operationPath.Segments.Select(x => { return(x.Kind.Equals(ODataSegmentKind.Key) ? x.EntityType.Name : x.Identifier); })) }; links[operationPath.LastSegment.Identifier] = link; } } return(links); } }
private void VerifyEntitySetPostOperation(string annotation, bool enableOperationId, bool hasStream, bool useHTTPStatusCodeClass2XX) { // Arrange IEdmModel model = GetEdmModel(annotation, hasStream); IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers"); OpenApiConvertSettings settings = new OpenApiConvertSettings { EnableOperationId = enableOperationId, UseSuccessStatusCodeRange = useHTTPStatusCodeClass2XX }; ODataContext context = new ODataContext(model, settings); ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet)); // Act var post = _operationHandler.CreateOperation(context, path); // Assert Assert.NotNull(post); Assert.Equal("Create customer.", post.Summary); Assert.Equal("Create a new customer.", post.Description); Assert.NotNull(post.Tags); var tag = Assert.Single(post.Tags); Assert.Equal("Customers.Customer", tag.Name); Assert.Empty(post.Parameters); Assert.NotNull(post.RequestBody); Assert.NotNull(post.Responses); Assert.Equal(2, post.Responses.Count); var statusCode = useHTTPStatusCodeClass2XX ? Constants.StatusCodeClass2XX : Constants.StatusCode201; if (hasStream) { Assert.NotNull(post.RequestBody); if (!string.IsNullOrEmpty(annotation)) { // RequestBody Assert.Equal(2, post.RequestBody.Content.Keys.Count); Assert.True(post.RequestBody.Content.ContainsKey("application/todo")); Assert.True(post.RequestBody.Content.ContainsKey(Constants.ApplicationJsonMediaType)); // Response Assert.Equal(2, post.Responses[statusCode].Content.Keys.Count); Assert.True(post.Responses[statusCode].Content.ContainsKey("application/todo")); Assert.True(post.Responses[statusCode].Content.ContainsKey(Constants.ApplicationJsonMediaType)); } else { // RequestBody Assert.Equal(2, post.RequestBody.Content.Keys.Count); Assert.True(post.RequestBody.Content.ContainsKey(Constants.ApplicationOctetStreamMediaType)); Assert.True(post.RequestBody.Content.ContainsKey(Constants.ApplicationJsonMediaType)); // Response Assert.Equal(2, post.Responses[statusCode].Content.Keys.Count); Assert.True(post.Responses[statusCode].Content.ContainsKey(Constants.ApplicationOctetStreamMediaType)); Assert.True(post.Responses[statusCode].Content.ContainsKey(Constants.ApplicationJsonMediaType)); } } else { // RequestBody Assert.NotNull(post.RequestBody); Assert.Equal(1, post.RequestBody.Content.Keys.Count); Assert.True(post.RequestBody.Content.ContainsKey(Constants.ApplicationJsonMediaType)); // Response Assert.Equal(1, post.Responses[Constants.StatusCode201].Content.Keys.Count); Assert.True(post.Responses[Constants.StatusCode201].Content.ContainsKey(Constants.ApplicationJsonMediaType)); } if (enableOperationId) { Assert.Equal("Customers.Customer.CreateCustomer", post.OperationId); } else { Assert.Null(post.OperationId); } }
/// <summary> /// Create the list of <see cref="OpenApiSecurityRequirement"/> object. /// </summary> /// <param name="context">The OData to Open API context.</param> /// <param name="securitySchemes">The securitySchemes.</param> /// <returns>The created <see cref="OpenApiSecurityRequirement"/> collection.</returns> public static IEnumerable <OpenApiSecurityRequirement> CreateSecurityRequirements(this ODataContext context, IList <SecurityScheme> securitySchemes) { Utils.CheckArgumentNull(context, nameof(context)); if (securitySchemes != null) { foreach (var securityScheme in securitySchemes) { yield return(new OpenApiSecurityRequirement { [ new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = securityScheme.AuthorizationSchemeName } } ] = new List <string>(securityScheme.RequiredScopes ?? new List <string>()) }); } } }
public PhonesServices(ODataContext context) { this.context = context; }
/// <inheritdoc/> protected override void Initialize(ODataContext context, ODataPath path) { ComplexPropertySegment = path.LastSegment as ODataComplexPropertySegment ?? throw Error.ArgumentNull(nameof(path)); }
/// <summary> /// Create a <see cref="OpenApiSchema"/> for a <see cref="IEdmPrimitiveType"/>. /// </summary> /// <param name="context">The OData context.</param> /// <param name="primitiveType">The Edm primitive type.</param> /// <returns>The created <see cref="OpenApiSchema"/>.</returns> public static OpenApiSchema CreateSchema(this ODataContext context, IEdmPrimitiveType primitiveType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(primitiveType, nameof(primitiveType)); // Spec has different configure for double, AnyOf or OneOf? OpenApiSchema schema = new OpenApiSchema { AllOf = null, OneOf = null, AnyOf = null }; switch (primitiveType.PrimitiveKind) { case EdmPrimitiveTypeKind.Binary: // binary schema.Type = "string"; schema.Format = "base64url"; break; case EdmPrimitiveTypeKind.Boolean: // boolean schema.Type = "boolean"; schema.Default = new OpenApiBoolean(false); break; case EdmPrimitiveTypeKind.Byte: // byte schema.Type = "integer"; schema.Format = "uint8"; break; case EdmPrimitiveTypeKind.DateTimeOffset: // datetime offset schema.Type = "string"; schema.Format = "date-time"; schema.Pattern = "^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?(Z|[+-][0-9][0-9]:[0-9][0-9])$"; break; case EdmPrimitiveTypeKind.Decimal: // decimal if (context.Settings.IEEE754Compatible) { schema.AnyOf = new List <OpenApiSchema> { new OpenApiSchema { Type = "number" }, new OpenApiSchema { Type = "string" }, }; } else { schema.Type = "number"; } schema.Format = "decimal"; break; case EdmPrimitiveTypeKind.Double: // double if (context.Settings.IEEE754Compatible) { schema.AnyOf = new List <OpenApiSchema> { new OpenApiSchema { Type = "number" }, new OpenApiSchema { Type = "string" }, new OpenApiSchema { Enum = new List <IOpenApiAny> { new OpenApiString("-INF"), new OpenApiString("INF"), new OpenApiString("NaN") } } }; } else { schema.Type = "number"; } schema.Format = "double"; break; case EdmPrimitiveTypeKind.Single: // single if (context.Settings.IEEE754Compatible) { schema.AnyOf = new List <OpenApiSchema> { new OpenApiSchema { Type = "number" }, new OpenApiSchema { Type = "string" }, new OpenApiSchema { Enum = new List <IOpenApiAny> { new OpenApiString("-INF"), new OpenApiString("INF"), new OpenApiString("NaN") } } }; } else { schema.Type = "number"; } schema.Format = "float"; break; case EdmPrimitiveTypeKind.Guid: // guid schema.Type = "string"; schema.Format = "uuid"; schema.Pattern = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"; break; case EdmPrimitiveTypeKind.Int16: schema.Type = "integer"; schema.Format = "int16"; schema.Minimum = Int16.MinValue; // -32768 schema.Maximum = Int16.MaxValue; // 32767 break; case EdmPrimitiveTypeKind.Int32: schema.Type = "integer"; schema.Format = "int32"; schema.Minimum = Int32.MinValue; // -2147483648 schema.Maximum = Int32.MaxValue; // 2147483647 break; case EdmPrimitiveTypeKind.Int64: if (context.Settings.IEEE754Compatible) { schema.AnyOf = new List <OpenApiSchema> { new OpenApiSchema { Type = "integer" }, new OpenApiSchema { Type = "string" } }; } else { schema.Type = "integer"; } schema.Format = "int64"; break; case EdmPrimitiveTypeKind.SByte: schema.Type = "integer"; schema.Format = "int8"; schema.Minimum = SByte.MinValue; // -128 schema.Maximum = SByte.MaxValue; // 127 break; case EdmPrimitiveTypeKind.String: // string schema.Type = "string"; break; case EdmPrimitiveTypeKind.Stream: // stream schema.Type = "string"; schema.Format = "base64url"; break; case EdmPrimitiveTypeKind.Duration: // duration schema.Type = "string"; schema.Format = "duration"; schema.Pattern = "^-?P([0-9]+D)?(T([0-9]+H)?([0-9]+M)?([0-9]+([.][0-9]+)?S)?)?$"; break; case EdmPrimitiveTypeKind.Date: schema.Type = "string"; schema.Format = "date"; schema.Pattern = "^[0-9]{4,}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])$"; break; case EdmPrimitiveTypeKind.TimeOfDay: schema.Type = "string"; schema.Format = "time"; schema.Pattern = "^([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]([.][0-9]{1,12})?$"; break; case EdmPrimitiveTypeKind.Geography: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.Geography" }; break; case EdmPrimitiveTypeKind.GeographyPoint: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeographyPoint" }; break; case EdmPrimitiveTypeKind.GeographyLineString: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeographyLineString" }; break; case EdmPrimitiveTypeKind.GeographyPolygon: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeographyPolygon" }; break; case EdmPrimitiveTypeKind.GeographyCollection: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeographyCollection" }; break; case EdmPrimitiveTypeKind.GeographyMultiPolygon: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeographyMultiPolygon" }; break; case EdmPrimitiveTypeKind.GeographyMultiLineString: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeographyMultiLineString" }; break; case EdmPrimitiveTypeKind.GeographyMultiPoint: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeographyMultiPoint" }; break; case EdmPrimitiveTypeKind.Geometry: // Geometry schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.Geometry" }; break; case EdmPrimitiveTypeKind.GeometryPoint: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeometryPoint" }; break; case EdmPrimitiveTypeKind.GeometryLineString: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeometryLineString" }; break; case EdmPrimitiveTypeKind.GeometryPolygon: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeometryPolygon" }; break; case EdmPrimitiveTypeKind.GeometryCollection: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeometryCollection" }; break; case EdmPrimitiveTypeKind.GeometryMultiPolygon: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeometryMultiPolygon" }; break; case EdmPrimitiveTypeKind.GeometryMultiLineString: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeometryMultiLineString" }; break; case EdmPrimitiveTypeKind.GeometryMultiPoint: schema.Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Edm.GeometryMultiPoint" }; break; case EdmPrimitiveTypeKind.None: default: throw new OpenApiException(String.Format(SRResource.NotSupportedEdmTypeKind, primitiveType.PrimitiveKind)); } return(schema); }
public void OperationRestrictionsTermWorksToCreateOperationForEdmAction(bool enableAnnotation) { string template = @"<?xml version=""1.0"" encoding=""utf-8""?> <edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx""> <edmx:DataServices> <Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm""> <EntityType Name=""user"" /> <Action Name=""getMemberGroups"" IsBound=""true""> <Parameter Name=""bindingParameter"" Type=""NS.user"" Nullable=""false"" /> {0} </Action> <EntityContainer Name=""GraphService""> <Singleton Name=""me"" Type=""NS.user"" /> </EntityContainer> </Schema> </edmx:DataServices> </edmx:Edmx> "; string annotation = @"<Annotation Term=""Org.OData.Capabilities.V1.OperationRestrictions""> <Record> <PropertyValue Property=""Permissions""> <Collection> <Record> <PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" /> <PropertyValue Property=""Scopes""> <Collection> <Record> <PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""User.Read.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""Directory.Read.All"" /> </Record> </Collection> </PropertyValue> </Record> <Record> <PropertyValue Property=""SchemeName"" String=""Application"" /> <PropertyValue Property=""Scopes""> <Collection> <Record> <PropertyValue Property=""Scope"" String=""User.Read.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""Directory.Read.All"" /> </Record> </Collection> </PropertyValue> </Record> </Collection> </PropertyValue> </Record> </Annotation>"; // Arrange string csdl = string.Format(template, enableAnnotation ? annotation : ""); var edmModel = CsdlReader.Parse(XElement.Parse(csdl).CreateReader()); Assert.NotNull(edmModel); IEdmSingleton me = edmModel.EntityContainer.FindSingleton("me"); Assert.NotNull(me); IEdmAction action = edmModel.SchemaElements.OfType <IEdmAction>().SingleOrDefault(); Assert.NotNull(action); Assert.Equal("getMemberGroups", action.Name); ODataContext context = new ODataContext(edmModel); ODataPath path = new ODataPath(new ODataNavigationSourceSegment(me), new ODataOperationSegment(action)); // Act var operation = _operationHandler.CreateOperation(context, path); // Assert Assert.NotNull(operation); Assert.NotNull(operation.Security); if (enableAnnotation) { Assert.Equal(2, operation.Security.Count); string json = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); Assert.Contains(@" ""security"": [ { ""Delegated (work or school account)"": [ ""User.ReadBasic.All"", ""User.Read.All"", ""Directory.Read.All"" ] }, { ""Application"": [ ""User.Read.All"", ""Directory.Read.All"" ] } ],".ChangeLineBreaks(), json); } else { Assert.Empty(operation.Security); } }
/// <summary> /// Create the dictionary of <see cref="OpenApiSecurityScheme"/> object. /// The name of each pair is the name of authorization. The value of each pair is a <see cref="OpenApiSecurityScheme"/>. /// </summary> /// <param name="context">The OData to Open API context.</param> /// <returns>The string/security scheme dictionary.</returns> public static IDictionary <string, OpenApiSecurityScheme> CreateSecuritySchemes(this ODataContext context) { Utils.CheckArgumentNull(context, nameof(context)); if (context.Model == null || context.Model.EntityContainer == null) { return(null); } IDictionary <string, OpenApiSecurityScheme> securitySchemes = new Dictionary <string, OpenApiSecurityScheme>(); var authorizations = context.Model.GetAuthorizations(context.EntityContainer); if (authorizations == null) { return(securitySchemes); } foreach (var authorization in authorizations) { OpenApiSecurityScheme scheme = new OpenApiSecurityScheme { Type = authorization.SchemeType, Description = authorization.Description }; switch (authorization.SchemeType) { case SecuritySchemeType.ApiKey: // ApiKey AppendApiKey(scheme, (ApiKey)authorization); break; case SecuritySchemeType.Http: // Http AppendHttp(scheme, (Http)authorization); break; case SecuritySchemeType.OpenIdConnect: // OpenIdConnect AppendOpenIdConnect(scheme, (OpenIDConnect)authorization); break; case SecuritySchemeType.OAuth2: // OAuth2 AppendOAuth2(scheme, (OAuthAuthorization)authorization); break; } securitySchemes[authorization.Name] = scheme; } return(securitySchemes); }
/// <summary> /// Create a map of string/<see cref="OpenApiSchema"/> map for a <see cref="IEdmStructuredType"/>'s all properties. /// </summary> /// <param name="context">The OData context.</param> /// <param name="structuredType">The Edm structured type.</param> /// <returns>The created map of <see cref="OpenApiSchema"/>.</returns> public static IDictionary <string, OpenApiSchema> CreateStructuredTypePropertiesSchema(this ODataContext context, IEdmStructuredType structuredType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(structuredType, nameof(structuredType)); // The name is the property name, the value is a Schema Object describing the allowed values of the property. IDictionary <string, OpenApiSchema> properties = new Dictionary <string, OpenApiSchema>(); // structure properties foreach (var property in structuredType.DeclaredStructuralProperties()) { // OpenApiSchema propertySchema = property.Type.CreateSchema(); // propertySchema.Default = property.DefaultValueString != null ? new OpenApiString(property.DefaultValueString) : null; properties.Add(property.Name, context.CreatePropertySchema(property)); } // navigation properties foreach (var property in structuredType.DeclaredNavigationProperties()) { OpenApiSchema propertySchema = context.CreateEdmTypeSchema(property.Type); propertySchema.Description = context.Model.GetDescriptionAnnotation(property); properties.Add(property.Name, propertySchema); } return(properties); }
protected ODataTestes() { context = CreateContext(); }
private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType, bool processBase, bool processExample) { Debug.Assert(context != null); Debug.Assert(structuredType != null); if (processBase && structuredType.BaseType != null) { // A structured type with a base type is represented as a Schema Object // that contains the keyword allOf whose value is an array with two items: return(new OpenApiSchema { AllOf = new List <OpenApiSchema> { // 1. a JSON Reference to the Schema Object of the base type new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = structuredType.BaseType.FullTypeName() } }, // 2. a Schema Object describing the derived type context.CreateStructuredTypeSchema(structuredType, false, false) }, AnyOf = null, OneOf = null, Properties = null, Example = CreateStructuredTypePropertiesExample(context, structuredType) }); } else { // A structured type without a base type is represented as a Schema Object of type object OpenApiSchema schema = new OpenApiSchema { Title = (structuredType as IEdmSchemaElement)?.Name, Type = "object", // Each structural property and navigation property is represented // as a name/value pair of the standard OpenAPI properties object. Properties = context.CreateStructuredTypePropertiesSchema(structuredType), // make others null AllOf = null, OneOf = null, AnyOf = null }; // It optionally can contain the field description, // whose value is the value of the unqualified annotation Core.Description of the structured type. if (structuredType.TypeKind == EdmTypeKind.Complex) { IEdmComplexType complex = (IEdmComplexType)structuredType; schema.Description = context.Model.GetDescriptionAnnotation(complex); } else if (structuredType.TypeKind == EdmTypeKind.Entity) { IEdmEntityType entity = (IEdmEntityType)structuredType; schema.Description = context.Model.GetDescriptionAnnotation(entity); } if (processExample) { schema.Example = CreateStructuredTypePropertiesExample(context, structuredType); } return(schema); } }
protected override void Initialize(ODataContext context, ODataPath path) { base.Initialize(context, path); _updateRestrictions = Context.Model.GetRecord <UpdateRestrictionsType>(Singleton, CapabilitiesConstants.UpdateRestrictions); }
public PeopleServices(ODataContext context) { this.context = context; }
/// <summary> /// Initialize the handler. /// It should be call ahead of in derived class. /// </summary> /// <param name="context">The context.</param> /// <param name="path">The path.</param> protected virtual void Initialize(ODataContext context, ODataPath path) { }
public void CreateComplexTypeWithBaseSchemaReturnCorrectSchema() { // Arrange IEdmModel model = EdmModelHelper.MultipleInheritanceEdmModel; ODataContext context = new ODataContext(model, new OpenApiConvertSettings { IEEE754Compatible = true }); IEdmComplexType complex = model.SchemaElements.OfType <IEdmComplexType>().First(t => t.Name == "Tree"); Assert.NotNull(complex); // Guard // Act var schema = context.CreateStructuredTypeSchema(complex); // Assert Assert.NotNull(schema); Assert.True(String.IsNullOrEmpty(schema.Type)); Assert.NotNull(schema.AllOf); Assert.Null(schema.AnyOf); Assert.Null(schema.OneOf); Assert.Null(schema.Properties); Assert.Equal(2, schema.AllOf.Count); var baseSchema = schema.AllOf.First(); Assert.NotNull(baseSchema.Reference); Assert.Equal(ReferenceType.Schema, baseSchema.Reference.Type); Assert.Equal("NS.LandPlant", baseSchema.Reference.Id); var declaredSchema = schema.AllOf.Last(); Assert.Equal("object", declaredSchema.Type); Assert.Null(declaredSchema.AllOf); Assert.Null(declaredSchema.AnyOf); Assert.Null(declaredSchema.OneOf); Assert.NotNull(declaredSchema.Properties); Assert.Equal(1, declaredSchema.Properties.Count); var property = Assert.Single(declaredSchema.Properties); Assert.Equal("Price", property.Key); Assert.Equal("decimal", property.Value.Format); Assert.NotNull(property.Value.AnyOf); Assert.Equal(new string[] { "number", "string" }, property.Value.AnyOf.Select(e => e.Type)); Assert.Equal("Complex type 'Tree' description.", declaredSchema.Description); Assert.Equal("Tree", declaredSchema.Title); // Act string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); // Assert Assert.NotNull(json); Assert.Equal(@"{ ""allOf"": [ { ""$ref"": ""#/components/schemas/NS.LandPlant"" }, { ""title"": ""Tree"", ""type"": ""object"", ""properties"": { ""Price"": { ""multipleOf"": 1, ""anyOf"": [ { ""type"": ""number"" }, { ""type"": ""string"" } ], ""format"": ""decimal"" } }, ""description"": ""Complex type 'Tree' description."" } ], ""example"": { ""Color"": { ""@odata.type"": ""NS.Color"" }, ""Continent"": { ""@odata.type"": ""NS.Continent"" }, ""Name"": ""string"", ""Price"": ""decimal"" } }" .ChangeLineBreaks(), json); }
public void CreateEntitySetGetOperationReturnsSecurityForReadRestrictions(bool enableAnnotation) { string annotation = @"<Annotation Term=""Org.OData.Capabilities.V1.ReadRestrictions""> <Record> <PropertyValue Property=""Permissions""> <Collection> <Record> <PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" /> <PropertyValue Property=""Scopes""> <Collection> <Record> <PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""User.Read.All"" /> </Record> </Collection> </PropertyValue> </Record> <Record> <PropertyValue Property=""SchemeName"" String=""Application"" /> <PropertyValue Property=""Scopes""> <Collection> <Record> <PropertyValue Property=""Scope"" String=""User.Read.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""Directory.Read.All"" /> </Record> </Collection> </PropertyValue> </Record> </Collection> </PropertyValue> <PropertyValue Property=""CustomHeaders""> <Collection> <Record> <PropertyValue Property=""Name"" String=""odata-debug"" /> <PropertyValue Property=""Description"" String=""Debug support for OData services"" /> <PropertyValue Property=""Required"" Bool=""false"" /> <PropertyValue Property=""ExampleValues""> <Collection> <Record> <PropertyValue Property=""Value"" String=""html"" /> <PropertyValue Property=""Description"" String=""Service responds with self-contained..."" /> </Record> <Record> <PropertyValue Property=""Value"" String=""json"" /> <PropertyValue Property=""Description"" String=""Service responds with JSON document..."" /> </Record> </Collection> </PropertyValue> </Record> </Collection> </PropertyValue> </Record> </Annotation>"; // Arrange IEdmModel model = GetEdmModel(enableAnnotation ? annotation : ""); ODataContext context = new ODataContext(model); IEdmEntitySet customers = model.EntityContainer.FindEntitySet("Customers"); Assert.NotNull(customers); // guard ODataPath path = new ODataPath(new ODataNavigationSourceSegment(customers)); // Act var get = _operationHandler.CreateOperation(context, path); // Assert Assert.NotNull(get); Assert.NotNull(get.Security); if (enableAnnotation) { Assert.Equal(2, get.Security.Count); string json = get.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); Assert.Contains(@" ""security"": [ { ""Delegated (work or school account)"": [ ""User.ReadBasic.All"", ""User.Read.All"" ] }, { ""Application"": [ ""User.Read.All"", ""Directory.Read.All"" ] } ]".ChangeLineBreaks(), json); } else { Assert.Empty(get.Security); } }
public PersonNumbersServices(ODataContext context) { this.context = context; }
/// <summary> /// Create $orderby parameter for the <see cref="IEdmEntitySet"/>. /// </summary> /// <param name="context">The OData context.</param> /// <param name="target">The Edm annotation target.</param> /// <returns>The created <see cref="OpenApiParameter"/> or null.</returns> public static OpenApiParameter CreateOrderBy(this ODataContext context, IEdmVocabularyAnnotatable target, IEdmEntityType entityType) { Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(target, nameof(target)); Utils.CheckArgumentNull(entityType, nameof(entityType)); SortRestrictionsType sort = context.Model.GetRecord <SortRestrictionsType>(target, CapabilitiesConstants.SortRestrictions); if (sort != null && !sort.IsSortable) { return(null); } IList <IOpenApiAny> orderByItems = new List <IOpenApiAny>(); foreach (var property in entityType.StructuralProperties()) { if (sort != null && sort.IsNonSortableProperty(property.Name)) { continue; } bool isAscOnly = sort != null?sort.IsAscendingOnlyProperty(property.Name) : false; bool isDescOnly = sort != null?sort.IsDescendingOnlyProperty(property.Name) : false; if (isAscOnly || isDescOnly) { if (isAscOnly) { orderByItems.Add(new OpenApiString(property.Name)); } else { orderByItems.Add(new OpenApiString(property.Name + " desc")); } } else { orderByItems.Add(new OpenApiString(property.Name)); orderByItems.Add(new OpenApiString(property.Name + " desc")); } } return(new OpenApiParameter { Name = "$orderby", In = ParameterLocation.Query, Description = "Order items by property values", Schema = new OpenApiSchema { Type = "array", UniqueItems = true, Items = new OpenApiSchema { Type = "string", Enum = orderByItems } }, Style = ParameterStyle.Form }); }
/// <summary> /// Create the collection of <see cref="OpenApiLink"/> object. /// </summary> /// <param name="context">The OData context.</param> /// <param name="entityType">The Entity type.</param> /// <param name ="entityName">The name of the source of the <see cref="IEdmEntityType"/> object.</param> /// <param name="entityKind">"The kind of the source of the <see cref="IEdmEntityType"/> object.</param> /// <param name="parameters">"The list of parameters of the incoming operation.</param> /// <param name="navPropOperationId">Optional parameter: The operation id of the source of the NavigationProperty object.</param> /// <returns>The created dictionary of <see cref="OpenApiLink"/> object.</returns> public static IDictionary <string, OpenApiLink> CreateLinks(this ODataContext context, IEdmEntityType entityType, string entityName, string entityKind, IList <OpenApiParameter> parameters, string navPropOperationId = null) { IDictionary <string, OpenApiLink> links = new Dictionary <string, OpenApiLink>(); Utils.CheckArgumentNull(context, nameof(context)); Utils.CheckArgumentNull(entityType, nameof(entityType)); Utils.CheckArgumentNullOrEmpty(entityName, nameof(entityName)); Utils.CheckArgumentNullOrEmpty(entityKind, nameof(entityKind)); Utils.CheckArgumentNull(parameters, nameof(parameters)); List <string> pathKeyNames = new List <string>(); // Fetch defined Id(s) from incoming parameters (if any) foreach (var parameter in parameters) { if (!string.IsNullOrEmpty(parameter.Description) && parameter.Description.ToLower().Contains("key")) { pathKeyNames.Add(parameter.Name); } } foreach (IEdmNavigationProperty navProp in entityType.NavigationProperties()) { string navPropName = navProp.Name; string operationId; string operationPrefix; switch (entityKind) { case "Navigation": // just for contained navigations operationPrefix = navPropOperationId; break; default: // EntitySet, Entity, Singleton operationPrefix = entityName; break; } if (navProp.TargetMultiplicity() == EdmMultiplicity.Many) { operationId = operationPrefix + ".List" + Utils.UpperFirstChar(navPropName); } else { operationId = operationPrefix + ".Get" + Utils.UpperFirstChar(navPropName); } OpenApiLink link = new OpenApiLink { OperationId = operationId, Parameters = new Dictionary <string, RuntimeExpressionAnyWrapper>() }; if (pathKeyNames.Any()) { foreach (var pathKeyName in pathKeyNames) { link.Parameters[pathKeyName] = new RuntimeExpressionAnyWrapper { Any = new OpenApiString("$request.path." + pathKeyName) }; } } links[navProp.Name] = link; } return(links); }
private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType, bool processBase, bool processExample, IEnumerable <IEdmEntityType> derivedTypes = null) { Debug.Assert(context != null); Debug.Assert(structuredType != null); if (context.Settings.EnableDiscriminatorValue && derivedTypes == null) { derivedTypes = context.Model.FindDirectlyDerivedTypes(structuredType).OfType <IEdmEntityType>(); } if (processBase && structuredType.BaseType != null) { // The x-ms-discriminator-value extension is added to structured types which are derived types. Dictionary <string, IOpenApiExtension> extension = null; if (context.Settings.EnableDiscriminatorValue && !derivedTypes.Any()) { extension = new Dictionary <string, IOpenApiExtension> { { Constants.xMsDiscriminatorValue, new OpenApiString("#" + structuredType.FullTypeName()) } }; } // A structured type with a base type is represented as a Schema Object // that contains the keyword allOf whose value is an array with two items: return(new OpenApiSchema { Extensions = extension, AllOf = new List <OpenApiSchema> { // 1. a JSON Reference to the Schema Object of the base type new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = structuredType.BaseType.FullTypeName() } }, // 2. a Schema Object describing the derived type context.CreateStructuredTypeSchema(structuredType, false, false, derivedTypes) }, AnyOf = null, OneOf = null, Properties = null, Example = CreateStructuredTypePropertiesExample(context, structuredType) }); } else { // The discriminator object is added to structured types which have derived types. OpenApiDiscriminator discriminator = null; if (context.Settings.EnableDiscriminatorValue && derivedTypes.Any() && structuredType.BaseType != null) { discriminator = new OpenApiDiscriminator { PropertyName = "@odata.type" }; } // A structured type without a base type is represented as a Schema Object of type object OpenApiSchema schema = new OpenApiSchema { Title = (structuredType as IEdmSchemaElement)?.Name, Type = "object", Discriminator = discriminator, // Each structural property and navigation property is represented // as a name/value pair of the standard OpenAPI properties object. Properties = context.CreateStructuredTypePropertiesSchema(structuredType), // make others null AllOf = null, OneOf = null, AnyOf = null }; // It optionally can contain the field description, // whose value is the value of the unqualified annotation Core.Description of the structured type. if (structuredType.TypeKind == EdmTypeKind.Complex) { IEdmComplexType complex = (IEdmComplexType)structuredType; schema.Description = context.Model.GetDescriptionAnnotation(complex); } else if (structuredType.TypeKind == EdmTypeKind.Entity) { IEdmEntityType entity = (IEdmEntityType)structuredType; schema.Description = context.Model.GetDescriptionAnnotation(entity); } if (processExample) { schema.Example = CreateStructuredTypePropertiesExample(context, structuredType); } return(schema); } }
/// <summary> /// Adds a mapping of custom extension values against custom attribute values for a given element to the provided /// extensions object. /// </summary> /// <param name="extensions">The target extensions object in which the mapped extensions and custom attribute /// values will be added to.</param> /// <param name="context">The OData context.</param> /// <param name="element">The target element.</param> internal static void AddCustomAtributesToExtensions(this IDictionary <string, IOpenApiExtension> extensions, ODataContext context, IEdmElement element) { if (extensions == null || context == null || element == null) { return; } Dictionary <string, string> atrributesValueMap = GetCustomXMLAtrributesValueMapping(context.Model, element, context.Settings.CustomXMLAttributesMapping); if (atrributesValueMap?.Any() ?? false) { foreach (var item in atrributesValueMap) { extensions.TryAdd(item.Key, new OpenApiString(item.Value)); } } }
public void ReadRestrictionsTermWorksToCreateOperationForSingletonGetOperation(bool enableAnnotation) { string annotation = @"<Annotation Term=""Org.OData.Capabilities.V1.ReadRestrictions""> <Record> <PropertyValue Property=""Permissions""> <Collection> <Record> <PropertyValue Property=""SchemeName"" String=""Delegated (work or school account)"" /> <PropertyValue Property=""Scopes""> <Collection> <Record> <PropertyValue Property=""Scope"" String=""User.ReadBasic.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""User.Read.All"" /> </Record> </Collection> </PropertyValue> </Record> <Record> <PropertyValue Property=""SchemeName"" String=""Application"" /> <PropertyValue Property=""Scopes""> <Collection> <Record> <PropertyValue Property=""Scope"" String=""User.Read.All"" /> </Record> <Record> <PropertyValue Property=""Scope"" String=""Directory.Read.All"" /> </Record> </Collection> </PropertyValue> </Record> </Collection> </PropertyValue> <PropertyValue Property=""Description"" String=""A brief description of GET '/me' request."" /> <PropertyValue Property=""CustomHeaders""> <Collection> <Record> <PropertyValue Property=""Name"" String=""odata-debug"" /> <PropertyValue Property=""Description"" String=""Debug support for OData services"" /> <PropertyValue Property=""Required"" Bool=""false"" /> <PropertyValue Property=""ExampleValues""> <Collection> <Record> <PropertyValue Property=""Value"" String=""html"" /> <PropertyValue Property=""Description"" String=""Service responds with self-contained..."" /> </Record> <Record> <PropertyValue Property=""Value"" String=""json"" /> <PropertyValue Property=""Description"" String=""Service responds with JSON document..."" /> </Record> </Collection> </PropertyValue> </Record> </Collection> </PropertyValue> </Record> </Annotation>"; // Arrange var edmModel = GetEdmModel(enableAnnotation ? annotation : ""); Assert.NotNull(edmModel); IEdmSingleton me = edmModel.EntityContainer.FindSingleton("Me"); Assert.NotNull(me); ODataContext context = new ODataContext(edmModel); ODataPath path = new ODataPath(new ODataNavigationSourceSegment(me)); // Act var operation = _operationHandler.CreateOperation(context, path); // Assert Assert.NotNull(operation); Assert.NotNull(operation.Security); if (enableAnnotation) { Assert.Equal(2, operation.Security.Count); string json = operation.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0); Assert.Contains(@" ""security"": [ { ""Delegated (work or school account)"": [ ""User.ReadBasic.All"", ""User.Read.All"" ] }, { ""Application"": [ ""User.Read.All"", ""Directory.Read.All"" ] } ],".ChangeLineBreaks(), json); // with custom header Assert.Contains(@" ""parameters"": [ { ""name"": ""odata-debug"", ""in"": ""header"", ""description"": ""Debug support for OData services"", ""schema"": { ""type"": ""string"" }, ""examples"": { ""example-1"": { ""description"": ""Service responds with self-contained..."", ""value"": ""html"" }, ""example-2"": { ""description"": ""Service responds with JSON document..."", ""value"": ""json"" } } }, {".ChangeLineBreaks(), json); } else { Assert.Empty(operation.Security); } }