private static IEdmOperation[] FindCandidates(ODataControllerActionContext context, IEdmEntityType entityType, string actionName,
                                                      out IEdmEntityType castTypeFromActionName, out bool isOnCollection)
        {
            // OperationNameOnCollectionOfEntityType
            StringComparison caseComparision = context.Options?.RouteOptions?.EnableActionNameCaseInsensitive == true ?
                                               StringComparison.OrdinalIgnoreCase :
                                               StringComparison.Ordinal;

            string operationName = SplitActionName(actionName, out string cast, out isOnCollection, caseComparision);

            castTypeFromActionName = null;
            if (cast != null)
            {
                if (cast.Length == 0)
                {
                    // Early return for the following cases:
                    // - {OperationName}On
                    // - {OperationName}OnCollectionOf
                    return(Array.Empty <IEdmOperation>());
                }

                castTypeFromActionName = entityType.FindTypeInInheritance(context.Model, cast, context.Options?.RouteOptions?.EnableActionNameCaseInsensitive == true) as IEdmEntityType;
                if (castTypeFromActionName == null)
                {
                    return(Array.Empty <IEdmOperation>());
                }
            }

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

            Debug.Assert(context.Singleton != null);
            Debug.Assert(context.Action != null);

            ActionModel action        = context.Action;
            string      singletonName = context.Singleton.Name;

            string actionMethodName = action.ActionName;

            if (IsSupportedActionName(actionMethodName, singletonName, out string httpMethod))
            {
                // ~/Me
                ODataPathTemplate template = new ODataPathTemplate(new SingletonSegmentTemplate(context.Singleton));
                action.AddSelector(httpMethod, context.Prefix, context.Model, template, context.Options?.RouteOptions);

                // processed
                return(true);
            }

            // type cast
            // GetFrom{EntityTypeName} or Get{SingletonName}From{EntityTypeName}
            int index = actionMethodName.IndexOf("From", StringComparison.Ordinal);

            if (index == -1)
            {
                return(false);
            }

            string actionPrefix = actionMethodName.Substring(0, index);

            if (IsSupportedActionName(actionPrefix, singletonName, out httpMethod))
            {
                string         castTypeName = actionMethodName.Substring(index + 4);
                IEdmEntityType entityType   = context.Singleton.EntityType();

                // Shall we cast to base type and the type itself? I think yes.
                IEdmStructuredType castType = entityType.FindTypeInInheritance(context.Model, castTypeName);
                if (castType != null)
                {
                    // ~/Me/Namespace.TypeCast
                    ODataPathTemplate template = new ODataPathTemplate(
                        new SingletonSegmentTemplate(context.Singleton),
                        new CastSegmentTemplate(castType, entityType, context.Singleton));

                    action.AddSelector(httpMethod, context.Prefix, context.Model, template, context.Options?.RouteOptions);
                    return(true);
                }
            }

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

            ActionModel    action     = context.Action;
            IEdmEntitySet  entitySet  = context.EntitySet;
            IEdmEntityType entityType = entitySet.EntityType();

            // if the action has key parameter, skip it.
            if (action.HasODataKeyParameter(entityType, context.Options?.RouteOptions?.EnablePropertyNameCaseInsensitive ?? false))
            {
                return(false);
            }

            string actionName = action.ActionName;

            // 1. Without type case
            if (ProcessEntitySetAction(actionName, entitySet, null, context, action))
            {
                return(true);
            }

            // 2. process the derived type (cast) by searching all derived types
            // GetFrom{EntityTypeName} or Get{EntitySet}From{EntityTypeName}
            int index = actionName.IndexOf("From", StringComparison.Ordinal);

            if (index == -1)
            {
                return(false);
            }

            string castTypeName = actionName.Substring(index + 4); // + 4 means to skip the "From"

            if (castTypeName.Length == 0)
            {
                // Early return for the following cases:
                // - Get|Post|PatchFrom
                // - Get|Patch{EntitySet}From
                // - Post{EntityType}From
                return(false);
            }

            IEdmStructuredType castType = entityType.FindTypeInInheritance(context.Model, castTypeName);

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

            string actionPrefix = actionName.Substring(0, index);

            return(ProcessEntitySetAction(actionPrefix, entitySet, castType, context, action));
        }
