/// <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());
        }
Exemple #3
0
        // 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);
            }
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        /// <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);
        }
Exemple #10
0
        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()));
        }
Exemple #12
0
        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);
            }
        }
Exemple #16
0
        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()));
            }
        }
Exemple #22
0
        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()));
            }
        }
Exemple #23
0
        /// <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()));
            }
        }
Exemple #35
0
        /// <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));
        }
Exemple #36
0
        /// <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;
        }