/// <summary>
        ///
        /// </summary>
        /// <param name="context"></param>
        public virtual bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            Debug.Assert(context.Controller != null);
            Debug.Assert(context.Action != null);
            ActionModel action = context.Action;

            if (action.Controller.ControllerType != typeof(MetadataController).GetTypeInfo())
            {
                return(false);
            }

            if (action.ActionMethod.Name == "GetMetadata")
            {
                ODataPathTemplate template = new ODataPathTemplate(MetadataSegmentTemplate.Instance);
                action.AddSelector(context.Prefix, context.Model, template);

                return(true);
            }

            if (action.ActionMethod.Name == "GetServiceDocument")
            {
                ODataPathTemplate template = new ODataPathTemplate();
                action.AddSelector(context.Prefix, context.Model, template);

                return(true);
            }

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

            Debug.Assert(context.Controller != null);
            Debug.Assert(context.Action != null);
            ActionModel action     = context.Action;
            string      actionName = action.ActionMethod.Name;

            // for ~$metadata
            if (actionName == "GetMetadata")
            {
                ODataPathTemplate template = new ODataPathTemplate(MetadataSegmentTemplate.Instance);
                action.AddSelector("Get", context.Prefix, context.Model, template, context.RouteOptions);
                return(true);
            }

            // for ~/
            if (actionName == "GetServiceDocument")
            {
                ODataPathTemplate template = new ODataPathTemplate();
                action.AddSelector("Get", context.Prefix, context.Model, template, context.RouteOptions);
                return(true);
            }

            return(false);
        }
        /// <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);
        }
        /// <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)
            {
                return(false);
            }

            IEdmEntitySet entitySet = context.EntitySet;

            if (action.Parameters.Count != 0)
            {
                // TODO: improve here to accept other parameters, for example ODataQueryOptions<T>
                return(false);
            }

            string actionName = action.ActionMethod.Name;

            if (actionName == "Get" ||
                actionName == $"Get{entitySet.Name}")
            {
                ODataPathTemplate template = new ODataPathTemplate(new EntitySetSegmentTemplate(entitySet));
                action.AddSelector(context.Prefix, context.Model, template);

                // $count
                template = new ODataPathTemplate(new EntitySetSegmentTemplate(entitySet), CountSegmentTemplate.Instance);
                action.AddSelector(context.Prefix, context.Model, template);
                return(true);
            }
            else if (actionName == "Post" ||
                     actionName == $"Post{entitySet.EntityType().Name}")
            {
                ODataPathTemplate template = new ODataPathTemplate(new EntitySetSegmentTemplate(entitySet));
                action.AddSelector(context.Prefix, context.Model, template);
                return(true);
            }
            else
            {
                // process the derive type (cast)
                // search all derived types
            }

            return(false);
        }
        /// <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 || action.Parameters.Count < 1)
            {
                // At lease one parameter for the key.
                return(false);
            }

            IEdmEntitySet entitySet      = context.EntitySet;
            var           entityType     = entitySet.EntityType();
            var           entityTypeName = entitySet.EntityType().Name;
            var           keys           = entitySet.EntityType().Key().ToArray();

            string actionName = action.ActionMethod.Name;

            if ((actionName == "Get" ||
                 actionName == $"Get{entityTypeName}" ||
                 actionName == "Put" ||
                 actionName == $"Put{entityTypeName}" ||
                 actionName == "Patch" ||
                 actionName == $"Patch{entityTypeName}" ||
                 actionName == "Delete" ||
                 actionName == $"Delete{entityTypeName}") &&
                keys.Length == action.Parameters.Count)
            {
                ODataPathTemplate template = new ODataPathTemplate(
                    new EntitySetSegmentTemplate(entitySet),
                    new KeySegmentTemplate(entityType)
                    );

                // support key in parenthesis
                action.AddSelector(context.Prefix, context.Model, template);

                // support key as segment
                ODataPathTemplate newTemplate = template.Clone();
                newTemplate.KeyAsSegment = true;
                action.AddSelector(context.Prefix, context.Model, newTemplate);
                return(true);
            }

            return(false);
        }