예제 #4
0
        /// <inheritdoc />
        public virtual bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            ActionModel    action     = context.Action;
            IEdmEntitySet  entitySet  = context.EntitySet;
            IEdmEntityType entityType = entitySet.EntityType();

            // if the action has key parameter, skip it.
            if (action.HasODataKeyParameter(entityType))
            {
                return(false);
            }

            string actionName = action.ActionMethod.Name;

            // 1. Without type case
            if (ProcessEntitySetAction(actionName, entitySet, null, context, action))
            {
                return(true);
            }

            // 2. process the derive type (cast) by searching all derived types
            // GetFrom{EntityTypeName} or Get{EntitySet}From{EntityTypeName}
            int index = actionName.IndexOf("From", StringComparison.Ordinal);

            if (index == -1)
            {
                return(false);
            }

            string             castTypeName = actionName.Substring(index + 4); // + 4 means to skip the "From"
            IEdmStructuredType castType     = entityType.FindTypeInInheritance(context.Model, castTypeName);

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

            string actionPrefix = actionName.Substring(0, index);

            return(ProcessEntitySetAction(actionPrefix, entitySet, castType, context, action));
        }
        /// <inheritdoc />
        public virtual bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            ActionModel    action     = context.Action;
            IEdmEntitySet  entitySet  = context.EntitySet;
            IEdmEntityType entityType = entitySet.EntityType();

            // if the action has no key parameter, skip it.
            if (!action.HasODataKeyParameter(entityType))
            {
                return(false);
            }

            string actionName = action.ActionMethod.Name;

            // We care about the action in this pattern: {HttpMethod}{EntityTypeName}
            (string httpMethod, string castTypeName) = Split(actionName);
            if (httpMethod == null)
            {
                return(false);
            }

            IEdmStructuredType castType = null;

            if (castTypeName != null)
            {
                castType = entityType.FindTypeInInheritance(context.Model, castTypeName);
                if (castType == null)
                {
                    return(false);
                }
            }

            AddSelector(entitySet, entityType, castType, context.Prefix, context.Model, action, httpMethod);
            return(true);
        }
        /// <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);
        }
예제 #7
0
        /// <summary>
        /// Process the operation candidates using the information.
        /// </summary>
        /// <param name="context">The controller and action context.</param>
        /// <param name="entityType">The Edm entity type.</param>
        /// <param name="navigationSource">The Edm navigation source.</param>
        protected void ProcessOperations(ODataControllerActionContext context, IEdmEntityType entityType, IEdmNavigationSource navigationSource)
        {
            Contract.Assert(context != null);
            Contract.Assert(entityType != null);
            Contract.Assert(navigationSource != null);

            string actionName = context.Action.ActionMethod.Name;

            bool hasKeyParameter = context.Action.HasODataKeyParameter(entityType);

            if (context.Singleton != null && hasKeyParameter)
            {
                // Singleton doesn't allow to call action with key.
                return;
            }

            // OperationNameOnCollectionOfEntityType
            string operationName = SplitActionName(actionName, out string cast, out bool isOnCollection);

            IEdmEntityType castTypeFromActionName = null;

            if (cast != null)
            {
                castTypeFromActionName = entityType.FindTypeInInheritance(context.Model, cast) as IEdmEntityType;
                if (castTypeFromActionName == null)
                {
                    return;
                }
            }

            // TODO: refactor here
            // If we have mulitple same function defined, we should match the best one?
            IEnumerable <IEdmOperation> candidates = context.Model.SchemaElements.OfType <IEdmOperation>().Where(f => f.IsBound && f.Name == operationName);

            foreach (IEdmOperation edmOperation in candidates)
            {
                IEdmOperationParameter bindingParameter = edmOperation.Parameters.FirstOrDefault();
                if (bindingParameter == null)
                {
                    // bound operation at least has one parameter which type is the binding type.
                    continue;
                }

                IEdmTypeReference bindingType = bindingParameter.Type;
                bool bindToCollection         = bindingType.TypeKind() == EdmTypeKind.Collection;
                if (bindToCollection)
                {
                    // if binding to collection the action has key parameter or a singleton, skip
                    if (context.Singleton != null || hasKeyParameter)
                    {
                        continue;
                    }
                }
                else
                {
                    // if binding to non-collection and the action hasn't key parameter, skip
                    if (isOnCollection || (context.EntitySet != null && !hasKeyParameter))
                    {
                        continue;
                    }
                }

                // We only allow the binding type is entity type or collection of entity type.
                if (!bindingType.Definition.IsEntityOrEntityCollectionType(out IEdmEntityType bindingEntityType))
                {
                    continue;
                }

                IEdmEntityType castType = null;
                if (castTypeFromActionName == null)
                {
                    if (entityType.IsOrInheritsFrom(bindingEntityType))
                    {
                        // True if and only if the thisType is equivalent to or inherits from otherType.
                        castType = null;
                    }
                    else if (bindingEntityType.InheritsFrom(entityType))
                    {
                        // True if and only if the type inherits from the potential base type.
                        castType = bindingEntityType;
                    }
                    else
                    {
                        continue;
                    }
                }
                else
                {
                    if (isOnCollection && !bindToCollection)
                    {
                        continue;
                    }

                    if (bindingEntityType != castTypeFromActionName)
                    {
                        continue;
                    }

                    if (castTypeFromActionName != entityType)
                    {
                        castType = castTypeFromActionName;
                    }
                }

                // TODO: need discussion ahout:
                // 1) Do we need to match the whole parameter count?
                // 2) Do we need to select the best match? So far, i don't think and let it go.
                if (!IsOperationParameterMeet(edmOperation, context.Action))
                {
                    continue;
                }

                AddSelector(context, edmOperation, hasKeyParameter, entityType, navigationSource, castType);
            }
        }
        /// <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);
        }
