/// <summary>Returns the entity type of the given navigation source.</summary>
        /// <param name="navigationSource">The navigation source to get the element type of.</param>
        /// <returns>The <see cref="IEdmEntityType"/> representing the entity type of the <paramref name="navigationSource" />.</returns>
        internal override IEdmEntityType GetElementType(IEdmNavigationSource navigationSource)
        {
            IEdmEntityType entityType = navigationSource.EntityType();
            
            if (entityType == null)
            {
                return null;
            }

            return (IEdmEntityType)this.ResolveType(entityType);
        }
        /// <summary>
        /// Initializes a new instance of <see cref="OperationImportSegment"/> class.
        /// </summary>
        /// <param name="operationImport">The wrapped Edm operation import (function import or action import).</param>
        /// <param name="navigationSource">The Edm navigation source.</param>
        public OperationImportSegment(IEdmOperationImport operationImport, IEdmNavigationSource navigationSource)
            : base(operationImport?.Name)
        {
            OperationImport = operationImport ?? throw new ArgumentNullException(nameof(operationImport));

            NavigationSource = navigationSource;
            EdmType          = navigationSource?.EntityType();

            if (operationImport.Operation.ReturnType != null)
            {
                IsSingle = !operationImport.Operation.ReturnType.IsCollection();
            }

            Target = operationImport.Operation.TargetName();
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="NavigationSourceLinkBuilderAnnotation"/> class.
        /// </summary>
        /// <param name="navigationSource">The navigation source for which the link builder is being constructed.</param>
        /// <param name="model">The EDM model that this navigation source belongs to.</param>
        /// <remarks>This constructor creates a link builder that generates URL's that follow OData conventions for the given navigation source.</remarks>
        public NavigationSourceLinkBuilderAnnotation(IEdmNavigationSource navigationSource, IEdmModel model)
        {
            if (navigationSource == null)
            {
                throw Error.ArgumentNull("navigationSource");
            }

            if (model == null)
            {
                throw Error.ArgumentNull("model");
            }

            IEdmEntityType elementType = navigationSource.EntityType();
            IEnumerable<IEdmEntityType> derivedTypes = model.FindAllDerivedTypes(elementType).Cast<IEdmEntityType>();

            // Add navigation link builders for all navigation properties of entity.
            foreach (IEdmNavigationProperty navigationProperty in elementType.NavigationProperties())
            {
                Func<EntityInstanceContext, IEdmNavigationProperty, Uri> navigationLinkFactory =
                    (entityInstanceContext, navProperty) => entityInstanceContext.GenerateNavigationPropertyLink(navProperty, includeCast: false);
                AddNavigationPropertyLinkBuilder(navigationProperty, new NavigationLinkBuilder(navigationLinkFactory, followsConventions: true));
            }

            // Add navigation link builders for all navigation properties in derived types.
            bool derivedTypesDefineNavigationProperty = false;
            foreach (IEdmEntityType derivedEntityType in derivedTypes)
            {
                foreach (IEdmNavigationProperty navigationProperty in derivedEntityType.DeclaredNavigationProperties())
                {
                    derivedTypesDefineNavigationProperty = true;
                    Func<EntityInstanceContext, IEdmNavigationProperty, Uri> navigationLinkFactory =
                    (entityInstanceContext, navProperty) => entityInstanceContext.GenerateNavigationPropertyLink(navProperty, includeCast: true);
                    AddNavigationPropertyLinkBuilder(navigationProperty, new NavigationLinkBuilder(navigationLinkFactory, followsConventions: true));
                }
            }

            _navigationSourceName = navigationSource.Name;
            _feedSelfLinkBuilder = (feedContext) => feedContext.GenerateFeedSelfLink();

            Func<EntityInstanceContext, string> selfLinkFactory =
                (entityInstanceContext) => entityInstanceContext.GenerateSelfLink(includeCast: derivedTypesDefineNavigationProperty);
            _idLinkBuilder = new SelfLinkBuilder<string>(selfLinkFactory, followsConventions: true);
        }
        /// <summary>
        /// Retrieve the paths for <see cref="IEdmNavigationSource"/>.
        /// </summary>
        /// <param name="navigationSource">The navigation source.</param>
        private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource)
        {
            Debug.Assert(navigationSource != null);

            // navigation source itself
            ODataPath path = new ODataPath(new ODataNavigationSourceSegment(navigationSource));

            AppendPath(path.Clone());

            IEdmEntitySet  entitySet  = navigationSource as IEdmEntitySet;
            IEdmEntityType entityType = navigationSource.EntityType();

            // for entity set, create a path with key
            if (entitySet != null)
            {
                path.Push(new ODataKeySegment(entityType));
                AppendPath(path.Clone());
            }

            // media entity
            RetrieveMediaEntityStreamPaths(entityType, path);

            // navigation property
            foreach (IEdmNavigationProperty np in entityType.DeclaredNavigationProperties())
            {
                if (CanFilter(np))
                {
                    RetrieveNavigationPropertyPaths(np, path);
                }
            }

            if (entitySet != null)
            {
                path.Pop(); // end of entity
            }

            path.Pop(); // end of navigation source.
            Debug.Assert(path.Any() == false);
        }
        public override Expression Visit(SingleValuePropertyAccessNode nodeIn)
        {
            Expression e;

            if (TuplePropertyByAliasName == null)
            {
                e = TranslateNode(nodeIn.Source);
                if (e == null)
                {
                    return(null);
                }

                PropertyInfo property = e.Type.GetProperty(nodeIn.Property.Name);
                if (property == null)
                {
                    if (!OeExpressionHelper.IsTupleType(e.Type))
                    {
                        throw new InvalidOperationException("must by Tuple " + e.Type.ToString());
                    }

                    IEdmNavigationSource navigationSource = ((ResourceRangeVariableReferenceNode)nodeIn.Source).NavigationSource;
                    property = GetTuplePropertyByEntityType(e.Type, navigationSource.EntityType());
                }
                return(Expression.Property(e, property));
            }

            Expression source = TranslateNode(nodeIn.Source);

            e = TuplePropertyByAliasName(source ?? Parameter, nodeIn);
            if (e == null)
            {
                e = GetPropertyExpression(nodeIn);
                if (e == null)
                {
                    throw new InvalidOperationException("property name " + nodeIn.Property.Name + " not found");
                }
            }
            return(e);
        }