Example #6
0
        internal static bool ProcessNonNavigationProperty(string httpMethod, ODataControllerActionContext context,
                                                          ActionModel action,
                                                          IEdmNavigationSource navigationSource,
                                                          IEdmEntityType entityType, IEdmStructuredType castType)
        {
            // Action parameter should have a (string navigationProperty) parameter
            if (!action.HasParameter <string>("navigationProperty"))
            {
                return(false);
            }

            // Let's only handle single-key convention, for composite key, use attribute routing or non-generic navigation.
            bool hasRelatedKey = action.Parameters.Any(p => p.Name == "relatedKey"); // case sensitive?
            bool hasRelatedId  = action.Parameters.Any(p => p.Name == "relatedId");

            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 != castType)
            {
                segments.Add(new CastSegmentTemplate(castType, entityType, navigationSource));
            }

            if (hasRelatedKey)
            {
                segments.Add(new NavigationLinkTemplateSegmentTemplate(entityType, navigationSource)
                {
                    RelatedKey = "relatedKey"
                });
            }
            else if (hasRelatedId)
            {
                segments.Add(new NavigationLinkTemplateSegmentTemplate(entityType, navigationSource)
                {
                    RelatedKey = "relatedId"
                });
            }
            else
            {
                segments.Add(new NavigationLinkTemplateSegmentTemplate(entityType, navigationSource));
            }

            ODataPathTemplate template = new ODataPathTemplate(segments);

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

            return(true);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="context"></param>
        public bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            ActionModel action = context.Action;

            if (action.Controller.ControllerName != "ODataOperationImport")
            {
                return(false);
            }

            IEdmModel model = context.Model;

            // By convention, we use the operation name as the action name in the controller
            string actionMethodName    = action.ActionMethod.Name;
            var    edmOperationImports = model.EntityContainer.FindOperationImports(actionMethodName);

            foreach (var edmOperationImport in edmOperationImports)
            {
                IEdmEntitySetBase targetSet = null;
                edmOperationImport.TryGetStaticEntitySet(model, out targetSet);

                if (edmOperationImport.IsActionImport())
                {
                    ODataPathTemplate template = new ODataPathTemplate(new ActionImportSegmentTemplate((IEdmActionImport)edmOperationImport));
                    action.AddSelector(context.Prefix, context.Model, template);
                }
                else
                {
                    IEdmFunctionImport functionImport = (IEdmFunctionImport)edmOperationImport;
                    ODataPathTemplate  template       = new ODataPathTemplate(new FunctionImportSegmentTemplate(functionImport));
                    action.AddSelector(context.Prefix, context.Model, template);
                }
            }

            // in OData operationImport routing convention, all action are processed by default
            // even it's not a really edm operation import call.
            return(true);
        }
Example #8
0
        private static void AddSelector(string httpMethod, ODataControllerActionContext context, ActionModel action,
                                        IEdmNavigationSource navigationSource,
                                        IEdmStructuralProperty edmProperty,
                                        IEdmType cast, IEdmEntityType declaringType, bool dollarValue, bool dollarCount)
        {
            IEdmEntitySet  entitySet  = navigationSource as IEdmEntitySet;
            IEdmEntityType entityType = navigationSource.EntityType();

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

            if (entitySet != null)
            {
                segments.Add(new EntitySetSegmentTemplate(entitySet));
                segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, navigationSource));
            }
            else
            {
                segments.Add(new SingletonSegmentTemplate(navigationSource as IEdmSingleton));
            }

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

            segments.Add(new PropertySegmentTemplate(edmProperty));

            if (cast != null)
            {
                if (edmProperty.Type.IsCollection())
                {
                    cast = new EdmCollectionType(cast.ToEdmTypeReference(edmProperty.Type.IsNullable));
                }

                // TODO: maybe create the collection type for the collection????
                segments.Add(new CastSegmentTemplate(cast, edmProperty.Type.Definition, navigationSource));
            }

            if (dollarValue)
            {
                segments.Add(new ValueSegmentTemplate(edmProperty.Type.Definition));
            }

            if (dollarCount)
            {
                segments.Add(CountSegmentTemplate.Instance);
            }

            ODataPathTemplate template = new ODataPathTemplate(segments);

            action.AddSelector(httpMethod.NormalizeHttpMethod(), context.Prefix, context.Model, template, context.Options?.RouteOptions);
        }
