/// <summary> /// Resolve operation's parameters. Using this extension, enum value could be written as string value. /// </summary> /// <param name="operation">Current operation for parameters.</param> /// <param name="input">A dictionary the parameter list.</param> /// <returns>A dictionary containing resolved parameters.</returns> public override IDictionary <IEdmOperationParameter, SingleValueNode> ResolveOperationParameters(IEdmOperation operation, IDictionary <string, SingleValueNode> input) { Dictionary <IEdmOperationParameter, SingleValueNode> result = new Dictionary <IEdmOperationParameter, SingleValueNode>(EqualityComparer <IEdmOperationParameter> .Default); foreach (var item in input) { IEdmOperationParameter functionParameter = null; if (EnableCaseInsensitive) { functionParameter = ODataUriResolver.ResolveOperationParameterNameCaseInsensitive(operation, item.Key); } else { functionParameter = operation.FindParameter(item.Key); } // ensure parameter name exists if (functionParameter == null) { throw new ODataException(Strings.ODataParameterWriterCore_ParameterNameNotFoundInOperation(item.Key, operation.Name)); } SingleValueNode newVal = item.Value; if (functionParameter.Type.IsEnum() && newVal is ConstantNode && newVal.TypeReference != null && newVal.TypeReference.IsString()) { string text = ((ConstantNode)item.Value).Value as string; ODataEnumValue val; IEdmTypeReference typeRef = functionParameter.Type; if (TryParseEnum(typeRef.Definition as IEdmEnumType, text, out val)) { newVal = new ConstantNode(val, text, typeRef); } } result.Add(functionParameter, newVal); } return(result); }
/// <summary> /// This is temp work around for $filter $orderby parameter expression which contains complex or collection /// like "Fully.Qualified.Namespace.CanMoveToAddresses(addresses=[{\"Street\":\"NE 24th St.\",\"City\":\"Redmond\"},{\"Street\":\"Pine St.\",\"City\":\"Seattle\"}])"; /// TODO: $filter $orderby parameter expression which contains nested complex or collection should NOT be supported in this way /// but should be parsed into token tree, and binded to node tree: parsedParameters.Select(p => this.bindMethod(p)); /// </summary> /// <param name="model">The model.</param> /// <param name="operation">IEdmFunction or IEdmOperation</param> /// <param name="parameterTokens">The tokens to bind.</param> /// <param name="enableCaseInsensitive">Whether to enable case-insensitive when resolving parameter name.</param> /// <param name="enableUriTemplateParsing">Whether Uri template parsing is enabled.</param> /// <returns>The FunctionParameterTokens with complex or collection values converted from string like "{...}", or "[..,..,..]".</returns> private static ICollection <FunctionParameterToken> HandleComplexOrCollectionParameterValueIfExists(IEdmModel model, IEdmOperation operation, ICollection <FunctionParameterToken> parameterTokens, bool enableCaseInsensitive, bool enableUriTemplateParsing = false) { ICollection <FunctionParameterToken> partiallyParsedParametersWithComplexOrCollection = new Collection <FunctionParameterToken>(); foreach (FunctionParameterToken paraToken in parameterTokens) { FunctionParameterToken funcParaToken; IEdmOperationParameter functionParameter = operation.FindParameter(paraToken.ParameterName); if (enableCaseInsensitive && functionParameter == null) { functionParameter = ODataUriResolver.ResolveOperationParameterNameCaseInsensitive(operation, paraToken.ParameterName); // The functionParameter can not be null here, else this method won't be called. funcParaToken = new FunctionParameterToken(functionParameter.Name, paraToken.ValueToken); } else { funcParaToken = paraToken; } FunctionParameterAliasToken aliasToken = funcParaToken.ValueToken as FunctionParameterAliasToken; if (aliasToken != null) { aliasToken.ExpectedParameterType = functionParameter.Type; } LiteralToken valueToken = funcParaToken.ValueToken as LiteralToken; string valueStr = null; if (valueToken != null && (valueStr = valueToken.Value as string) != null && !string.IsNullOrEmpty(valueToken.OriginalText)) { ExpressionLexer lexer = new ExpressionLexer(valueToken.OriginalText, true /*moveToFirstToken*/, false /*useSemicolonDelimiter*/, true /*parsingFunctionParameters*/); if (lexer.CurrentToken.Kind == ExpressionTokenKind.BracketedExpression || lexer.CurrentToken.Kind == ExpressionTokenKind.BracedExpression) { object result; UriTemplateExpression expression; if (enableUriTemplateParsing && UriTemplateParser.TryParseLiteral(lexer.CurrentToken.Text, functionParameter.Type, out expression)) { result = expression; } else if (!functionParameter.Type.IsStructured() && !functionParameter.Type.IsStructuredCollectionType()) { // ExpressionTokenKind.BracketedExpression means text like [1,2] // so now try convert it to collection type value: result = ODataUriUtils.ConvertFromUriLiteral(valueStr, ODataVersion.V4, model, functionParameter.Type); } else { // For complex & colleciton of complex directly return the raw string. partiallyParsedParametersWithComplexOrCollection.Add(funcParaToken); continue; } LiteralToken newValueToken = new LiteralToken(result, valueToken.OriginalText); FunctionParameterToken newFuncParaToken = new FunctionParameterToken(funcParaToken.ParameterName, newValueToken); partiallyParsedParametersWithComplexOrCollection.Add(newFuncParaToken); continue; } } partiallyParsedParametersWithComplexOrCollection.Add(funcParaToken); } return(partiallyParsedParametersWithComplexOrCollection); }