Example #6
0
        /// <inheritdoc />
        public override bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            IEdmNavigationSource navigationSource = context.EntitySet == null ?
                                                    (IEdmNavigationSource)context.Singleton :
                                                    (IEdmNavigationSource)context.EntitySet;

            IEdmEntityType entityType = navigationSource.EntityType();

            // function should have the [HttpGet]
            if (!context.Action.Attributes.Any(a => a is HttpGetAttribute))
            {
                return(false);
            }

            ProcessOperations(context, entityType, navigationSource);
            return(false);
        }
Example #7
0
        /// <summary>
        /// Load the annotation value.
        /// </summary>
        /// <param name="model">The Edm model.</param>
        /// <param name="target">The target.</param>
        /// <returns>True/False</returns>
        public virtual bool Load(IEdmModel model, IEdmVocabularyAnnotatable target)
        {
            Utils.CheckArgumentNull(model, nameof(model));
            Utils.CheckArgumentNull(target, nameof(target));

            string termQualifiedName            = CapabilitiesConstants.Namespace + "." + Kind.ToString();
            IEdmVocabularyAnnotation annotation = model.GetVocabularyAnnotation(target, termQualifiedName);

            if (annotation == null)
            {
                IEdmNavigationSource navigationSource = target as IEdmNavigationSource;

                // if not, search the entity type.
                if (navigationSource != null)
                {
                    IEdmEntityType entityType = navigationSource.EntityType();
                    annotation = model.GetVocabularyAnnotation(entityType, termQualifiedName);
                }
            }

            return(Initialize(annotation));
        }
        public override Expression Visit(SingleValuePropertyAccessNode nodeIn)
        {
            if (TuplePropertyMapper == null)
            {
                Expression   e        = TranslateNode(nodeIn.Source);
                PropertyInfo property = e.Type.GetTypeInfo().GetProperty(nodeIn.Property.Name);
                if (property == null)
                {
                    if (!OeExpressionHelper.IsTupleType(e.Type))
                    {
                        throw new InvalidOperationException("must by Tuple " + e.Type.ToString());
                    }

                    IEdmNavigationSource navigationSource = ((ResourceRangeVariableReferenceNode)nodeIn.Source).NavigationSource;
                    property = GetTuplePropertyByEntityType(e.Type, navigationSource.EntityType());

                    e        = Expression.Property(e, property);
                    property = e.Type.GetTypeInfo().GetProperty(nodeIn.Property.Name);
                }
                return(Expression.Property(e, property));
            }

            Expression source;
            String     aliasName = nodeIn.Property.Name;

            try
            {
                source = TranslateNode(nodeIn.Source);
            }
            catch (TupleNavigationPropertyException e)
            {
                source    = Parameter;
                aliasName = e.NavigationProperty.Name + "_" + aliasName;
            }
            return(TuplePropertyMapper(source, aliasName));
        }
Example #9
0
        /// <inheritdoc />
        public override bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            IEdmNavigationSource navigationSource = context.NavigationSource;
            IEdmEntityType       entityType       = navigationSource.EntityType();

            // action should have the [HttpPost]
            if (!context.Action.Attributes.Any(a => a is HttpPostAttribute))
            {
                return(false);
            }

            // action overload on binding type, only one action overload on the same binding type.
            // however, it supports the bound action on derived type.
            ProcessOperations(context, entityType, navigationSource);

            // in OData operationImport routing convention, all action are processed by default
            // even it's not a really edm operation import call.
            return(false);
        }
