/// <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> CreateStructuredTypeCombinedPropertiesSchema(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.StructuralProperties()) { // OpenApiSchema propertySchema = property.Type.CreateSchema(); // propertySchema.Default = property.DefaultValueString != null ? new OpenApiString(property.DefaultValueString) : null; if (property.Type.FullName() != structuredType.FullTypeName() && property.Type.FullName() != $"Collection({structuredType.FullTypeName()})") { properties.Add(property.Name, context.CreatePropertySchema(property)); } } // navigation properties foreach (var property in structuredType.NavigationProperties()) { if (property.Type.FullName() != structuredType.FullTypeName() && property.Type.FullName() != $"Collection({structuredType.FullTypeName()})") { OpenApiSchema propertySchema = context.CreateEdmTypeSchema(property.Type); properties.Add(property.Name, propertySchema); } } return(properties); }
/// <summary> /// Build a segment from a token. /// </summary> /// <param name="tokenIn">the token to bind</param> /// <param name="model">The model.</param> /// <param name="edmType">the type of the current scope based on type segments.</param> /// <param name="resolver">Resolver for uri parser.</param> /// <returns>The segment created from the token.</returns> public static ODataPathSegment ConvertNonTypeTokenToSegment(PathSegmentToken tokenIn, IEdmModel model, IEdmStructuredType edmType, ODataUriResolver resolver) { ExceptionUtils.CheckArgumentNotNull(resolver, "resolver"); ODataPathSegment nextSegment; if (TryBindAsDeclaredProperty(tokenIn, edmType, resolver, out nextSegment)) { return(nextSegment); } // Operations must be container-qualified, and because the token type indicates it was not a .-seperated identifier, we should not try to look up operations. if (tokenIn.IsNamespaceOrContainerQualified()) { if (TryBindAsOperation(tokenIn, model, edmType, out nextSegment)) { return(nextSegment); } // If an action or function is requested in a selectItem using a qualifiedActionName or a qualifiedFunctionName // and that operation cannot be bound to the entities requested, the service MUST ignore the selectItem. if (!edmType.IsOpen) { return(null); } } if (edmType.IsOpen) { return(new DynamicPathSegment(tokenIn.Identifier)); } throw ExceptionUtil.CreatePropertyNotFoundException(tokenIn.Identifier, edmType.FullTypeName()); }
// OData formatter requires the type name of the entity that is being written if the type has derived types. // Expression // source is GrandChild ? "GrandChild" : ( source is Child ? "Child" : "Root" ) // Notice that the order is important here. The most derived type must be the first to check. // If entity framework had a way to figure out the type name without selecting the whole object, we don't have to do this magic. internal static Expression CreateTypeNameExpression(Expression source, IEdmStructuredType elementType, IEdmModel model) { IReadOnlyList <IEdmStructuredType> derivedTypes = GetAllDerivedTypes(elementType, model); if (derivedTypes.Count == 0) { // no inheritance. return(null); } else { Expression expression = Expression.Constant(elementType.FullTypeName()); for (int i = 0; i < derivedTypes.Count; i++) { Type clrType = EdmLibHelpers.GetClrType(derivedTypes[i], model); if (clrType == null) { throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType, derivedTypes[0].FullTypeName())); } expression = Expression.Condition( test: Expression.TypeIs(source, clrType), ifTrue: Expression.Constant(derivedTypes[i].FullTypeName()), ifFalse: expression); } return(expression); } }
private static RecordSchema GetSchemaFromModel(IEdmStructuredType type) { RecordSchema rs = Schema.CreateRecord(type.FullTypeName(), null); Schema.SetFields(rs, type.Properties().Select(property => Schema.CreateField(property.Name, GetSchemaFromModel(property.Type)))); return(rs); }
/// <summary> /// Writes an OData feed. /// </summary> /// <param name="writer">The ODataWriter that will write the feed.</param> /// <param name="entityType">The type of the entity in the feed.</param> /// <param name="entries">The items from the data store to write to the feed.</param> /// <param name="entitySet">The entity set in the model that the feed belongs to.</param> /// <param name="targetVersion">The OData version this segment is targeting.</param> /// <param name="selectExpandClause">The SelectExpandClause.</param> public static void WriteFeed(ODataWriter writer, IEdmStructuredType entityType, IEnumerable entries, IEdmEntitySetBase entitySet, ODataVersion targetVersion, SelectExpandClause selectExpandClause, long?count, Uri deltaLink, Uri nextPageLink, Dictionary <string, string> incomingHeaders = null) { var feed = new ODataResourceSet { Id = entitySet == null ? null : new Uri(ServiceConstants.ServiceBaseUri, entitySet.Name), DeltaLink = deltaLink, NextPageLink = nextPageLink }; if (entitySet == null) { feed.SetSerializationInfo(new ODataResourceSerializationInfo() { NavigationSourceEntityTypeName = entityType.FullTypeName(), NavigationSourceName = null, NavigationSourceKind = EdmNavigationSourceKind.UnknownEntitySet, IsFromCollection = true }); } if (count.HasValue) { feed.Count = count; } writer.WriteStart(feed); foreach (var element in entries) { WriteEntry(writer, element, entitySet, targetVersion, selectExpandClause, incomingHeaders); } writer.WriteEnd(); }
internal EdmTypeKey(IEdmStructuredType type, ApiVersion apiVersion) { Contract.Requires(type != null); Contract.Requires(apiVersion != null); hashCode = ComputeHash(type.FullTypeName(), apiVersion); }
private static RecordSchema GetSchemaFromModel(IEdmStructuredType type) { if (type.IsOpen) { throw new ApplicationException("not supported."); } RecordSchema rs = Schema.CreateRecord(type.FullTypeName(), null); Schema.SetFields(rs, type.Properties().Select(property => Schema.CreateField(property.Name, GetSchemaFromModel(property.Type)))); return(rs); }
private static IOpenApiAny CreateStructuredTypePropertiesExample(ODataContext context, IEdmStructuredType structuredType) { OpenApiObject example = new OpenApiObject(); IEdmEntityType entityType = structuredType as IEdmEntityType; // properties foreach (var property in structuredType.Properties()) { // Remove properties of the same type as they are not supported by PowerApps if (property.Type.FullName() != structuredType.FullTypeName() && property.Type.FullName() != $"Collection({structuredType.FullTypeName()})") { // IOpenApiAny item; IEdmTypeReference propertyType = property.Type; IOpenApiAny item = GetTypeNameForExample(context, propertyType); EdmTypeKind typeKind = propertyType.TypeKind(); if (typeKind == EdmTypeKind.Primitive && item is OpenApiString) { OpenApiString stringAny = item as OpenApiString; string value = stringAny.Value; if (entityType != null && entityType.Key().Any(k => k.Name == property.Name)) { value += " (identifier)"; } if (propertyType.IsDateTimeOffset() || propertyType.IsDate() || propertyType.IsTimeOfDay()) { value += " (timestamp)"; } item = new OpenApiString(value); } example.Add(property.Name, item); } } return(example); }
private static bool ApplyDynamicProperty(ODataProperty property, IEdmStructuredType structuredType, object resource, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext) { PropertyInfo propertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(structuredType, readContext.Model); if (propertyInfo == null) { return(false); } IDictionary <string, object> dynamicPropertyDictionary = propertyInfo.GetValue(resource) as IDictionary <string, object>; if (dynamicPropertyDictionary == null) { dynamicPropertyDictionary = new Dictionary <string, object>(); propertyInfo.SetValue(resource, dynamicPropertyDictionary); } if (dynamicPropertyDictionary.ContainsKey(property.Name)) { throw Error.InvalidOperation(SRResources.DuplicateDynamicPropertyNameFound, property.Name, structuredType.FullTypeName()); } EdmTypeKind propertyKind; IEdmTypeReference propertyType = null; object value = ConvertValue(property.Value, ref propertyType, deserializerProvider, readContext, out propertyKind); if (propertyKind == EdmTypeKind.Collection) { throw Error.InvalidOperation(SRResources.CollectionNotAllowedAsDynamicProperty, property.Name); } if (propertyKind == EdmTypeKind.Enum) { ODataEnumValue enumValue = (ODataEnumValue)value; IEdmModel model = readContext.Model; IEdmType edmType = model.FindType(enumValue.TypeName); if (edmType == null) { return(false); } Type enumType = EdmLibHelpers.GetClrType(edmType, model); value = Enum.Parse(enumType, enumValue.Value); } dynamicPropertyDictionary.Add(property.Name, value); return(true); }
public PropertySerializationInfo GetProperty(IEdmModel model, int depth, string name, IEdmStructuredType owningType) { PropertySerializationInfo propertyInfo; PropertyKey propertyKey = new PropertyKey(depth, name, owningType?.FullTypeName()); if (!propertyInfoDictionary.TryGetValue(propertyKey, out propertyInfo)) { propertyInfo = new PropertySerializationInfo(model, name, owningType); propertyInfoDictionary[propertyKey] = propertyInfo; } return(propertyInfo); }
private static OpenApiSchema CreateCollectionSchema(ODataContext context, IEdmStructuredType structuredType) { OpenApiSchema schema = null; var entityType = structuredType as IEdmEntityType; if (context.Settings.EnableDerivedTypesReferencesForResponses && entityType != null) { schema = EdmModelHelper.GetDerivedTypesReferenceSchema(entityType, context.Model); } if (schema == null) { schema = new OpenApiSchema { UnresolvedReference = true, Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = entityType?.FullName() ?? structuredType.FullTypeName() } }; } return(CreateCollectionSchema(context, schema, entityType?.Name ?? structuredType.FullTypeName())); }
public PropertySerializationInfo GetProperty(IEdmModel model, string name, IEdmStructuredType owningType) { int depth = this.currentResourceScopeLevel - this.resourceSetScopeLevel; Debug.Assert(depth >= 1, "'depth' should always be greater than or equal to 1"); // In production, depthStr == 1 in most cases. So we optimize string allocation for this case. string depthStr = depth == 1 ? string.Empty : depth.ToString(CultureInfo.InvariantCulture); string uniqueName = owningType != null ? string.Concat(owningType.FullTypeName(), PropertyCacheHandler.PropertyTypeDelimiter, depthStr, name) : string.Concat(depthStr, name); return(this.currentPropertyCache.GetProperty(model, name, uniqueName, owningType)); }
/// <summary> /// If an entity type name is found in the payload this method is called to apply it to the current scope. /// This method should be called even if the type name was not found in which case a null should be passed in. /// The method validates that some type will be available as the current entity type after it returns (if we are parsing using metadata). /// </summary> /// <param name="resourceTypeNameFromPayload">The entity type name found in the payload or null if no type was specified in the payload.</param> protected void ApplyResourceTypeNameFromPayload(string resourceTypeNameFromPayload) { Debug.Assert( this.scopes.Count > 0 && this.scopes.Peek().Item is ODataResourceBase, "Resource type can be applied only when in resource scope."); ODataTypeAnnotation typeAnnotation; EdmTypeKind targetTypeKind; IEdmStructuredTypeReference targetResourceTypeReference = this.inputContext.MessageReaderSettings.Validator.ResolvePayloadTypeNameAndComputeTargetType( EdmTypeKind.None, /*expectStructuredType*/ true, /*defaultPrimitivePayloadType*/ null, this.CurrentResourceTypeReference, resourceTypeNameFromPayload, this.inputContext.Model, () => EdmTypeKind.Entity, out targetTypeKind, out typeAnnotation) as IEdmStructuredTypeReference; IEdmStructuredType targetResourceType = null; ODataResourceBase resource = this.Item as ODataResourceBase; if (targetResourceTypeReference != null) { targetResourceType = targetResourceTypeReference.StructuredDefinition(); resource.TypeName = targetResourceType.FullTypeName(); if (typeAnnotation != null) { resource.TypeAnnotation = typeAnnotation; } } else if (resourceTypeNameFromPayload != null) { resource.TypeName = resourceTypeNameFromPayload; } else if (this.CurrentResourceTypeReference.IsUntyped()) { targetResourceTypeReference = this.CurrentResourceTypeReference.IsNullable ? EdmUntypedStructuredTypeReference.NullableTypeReference : EdmUntypedStructuredTypeReference.NonNullableTypeReference; } // Set the current resource type since the type might be derived from the expected one. this.CurrentResourceTypeReference = targetResourceTypeReference; }
/// <summary> /// Validates the input <see cref="IEdmStructuredType"/> meets the derived type constraints on the odata item. /// </summary> /// <param name="resourceType">The input resource type.</param> /// <param name="metadataType">The type from metadata.</param> /// <param name="derivedTypeConstraints">The derived type constraints on the nested resource.</param> /// <param name="itemKind">The item kind.</param> /// <param name="itemName">The item name.</param> internal static void ValidateDerivedTypeConstraint(IEdmStructuredType resourceType, IEdmStructuredType metadataType, IEnumerable <string> derivedTypeConstraints, string itemKind, string itemName) { if (resourceType == null || metadataType == null || derivedTypeConstraints == null || resourceType == metadataType) { return; } string fullTypeName = resourceType.FullTypeName(); if (derivedTypeConstraints.Any(c => c == fullTypeName)) { return; } throw new ODataException(Strings.WriterValidationUtils_ValueTypeNotAllowedInDerivedTypeConstraint(fullTypeName, itemKind, itemName)); }
internal static void SetDynamicProperty(object resource, string propertyName, object value, IEdmStructuredType structuredType, ODataDeserializerContext readContext) { IDelta delta = resource as IDelta; if (delta != null) { delta.TrySetPropertyValue(propertyName, value); } else { PropertyInfo propertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(structuredType, readContext.Model); if (propertyInfo == null) { return; } IDictionary <string, object> dynamicPropertyDictionary; object dynamicDictionaryObject = propertyInfo.GetValue(resource); if (dynamicDictionaryObject == null) { if (!propertyInfo.CanWrite) { throw Error.InvalidOperation(SRResources.CannotSetDynamicPropertyDictionary, propertyName, resource.GetType().FullName); } dynamicPropertyDictionary = new Dictionary <string, object>(); propertyInfo.SetValue(resource, dynamicPropertyDictionary); } else { dynamicPropertyDictionary = (IDictionary <string, object>)dynamicDictionaryObject; } if (dynamicPropertyDictionary.ContainsKey(propertyName)) { throw Error.InvalidOperation(SRResources.DuplicateDynamicPropertyNameFound, propertyName, structuredType.FullTypeName()); } dynamicPropertyDictionary.Add(propertyName, value); } }
public IDictionary <string, object> ToDictionary(Func <IEdmModel, IEdmStructuredType, IPropertyMapper> mapperProvider) { if (mapperProvider == null) { throw Error.ArgumentNull("mapperProvider"); } Dictionary <string, object> dictionary = new Dictionary <string, object>(); IEdmStructuredType type = GetEdmType().AsStructured().StructuredDefinition(); IPropertyMapper mapper = mapperProvider(GetModel(), type); if (mapper == null) { throw Error.InvalidOperation(SRResources.InvalidPropertyMapper, typeof(IPropertyMapper).FullName, type.FullTypeName()); } if (Container != null) { dictionary = Container.ToDictionary(mapper, includeAutoSelected: false); } // The user asked for all the structural properties on this instance. if (UseInstanceForProperties && UntypedInstance != null) { foreach (IEdmStructuralProperty property in type.StructuralProperties()) { object propertyValue; if (TryGetPropertyValue(property.Name, out propertyValue)) { string mappingName = mapper.MapProperty(property.Name); if (String.IsNullOrWhiteSpace(mappingName)) { throw Error.InvalidOperation(SRResources.InvalidPropertyMapping, property.Name); } dictionary[mappingName] = propertyValue; } } } return(dictionary); }
public PropertySerializationInfo GetProperty(string name, IEdmStructuredType owningType) { StringBuilder uniqueName = new StringBuilder(); if (owningType != null) { uniqueName.Append(owningType.FullTypeName()); uniqueName.Append("-"); } uniqueName.Append(name); if (this.currentResourceScopeLevel != this.resourceSetScopeLevel + 1) { // To avoid the property name conflicts of single navigation property and navigation source uniqueName.Append(this.currentResourceScopeLevel - this.resourceSetScopeLevel); } return(this.currentPropertyCache.GetProperty(name, uniqueName.ToString(), owningType)); }
/// <summary> /// Validates the input <see cref="IEdmStructuredType"/> meets the derived type constraints on the odata item. /// </summary> /// <param name="resourceType">The input resource type.</param> /// <param name="metadataType">The type from metadata.</param> /// <param name="derivedTypeConstraints">The derived type constraints on the nested resource.</param> /// <param name="itemKind">The item kind.</param> /// <param name="itemName">The item name.</param> internal static void ValidateDerivedTypeConstraint(IEdmStructuredType resourceType, IEdmStructuredType metadataType, IEnumerable <string> derivedTypeConstraints, string itemKind, string itemName) { if (resourceType == null || metadataType == null || derivedTypeConstraints == null || resourceType == metadataType) { return; } string fullTypeName = resourceType.FullTypeName(); // this runs in a hot path, hence the use of a loop instead of LINQ to avoid allocations foreach (string c in derivedTypeConstraints) { if (c == fullTypeName) { return; } } throw new ODataException(Strings.WriterValidationUtils_ValueTypeNotAllowedInDerivedTypeConstraint(fullTypeName, itemKind, itemName)); }
/// <summary> /// Build a segment from a token. /// </summary> /// <param name="tokenIn">the token to bind</param> /// <param name="model">The model.</param> /// <param name="edmType">the type of the current scope based on type segments.</param> /// <param name="resolver">Resolver for uri parser.</param> /// <returns>The segment created from the token.</returns> public static ODataPathSegment ConvertNonTypeTokenToSegment(PathSegmentToken tokenIn, IEdmModel model, IEdmStructuredType edmType, ODataUriResolver resolver = null) { if (resolver == null) { resolver = ODataUriResolver.Default; } ODataPathSegment nextSegment; if (TryBindAsDeclaredProperty(tokenIn, edmType, resolver, out nextSegment)) { return nextSegment; } // Operations must be container-qualified, and because the token type indicates it was not a .-seperated identifier, we should not try to look up operations. if (tokenIn.IsNamespaceOrContainerQualified()) { if (TryBindAsOperation(tokenIn, model, edmType, out nextSegment)) { return nextSegment; } // If an action or function is requested in a selectItem using a qualifiedActionName or a qualifiedFunctionName // and that operation cannot be bound to the entities requested, the service MUST ignore the selectItem. if (!edmType.IsOpen) { return null; } } if (edmType.IsOpen) { return new OpenPropertySegment(tokenIn.Identifier); } throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(edmType.FullTypeName(), tokenIn.Identifier)); }
internal static bool ShouldSuppressTypeNameSerialization(ODataResource resource, IEdmStructuredType edmType, ODataMetadataLevel metadataLevel) { Contract.Assert(resource != null); switch (metadataLevel) { case ODataMetadataLevel.NoMetadata: return(true); case ODataMetadataLevel.FullMetadata: return(false); case ODataMetadataLevel.MinimalMetadata: default: // All values already specified; just keeping the compiler happy. string pathTypeName = null; if (edmType != null) { pathTypeName = edmType.FullTypeName(); } string resourceTypeName = resource.TypeName; return(String.Equals(resourceTypeName, pathTypeName, StringComparison.Ordinal)); } }
/// <summary> /// Verifies that CreateResourceReader, CreateResourceSetReader, CreateDeltaResourceSetReader or CreateDeltaReader can be called. /// </summary> /// <param name="navigationSource">The navigation source we are going to read resources for.</param> /// <param name="structuredType">The expected structured type for the resource/resource set to be read.</param> private void VerifyCanCreateODataReader(IEdmNavigationSource navigationSource, IEdmStructuredType structuredType) { Debug.Assert(navigationSource == null || structuredType != null, "If an navigation source is specified, the structured type must be specified as well."); // We require metadata information for reading requests. if (!this.ReadingResponse) { this.VerifyUserModel(); // TODO: check for entity only if (navigationSource == null && (structuredType != null && structuredType.IsODataEntityTypeKind())) { throw new ODataException(ODataErrorStrings.ODataJsonLightInputContext_NoEntitySetForRequest); } } // We only check that the base type of the entity set is assignable from the specified entity type. // If no resource set/resource type is specified in the API, we will read it from the context URI. IEdmEntityType entitySetElementType = this.EdmTypeResolver.GetElementType(navigationSource); if (navigationSource != null && structuredType != null && !structuredType.IsOrInheritsFrom(entitySetElementType)) { throw new ODataException(ODataErrorStrings.ODataJsonLightInputContext_EntityTypeMustBeCompatibleWithEntitySetBaseType(structuredType.FullTypeName(), entitySetElementType.FullName(), navigationSource.FullNavigationSourceName())); } }
private IEdmNavigationProperty ParseComplexTypesBeforeNavigation(IEdmStructuralProperty edmProperty, ref PathSegmentToken currentToken, List <ODataPathSegment> pathSoFar) { pathSoFar.Add(new PropertySegment(edmProperty)); if (currentToken.NextToken == null) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_PropertyIsNotANavigationPropertyOrComplexProperty(currentToken.Identifier, edmProperty.DeclaringType.FullTypeName())); } currentToken = currentToken.NextToken; IEdmType complexType = edmProperty.Type.Definition; IEdmCollectionType collectionType = complexType as IEdmCollectionType; if (collectionType != null) { complexType = collectionType.ElementType.Definition; } IEdmStructuredType currentType = complexType as IEdmStructuredType; if (currentType == null) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_InvaidSegmentInExpand(currentToken.Identifier)); } if (currentToken.IsNamespaceOrContainerQualified()) { pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(currentToken, this.Model, this.Settings.SelectExpandLimit, this.configuration.Resolver, ref currentType, out currentToken)); } IEdmProperty property = this.configuration.Resolver.ResolveProperty(currentType, currentToken.Identifier); if (edmProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(currentType.FullTypeName(), currentToken.Identifier)); } IEdmStructuralProperty complexProp = property as IEdmStructuralProperty; if (complexProp != null) { property = ParseComplexTypesBeforeNavigation(complexProp, ref currentToken, pathSoFar); } IEdmNavigationProperty navProp = property as IEdmNavigationProperty; if (navProp != null) { return(navProp); } else { throw new ODataException(ODataErrorStrings.ExpandItemBinder_PropertyIsNotANavigationPropertyOrComplexProperty(currentToken.Identifier, currentType.FullTypeName())); } }
/// <summary> /// Generate an expand item (and a select item for the implicit nav prop if necessary) based on an ExpandTermToken /// </summary> /// <param name="tokenIn">the expandTerm token to visit</param> /// <returns>the expand item for this expand term token.</returns> private SelectItem GenerateExpandItem(ExpandTermToken tokenIn) { ExceptionUtils.CheckArgumentNotNull(tokenIn, "tokenIn"); PathSegmentToken currentToken = tokenIn.PathToNavigationProp; IEdmStructuredType currentLevelEntityType = this.EdmType; List <ODataPathSegment> pathSoFar = new List <ODataPathSegment>(); PathSegmentToken firstNonTypeToken = currentToken; if (currentToken.IsNamespaceOrContainerQualified()) { pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(currentToken, this.Model, this.Settings.SelectExpandLimit, this.configuration.Resolver, ref currentLevelEntityType, out firstNonTypeToken)); } IEdmProperty edmProperty = this.configuration.Resolver.ResolveProperty(currentLevelEntityType, firstNonTypeToken.Identifier); if (edmProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(currentLevelEntityType.FullTypeName(), currentToken.Identifier)); } IEdmNavigationProperty currentNavProp = edmProperty as IEdmNavigationProperty; IEdmStructuralProperty currentComplexProp = edmProperty as IEdmStructuralProperty; if (currentNavProp == null && currentComplexProp == null) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_PropertyIsNotANavigationPropertyOrComplexProperty(currentToken.Identifier, currentLevelEntityType.FullTypeName())); } if (currentComplexProp != null) { currentNavProp = ParseComplexTypesBeforeNavigation(currentComplexProp, ref firstNonTypeToken, pathSoFar); } // ensure that we're always dealing with proper V4 syntax if (firstNonTypeToken.NextToken != null && firstNonTypeToken.NextToken.NextToken != null) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_TraversingMultipleNavPropsInTheSamePath); } bool isRef = false; if (firstNonTypeToken.NextToken != null) { // lastly... make sure that, since we're on a NavProp, that the next token isn't null. if (firstNonTypeToken.NextToken.Identifier == UriQueryConstants.RefSegment) { isRef = true; } else { throw new ODataException(ODataErrorStrings.ExpandItemBinder_TraversingMultipleNavPropsInTheSamePath); } } // Add the segments in select and expand to parsed segments List <ODataPathSegment> parsedPath = new List <ODataPathSegment>(this.parsedSegments); parsedPath.AddRange(pathSoFar); IEdmNavigationSource targetNavigationSource = null; if (this.NavigationSource != null) { IEdmPathExpression bindingPath; targetNavigationSource = this.NavigationSource.FindNavigationTarget(currentNavProp, BindingPathHelper.MatchBindingPath, parsedPath, out bindingPath); } NavigationPropertySegment navSegment = new NavigationPropertySegment(currentNavProp, targetNavigationSource); pathSoFar.Add(navSegment); parsedPath.Add(navSegment); // Add the navigation property segment to parsed segments for future usage. ODataExpandPath pathToNavProp = new ODataExpandPath(pathSoFar); // $apply ApplyClause applyOption = BindApply(tokenIn.ApplyOptions, targetNavigationSource); // $compute ComputeClause computeOption = BindCompute(tokenIn.ComputeOption, targetNavigationSource); var generatedProperties = GetGeneratedProperties(computeOption, applyOption); bool collapsed = applyOption?.Transformations.Any(t => t.Kind == TransformationNodeKind.Aggregate || t.Kind == TransformationNodeKind.GroupBy) ?? false; // $filter FilterClause filterOption = BindFilter(tokenIn.FilterOption, targetNavigationSource, null, generatedProperties, collapsed); // $orderby OrderByClause orderbyOption = BindOrderby(tokenIn.OrderByOptions, targetNavigationSource, null, generatedProperties, collapsed); // $search SearchClause searchOption = BindSearch(tokenIn.SearchOption, targetNavigationSource, null); if (isRef) { return(new ExpandedReferenceSelectItem(pathToNavProp, targetNavigationSource, filterOption, orderbyOption, tokenIn.TopOption, tokenIn.SkipOption, tokenIn.CountQueryOption, searchOption, computeOption, applyOption)); } // $select & $expand SelectExpandClause subSelectExpand = BindSelectExpand(tokenIn.ExpandOption, tokenIn.SelectOption, parsedPath, targetNavigationSource, null, generatedProperties, collapsed); // $levels LevelsClause levelsOption = ParseLevels(tokenIn.LevelsOption, currentLevelEntityType, currentNavProp); return(new ExpandedNavigationSelectItem(pathToNavProp, targetNavigationSource, subSelectExpand, filterOption, orderbyOption, tokenIn.TopOption, tokenIn.SkipOption, tokenIn.CountQueryOption, searchOption, levelsOption, computeOption, applyOption)); }
private static bool ApplyDynamicProperty(ODataProperty property, IEdmStructuredType structuredType, object resource, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext) { PropertyInfo propertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(structuredType, readContext.Model); if (propertyInfo == null) { return false; } IDictionary<string, object> dynamicPropertyDictionary = propertyInfo.GetValue(resource) as IDictionary<string, object>; if (dynamicPropertyDictionary == null) { dynamicPropertyDictionary = new Dictionary<string, object>(); propertyInfo.SetValue(resource, dynamicPropertyDictionary); } if (dynamicPropertyDictionary.ContainsKey(property.Name)) { throw Error.InvalidOperation(SRResources.DuplicateDynamicPropertyNameFound, property.Name, structuredType.FullTypeName()); } EdmTypeKind propertyKind; IEdmTypeReference propertyType = null; object value = ConvertValue(property.Value, ref propertyType, deserializerProvider, readContext, out propertyKind); if (propertyKind == EdmTypeKind.Collection) { throw Error.InvalidOperation(SRResources.CollectionNotAllowedAsDynamicProperty, property.Name); } if (propertyKind == EdmTypeKind.Enum) { ODataEnumValue enumValue = (ODataEnumValue)value; IEdmModel model = readContext.Model; IEdmType edmType = model.FindType(enumValue.TypeName); if (edmType == null) { return false; } Type enumType = EdmLibHelpers.GetClrType(edmType, model); value = Enum.Parse(enumType, enumValue.Value); } dynamicPropertyDictionary.Add(property.Name, value); return true; }
/// <summary> /// Resolve property from property name /// </summary> /// <param name="type">The declaring type.</param> /// <param name="propertyName">The property name.</param> /// <returns>The resolved <see cref="IEdmProperty"/></returns> public virtual IEdmProperty ResolveProperty(IEdmStructuredType type, string propertyName) { if (EnableCaseInsensitive) { var result = type.Properties() .Where(_ => string.Equals(propertyName, _.Name, StringComparison.OrdinalIgnoreCase)) .ToList(); if (result.Count == 1) { return(result.Single()); } else if (result.Count > 1) { throw new ODataException(Strings.UriParserMetadata_MultipleMatchingPropertiesFound(propertyName, type.FullTypeName())); } } return(type.FindProperty(propertyName)); }
/// <summary> /// Validates that a property with the specified name exists on a given structured type. /// The structured type can be null if no metadata is available. /// </summary> /// <param name="propertyName">The name of the property to validate.</param> /// <param name="owningStructuredType">The owning type of the property with name <paramref name="propertyName"/> /// or null if no metadata is available.</param> /// <param name="throwOnUndeclaredProperty">Flag indicating whether undeclared property on non open type should be prohibited.</param> /// <returns>The <see cref="IEdmProperty"/> instance representing the property with name <paramref name="propertyName"/> /// or null if no metadata is available.</returns> internal static IEdmProperty ValidatePropertyDefined( string propertyName, IEdmStructuredType owningStructuredType, bool throwOnUndeclaredProperty) { Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)"); if (owningStructuredType == null) { return(null); } IEdmProperty property = owningStructuredType.FindProperty(propertyName); if (throwOnUndeclaredProperty && !owningStructuredType.IsOpen && property == null) { throw new ODataException(Strings.ValidationUtils_PropertyDoesNotExistOnType(propertyName, owningStructuredType.FullTypeName())); } return(property); }
internal static void SetDynamicProperty(object resource, string propertyName, object value, IEdmStructuredType structuredType, ODataDeserializerContext readContext) { IDelta delta = resource as IDelta; if (delta != null) { delta.TrySetPropertyValue(propertyName, value); } else { PropertyInfo propertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(structuredType, readContext.Model); if (propertyInfo == null) { return; } IDictionary<string, object> dynamicPropertyDictionary; object dynamicDictionaryObject = propertyInfo.GetValue(resource); if (dynamicDictionaryObject == null) { if (!propertyInfo.CanWrite) { throw Error.InvalidOperation(SRResources.CannotSetDynamicPropertyDictionary, propertyName, resource.GetType().FullName); } dynamicPropertyDictionary = new Dictionary<string, object>(); propertyInfo.SetValue(resource, dynamicPropertyDictionary); } else { dynamicPropertyDictionary = (IDictionary<string, object>)dynamicDictionaryObject; } if (dynamicPropertyDictionary.ContainsKey(propertyName)) { throw Error.InvalidOperation(SRResources.DuplicateDynamicPropertyNameFound, propertyName, structuredType.FullTypeName()); } dynamicPropertyDictionary.Add(propertyName, value); } }
/// <summary> /// Resolve property from property name /// </summary> /// <param name="type">The declaring type.</param> /// <param name="propertyName">The property name.</param> /// <returns>The resolved <see cref="IEdmProperty"/></returns> public virtual IEdmProperty ResolveProperty(IEdmStructuredType type, string propertyName) { if (EnableCaseInsensitive) { var result = type.Properties() .Where(_ => string.Equals(propertyName, _.Name, StringComparison.OrdinalIgnoreCase)) .ToList(); if (result.Count == 1) { return result.Single(); } else if (result.Count > 1) { throw new ODataException(Strings.UriParserMetadata_MultipleMatchingPropertiesFound(propertyName, type.FullTypeName())); } } return type.FindProperty(propertyName); }
public static IEdmProperty GetPropertyIgnoreCase(this IEdmStructuredType entityType, String propertyName) { IEdmProperty?edmProperty = entityType.GetPropertyIgnoreCaseOrNull(propertyName); if (edmProperty == null) { throw new InvalidOperationException("Property " + propertyName + " not found in IEdmStructuredType " + entityType.FullTypeName()); } return(edmProperty); }
/// <summary> /// Validates that a property with the specified name exists on a given structured type. /// The structured type can be null if no metadata is available. /// </summary> /// <param name="propertyName">The name of the property to validate.</param> /// <param name="owningStructuredType">The owning type of the property with name <paramref name="propertyName"/> /// or null if no metadata is available.</param> /// <param name="messageReaderSettings">The message reader settings being used.</param> /// <returns>The <see cref="IEdmProperty"/> instance representing the property with name <paramref name="propertyName"/> /// or null if no metadata is available.</returns> internal static IEdmProperty ValidateLinkPropertyDefined(string propertyName, IEdmStructuredType owningStructuredType, ODataMessageReaderSettings messageReaderSettings) { Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)"); Debug.Assert(messageReaderSettings != null, "messageReaderSettings != null"); if (owningStructuredType == null) { return null; } IEdmProperty property = FindDefinedProperty(propertyName, owningStructuredType); if (property == null && !owningStructuredType.IsOpen) { if (!messageReaderSettings.ReportUndeclaredLinkProperties) { throw new ODataException(Strings.ValidationUtils_PropertyDoesNotExistOnType(propertyName, owningStructuredType.FullTypeName())); } } return property; }
private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType, bool processBase, bool processExample, IEnumerable <IEdmStructuredType> derivedTypes = null) { Debug.Assert(context != null); Debug.Assert(structuredType != null); IOpenApiAny example = null; if (context.Settings.ShowSchemaExamples) { example = CreateStructuredTypePropertiesExample(context, structuredType); } if (context.Settings.EnableDiscriminatorValue && derivedTypes == null) { derivedTypes = context.Model.FindAllDerivedTypes(structuredType); } 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 { UnresolvedReference = true, 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 = example }); } else { // The discriminator object is added to structured types which have derived types. OpenApiDiscriminator discriminator = null; if (context.Settings.EnableDiscriminatorValue && derivedTypes.Any()) { Dictionary <string, string> mapping = derivedTypes .ToDictionary(x => $"#{x.FullTypeName()}", x => new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = x.FullTypeName() } }.Reference.ReferenceV3); discriminator = new OpenApiDiscriminator { PropertyName = Constants.OdataType, Mapping = mapping }; } // A structured type without a base type is represented as a Schema Object of type object OpenApiSchema schema = new() { 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 }; if (context.Settings.EnableDiscriminatorValue) { if (!schema.Properties.TryAdd(Constants.OdataType, new OpenApiSchema() { Type = "string", Default = new OpenApiString("#" + structuredType.FullTypeName()), })) { throw new InvalidOperationException( $"Property {Constants.OdataType} is already present in schema {structuredType.FullTypeName()}; verify CSDL."); } schema.Required.Add(Constants.OdataType); } // 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 = example; } return(schema); } }
/// <summary> /// Validates that a property with the specified name exists on a given structured type. /// The structured type can be null if no metadata is available. /// </summary> /// <param name="propertyName">The name of the property to validate.</param> /// <param name="owningStructuredType">The owning type of the property with name <paramref name="propertyName"/> /// or null if no metadata is available.</param> /// <param name="throwOnMissingProperty">Whether throw exception on missing property.</param> /// <returns>The <see cref="IEdmProperty"/> instance representing the property with name <paramref name="propertyName"/> /// or null if no metadata is available.</returns> internal static IEdmProperty ValidatePropertyDefined( string propertyName, IEdmStructuredType owningStructuredType, bool throwOnMissingProperty = true) { Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)"); if (owningStructuredType == null) { return null; } IEdmProperty property = owningStructuredType.FindProperty(propertyName); // verify that the property is declared if the type is not an open type. if (throwOnMissingProperty && !owningStructuredType.IsOpen && property == null) { throw new ODataException(Strings.ValidationUtils_PropertyDoesNotExistOnType(propertyName, owningStructuredType.FullTypeName())); } return property; }
/// <summary> /// Validates that a navigation property with the specified name exists on a given entity type. /// The entity type can be null if no metadata is available. /// </summary> /// <param name="propertyName">The name of the property to validate.</param> /// <param name="owningType">The owning entity type/complex type or null if no metadata is available.</param> /// <param name="throwOnUndeclaredProperty">Flag indicating whether undeclared property on non open type should be prohibited.</param> /// <returns>The <see cref="IEdmProperty"/> instance representing the navigation property with name <paramref name="propertyName"/> /// or null if no metadata is available.</returns> internal static IEdmNavigationProperty ValidateNavigationPropertyDefined(string propertyName, IEdmStructuredType owningType, bool throwOnUndeclaredProperty) { Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)"); if (owningType == null) { return(null); } IEdmProperty property = ValidatePropertyDefined(propertyName, owningType, throwOnUndeclaredProperty); if (property == null) { return(null); } if (property.PropertyKind != EdmPropertyKind.Navigation) { // The property must be a navigation property throw new ODataException(Strings.ValidationUtils_NavigationPropertyExpected(propertyName, owningType.FullTypeName(), property.PropertyKind.ToString())); } return((IEdmNavigationProperty)property); }
/// <summary> /// Validates a resource in an expanded link to make sure the entity types match. /// </summary> /// <param name="resourceType">The <see cref="IEdmEntityType"/> of the resource.</param> /// <param name="parentNavigationPropertyType">The type of the parent navigation property.</param> internal static void ValidateNestedResource(IEdmStructuredType resourceType, IEdmStructuredType parentNavigationPropertyType) { if (parentNavigationPropertyType == null) { return; } Debug.Assert(resourceType != null, "If we have a parent navigation property type we should also have a resource type."); // Make sure the entity types are compatible if (!parentNavigationPropertyType.IsAssignableFrom(resourceType)) { throw new ODataException(Strings.WriterValidationUtils_NestedResourceTypeNotCompatibleWithParentPropertyType(resourceType.FullTypeName(), parentNavigationPropertyType.FullTypeName())); } }
/// <summary> /// Generate an expand item (and a select item for the implicit nav prop if necessary) based on an ExpandTermToken /// </summary> /// <param name="tokenIn">the expandTerm token to visit</param> /// <returns>the expand item for this expand term token.</returns> private SelectItem GenerateExpandItem(ExpandTermToken tokenIn) { ExceptionUtils.CheckArgumentNotNull(tokenIn, "tokenIn"); // ensure that we're always dealing with proper V4 syntax if (tokenIn.PathToNavProp.NextToken != null && !tokenIn.PathToNavProp.IsNamespaceOrContainerQualified()) { if (tokenIn.PathToNavProp.NextToken.Identifier != UriQueryConstants.RefSegment || tokenIn.PathToNavProp.NextToken.NextToken != null) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_TraversingMultipleNavPropsInTheSamePath); } } PathSegmentToken currentToken = tokenIn.PathToNavProp; IEdmStructuredType currentLevelEntityType = this.EdmType; List <ODataPathSegment> pathSoFar = new List <ODataPathSegment>(); PathSegmentToken firstNonTypeToken = currentToken; if (currentToken.IsNamespaceOrContainerQualified()) { pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(currentToken, this.Model, this.Settings.SelectExpandLimit, this.configuration.Resolver, ref currentLevelEntityType, out firstNonTypeToken)); } IEdmProperty edmProperty = this.configuration.Resolver.ResolveProperty(currentLevelEntityType, firstNonTypeToken.Identifier); if (edmProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(currentLevelEntityType.FullTypeName(), currentToken.Identifier)); } IEdmNavigationProperty currentNavProp = edmProperty as IEdmNavigationProperty; if (currentNavProp == null) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_PropertyIsNotANavigationProperty(currentToken.Identifier, currentLevelEntityType.FullTypeName())); } bool isRef = false; if (firstNonTypeToken.NextToken != null) { // lastly... make sure that, since we're on a NavProp, that the next token isn't null. if (firstNonTypeToken.NextToken.Identifier == UriQueryConstants.RefSegment) { isRef = true; } else { throw new ODataException(ODataErrorStrings.ExpandItemBinder_TraversingMultipleNavPropsInTheSamePath); } } pathSoFar.Add(new NavigationPropertySegment(currentNavProp, /*entitySet*/ null)); ODataExpandPath pathToNavProp = new ODataExpandPath(pathSoFar); IEdmNavigationSource targetNavigationSource = null; if (this.NavigationSource != null) { targetNavigationSource = this.NavigationSource.FindNavigationTarget(currentNavProp); } // call MetadataBinder to build the filter clause FilterClause filterOption = null; if (tokenIn.FilterOption != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetNavigationSource); FilterBinder filterBinder = new FilterBinder(binder.Bind, binder.BindingState); filterOption = filterBinder.BindFilter(tokenIn.FilterOption); } // call MetadataBinder again to build the orderby clause OrderByClause orderbyOption = null; if (tokenIn.OrderByOptions != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetNavigationSource); OrderByBinder orderByBinder = new OrderByBinder(binder.Bind); orderbyOption = orderByBinder.BindOrderBy(binder.BindingState, tokenIn.OrderByOptions); } SearchClause searchOption = null; if (tokenIn.SearchOption != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetNavigationSource); SearchBinder searchBinder = new SearchBinder(binder.Bind); searchOption = searchBinder.BindSearch(tokenIn.SearchOption); } if (isRef) { return(new ExpandedReferenceSelectItem(pathToNavProp, targetNavigationSource, filterOption, orderbyOption, tokenIn.TopOption, tokenIn.SkipOption, tokenIn.CountQueryOption, searchOption)); } SelectExpandClause subSelectExpand; if (tokenIn.ExpandOption != null) { subSelectExpand = this.GenerateSubExpand(currentNavProp, tokenIn); } else { subSelectExpand = BuildDefaultSubExpand(); } subSelectExpand = this.DecorateExpandWithSelect(subSelectExpand, currentNavProp, tokenIn.SelectOption); LevelsClause levelsOption = this.ParseLevels(tokenIn.LevelsOption, currentLevelEntityType, currentNavProp); return(new ExpandedNavigationSelectItem(pathToNavProp, targetNavigationSource, subSelectExpand, filterOption, orderbyOption, tokenIn.TopOption, tokenIn.SkipOption, tokenIn.CountQueryOption, searchOption, levelsOption)); }
/// <summary> /// Build a segment from a token. /// </summary> /// <param name="tokenIn">the token to bind</param> /// <param name="model">The model.</param> /// <param name="edmType">the type of the current scope based on type segments.</param> /// <param name="resolver">Resolver for uri parser.</param> /// <param name="state">The binding state.</param> /// <returns>The segment created from the token.</returns> public static ODataPathSegment ConvertNonTypeTokenToSegment(PathSegmentToken tokenIn, IEdmModel model, IEdmStructuredType edmType, ODataUriResolver resolver, BindingState state = null) { ExceptionUtils.CheckArgumentNotNull(resolver, "resolver"); ODataPathSegment nextSegment; if (UriParserHelper.IsAnnotation(tokenIn.Identifier)) { if (TryBindAsDeclaredTerm(tokenIn, model, resolver, out nextSegment)) { return(nextSegment); } string qualifiedTermName = tokenIn.Identifier.Remove(0, 1); int separator = qualifiedTermName.LastIndexOf(".", StringComparison.Ordinal); string namespaceName = qualifiedTermName.Substring(0, separator); string termName = qualifiedTermName.Substring(separator == 0 ? 0 : separator + 1); // Don't allow selecting odata control information if (String.Compare(namespaceName, ODataConstants.ODataPrefix, StringComparison.OrdinalIgnoreCase) == 0) { throw new ODataException(ODataErrorStrings.UriSelectParser_TermIsNotValid(tokenIn.Identifier)); } return(new AnnotationSegment(new EdmTerm(namespaceName, termName, EdmCoreModel.Instance.GetUntyped()))); } EndPathToken endPathToken = new EndPathToken(tokenIn.Identifier, null); if ((state?.IsCollapsed ?? false) && !(state?.AggregatedPropertyNames?.Contains(endPathToken) ?? false)) { throw new ODataException(ODataErrorStrings.ApplyBinder_GroupByPropertyNotPropertyAccessValue(tokenIn.Identifier)); } if (TryBindAsDeclaredProperty(tokenIn, edmType, resolver, out nextSegment)) { return(nextSegment); } // Operations must be container-qualified, and because the token type indicates it was not a .-separated identifier, we should not try to look up operations. if (tokenIn.IsNamespaceOrContainerQualified()) { if (TryBindAsOperation(tokenIn, model, edmType, out nextSegment)) { return(nextSegment); } // If an action or function is requested in a selectItem using a qualifiedActionName or a qualifiedFunctionName // and that operation cannot be bound to the entities requested, the service MUST ignore the selectItem. if (!edmType.IsOpen) { return(null); } } if (edmType.IsOpen || (state?.AggregatedPropertyNames?.Contains(endPathToken) ?? false)) { return(new DynamicPathSegment(tokenIn.Identifier)); } throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(edmType.FullTypeName(), tokenIn.Identifier)); }
private static RecordSchema GetSchemaFromModel(IEdmStructuredType type) { if (type.IsOpen) { throw new ApplicationException("not supported."); } RecordSchema rs = Schema.CreateRecord(type.FullTypeName(), null); Schema.SetFields(rs, type.Properties().Select(property => Schema.CreateField(property.Name, GetSchemaFromModel(property.Type)))); return rs; }