Example #1
0
        public void HasODataKeyParameter_ThrowsArgumentNull_EntityType()
        {
            // Arrange & Act & Assert
            ActionModel action = new ActionModel(_methodInfo, new List <object>());

            ExceptionAssert.ThrowsArgumentNull(() => action.HasODataKeyParameter(entityType: null), "entityType");
        }
Example #2
0
        public void HasODataKeyParameter_ThrowsArgumentNull_Action()
        {
            // Arrange & Act & Assert
            ActionModel action = null;

            ExceptionAssert.ThrowsArgumentNull(() => action.HasODataKeyParameter(entityType: null), "action");
        }
Example #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));
        }
Example #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);
        }
        /// <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 #7
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);
        }
Example #9
0
        /// <inheritdoc />
        public bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

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

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

            // 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);
            }

            // Action parameter should have a (string navigationProperty) parameter
            if (!action.HasParameter <string>("navigationProperty"))
            {
                return(false);
            }

            IEdmNavigationSource navigationSource;
            IEdmEntityType       entityType;

            if (context.EntitySet != null)
            {
                entityType       = context.EntitySet.EntityType();
                navigationSource = context.EntitySet;
            }
            else
            {
                entityType       = context.Singleton.EntityType();
                navigationSource = context.Singleton;
            }

            // 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);
                }
            }

            // 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(new KeySegmentTemplate(entityType));
            }
            else
            {
                segments.Add(new SingletonSegmentTemplate(context.Singleton));
            }

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

            if (navigationProperty != null)
            {
                segments.Add(new NavigationSegmentTemplate(navigationProperty));
            }
            else
            {
                //TODO: Add the navigation template segment template,
                // Or add the template for all navigation properties?
                return(false);
            }

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

            if (hasNavigationPropertyKeyParameter)
            {
                segments.Add(new KeySegmentTemplate(navigationPropertyType, "relatedKey"));
            }

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

            segments.Add(new RefSegmentTemplate(navigationProperty, targetNavigationSource));

            // TODO: support key as segment?
            ODataPathTemplate template = new ODataPathTemplate(segments);

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

            // processed
            return(true);
        }
Example #10
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);
        }