Example #10
0
        /// <inheritdoc />
        public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter,
                                         ODataSerializerContext writeContext)
        {
            if (messageWriter == null)
            {
                throw Error.ArgumentNull("messageWriter");
            }

            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            IEdmNavigationSource navigationSource = writeContext.NavigationSource;

            if (navigationSource == null)
            {
                throw new SerializationException(SRResources.NavigationSourceMissingDuringSerialization);
            }

            ODataWriter writer = messageWriter.CreateODataEntryWriter(navigationSource, navigationSource.EntityType());

            WriteObjectInline(graph, navigationSource.EntityType().ToEdmTypeReference(isNullable: false), writer, writeContext);
        }
 /// <summary>
 /// Create ODataContextUrlInfo from basic information
 /// </summary>
 /// <param name="navigationSource">Navigation source for current element.</param>\
 /// <param name="expectedEntityTypeName">The expectedEntity for current element.</param>
 /// <param name="isSingle">Whether target is single item.</param>
 /// <param name="odataUri">The odata uri info for current query.</param>
 /// <returns>The generated ODataContextUrlInfo.</returns>
 internal static ODataContextUrlInfo Create(IEdmNavigationSource navigationSource, string expectedEntityTypeName, bool isSingle, ODataUri odataUri)
 {
     EdmNavigationSourceKind kind = navigationSource.NavigationSourceKind();
     string navigationSourceEntityType = navigationSource.EntityType().FullName();
     return new ODataContextUrlInfo()
     {
         isContained = kind == EdmNavigationSourceKind.ContainedEntitySet,
         IsUnknownEntitySet = kind == EdmNavigationSourceKind.UnknownEntitySet,
         navigationSource = navigationSource.Name,
         TypeCast = navigationSourceEntityType == expectedEntityTypeName ? null : expectedEntityTypeName,
         TypeName = navigationSourceEntityType,
         IncludeFragmentItemSelector = isSingle && kind != EdmNavigationSourceKind.Singleton,
         odataUri = odataUri
     };
 }
 internal void WriteNavigationPropertyBinding(IEdmNavigationSource navigationSource, IEdmNavigationPropertyBinding binding)
 {
     this.WriteNavigationPropertyBinding(binding, navigationSource.EntityType());
 }
        /// <summary>
        ///
        /// </summary>
        /// <param name="context"></param>
        public virtual bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            ActionModel action = context.Action;

            if (context.EntitySet == null && context.Singleton == null)
            {
                return(false);
            }
            IEdmNavigationSource navigationSource = context.EntitySet == null ?
                                                    (IEdmNavigationSource)context.Singleton :
                                                    (IEdmNavigationSource)context.EntitySet;

            string actionName = action.ActionMethod.Name;

            string method = Split(actionName, out string property, out string cast, out string declared);

            if (method == null || string.IsNullOrEmpty(property))
            {
                return(false);
            }

            IEdmEntityType entityType         = navigationSource.EntityType();
            IEdmModel      model              = context.Model;
            string         prefix             = context.Prefix;
            IEdmEntityType declaredEntityType = null;

            if (declared != null)
            {
                declaredEntityType = entityType.FindTypeInInheritance(model, declared) as IEdmEntityType;
                if (declaredEntityType == null)
                {
                    return(false);
                }

                if (declaredEntityType == entityType)
                {
                    declaredEntityType = null;
                }
            }

            bool          hasKeyParameter = HasKeyParameter(entityType, action);
            IEdmSingleton singleton       = navigationSource as IEdmSingleton;

            if (singleton != null && hasKeyParameter)
            {
                // Singleton, doesn't allow to query property with key
                return(false);
            }

            if (singleton == null && !hasKeyParameter)
            {
                // in entityset, doesn't allow for non-key to query property
                return(false);
            }

            IEdmProperty edmProperty = entityType.FindProperty(property);

            if (edmProperty != null && edmProperty.PropertyKind == EdmPropertyKind.Structural)
            {
                // only process structural property
                IEdmStructuredType castComplexType = null;
                if (cast != null)
                {
                    IEdmTypeReference propertyType = edmProperty.Type;
                    if (propertyType.IsCollection())
                    {
                        propertyType = propertyType.AsCollection().ElementType();
                    }
                    if (!propertyType.IsComplex())
                    {
                        return(false);
                    }

                    castComplexType = propertyType.ToStructuredType().FindTypeInInheritance(model, cast);
                    if (castComplexType == null)
                    {
                        return(false);
                    }
                }

                IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>();

                if (context.EntitySet != null)
                {
                    segments.Add(new EntitySetSegmentTemplate(context.EntitySet));
                }
                else
                {
                    segments.Add(new SingletonSegmentTemplate(context.Singleton));
                }

                if (hasKeyParameter)
                {
                    segments.Add(new KeySegmentTemplate(entityType));
                }
                if (declaredEntityType != null && declaredEntityType != entityType)
                {
                    segments.Add(new CastSegmentTemplate(declaredEntityType));
                }

                segments.Add(new PropertySegmentTemplate((IEdmStructuralProperty)edmProperty));

                ODataPathTemplate template = new ODataPathTemplate(segments);
                action.AddSelector(prefix, model, template);
                return(true);
            }
            else
            {
                // map to a static action like:  <method>Property(int key, string property)From<...>
                if (property == "Property" && cast == null)
                {
                    if (action.Parameters.Any(p => p.ParameterInfo.Name == "property" && p.ParameterType == typeof(string)))
                    {
                        // we find a static method mapping for all property
                        // we find a action route
                        IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>();

                        if (context.EntitySet != null)
                        {
                            segments.Add(new EntitySetSegmentTemplate(context.EntitySet));
                        }
                        else
                        {
                            segments.Add(new SingletonSegmentTemplate(context.Singleton));
                        }

                        if (hasKeyParameter)
                        {
                            segments.Add(new KeySegmentTemplate(entityType));
                        }
                        if (declaredEntityType != null)
                        {
                            segments.Add(new CastSegmentTemplate(declaredEntityType));
                        }

                        segments.Add(new PropertySegmentTemplate((string)null /*entityType*/));

                        ODataPathTemplate template = new ODataPathTemplate(segments);
                        action.AddSelector(prefix, model, template);
                        return(true);
                    }
                }
            }

            return(false);
        }
        /// <inheritdoc />
        public virtual bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            if (context.EntitySet == null && context.Singleton == null)
            {
                return(false);
            }

            ActionModel action = context.Action;

            // Filter by the action name.
            // The action for navigation property request should follow up {httpMethod}{PropertyName}[From{Declaring}]
            string actionName = action.ActionMethod.Name;
            string method     = SplitActionName(actionName, out string property, out string declared);

            if (method == null || string.IsNullOrEmpty(property))
            {
                return(false);
            }

            IEdmNavigationSource navigationSource = context.EntitySet == null ?
                                                    (IEdmNavigationSource)context.Singleton :
                                                    (IEdmNavigationSource)context.EntitySet;

            // filter by action parameter
            IEdmEntityType entityType      = navigationSource.EntityType();
            bool           hasKeyParameter = action.HasODataKeyParameter(entityType);

            if (!(context.Singleton != null ^ hasKeyParameter))
            {
                // Singleton, doesn't allow to query property with key
                // entityset, doesn't allow for non-key to query property
                return(false);
            }

            // Find the declaring type of the property if we have the declaring type name in the action name.
            // eitherwise, it means the property is defined on the entity type of the navigation source.
            IEdmEntityType declaringEntityType = entityType;

            if (declared != null)
            {
                declaringEntityType = entityType.FindTypeInInheritance(context.Model, declared) as IEdmEntityType;
                if (declaringEntityType == null)
                {
                    return(false);
                }
            }

            // Find the property, and we only care about the navigation property.
            IEdmProperty edmProperty = declaringEntityType.FindProperty(property);

            if (edmProperty == null || edmProperty.PropertyKind == EdmPropertyKind.Structural)
            {
                return(false);
            }

            // Starts the routing template
            //IList<ODataSegmentTemplate> segments = new List<ODataSegmentTemplate>();
            //if (context.EntitySet != null)
            //{
            //    segments.Add(new EntitySetSegmentTemplate(context.EntitySet));
            //}
            //else
            //{
            //    segments.Add(new SingletonSegmentTemplate(context.Singleton));
            //}

            //if (hasKeyParameter)
            //{
            //    segments.Add(new KeySegmentTemplate(entityType));
            //}

            //if (declared != null)
            //{
            //    // It should be always single type
            //    segments.Add(new CastSegmentTemplate(declaringEntityType, entityType, navigationSource));
            //}

            IEdmNavigationProperty navigationProperty = (IEdmNavigationProperty)edmProperty;

            //IEdmNavigationSource targetNavigationSource = navigationSource.FindNavigationTarget(navigationProperty, segments, out _);

            //segments.Add(new NavigationSegmentTemplate(navigationProperty, targetNavigationSource));

            //ODataPathTemplate template = new ODataPathTemplate(segments);
            //action.AddSelector(method, context.Prefix, context.Model, template);

            AddSelector(method, context.Prefix, context.Model, action, navigationSource, declared, declaringEntityType, navigationProperty, hasKeyParameter, false);

            if (CanApplyDollarCount(navigationProperty, method))
            {
                AddSelector(method, context.Prefix, context.Model, action, navigationSource, declared, declaringEntityType, navigationProperty, hasKeyParameter, true);
            }

            return(true);
        }