Example #9
0
        public void AddSelector_ThrowsArgumentNull_ForInputParameter()
        {
            // Arrange & Act & Assert
            ActionModel action = null;

            ExceptionAssert.ThrowsArgumentNull(() => action.AddSelector(null, null, null, null), "action");

            // Arrange & Act & Assert
            MethodInfo methodInfo = typeof(TestController).GetMethod("Get");

            action = methodInfo.BuildActionModel();
            ExceptionAssert.ThrowsArgumentNullOrEmpty(() => action.AddSelector(null, null, null, null), "httpMethods");

            // Arrange & Act & Assert
            string httpMethods = "get";

            ExceptionAssert.ThrowsArgumentNull(() => action.AddSelector(httpMethods, null, null, null), "model");

            // Arrange & Act & Assert
            IEdmModel model = new Mock <IEdmModel>().Object;

            ExceptionAssert.ThrowsArgumentNull(() => action.AddSelector(httpMethods, null, model, null), "path");
        }
        private static void AddSelector(IEdmEntitySet entitySet, IEdmEntityType entityType,
                                        IEdmStructuredType castType, string prefix, IEdmModel model, ActionModel action, string httpMethod)
        {
            IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>
            {
                new EntitySetSegmentTemplate(entitySet),
                KeySegmentTemplate.CreateKeySegment(entityType, entitySet)
            };

            // If we have the type cast
            if (castType != null)
            {
                if (castType == entityType)
                {
                    // If cast type is the entity type of the entity set.
                    // we support two templates
                    // ~/Customers({key})
                    action.AddSelector(httpMethod, prefix, model, new ODataPathTemplate(segments));

                    // ~/Customers({key})/Ns.Customer
                    segments.Add(new CastSegmentTemplate(castType, entityType, entitySet));
                    action.AddSelector(httpMethod, prefix, model, new ODataPathTemplate(segments));
                }
                else
                {
                    // ~/Customers({key})/Ns.VipCustomer
                    segments.Add(new CastSegmentTemplate(castType, entityType, entitySet));
                    action.AddSelector(httpMethod, prefix, model, new ODataPathTemplate(segments));
                }
            }
            else
            {
                // ~/Customers({key})
                action.AddSelector(httpMethod, prefix, model, new ODataPathTemplate(segments));
            }
        }
Example #11
0
        private void AddSelector(string httpMethod, ODataControllerActionContext context, ActionModel action,
                                 IEdmNavigationSource navigationSource, string declared, IEdmEntityType declaringEntityType,
                                 IEdmNavigationProperty navigationProperty, bool hasKey, bool dollarCount)
        {
            IEdmEntitySet  entitySet  = navigationSource as IEdmEntitySet;
            IEdmEntityType entityType = navigationSource.EntityType();

            // Starts the routing template
            IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>();

            if (entitySet != null)
            {
                segments.Add(new EntitySetSegmentTemplate(entitySet));
            }
            else
            {
                segments.Add(new SingletonSegmentTemplate(navigationSource as IEdmSingleton));
            }

            if (hasKey)
            {
                segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, navigationSource));
            }

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

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

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

            if (dollarCount)
            {
                segments.Add(CountSegmentTemplate.Instance);
            }

            ODataPathTemplate template = new ODataPathTemplate(segments);

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

            Log.AddedODataSelector(_logger, action, template);
        }
