Exemplo n.º 1
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);
        }