Example #1
0
        /// <summary>
        /// Try to resolve a function from the given inputs.
        /// </summary>
        /// <param name="identifier">The identifier of the function that we're trying to find</param>
        /// <param name="parameterNames">the names of the parameters to search for.</param>
        /// <param name="bindingType">the type of the previous segment</param>
        /// <param name="model">the model to use to look up the function import</param>
        /// <param name="matchingFunctionImport">The single matching function found.</param>
        /// <returns>True if a function was matched, false otherwise. Will throw if the model has illegal function imports.</returns>
        internal static bool ResolveFunctionsFromList(string identifier, IList <string> parameterNames, IEdmType bindingType, IEdmModel model, out IEdmFunctionImport matchingFunctionImport)
        {
            DebugUtils.CheckNoExternalCallers();

            // If the previous segment is an open type, the service action name is required to be fully qualified or else we always treat it as an open property name.
            if (bindingType != null)
            {
                // TODO: look up actual container names here?
                if (bindingType.IsOpenType() && !identifier.Contains("."))
                {
                    matchingFunctionImport = null;
                    return(false);
                }
            }

            // if the model implements the extensions interface, then leave resolution entirely up to the user.
            var extendedModel = model as IODataUriParserModelExtensions;

            if (extendedModel != null)
            {
                matchingFunctionImport = extendedModel.FindFunctionImportByBindingParameterType(bindingType, identifier, parameterNames);
                if (matchingFunctionImport == null)
                {
                    return(false);
                }

                return(true);
            }

            // Get all the possible functions by name and binding type
            // For this method to end up NOT throwing, this call must return a single action or 1 or more functions
            IList <IEdmFunctionImport> functionImports = model.FindFunctionImportsBySpecificBindingParameterType(bindingType, identifier).ToList();

            if (functionImports.Count == 0)
            {
                matchingFunctionImport = null;
                return(false);
            }

            Debug.Assert(functionImports != null && functionImports.Count > 0, "Should have returned at least one function import to get here.");
            Debug.Assert(functionImports.All(f => f.Name == identifier.Split('.').Last()), "list of possible functions must have same name as identifier");

            if (!functionImports.AllHaveEqualReturnTypeAndAttributes())
            {
                throw new ODataException(ODataErrorStrings.RequestUriProcessor_FoundInvalidFunctionImport(identifier));
            }

            // If any of the things returned are an action, it better be the only thing returned, and there can't be parameters in the URL
            if (functionImports.Any(f => f.IsSideEffecting))
            {
                if (functionImports.Count > 1)
                {
                    throw new ODataException(ODataErrorStrings.FunctionOverloadResolver_MultipleActionOverloads(identifier));
                }

                if (parameterNames.Count() != 0)
                {
                    throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_SegmentDoesNotSupportKeyPredicates(identifier));
                }

                matchingFunctionImport = functionImports.Single();
                return(true);
            }

            // Functions - resolve overloads as needed
            matchingFunctionImport = ResolveOverloadsByParameterNames(functionImports, parameterNames, identifier);
            return(matchingFunctionImport != null);
        }