Example #12
0
        public void AddSelector_AddsCors_ForActionsWithCorsAttribute(Type controllerType, string actionName, bool expectedCorsSetting)
        {
            // Arrange
            IEdmModel   model      = new Mock <IEdmModel>().Object;
            MethodInfo  methodInfo = controllerType.GetMethod(actionName);
            ActionModel action     = methodInfo.BuildActionModel();

            action.Controller = ControllerModelHelpers.BuildControllerModel(controllerType);

            // Act
            action.AddSelector("Get", string.Empty, model, new ODataPathTemplate(CountSegmentTemplate.Instance));

            // Assert
            SelectorModel newSelector = action.Selectors.FirstOrDefault();

            Assert.NotNull(newSelector);
            HttpMethodMetadata httpMethodMetadata = newSelector.EndpointMetadata.OfType <HttpMethodMetadata>().FirstOrDefault();

            Assert.NotNull(httpMethodMetadata);
            Assert.Equal(httpMethodMetadata.AcceptCorsPreflight, expectedCorsSetting);
        }
Example #13
0
        /// <inheritdoc />
        public virtual bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            ActionModel action = context.Action;
            IEdmModel   model  = context.Model;

            // By convention, we use the operation import name as the action name in the controller
            string actionMethodName = action.ActionName;

            var edmOperationImports = model.ResolveOperationImports(actionMethodName, enableCaseInsensitive: true);

            if (!edmOperationImports.Any())
            {
                return(true);
            }

            (var actionImports, var functionImports) = edmOperationImports.SplitOperationImports();

            // It's not allowed to have an action import and function import with the same name.
            if (actionImports.Count > 0 && functionImports.Count > 0)
            {
                throw new ODataException(Error.Format(SRResources.OperationMustBeUniqueInEntitySetContainer, actionMethodName));
            }
            else if (actionImports.Count > 0 && context.Action.Attributes.Any(a => a is HttpPostAttribute))
            {
                if (actionImports.Count != 1)
                {
                    throw new ODataException(Error.Format(SRResources.MultipleActionImportFound, actionMethodName));
                }

                IEdmActionImport actionImport = actionImports[0];

                IEdmEntitySetBase targetEntitySet;
                actionImport.TryGetStaticEntitySet(model, out targetEntitySet);

                // TODO:
                // 1. shall we check the [HttpPost] attribute, or does the ASP.NET Core have the default?
                // 2) shall we check the action has "ODataActionParameters" parameter type?
                ODataPathTemplate template = new ODataPathTemplate(new ActionImportSegmentTemplate(actionImport, targetEntitySet));
                action.AddSelector("Post", context.Prefix, context.Model, template, context.Options?.RouteOptions);
                return(true);
            }
            else if (functionImports.Count > 0 && context.Action.Attributes.Any(a => a is HttpGetAttribute))
            {
                IEdmFunctionImport functionImport = FindFunctionImport(functionImports, action);
                if (functionImport == null)
                {
                    return(false);
                }

                IEdmEntitySetBase targetSet;
                functionImport.TryGetStaticEntitySet(model, out targetSet);

                // TODO:
                // 1) shall we check the [HttpGet] attribute, or does the ASP.NET Core have the default?
                ODataPathTemplate template = new ODataPathTemplate(new FunctionImportSegmentTemplate(functionImport, targetSet));
                action.AddSelector("Get", context.Prefix, context.Model, template, context.Options?.RouteOptions);
                return(true);
            }
            else
            {
                // doesn't find an operation, return true means to skip the remaining conventions.
                return(false);
            }
        }
        /// <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);
        }