Example #15
0
 /// <summary>
 /// Build a type segment using the given <paramref name="actualType"/>.
 /// </summary>
 /// <param name="actualType">The target type of this segment, which may be collection type.</param>
 /// <param name="navigationSource">The navigation source containing the entities that we are casting. This can be null.</param>
 /// <exception cref="System.ArgumentNullException">Throws if the actual edmType is null.</exception>
 /// <exception cref="ODataException">Throws if the actual edmType is not related to the type of elements in the input navigationSource.</exception>
 public TypeSegment(IEdmType actualType, IEdmNavigationSource navigationSource)
     : this(actualType, navigationSource == null ? actualType : navigationSource.EntityType(), navigationSource)
 {
 }
Example #16
0
        public static IEnumerable <IEdmStructuralProperty> GetConcurrencyProperties(this IEdmModel model, IEdmNavigationSource navigationSource)
        {
            Contract.Assert(model != null);
            Contract.Assert(navigationSource != null);

            // Ensure that concurrency properties cache is attached to model as an annotation to avoid expensive calculations each time
            ConcurrentDictionary <IEdmNavigationSource, IEnumerable <IEdmStructuralProperty> > concurrencyProperties = model.GetAnnotationValue <ConcurrencyPropertiesAnnotation>(model);

            if (concurrencyProperties == null)
            {
                concurrencyProperties = new ConcurrentDictionary <IEdmNavigationSource, IEnumerable <IEdmStructuralProperty> >();
                model.SetAnnotationValue(model, concurrencyProperties);
            }

            IEnumerable <IEdmStructuralProperty> cachedProperties;

            if (concurrencyProperties != null && concurrencyProperties.TryGetValue(navigationSource, out cachedProperties))
            {
                return(cachedProperties);
            }

            IList <IEdmStructuralProperty> results = new List <IEdmStructuralProperty>();
            IEdmEntityType            entityType   = navigationSource.EntityType();
            IEdmVocabularyAnnotatable annotatable  = navigationSource as IEdmVocabularyAnnotatable;

            if (annotatable != null)
            {
                var annotations = model.FindVocabularyAnnotations <IEdmVocabularyAnnotation>(annotatable, CoreVocabularyModel.ConcurrencyTerm);
                IEdmVocabularyAnnotation annotation = annotations.FirstOrDefault();
                if (annotation != null)
                {
                    IEdmCollectionExpression properties = annotation.Value as IEdmCollectionExpression;
                    if (properties != null)
                    {
                        foreach (var property in properties.Elements)
                        {
                            IEdmPathExpression pathExpression = property as IEdmPathExpression;
                            if (pathExpression != null)
                            {
                                // So far, we only consider the single path, because only the direct properties from declaring type are used.
                                // However we have an issue tracking on: https://github.com/OData/WebApi/issues/472
                                string                 propertyName       = pathExpression.PathSegments.First();
                                IEdmProperty           edmProperty        = entityType.FindProperty(propertyName);
                                IEdmStructuralProperty structuralProperty = edmProperty as IEdmStructuralProperty;
                                if (structuralProperty != null)
                                {
                                    results.Add(structuralProperty);
                                }
                            }
                        }
                    }
                }
            }

            if (concurrencyProperties == null)
            {
                concurrencyProperties = new ConcurrentDictionary <IEdmNavigationSource, IEnumerable <IEdmStructuralProperty> >();
            }

            if (results.Any())
            {
                concurrencyProperties[navigationSource] = results;
            }
            return(results);
        }
