Beispiel #1
0
        /// <inheritdoc/>
        internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext,
                                                IWebApiActionMap actionMap)
        {
            if (odataPath.PathTemplate == "~/singleton")
            {
                SingletonSegment singletonSegment = (SingletonSegment)odataPath.Segments[0];
                string           httpMethodName   = GetActionNamePrefix(controllerContext.Request.GetRequestMethodOrPreflightMethod());

                if (httpMethodName != null)
                {
                    // e.g. Try Get{SingletonName} first, then fallback on Get action name
                    return(actionMap.FindMatchingAction(
                               httpMethodName + singletonSegment.Singleton.Name,
                               httpMethodName));
                }
            }
            else if (odataPath.PathTemplate == "~/singleton/cast")
            {
                SingletonSegment singletonSegment = (SingletonSegment)odataPath.Segments[0];
                IEdmEntityType   entityType       = (IEdmEntityType)odataPath.EdmType;
                string           httpMethodName   = GetActionNamePrefix(controllerContext.Request.GetRequestMethodOrPreflightMethod());

                if (httpMethodName != null)
                {
                    // e.g. Try Get{SingletonName}From{EntityTypeName} first, then fallback on Get action name
                    return(actionMap.FindMatchingAction(
                               httpMethodName + singletonSegment.Singleton.Name + "From" + entityType.Name,
                               httpMethodName + "From" + entityType.Name));
                }
            }

            return(null);
        }
        private static string FindRefActionName(IWebApiActionMap actionMap,
                                                IEdmNavigationProperty navigationProperty, IEdmEntityType declaringType, ODataRequestMethod method)
        {
            string actionNamePrefix;

            switch (method)
            {
            case ODataRequestMethod.Delete:
                actionNamePrefix = DeleteRefActionNamePrefix;
                break;

            case ODataRequestMethod.Get:
                actionNamePrefix = GetRefActionNamePrefix;
                break;

            default:
                actionNamePrefix = CreateRefActionNamePrefix;
                break;
            }

            // Examples: CreateRefToOrdersFromCustomer, CreateRefToOrders, CreateRef.
            return(actionMap.FindMatchingAction(
                       actionNamePrefix + "To" + navigationProperty.Name + "From" + declaringType.Name,
                       actionNamePrefix + "To" + navigationProperty.Name,
                       actionNamePrefix));
        }
Beispiel #3
0
        /// <inheritdoc/>
        internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext,
                                                IWebApiActionMap actionMap)
        {
            OperationImportSegment operationImportSegment = null;

            if (odataPath.PathTemplate == "~/unboundfunction" &&
                ODataRequestMethod.Get == controllerContext.Request.Method)
            {
                // The same function name may be used multiple times within a schema, each with a different set of parameters.
                // For unbound overloads the combination of the function name and the unordered set of parameter names
                // MUST identify a particular function overload.
                operationImportSegment = (OperationImportSegment)odataPath.Segments[0];
            }
            else if (odataPath.PathTemplate == "~/unboundaction" &&
                     ODataRequestMethod.Post == controllerContext.Request.Method)
            {
                // The same action name may be used multiple times within a schema provided there is at most one unbound overload
                operationImportSegment = (OperationImportSegment)odataPath.Segments[0];
            }

            string actionName = SelectAction(operationImportSegment, actionMap);

            if (actionName != null)
            {
                controllerContext.AddFunctionParameterToRouteData(operationImportSegment);
                return(actionName);
            }

            return(null);
        }
        /// <inheritdoc/>
        internal static string SelectActionImpl(IWebApiActionMap actionMap)
        {
            if (actionMap.Contains(UnmappedRequestActionName))
            {
                return(UnmappedRequestActionName);
            }

            return(null);
        }
Beispiel #5
0
        public static string FindMatchingAction(this IWebApiActionMap actionMap, params string[] targetActionNames)
        {
            foreach (string targetActionName in targetActionNames)
            {
                if (actionMap.Contains(targetActionName))
                {
                    return(targetActionName);
                }
            }

            return(null);
        }