Example #15
0
        private static bool ProcessEntitySetAction(string actionName, IEdmEntitySet entitySet, IEdmStructuredType castType,
                                                   ODataControllerActionContext context, ActionModel action)
        {
            if (actionName == "Get" || actionName == $"Get{entitySet.Name}")
            {
                IEdmCollectionType castCollectionType = null;
                if (castType != null)
                {
                    castCollectionType = castType.ToCollection(true);
                }

                IEdmCollectionType entityCollectionType = entitySet.EntityType().ToCollection(true);

                // GET ~/Customers or GET ~/Customers/Ns.VipCustomer
                IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>
                {
                    new EntitySetSegmentTemplate(entitySet)
                };
                if (castType != null)
                {
                    segments.Add(new CastSegmentTemplate(castCollectionType, entityCollectionType, entitySet));
                }
                ODataPathTemplate template = new ODataPathTemplate(segments);
                action.AddSelector("Get", context.Prefix, context.Model, template, context.Options?.RouteOptions);

                // GET ~/Customers/$count or GET ~/Customers/Ns.VipCustomer/$count
                segments = new List <ODataSegmentTemplate>
                {
                    new EntitySetSegmentTemplate(entitySet)
                };
                if (castType != null)
                {
                    segments.Add(new CastSegmentTemplate(castCollectionType, entityCollectionType, entitySet));
                }
                segments.Add(CountSegmentTemplate.Instance);

                template = new ODataPathTemplate(segments);
                action.AddSelector("Get", context.Prefix, context.Model, template, context.Options?.RouteOptions);
                return(true);
            }
            else if (actionName == "Post" || actionName == $"Post{entitySet.EntityType().Name}")
            {
                // POST ~/Customers
                IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>
                {
                    new EntitySetSegmentTemplate(entitySet)
                };
                if (castType != null)
                {
                    IEdmCollectionType castCollectionType   = castType.ToCollection(true);
                    IEdmCollectionType entityCollectionType = entitySet.EntityType().ToCollection(true);
                    segments.Add(new CastSegmentTemplate(castCollectionType, entityCollectionType, entitySet));
                }
                ODataPathTemplate template = new ODataPathTemplate(segments);
                action.AddSelector("Post", context.Prefix, context.Model, template, context.Options?.RouteOptions);
                return(true);
            }
            else if (actionName == "Patch" || actionName == $"Patch{entitySet.Name}")
            {
                // PATCH ~/Patch  , ~/PatchCustomers
                IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>
                {
                    new EntitySetSegmentTemplate(entitySet)
                };

                if (castType != null)
                {
                    IEdmCollectionType castCollectionType   = castType.ToCollection(true);
                    IEdmCollectionType entityCollectionType = entitySet.EntityType().ToCollection(true);
                    segments.Add(new CastSegmentTemplate(castCollectionType, entityCollectionType, entitySet));
                }

                ODataPathTemplate template = new ODataPathTemplate(segments);
                action.AddSelector("Patch", context.Prefix, context.Model, template, context.Options?.RouteOptions);
                return(true);
            }

            return(false);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="context"></param>
        public bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            // use the cached
            Debug.Assert(context.Singleton != null);
            Debug.Assert(context.Action != null);
            ActionModel action = context.Action;

            string    singletonName = context.Singleton.Name;
            string    prefix        = context.Prefix;
            IEdmModel model         = context.Model;

            string actionMethodName = action.ActionMethod.Name;

            if (IsSupportedActionName(actionMethodName, singletonName))
            {
                ODataPathTemplate template = new ODataPathTemplate(new SingletonSegmentTemplate(context.Singleton));
                action.AddSelector(context.Prefix, context.Model, template);

                // processed
                return(true);
            }

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

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

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

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

                // Shall we cast to base type and the type itself? I think yes.
                IEdmEntityType baseType = entityType;
                while (baseType != null)
                {
                    if (baseType.Name == castTypeName)
                    {
                        ODataPathTemplate template = new ODataPathTemplate(new SingletonSegmentTemplate(context.Singleton),
                                                                           new CastSegmentTemplate(baseType));
                        action.AddSelector(context.Prefix, context.Model, template);

                        return(true);
                    }

                    baseType = baseType.BaseEntityType();
                }

                // shall we cast to derived type
                IEdmEntityType castType = model.FindAllDerivedTypes(entityType).OfType <IEdmEntityType>().FirstOrDefault(c => c.Name == castTypeName);
                if (castType != null)
                {
                    ODataPathTemplate template = new ODataPathTemplate(new SingletonSegmentTemplate(context.Singleton),
                                                                       new CastSegmentTemplate(castType));
                    action.AddSelector(context.Prefix, context.Model, template);

                    return(true);
                }
            }

            return(false);
        }
Example #17
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 #18
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);
        }
Example #19
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);
        }