Example #17
0
        private static void GenerateBaseODataPathSegmentsForNonSingletons(
            ODataPath path,
            IEdmNavigationSource navigationSource,
            IList <ODataPathSegment> odataPath)
        {
            // If the navigation is not a singleton we need to walk all of the path segments to generate a
            // contextually accurate URI.
            bool segmentFound   = false;
            bool containedFound = false;

            if (path != null)
            {
                var segments = path.Segments;
                int length   = segments.Count;
                int previousNavigationPathIndex = -1;
                for (int i = 0; i < length; i++)
                {
                    ODataPathSegment     pathSegment             = segments[i];
                    IEdmNavigationSource currentNavigationSource = null;

                    var entitySetPathSegment = pathSegment as EntitySetSegment;
                    if (entitySetPathSegment != null)
                    {
                        currentNavigationSource = entitySetPathSegment.EntitySet;
                    }

                    var navigationPathSegment = pathSegment as NavigationPropertySegment;
                    if (navigationPathSegment != null)
                    {
                        currentNavigationSource = navigationPathSegment.NavigationSource;
                    }
                    if (containedFound)
                    {
                        odataPath.Add(pathSegment);
                    }
                    else
                    {
                        if (navigationPathSegment != null &&
                            navigationPathSegment.NavigationProperty.ContainsTarget)
                        {
                            containedFound = true;
                            //The path should have the last non-contained navigation property
                            if (previousNavigationPathIndex != -1)
                            {
                                for (int j = previousNavigationPathIndex; j <= i; j++)
                                {
                                    odataPath.Add(segments[j]);
                                }
                            }
                        }
                    }

                    // If we've found our target navigation in the path that means we've correctly populated the
                    // segments up to the navigation and we can ignore the remaining segments.
                    if (currentNavigationSource != null)
                    {
                        previousNavigationPathIndex = i;
                        if (currentNavigationSource == navigationSource)
                        {
                            segmentFound = true;
                            break;
                        }
                    }
                }
            }

            if (!segmentFound || !containedFound)
            {
                // If the target navigation was not found in the current path that means we lack any context that
                // would suggest a scenario other than directly accessing an entity set, so we must assume that's
                // the case.
                odataPath.Clear();

                IEdmContainedEntitySet containmnent = navigationSource as IEdmContainedEntitySet;
                if (containmnent != null)
                {
                    EdmEntityContainer container = new EdmEntityContainer("NS", "Default");
                    IEdmEntitySet      entitySet = new EdmEntitySet(container, navigationSource.Name,
                                                                    navigationSource.EntityType());
                    odataPath.Add(new EntitySetSegment(entitySet));
                }
                else
                {
                    odataPath.Add(new EntitySetSegment((IEdmEntitySet)navigationSource));
                }
            }
        }
Example #18
0
        /// <inheritdoc />
        public virtual bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            if (context.EntitySet == null && context.Singleton == null)
            {
                return(false);
            }

            IEdmNavigationSource navigationSource = context.EntitySet == null ?
                                                    (IEdmNavigationSource)context.Singleton :
                                                    (IEdmNavigationSource)context.EntitySet;

            ActionModel action     = context.Action;
            string      actionName = action.ActionMethod.Name;

            string method = SplitActionName(actionName, out string property, out string cast, out string declared);

            if (method == null || string.IsNullOrEmpty(property))
            {
                return(false);
            }

            // filter by action parameter
            IEdmEntityType entityType      = navigationSource.EntityType();
            bool           hasKeyParameter = action.HasODataKeyParameter(entityType);

            if (!(context.Singleton != null ^ hasKeyParameter))
            {
                // Singleton, doesn't allow to query property with key
                // entityset, doesn't allow for non-key to query property
                return(false);
            }

            // Find the declaring type of the property if we have the declaring type name in the action name.
            // eitherwise, it means the property is defined on the entity type of the navigation source.
            IEdmEntityType declaringEntityType = entityType;

            if (declared != null)
            {
                declaringEntityType = entityType.FindTypeInInheritance(context.Model, declared) as IEdmEntityType;
                if (declaringEntityType == null)
                {
                    return(false);
                }
            }

            IEdmProperty edmProperty = declaringEntityType.FindProperty(property);

            if (edmProperty == null || edmProperty.PropertyKind != EdmPropertyKind.Structural)
            {
                return(false);
            }

            if (!CanApply(edmProperty, method))
            {
                return(false);
            }

            IEdmComplexType castType = null;

            if (cast != null)
            {
                IEdmType propertyElementType = edmProperty.Type.Definition.AsElementType();
                if (propertyElementType.TypeKind == EdmTypeKind.Complex)
                {
                    IEdmComplexType complexType = (IEdmComplexType)propertyElementType;
                    castType = complexType.FindTypeInInheritance(context.Model, cast) as IEdmComplexType;
                    if (castType == null)
                    {
                        return(false);
                    }
                }
                else
                {
                    // only support complex type cast, (TODO: maybe consider to support Edm.PrimitiveType cast)
                    return(false);
                }
            }

            // only process structural property
            IEdmStructuredType castComplexType = null;

            if (cast != null)
            {
                IEdmTypeReference propertyType = edmProperty.Type;
                if (propertyType.IsCollection())
                {
                    propertyType = propertyType.AsCollection().ElementType();
                }
                if (!propertyType.IsComplex())
                {
                    return(false);
                }

                castComplexType = propertyType.ToStructuredType().FindTypeInInheritance(context.Model, cast);
                if (castComplexType == null)
                {
                    return(false);
                }
            }

            AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, false, false);

            if (CanApplyDollarCount(edmProperty, method))
            {
                AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, false, true);
            }

            if (CanApplyDollarValue(edmProperty, method))
            {
                AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, true, false);
            }

            return(true);
        }