Beispiel #6
0
        public static string SelectAction(this IEdmOperation operation, IWebApiActionMap actionMap, bool isCollection)
        {
            Contract.Assert(actionMap != null);

            if (operation == null)
            {
                return(null);
            }

            // The binding parameter is the first parameter by convention
            IEdmOperationParameter bindingParameter = operation.Parameters.FirstOrDefault();

            if (operation.IsBound && bindingParameter != null)
            {
                IEdmEntityType entityType = null;
                if (!isCollection)
                {
                    entityType = bindingParameter.Type.Definition as IEdmEntityType;
                }
                else
                {
                    IEdmCollectionType bindingParameterType = bindingParameter.Type.Definition as IEdmCollectionType;
                    if (bindingParameterType != null)
                    {
                        entityType = bindingParameterType.ElementType.Definition as IEdmEntityType;
                    }
                }

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

                string targetActionName = isCollection
                    ? operation.Name + "OnCollectionOf" + entityType.Name
                    : operation.Name + "On" + entityType.Name;
                return(actionMap.FindMatchingAction(targetActionName, operation.Name));
            }

            return(null);
        }
        /// <inheritdoc/>
        internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap)
        {
            ODataRequestMethod requestMethod = controllerContext.Request.Method;

            if (!IsSupportedRequestMethod(requestMethod))
            {
                return(null);
            }

            if (odataPath.PathTemplate == "~/entityset/key/navigation/$ref" ||
                odataPath.PathTemplate == "~/entityset/key/cast/navigation/$ref" ||
                odataPath.PathTemplate == "~/singleton/navigation/$ref" ||
                odataPath.PathTemplate == "~/singleton/cast/navigation/$ref")
            {
                NavigationPropertyLinkSegment navigationLinkSegment = (NavigationPropertyLinkSegment)odataPath.Segments.Last();
                IEdmNavigationProperty        navigationProperty    = navigationLinkSegment.NavigationProperty;
                IEdmEntityType declaringType = navigationProperty.DeclaringEntityType();

                string refActionName = FindRefActionName(actionMap, navigationProperty, declaringType, requestMethod);
                if (refActionName != null)
                {
                    if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal))
                    {
                        controllerContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1]);
                    }

                    controllerContext.RouteData.Add(ODataRouteConstants.NavigationProperty, navigationLinkSegment.NavigationProperty.Name);
                    return(refActionName);
                }
            }
            else if ((ODataRequestMethod.Delete == requestMethod) && (
                         odataPath.PathTemplate == "~/entityset/key/navigation/key/$ref" ||
                         odataPath.PathTemplate == "~/entityset/key/cast/navigation/key/$ref" ||
                         odataPath.PathTemplate == "~/singleton/navigation/key/$ref" ||
                         odataPath.PathTemplate == "~/singleton/cast/navigation/key/$ref"))
            {
                // the second key segment is the last segment in the path.
                // So the previous of last segment is the navigation property link segment.
                NavigationPropertyLinkSegment navigationLinkSegment = (NavigationPropertyLinkSegment)odataPath.Segments[odataPath.Segments.Count - 2];
                IEdmNavigationProperty        navigationProperty    = navigationLinkSegment.NavigationProperty;
                IEdmEntityType declaringType = navigationProperty.DeclaringEntityType();

                string refActionName = FindRefActionName(actionMap, navigationProperty, declaringType, requestMethod);
                if (refActionName != null)
                {
                    if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal))
                    {
                        controllerContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1]);
                    }

                    controllerContext.RouteData.Add(ODataRouteConstants.NavigationProperty, navigationLinkSegment.NavigationProperty.Name);
                    controllerContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments.Last(e => e is KeySegment), ODataRouteConstants.RelatedKey);
                    return(refActionName);
                }
            }

            return(null);
        }