예제 #9
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);
        }
        /// <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);
        }
예제 #11
0
        /// <inheritdoc />
        public bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            Debug.Assert(context.Action != null);

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

            // Need to refactor the following
            // for example:  CreateRef( with the navigation property parameter) should for all navigation properties
            // CreateRefToOrdersFromCustomer, CreateRefToOrders, CreateRef.
            string method = SplitRefActionName(actionMethodName, out string httpMethod, out string property, out string declaring);

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

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

            // For entity set, we should have the key parameter
            // For Singleton, we should not have the key parameter
            bool hasODataKeyParameter = action.HasODataKeyParameter(entityType);

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

            // Find the navigation property declaring type
            IEdmStructuredType declaringType = entityType;

            if (declaring != null)
            {
                declaringType = entityType.FindTypeInInheritance(context.Model, declaring);
                if (declaringType == null)
                {
                    return(false);
                }
            }

            // Process the generic scenario
            if (property == null)
            {
                return(ProcessNonNavigationProperty(httpMethod, context, action, navigationSource, entityType, declaringType));
            }

            // Find the navigation property if have
            IEdmNavigationProperty navigationProperty = null;

            if (property != null)
            {
                navigationProperty = declaringType.DeclaredNavigationProperties().FirstOrDefault(p => p.Name == property);
            }

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

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

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

            if (entityType != declaringType)
            {
                segments.Add(new CastSegmentTemplate(declaringType, entityType, navigationSource));
            }

            IEdmNavigationSource          targetNavigationSource = navigationSource.FindNavigationTarget(navigationProperty, segments, out _);
            NavigationLinkSegmentTemplate linkTemplate           = new NavigationLinkSegmentTemplate(navigationProperty, targetNavigationSource);

            IEdmEntityType navigationPropertyType            = navigationProperty.Type.GetElementTypeOrSelf().AsEntity().EntityDefinition();
            bool           hasNavigationPropertyKeyParameter = action.HasODataKeyParameter(navigationPropertyType, "relatedKey");

            if (hasNavigationPropertyKeyParameter)
            {
                linkTemplate.Key = KeySegmentTemplate.CreateKeySegment(navigationPropertyType, targetNavigationSource, "relatedKey");
            }
            else
            {
                hasNavigationPropertyKeyParameter = action.HasODataKeyParameter(navigationPropertyType, "relatedId");
                if (hasNavigationPropertyKeyParameter)
                {
                    linkTemplate.Key = KeySegmentTemplate.CreateKeySegment(navigationPropertyType, targetNavigationSource, "relatedId");
                }
            }

            segments.Add(linkTemplate);

            ODataPathTemplate template = new ODataPathTemplate(segments);

            action.AddSelector(httpMethod, context.Prefix, context.Model, template, context.Options?.RouteOptions);

            // processed
            return(true);
        }