Example #19
0
        private void GetAutoSelectExpandItems(
            IEdmEntityType baseEntityType,
            IEdmModel model,
            IEdmNavigationSource navigationSource,
            bool isAllSelected,
            ModelBoundQuerySettings modelBoundQuerySettings,
            int depth,
            out List <SelectItem> autoSelectItems,
            out List <SelectItem> autoExpandItems)
        {
            autoSelectItems = new List <SelectItem>();
            var autoSelectProperties = EdmLibHelpers.GetAutoSelectProperties(null,
                                                                             baseEntityType, model, modelBoundQuerySettings);

            foreach (var autoSelectProperty in autoSelectProperties)
            {
                List <ODataPathSegment> pathSegments = new List <ODataPathSegment>()
                {
                    new PropertySegment(autoSelectProperty)
                };

                PathSelectItem pathSelectItem = new PathSelectItem(
                    new ODataSelectPath(pathSegments));
                autoSelectItems.Add(pathSelectItem);
            }

            autoExpandItems = new List <SelectItem>();
            depth--;
            if (depth < 0)
            {
                return;
            }

            var autoExpandNavigationProperties = EdmLibHelpers.GetAutoExpandNavigationProperties(null, baseEntityType,
                                                                                                 model, !isAllSelected, modelBoundQuerySettings);

            foreach (var navigationProperty in autoExpandNavigationProperties)
            {
                IEdmNavigationSource currentEdmNavigationSource =
                    navigationSource.FindNavigationTarget(navigationProperty);

                if (currentEdmNavigationSource != null)
                {
                    List <ODataPathSegment> pathSegments = new List <ODataPathSegment>()
                    {
                        new NavigationPropertySegment(navigationProperty, currentEdmNavigationSource)
                    };

                    ODataExpandPath    expandPath         = new ODataExpandPath(pathSegments);
                    SelectExpandClause selectExpandClause = new SelectExpandClause(new List <SelectItem>(),
                                                                                   true);
                    ExpandedNavigationSelectItem item = new ExpandedNavigationSelectItem(expandPath,
                                                                                         currentEdmNavigationSource, selectExpandClause);
                    modelBoundQuerySettings = EdmLibHelpers.GetModelBoundQuerySettings(navigationProperty,
                                                                                       navigationProperty.ToEntityType(), model);
                    List <SelectItem> nestedSelectItems;
                    List <SelectItem> nestedExpandItems;

                    int maxExpandDepth = GetMaxExpandDepth(modelBoundQuerySettings, navigationProperty.Name);
                    if (maxExpandDepth != 0 && maxExpandDepth < depth)
                    {
                        depth = maxExpandDepth;
                    }

                    GetAutoSelectExpandItems(
                        currentEdmNavigationSource.EntityType(),
                        model,
                        item.NavigationSource,
                        true,
                        modelBoundQuerySettings,
                        depth,
                        out nestedSelectItems,
                        out nestedExpandItems);

                    selectExpandClause = new SelectExpandClause(nestedSelectItems.Concat(nestedExpandItems),
                                                                nestedSelectItems.Count == 0);
                    item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource,
                                                            selectExpandClause);

                    autoExpandItems.Add(item);
                    if (!isAllSelected || autoSelectProperties.Count() != 0)
                    {
                        PathSelectItem pathSelectItem = new PathSelectItem(
                            new ODataSelectPath(pathSegments));
                        autoExpandItems.Add(pathSelectItem);
                    }
                }
            }
        }