Beispiel #8
0
        /// <summary>
        /// Selects the action for OData requests.
        /// </summary>
        /// <param name="odataPath">The OData path.</param>
        /// <param name="controllerContext">The controller context.</param>
        /// <param name="actionMap">The action map.</param>
        /// <returns>
        ///   <c>null</c> if the request isn't handled by this convention; otherwise, the name of the selected action
        /// </returns>
        internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap)
        {
            if (odataPath == null)
            {
                throw Error.ArgumentNull("odataPath");
            }

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

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

            if (odataPath.PathTemplate == "~")
            {
                return("GetServiceDocument");
            }

            if (odataPath.PathTemplate == "~/$metadata")
            {
                return("GetMetadata");
            }

            return(null);
        }
        /// <inheritdoc/>
        internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap)
        {
            string         prefix;
            TypeSegment    cast;
            IEdmProperty   property      = GetProperty(odataPath, controllerContext.Request.Method, out prefix, out cast);
            IEdmEntityType declaringType = property == null ? null : property.DeclaringType as IEdmEntityType;

            if (declaringType != null)
            {
                string actionName;
                if (cast == null)
                {
                    actionName = actionMap.FindMatchingAction(
                        prefix + property.Name + "From" + declaringType.Name,
                        prefix + property.Name);
                }
                else
                {
                    IEdmComplexType typeCast;
                    if (cast.EdmType.TypeKind == EdmTypeKind.Collection)
                    {
                        typeCast = ((IEdmCollectionType)cast.EdmType).ElementType.AsComplex().ComplexDefinition();
                    }
                    else
                    {
                        typeCast = (IEdmComplexType)cast.EdmType;
                    }

                    // for example: GetCityOfSubAddressFromVipCustomer or GetCityOfSubAddress
                    actionName = actionMap.FindMatchingAction(
                        prefix + property.Name + "Of" + typeCast.Name + "From" + declaringType.Name,
                        prefix + property.Name + "Of" + typeCast.Name);
                }

                if (actionName != null)
                {
                    if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal))
                    {
                        KeySegment keyValueSegment = (KeySegment)odataPath.Segments[1];
                        controllerContext.AddKeyValueToRouteData(keyValueSegment);
                    }

                    return(actionName);
                }
            }

            return(null);
        }
Beispiel #10
0
        private static string SelectAction(OperationImportSegment operationImportSegment, IWebApiActionMap actionMap)
        {
            if (operationImportSegment == null)
            {
                return(null);
            }

            IEdmOperationImport operationImport = operationImportSegment.OperationImports.FirstOrDefault();

            if (operationImport == null)
            {
                return(null);
            }

            return(actionMap.FindMatchingAction(operationImport.Name, "Invoke" + operationImport.Name));
        }
Beispiel #11
0
        /// <inheritdoc/>
        internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap)
        {
            if (odataPath.PathTemplate == "~/entityset/key" ||
                odataPath.PathTemplate == "~/entityset/key/cast")
            {
                string httpMethodName;

                switch (controllerContext.Request.GetRequestMethodOrPreflightMethod())
                {
                case ODataRequestMethod.Get:
                    httpMethodName = "Get";
                    break;

                case ODataRequestMethod.Put:
                    httpMethodName = "Put";
                    break;

                case ODataRequestMethod.Patch:
                case ODataRequestMethod.Merge:
                    httpMethodName = "Patch";
                    break;

                case ODataRequestMethod.Delete:
                    httpMethodName = "Delete";
                    break;

                default:
                    return(null);
                }

                Contract.Assert(httpMethodName != null);

                IEdmEntityType entityType = (IEdmEntityType)odataPath.EdmType;

                // e.g. Try GetCustomer first, then fallback on Get action name
                string actionName = actionMap.FindMatchingAction(
                    httpMethodName + entityType.Name,
                    httpMethodName);

                if (actionName != null)
                {
                    KeySegment keySegment = (KeySegment)odataPath.Segments[1];
                    controllerContext.AddKeyValueToRouteData(keySegment);
                    return(actionName);
                }
            }
            return(null);
        }