Example #20
0
 private MetadataBinder BuildNewMetadataBinder(IEdmNavigationSource targetNavigationSource)
 {
     BindingState state = new BindingState(this.configuration)
     {
         ImplicitRangeVariable =
             NodeFactory.CreateImplicitRangeVariable(targetNavigationSource.EntityType().ToTypeReference(), targetNavigationSource)
     };
     state.RangeVariables.Push(state.ImplicitRangeVariable);
     return new MetadataBinder(state);
 }
        /// <inheritdoc />
        public virtual bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            IEdmNavigationSource navigationSource = context.NavigationSource;

            if (navigationSource == null)
            {
                return(false);
            }

            ActionModel action     = context.Action;
            string      actionName = action.ActionName;

            string method = SplitActionName(actionName, out string property, out string cast, out string declared);

            if (method == null || string.IsNullOrEmpty(property))
            {
                return(false);
            }

            // filter by action parameter
            IEdmEntityType entityType      = navigationSource.EntityType();
            bool           hasKeyParameter = action.HasODataKeyParameter(entityType, context.Options?.RouteOptions?.EnablePropertyNameCaseInsensitive ?? false);

            if (!(context.Singleton != null ^ hasKeyParameter))
            {
                // Singleton, doesn't allow to query property with key
                // entityset, doesn't allow for non-key to query property
                return(false);
            }

            // Find the declaring type of the property if we have the declaring type name in the action name.
            // otherwise, it means the property is defined on the entity type of the navigation source.
            IEdmEntityType declaringEntityType = entityType;

            if (declared != null)
            {
                if (declared.Length == 0)
                {
                    // Early return for the following cases:
                    // - Get|PostTo|PutTo|PatchTo|DeleteTo{PropertyName}From
                    // - Get|PostTo|PutTo|PatchTo|DeleteTo{PropertyName}Of{Cast}From
                    return(false);
                }

                declaringEntityType = entityType.FindTypeInInheritance(context.Model, declared) as IEdmEntityType;
                if (declaringEntityType == null)
                {
                    return(false);
                }
            }

            bool         enablePropertyNameCaseInsensitive = context?.Options?.RouteOptions.EnablePropertyNameCaseInsensitive ?? false;
            IEdmProperty edmProperty = declaringEntityType.FindProperty(property, enablePropertyNameCaseInsensitive);

            if (edmProperty == null || edmProperty.PropertyKind != EdmPropertyKind.Structural)
            {
                return(false);
            }

            if (!CanApply(edmProperty, method))
            {
                return(false);
            }

            IEdmComplexType castType;
            // Only process structural property
            IEdmStructuredType castComplexType = null;

            if (cast != null)
            {
                if (cast.Length == 0)
                {
                    // Avoid unnecessary call to FindTypeInheritance
                    // Cases handled: Get|PostTo|PutTo|PatchTo|DeleteTo{PropertyName}Of
                    return(false);
                }

                IEdmType propertyElementType = edmProperty.Type.Definition.AsElementType();
                if (propertyElementType.TypeKind == EdmTypeKind.Complex)
                {
                    IEdmComplexType complexType = (IEdmComplexType)propertyElementType;
                    castType = complexType.FindTypeInInheritance(context.Model, cast) as IEdmComplexType;
                    if (castType == null)
                    {
                        return(false);
                    }
                }
                else
                {
                    // only support complex type cast, (TODO: maybe consider to support Edm.PrimitiveType cast)
                    return(false);
                }

                IEdmTypeReference propertyType = edmProperty.Type;
                if (propertyType.IsCollection())
                {
                    propertyType = propertyType.AsCollection().ElementType();
                }

                if (!propertyType.IsComplex())
                {
                    return(false);
                }

                castComplexType = propertyType.ToStructuredType().FindTypeInInheritance(context.Model, cast);
                if (castComplexType == null)
                {
                    return(false);
                }
            }

            AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, false, false);

            if (CanApplyDollarCount(edmProperty, method))
            {
                AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, false, true);
            }

            if (CanApplyDollarValue(edmProperty, method))
            {
                AddSelector(method, context, action, navigationSource, (IEdmStructuralProperty)edmProperty, castComplexType, declaringEntityType, true, false);
            }

            return(true);
        }
 internal override IEdmEntityType GetElementType(IEdmNavigationSource navigationSource)
 {
     return navigationSource.EntityType();
 }
Example #23
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="context"></param>
        public virtual bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            ActionModel action = context.Action;

            if (context.EntitySet == null && context.Singleton == null)
            {
                return(false);
            }
            IEdmNavigationSource navigationSource = context.EntitySet == null ?
                                                    (IEdmNavigationSource)context.Singleton :
                                                    (IEdmNavigationSource)context.EntitySet;

            IEdmModel      model           = context.Model;
            string         prefix          = context.Prefix;
            IEdmEntityType entityType      = navigationSource.EntityType();
            bool           hasKeyParameter = HasKeyParameter(entityType, action);

            // found
            int      keyNumber = entityType.Key().Count();
            IEdmType bindType  = entityType;

            if (!hasKeyParameter)
            {
                // bond to collection
                bindType  = new EdmCollectionType(new EdmEntityTypeReference(entityType, true));
                keyNumber = 0;
            }

            string actionName = action.ActionMethod.Name;
            var    operations = model.FindBoundOperations(bindType).Where(p => p.Name == actionName);

            var actions = operations.OfType <IEdmAction>().ToList();

            if (actions.Count == 1) // action overload on binding type, only one action overload on the same binding type
            {
                if (action.Parameters.Any(p => p.ParameterType == typeof(ODataActionParameters)))
                {
                    // we find a action route
                    IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>();

                    if (context.EntitySet != null)
                    {
                        segments.Add(new EntitySetSegmentTemplate(context.EntitySet));
                    }
                    else
                    {
                        segments.Add(new SingletonSegmentTemplate(context.Singleton));
                    }


                    if (hasKeyParameter)
                    {
                        segments.Add(new KeySegmentTemplate(entityType));
                    }
                    segments.Add(new ActionSegmentTemplate(actions[0], false));

                    ODataPathTemplate template = new ODataPathTemplate(segments);

                    action.AddSelector(prefix, model, template);
                    return(true);
                }
            }

            var          functions = operations.OfType <IEdmFunction>().ToList();
            IEdmFunction function  = FindMatchFunction(keyNumber, functions, action);

            if (function != null)
            {
                IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>();

                if (context.EntitySet != null)
                {
                    segments.Add(new EntitySetSegmentTemplate(context.EntitySet));
                }
                else
                {
                    segments.Add(new SingletonSegmentTemplate(context.Singleton));
                }

                if (hasKeyParameter)
                {
                    segments.Add(new KeySegmentTemplate(entityType));
                }
                segments.Add(new FunctionSegmentTemplate(function, false));

                ODataPathTemplate template = new ODataPathTemplate(segments);

                action.AddSelector(prefix, model, template);
                return(true);
            }

            // in OData operationImport routing convention, all action are processed by default
            // even it's not a really edm operation import call.
            return(false);
        }
        /// <summary>
        /// Converts an item from the data store into an ODataEntry.
        /// </summary>
        /// <param name="element">The item to convert.</param>
        /// <param name="navigationSource">The navigation source that the item belongs to.</param>
        /// <param name="targetVersion">The OData version this segment is targeting.</param>
        /// <returns>The converted ODataEntry.</returns>
        public static ODataEntry ConvertToODataEntry(object element, IEdmNavigationSource entitySource, ODataVersion targetVersion)
        {
            IEdmStructuredType entityType = EdmClrTypeUtils.GetEdmType(DataSourceManager.GetCurrentDataSource().Model, element) as IEdmStructuredType;

            if (entityType == null)
            {
                throw new InvalidOperationException("Can not create an entry for " + entitySource.Name);
            }

            var entry = new ODataEntry
            {
                Properties = GetProperties(element, entityType)
            };

            // Add Annotation in Entity Level
            if (((ClrObject)element).Annotations != null)
            {
                foreach (InstanceAnnotationType annotation in ((ClrObject)element).Annotations)
                {
                    if (string.IsNullOrEmpty(annotation.Target))
                    {
                        entry.InstanceAnnotations.Add(new ODataInstanceAnnotation(annotation.Name, annotation.ConvertValueToODataValue()));
                    }
                }
            }

            string typeName;

            if (entityType is IEdmEntityType)
            {
                typeName = (entityType as IEdmEntityType).Name;
            }
            else if (entityType is IEdmComplexType)
            {
                typeName = (entityType as IEdmComplexType).Name;
            }
            else
            {
                throw new InvalidOperationException("Not Supported Edmtype to convert to OData Entry.");
            }
            entry.TypeName = element.GetType().Namespace + "." + typeName;

            // TODO: work around for now
            if (!(entitySource is IEdmContainedEntitySet))
            {
                Uri entryUri = BuildEntryUri(element, entitySource, targetVersion);
                if (element.GetType().BaseType != null && entitySource.EntityType().Name != typeName)
                {
                    var editLink = new Uri(entryUri.AbsoluteUri.TrimEnd('/') + "/" + entry.TypeName);
                    entry.EditLink = editLink;
                    entry.ReadLink = editLink;
                }
                else
                {
                    entry.EditLink = entryUri;
                    entry.ReadLink = entryUri;
                }
                entry.Id = entryUri;
            }

            if (Utility.IsMediaEntity(element.GetType()))
            {
                var streamProvider = DataSourceManager.GetCurrentDataSource().StreamProvider;
                entry.MediaResource = new ODataStreamReferenceValue()
                {
                    ContentType = streamProvider.GetContentType(element),
                    ETag        = streamProvider.GetETag(element),
                };
            }

            return(entry);
        }
Example #25
0
 internal override IEdmEntityType GetElementType(IEdmNavigationSource navigationSource)
 {
     return(navigationSource.EntityType());
 }
        /// <summary>
        /// Converts an item from the data store into an ODataEntry.
        /// </summary>
        /// <param name="element">The item to convert.</param>
        /// <param name="navigationSource">The navigation source that the item belongs to.</param>
        /// <param name="targetVersion">The OData version this segment is targeting.</param>
        /// <returns>The converted ODataEntry.</returns>
        public static ODataEntry ConvertToODataEntry(object element, IEdmNavigationSource entitySource, ODataVersion targetVersion)
        {
            IEdmStructuredType entityType = EdmClrTypeUtils.GetEdmType(DataSourceManager.GetCurrentDataSource().Model, element) as IEdmStructuredType;

            if (entityType == null)
            {
                throw new InvalidOperationException("Can not create an entry for " + entitySource.Name);
            }

            var entry = new ODataEntry
            {
                Properties = GetProperties(element, entityType)
            };

            // Add Annotation in Entity Level
            if (((ClrObject)element).Annotations != null)
            {
                foreach (InstanceAnnotationType annotation in ((ClrObject)element).Annotations)
                {
                    if (string.IsNullOrEmpty(annotation.Target))
                    {
                        entry.InstanceAnnotations.Add(new ODataInstanceAnnotation(annotation.Name, annotation.ConvertValueToODataValue()));
                    }
                }
            }

            string typeName;
            if (entityType is IEdmEntityType)
            {
                typeName = (entityType as IEdmEntityType).Name;
            }
            else if (entityType is IEdmComplexType)
            {
                typeName = (entityType as IEdmComplexType).Name;
            }
            else
            {
                throw new InvalidOperationException("Not Supported Edmtype to convert to OData Entry.");
            }
            entry.TypeName = element.GetType().Namespace + "." + typeName;

            // TODO tiano. work around for now
            if (!(entitySource is IEdmContainedEntitySet))
            {
                Uri entryUri = BuildEntryUri(element, entitySource, targetVersion);
                if (element.GetType().BaseType != null && entitySource.EntityType().Name != typeName)
                {
                    var editLink = new Uri(entryUri.AbsoluteUri.TrimEnd('/') + "/" + entry.TypeName);
                    entry.EditLink = editLink;
                    entry.ReadLink = editLink;
                }
                else
                {
                    entry.EditLink = entryUri;
                    entry.ReadLink = entryUri;
                }
                entry.Id = entryUri;
            }

            if (Utility.IsMediaEntity(element.GetType()))
            {
                var streamProvider = DataSourceManager.GetCurrentDataSource().StreamProvider;
                entry.MediaResource = new ODataStreamReferenceValue()
                {
                    ContentType = streamProvider.GetContentType(element),
                    ETag = streamProvider.GetETag(element),
                };
            }

            return entry;
        }