Beispiel #12
0
        /// <inheritdoc/>
        internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap)
        {
            if (ODataRequestMethod.Post == controllerContext.Request.Method)
            {
                switch (odataPath.PathTemplate)
                {
                case "~/entityset/key/cast/action":
                case "~/entityset/key/action":
                    string actionName = GetAction(odataPath).SelectAction(actionMap, isCollection: false);
                    if (actionName != null)
                    {
                        KeySegment keySegment = (KeySegment)odataPath.Segments[1];
                        controllerContext.AddKeyValueToRouteData(keySegment);
                    }
                    return(actionName);

                case "~/entityset/cast/action":
                case "~/entityset/action":
                    return(GetAction(odataPath).SelectAction(actionMap, isCollection: true));

                case "~/singleton/action":
                case "~/singleton/cast/action":
                    return(GetAction(odataPath).SelectAction(actionMap, isCollection: false));
                }
            }

            return(null);
        }
        /// <inheritdoc/>
        internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap)
        {
            ODataRequestMethod method           = controllerContext.Request.GetRequestMethodOrPreflightMethod();
            string             actionNamePrefix = GetActionMethodPrefix(method);

            if (actionNamePrefix == null)
            {
                return(null);
            }

            if (odataPath.PathTemplate == "~/entityset/key/navigation" ||
                odataPath.PathTemplate == "~/entityset/key/navigation/$count" ||
                odataPath.PathTemplate == "~/entityset/key/cast/navigation" ||
                odataPath.PathTemplate == "~/entityset/key/cast/navigation/$count" ||
                odataPath.PathTemplate == "~/singleton/navigation" ||
                odataPath.PathTemplate == "~/singleton/navigation/$count" ||
                odataPath.PathTemplate == "~/singleton/cast/navigation" ||
                odataPath.PathTemplate == "~/singleton/cast/navigation/$count")
            {
                NavigationPropertySegment navigationSegment =
                    (odataPath.Segments.Last() as NavigationPropertySegment) ??
                    odataPath.Segments[odataPath.Segments.Count - 2] as NavigationPropertySegment;
                IEdmNavigationProperty navigationProperty = navigationSegment.NavigationProperty;
                IEdmEntityType         declaringType      = navigationProperty.DeclaringType as IEdmEntityType;

                // It is not valid to *Post* to any non-collection valued navigation property.
                if (navigationProperty.TargetMultiplicity() != EdmMultiplicity.Many &&
                    ODataRequestMethod.Post == method)
                {
                    return(null);
                }

                // It is not valid to *Put/Patch" to any collection-valued navigation property.
                if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many &&
                    (ODataRequestMethod.Put == method || ODataRequestMethod.Patch == method))
                {
                    return(null);
                }

                // *Get* is the only supported method for $count request.
                if (odataPath.Segments.Last() is CountSegment && ODataRequestMethod.Get != method)
                {
                    return(null);
                }

                if (declaringType != null)
                {
                    // e.g. Try GetNavigationPropertyFromDeclaringType first, then fallback on GetNavigationProperty action name
                    string actionName = actionMap.FindMatchingAction(
                        actionNamePrefix + navigationProperty.Name + "From" + declaringType.Name,
                        actionNamePrefix + navigationProperty.Name);

                    if (actionName != null)
                    {
                        if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal))
                        {
                            KeySegment keyValueSegment = (KeySegment)odataPath.Segments[1];
                            controllerContext.AddKeyValueToRouteData(keyValueSegment);
                        }

                        return(actionName);
                    }
                }
            }

            return(null);
        }
        internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext,
                                                IWebApiActionMap actionMap)
        {
            string             actionName            = null;
            DynamicPathSegment dynamicPropertSegment = null;

            switch (odataPath.PathTemplate)
            {
            case "~/entityset/key/dynamicproperty":
            case "~/entityset/key/cast/dynamicproperty":
            case "~/singleton/dynamicproperty":
            case "~/singleton/cast/dynamicproperty":
                dynamicPropertSegment = odataPath.Segments.Last() as DynamicPathSegment;
                if (dynamicPropertSegment == null)
                {
                    return(null);
                }

                if (ODataRequestMethod.Get == controllerContext.Request.Method)
                {
                    string actionNamePrefix = String.Format(CultureInfo.InvariantCulture, "Get{0}", ActionName);
                    actionName = actionMap.FindMatchingAction(actionNamePrefix);
                }
                break;

            case "~/entityset/key/property/dynamicproperty":
            case "~/entityset/key/cast/property/dynamicproperty":
            case "~/singleton/property/dynamicproperty":
            case "~/singleton/cast/property/dynamicproperty":
                dynamicPropertSegment = odataPath.Segments.Last() as DynamicPathSegment;
                if (dynamicPropertSegment == null)
                {
                    return(null);
                }

                PropertySegment propertyAccessSegment = odataPath.Segments[odataPath.Segments.Count - 2]
                                                        as PropertySegment;
                if (propertyAccessSegment == null)
                {
                    return(null);
                }

                EdmComplexType complexType = propertyAccessSegment.Property.Type.Definition as EdmComplexType;
                if (complexType == null)
                {
                    return(null);
                }

                if (ODataRequestMethod.Get == controllerContext.Request.Method)
                {
                    string actionNamePrefix = String.Format(CultureInfo.InvariantCulture, "Get{0}", ActionName);
                    actionName = actionMap.FindMatchingAction(actionNamePrefix + "From" + propertyAccessSegment.Property.Name);
                }
                break;

            default: break;
            }

            if (actionName != null)
            {
                if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal))
                {
                    KeySegment keyValueSegment = (KeySegment)odataPath.Segments[1];
                    controllerContext.AddKeyValueToRouteData(keyValueSegment);
                }

                controllerContext.RouteData.Add(ODataRouteConstants.DynamicProperty, dynamicPropertSegment.Identifier);
                var key   = ODataParameterValue.ParameterValuePrefix + ODataRouteConstants.DynamicProperty;
                var value = new ODataParameterValue(dynamicPropertSegment.Identifier, EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(string)));
                controllerContext.RouteData.Add(key, value);
                controllerContext.Request.Context.RoutingConventionsStore.Add(key, value);
                return(actionName);
            }
            return(null);
        }
        /// <summary>
        /// Selects the action for OData requests.
        /// </summary>
        /// <param name="odataPath">The OData path.</param>
        /// <param name="controllerContext">The controller context.</param>
        /// <param name="actionMap">The action map.</param>
        /// <returns>
        ///   <c>null</c> if the request isn't handled by this convention; otherwise, the name of the selected action
        /// </returns>
        internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap)
        {
            if (odataPath.PathTemplate == "~/entityset")
            {
                EntitySetSegment  entitySetSegment = (EntitySetSegment)odataPath.Segments[0];
                IEdmEntitySetBase entitySet        = entitySetSegment.EntitySet;

                if (ODataRequestMethod.Get == controllerContext.Request.GetRequestMethodOrPreflightMethod())
                {
                    // e.g. Try GetCustomers first, then fall back to Get action name
                    return(actionMap.FindMatchingAction(
                               "Get" + entitySet.Name,
                               "Get"));
                }
                else if (ODataRequestMethod.Post == controllerContext.Request.GetRequestMethodOrPreflightMethod())
                {
                    // e.g. Try PostCustomer first, then fall back to Post action name
                    return(actionMap.FindMatchingAction(
                               "Post" + entitySet.EntityType().Name,
                               "Post"));
                }
            }
            else if (odataPath.PathTemplate == "~/entityset/$count" &&
                     ODataRequestMethod.Get == controllerContext.Request.GetRequestMethodOrPreflightMethod())
            {
                EntitySetSegment  entitySetSegment = (EntitySetSegment)odataPath.Segments[0];
                IEdmEntitySetBase entitySet        = entitySetSegment.EntitySet;

                // e.g. Try GetCustomers first, then fall back to Get action name
                return(actionMap.FindMatchingAction(
                           "Get" + entitySet.Name,
                           "Get"));
            }
            else if (odataPath.PathTemplate == "~/entityset/cast")
            {
                EntitySetSegment   entitySetSegment = (EntitySetSegment)odataPath.Segments[0];
                IEdmEntitySetBase  entitySet        = entitySetSegment.EntitySet;
                IEdmCollectionType collectionType   = (IEdmCollectionType)odataPath.EdmType;
                IEdmEntityType     entityType       = (IEdmEntityType)collectionType.ElementType.Definition;

                if (ODataRequestMethod.Get == controllerContext.Request.GetRequestMethodOrPreflightMethod())
                {
                    // e.g. Try GetCustomersFromSpecialCustomer first, then fall back to GetFromSpecialCustomer
                    return(actionMap.FindMatchingAction(
                               "Get" + entitySet.Name + "From" + entityType.Name,
                               "GetFrom" + entityType.Name));
                }
                else if (ODataRequestMethod.Post == controllerContext.Request.GetRequestMethodOrPreflightMethod())
                {
                    // e.g. Try PostCustomerFromSpecialCustomer first, then fall back to PostFromSpecialCustomer
                    return(actionMap.FindMatchingAction(
                               "Post" + entitySet.EntityType().Name + "From" + entityType.Name,
                               "PostFrom" + entityType.Name));
                }
            }
            else if (odataPath.PathTemplate == "~/entityset/cast/$count" &&
                     ODataRequestMethod.Get == controllerContext.Request.GetRequestMethodOrPreflightMethod())
            {
                EntitySetSegment   entitySetSegment = (EntitySetSegment)odataPath.Segments[0];
                IEdmEntitySetBase  entitySet        = entitySetSegment.EntitySet;
                IEdmCollectionType collectionType   = (IEdmCollectionType)odataPath.Segments[1].EdmType;
                IEdmEntityType     entityType       = (IEdmEntityType)collectionType.ElementType.Definition;

                // e.g. Try GetCustomersFromSpecialCustomer first, then fall back to GetFromSpecialCustomer
                return(actionMap.FindMatchingAction(
                           "Get" + entitySet.Name + "From" + entityType.Name,
                           "GetFrom" + entityType.Name));
            }

            return(null);
        }
        internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext,
                                                IWebApiActionMap actionMap)
        {
            if (ODataRequestMethod.Get == controllerContext.Request.GetRequestMethodOrPreflightMethod())
            {
                string           actionName = null;
                OperationSegment function   = null;
                switch (odataPath.PathTemplate)
                {
                case "~/entityset/key/cast/function":
                case "~/entityset/key/function":
                    function   = odataPath.Segments.Last() as OperationSegment;
                    actionName = GetFunction(function).SelectAction(actionMap, isCollection: false);
                    if (actionName != null)
                    {
                        controllerContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1]);
                    }
                    break;

                case "~/entityset/key/cast/function/$count":
                case "~/entityset/key/function/$count":
                    function   = odataPath.Segments[odataPath.Segments.Count - 2] as OperationSegment;
                    actionName = GetFunction(function).SelectAction(actionMap, isCollection: false);
                    if (actionName != null)
                    {
                        controllerContext.AddKeyValueToRouteData((KeySegment)odataPath.Segments[1]);
                    }
                    break;

                case "~/entityset/cast/function":
                case "~/entityset/function":
                    function   = odataPath.Segments.Last() as OperationSegment;
                    actionName = GetFunction(function).SelectAction(actionMap, isCollection: true);
                    break;

                case "~/entityset/cast/function/$count":
                case "~/entityset/function/$count":
                    function   = odataPath.Segments[odataPath.Segments.Count - 2] as OperationSegment;
                    actionName = GetFunction(function).SelectAction(actionMap, isCollection: true);
                    break;

                case "~/singleton/function":
                case "~/singleton/cast/function":
                    function   = odataPath.Segments.Last() as OperationSegment;
                    actionName = GetFunction(function).SelectAction(actionMap, isCollection: false);
                    break;

                case "~/singleton/function/$count":
                case "~/singleton/cast/function/$count":
                    function   = odataPath.Segments[odataPath.Segments.Count - 2] as OperationSegment;
                    actionName = GetFunction(function).SelectAction(actionMap, isCollection: false);
                    break;
                }

                if (actionName != null)
                {
                    controllerContext.AddFunctionParameterToRouteData(function);
                    return(actionName);
                }
            }

            return(null);
        }
        /// <summary>
        /// Selects the action for OData requests.
        /// </summary>
        /// <param name="odataPath">The OData path.</param>
        /// <param name="controllerContext">The controller context.</param>
        /// <param name="actionMap">The action map.</param>
        /// <returns>
        ///   <c>null</c> if the request isn't handled by this convention; otherwise, the name of the selected action
        /// </returns>
        internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap)
        {
            ODataRequestMethod method = controllerContext.Request.GetRequestMethodOrPreflightMethod();

            if (method != ODataRequestMethod.Get)
            {
                // [EnableNestedPaths] only supports GET requests
                return(null);
            }

            // unsupported path segments
            if (odataPath.PathTemplate.EndsWith("$ref"))
            {
                return(null);
            }

            ODataPathSegment firstSegment = odataPath.Segments.FirstOrDefault();

            string sourceName;

            if (firstSegment is EntitySetSegment entitySetSegment)
            {
                sourceName = entitySetSegment.EntitySet.Name;
            }
            else if (firstSegment is SingletonSegment singletonSegment)
            {
                sourceName = singletonSegment.Singleton.Name;
            }
            else
            {
                // this only supports paths starting with an entity set or singleton
                return(null);
            }

            // if we did not find a matching action amongst the conventional user-defined methods
            // then let's check if the controller has a Get method with [EnableNestedPaths] attribute
            // which should be used to catch any nested GET request
            string action = actionMap.FindMatchingAction("Get" + sourceName, "Get");

            if (action == null)
            {
                return(null);
            }

            IWebApiActionDescriptor descriptor = actionMap.GetActionDescriptor(action);

            if (descriptor == null)
            {
                return(null);
            }

            if (!descriptor.GetCustomAttributes <EnableNestedPathsAttribute>(/* inherit */ true).Any())
            {
                return(null);
            }

            return(descriptor.ActionName);
        }