/// <inheritdoc />
        public override ODataPathSegment Translate(ODataTemplateTranslateContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            IEdmModel            model       = context.Model;
            RouteValueDictionary routeValues = context.RouteValues;
            // TODO: process the parameter alias
            IList <OperationSegmentParameter> parameters = new List <OperationSegmentParameter>();

            foreach (var parameter in FunctionImport.Function.Parameters)
            {
                if (routeValues.TryGetValue(parameter.Name, out object rawValue))
                {
                    // for resource or collection resource, this method will return "ODataResourceValue, ..." we should support it.
                    if (parameter.Type.IsResourceOrCollectionResource())
                    {
                        // For FromODataUri
                        string prefixName = ODataParameterValue.ParameterValuePrefix + parameter.Name;
                        routeValues[prefixName] = new ODataParameterValue(rawValue, parameter.Type);

                        parameters.Add(new OperationSegmentParameter(parameter.Name, rawValue));
                    }
                    else
                    {
                        string strValue = rawValue as string;
                        object newValue = ODataUriUtils.ConvertFromUriLiteral(strValue, ODataVersion.V4, model, parameter.Type);

                        // for without FromODataUri, so update it, for example, remove the single quote for string value.
                        routeValues[parameter.Name] = newValue;

                        // For FromODataUri
                        string prefixName = ODataParameterValue.ParameterValuePrefix + parameter.Name;
                        routeValues[prefixName] = new ODataParameterValue(newValue, parameter.Type);

                        parameters.Add(new OperationSegmentParameter(parameter.Name, newValue));
                    }
                }
            }

            return(new OperationImportSegment(FunctionImport, NavigationSource as IEdmEntitySetBase, parameters));
        }
Exemple #2
0
        public static void AddFunctionParameters(IEdmFunction function, string paramName, object paramValue,
                                                 IDictionary <string, object> routeData, IDictionary <string, object> values, IDictionary <string, string> paramMapping)
        {
            Contract.Assert(function != null);

            // using the following codes to support [FromODataUriAttribute]
            IEdmOperationParameter edmParam = function.FindParameter(paramName);

            Contract.Assert(edmParam != null);
            ODataParameterValue parameterValue = new ODataParameterValue(paramValue, edmParam.Type);

            string name = paramName;

            if (paramMapping != null)
            {
                Contract.Assert(paramMapping.ContainsKey(paramName));
                name = paramMapping[paramName];
            }

            string prefixName = ODataParameterValue.ParameterValuePrefix + name;

            values[prefixName] = parameterValue;

            // using the following codes to support [FromUriAttribute]
            if (!routeData.ContainsKey(name))
            {
                routeData.Add(name, paramValue);
            }

            ODataNullValue nullValue = paramValue as ODataNullValue;

            if (nullValue != null)
            {
                routeData[name] = null;
            }

            ODataEnumValue enumValue = paramValue as ODataEnumValue;

            if (enumValue != null)
            {
                // Remove the type name of the ODataEnumValue and keep the value.
                routeData[name] = enumValue.Value;
            }
        }
        /// <inheritdoc />
        public override ODataPathSegment GenerateODataSegment(IEdmModel model, IEdmNavigationSource previous,
                                                              RouteValueDictionary routeValue, QueryString queryString)
        {
            // TODO: process the parameter alias
            int skip = Function.IsBound ? 1 : 0;

            IList <OperationSegmentParameter> parameters = new List <OperationSegmentParameter>();

            foreach (var parameter in Function.Parameters.Skip(skip))
            {
                if (routeValue.TryGetValue(parameter.Name, out object rawValue))
                {
                    // for resource or collection resource, this method will return "ODataResourceValue, ..." we should support it.
                    if (parameter.Type.IsResourceOrCollectionResource())
                    {
                        // For FromODataUri
                        string prefixName = ODataParameterValue.ParameterValuePrefix + parameter.Name;
                        routeValue[prefixName] = new ODataParameterValue(rawValue, parameter.Type);

                        parameters.Add(new OperationSegmentParameter(parameter.Name, rawValue));
                    }
                    else
                    {
                        string strValue = rawValue as string;
                        object newValue = ODataUriUtils.ConvertFromUriLiteral(strValue, ODataVersion.V4, model, parameter.Type);

                        // for without FromODataUri, so update it, for example, remove the single quote for string value.
                        routeValue[parameter.Name] = newValue;

                        // For FromODataUri
                        string prefixName = ODataParameterValue.ParameterValuePrefix + parameter.Name;
                        routeValue[prefixName] = new ODataParameterValue(newValue, parameter.Type);

                        parameters.Add(new OperationSegmentParameter(parameter.Name, newValue));
                    }
                }
            }

            IEdmNavigationSource targetset = Function.GetTargetEntitySet(previous, model);

            return(new OperationSegment(Function, parameters, targetset as IEdmEntitySetBase));
        }
Exemple #4
0
        /// <inheritdoc />
        public override ODataPathSegment Translate(ODataTemplateTranslateContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            // Context.RouteValues contains the key value string.
            RouteValueDictionary         routeValues = context.RouteValues;
            IDictionary <string, object> keysValues  = new Dictionary <string, object>();

            foreach (var key in KeyMappings)
            {
                string keyName      = key.Key;
                string templateName = key.Value;

                IEdmProperty keyProperty = EntityType.Key().FirstOrDefault(k => k.Name == keyName);
                Contract.Assert(keyProperty != null);

                IEdmTypeReference edmType = keyProperty.Type;
                if (routeValues.TryGetValue(templateName, out object rawValue))
                {
                    string strValue = rawValue as string;

                    strValue = context.GetParameterAliasOrSelf(strValue);

                    object newValue = ODataUriUtils.ConvertFromUriLiteral(strValue, ODataVersion.V4, context.Model, edmType);

                    // for without FromODataUri, so update it, for example, remove the single quote for string value.
                    routeValues[templateName] = newValue;

                    // For FromODataUri
                    string prefixName = ODataParameterValue.ParameterValuePrefix + templateName;
                    routeValues[prefixName] = new ODataParameterValue(newValue, edmType);

                    keysValues[keyName] = newValue;
                }
            }

            return(new KeySegment(keysValues, EntityType, NavigationSource));
        }
Exemple #5
0
        private static void AddKeyValues(string key, string name, object value, IEdmTypeReference edmTypeReference, IDictionary <string, object> routeValues, IDictionary <string, object> odataValues)
        {
            Contract.Assert(routeValues != null);
            Contract.Assert(odataValues != null);

            object       routeValue = null;
            object       odataValue = null;
            ConstantNode node       = value as ConstantNode;

            if (node != null)
            {
                ODataEnumValue enumValue = node.Value as ODataEnumValue;
                if (enumValue != null)
                {
                    odataValue = new ODataParameterValue(enumValue, edmTypeReference);
                    routeValue = enumValue.Value;
                }
            }
            else
            {
                odataValue = new ODataParameterValue(value, edmTypeReference);
                routeValue = value;
            }

            // for without FromODataUri
            var keyValues = routeValues["keys"] as List <KeyValue>;

            if (keyValues == null)
            {
                keyValues           = new List <KeyValue>();
                routeValues["keys"] = keyValues;
            }
            keyValues.Add(new KeyValue(key, value));
            routeValues[name] = routeValue;

            // For FromODataUri
            string prefixName = ODataParameterValue.ParameterValuePrefix + name;

            odataValues[prefixName] = odataValue;
        }
        /// <summary>
        /// Match the function parameter
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="function">The Edm function.</param>
        /// <param name="parameterMappings">The parameter mapping.</param>
        /// <returns></returns>
        public static IList <OperationSegmentParameter> Match(ODataTemplateTranslateContext context,
                                                              IEdmFunction function,
                                                              IDictionary <string, string> parameterMappings)
        {
            Contract.Assert(context != null);
            Contract.Assert(function != null);
            Contract.Assert(parameterMappings != null);

            RouteValueDictionary routeValues   = context.RouteValues;
            RouteValueDictionary updatedValues = context.UpdatedValues;

            IList <OperationSegmentParameter> parameters = new List <OperationSegmentParameter>();

            foreach (var parameter in parameterMappings)
            {
                string parameterName = parameter.Key;
                string parameterTemp = parameter.Value;

                IEdmOperationParameter edmParameter = function.Parameters.FirstOrDefault(p => p.Name == parameterName);
                Contract.Assert(edmParameter != null);

                // For a parameter mapping like: minSalary={min}
                // and a request like: ~/MyFunction(minSalary=2)
                // the routeValue includes the [min=2], so we should use the mapping name to retrieve the value.
                if (routeValues.TryGetValue(parameterTemp, out object rawValue))
                {
                    string strValue    = rawValue as string;
                    string newStrValue = context.GetParameterAliasOrSelf(strValue);
                    if (newStrValue != strValue)
                    {
                        updatedValues[parameterTemp] = newStrValue;
                        strValue = newStrValue;
                    }

                    // for resource or collection resource, this method will return "ODataResourceValue, ..." we should support it.
                    if (edmParameter.Type.IsResourceOrCollectionResource())
                    {
                        // For FromODataUri
                        string prefixName = ODataParameterValue.ParameterValuePrefix + parameterTemp;
                        updatedValues[prefixName] = new ODataParameterValue(strValue, edmParameter.Type);

                        parameters.Add(new OperationSegmentParameter(parameterName, strValue));
                    }
                    else
                    {
                        object newValue = ODataUriUtils.ConvertFromUriLiteral(strValue, ODataVersion.V4, context.Model, edmParameter.Type);

                        // for without FromODataUri, so update it, for example, remove the single quote for string value.
                        updatedValues[parameterTemp] = newValue;

                        // For FromODataUri
                        string prefixName = ODataParameterValue.ParameterValuePrefix + parameterTemp;
                        updatedValues[prefixName] = new ODataParameterValue(newValue, edmParameter.Type);

                        parameters.Add(new OperationSegmentParameter(parameterName, newValue));
                    }
                }
                else
                {
                    return(null);
                }
            }

            return(parameters);
        }
        /// <inheritdoc/>
        public override ActionDescriptor SelectAction(RouteContext routeContext, IEnumerable <ControllerActionDescriptor> actionDescriptors)
        {
            if (routeContext == null)
            {
                throw Error.ArgumentNull("routeContext");
            }

            ODataPath   odataPath  = routeContext.HttpContext.Request.ODataFeature().Path;
            HttpRequest request    = routeContext.HttpContext.Request;
            string      httpMethod = request.Method.ToUpperInvariant();

            ControllerActionDescriptor actionDescriptor      = 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 (httpMethod == ODataRouteConstants.HttpGet)
                {
                    string actionNamePrefix = String.Format(CultureInfo.InvariantCulture, "Get{0}", _actionName);
                    actionDescriptor = actionDescriptors.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 (httpMethod == ODataRouteConstants.HttpGet)
                {
                    string actionNamePrefix = String.Format(CultureInfo.InvariantCulture, "Get{0}", _actionName);
                    actionDescriptor = actionDescriptors.FindMatchingAction(actionNamePrefix + "From" + propertyAccessSegment.Property.Name);
                }
                break;

            default:
                break;
            }

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

                routeContext.RouteData.Values[ODataRouteConstants.DynamicProperty] = dynamicPropertSegment.Identifier;
                var key   = ODataParameterValue.ParameterValuePrefix + ODataRouteConstants.DynamicProperty;
                var value = new ODataParameterValue(dynamicPropertSegment.Identifier, EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(string)));
                routeContext.RouteData.Values[key] = value;
                request.ODataFeature().RoutingConventionsStore[key] = value;
                return(actionDescriptor);
            }

            return(null);
        }
Exemple #8
0
            public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
            {
                if (bindingContext == null)
                {
                    throw Error.ArgumentNull("bindingContext");
                }

                if (bindingContext.ModelMetadata == null)
                {
                    throw Error.Argument("bindingContext", SRResources.ModelBinderUtil_ModelMetadataCannotBeNull);
                }

                string modelName          = ODataParameterValue.ParameterValuePrefix + bindingContext.ModelName;
                ValueProviderResult value = bindingContext.ValueProvider.GetValue(modelName);

                if (value == null)
                {
                    value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
                    if (value == null)
                    {
                        return(false);
                    }
                }

                bindingContext.ModelState.SetModelValue(bindingContext.ModelName, value);

                try
                {
                    ODataParameterValue paramValue = value.RawValue as ODataParameterValue;
                    if (paramValue != null)
                    {
                        bindingContext.Model = ConvertTo(paramValue, actionContext, bindingContext);
                        return(true);
                    }

                    // Support key value's [FromODataUri] binding
                    string valueString = value.RawValue as string;
                    if (valueString != null)
                    {
                        bindingContext.Model = ConvertTo(valueString, bindingContext.ModelType);
                        return(true);
                    }

                    return(false);
                }
                catch (ODataException ex)
                {
                    bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex.Message);
                    return(false);
                }
                catch (ValidationException ex)
                {
                    bindingContext.ModelState.AddModelError(bindingContext.ModelName, Error.Format(SRResources.ValueIsInvalid, value.RawValue, ex.Message));
                    return(false);
                }
                catch (FormatException ex)
                {
                    bindingContext.ModelState.AddModelError(bindingContext.ModelName, Error.Format(SRResources.ValueIsInvalid, value.RawValue, ex.Message));
                    return(false);
                }
                catch (Exception e)
                {
                    bindingContext.ModelState.AddModelError(bindingContext.ModelName, e);
                    return(false);
                }
            }
        public static void AddFunctionParameters(IEdmFunction function, string paramName, object paramValue, 
            IDictionary<string, object> routeData, IDictionary<string, object> values, IDictionary<string, string> paramMapping)
        {
            Contract.Assert(function != null);

            // using the following codes to support [FromODataUriAttribute]
            IEdmOperationParameter edmParam = function.FindParameter(paramName);
            Contract.Assert(edmParam != null);
            ODataParameterValue parameterValue = new ODataParameterValue(paramValue, edmParam.Type);

            string name = paramName;
            if (paramMapping != null)
            {
                Contract.Assert(paramMapping.ContainsKey(paramName));
                name = paramMapping[paramName];
            }

            string prefixName = ODataParameterValue.ParameterValuePrefix + name;
            values[prefixName] = parameterValue;

            // using the following codes to support [FromUriAttribute]
            if (!routeData.ContainsKey(name))
            {
                routeData.Add(name, paramValue);
            }

            ODataNullValue nullValue = paramValue as ODataNullValue;
            if (nullValue != null)
            {
                routeData[name] = null;
            }

            ODataEnumValue enumValue = paramValue as ODataEnumValue;
            if (enumValue != null)
            {
                // Remove the type name of the ODataEnumValue and keep the value.
                routeData[name] = enumValue.Value;
            }
        }
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw Error.ArgumentNull("bindingContext");
            }

            if (bindingContext.ModelMetadata == null)
            {
                throw Error.Argument("bindingContext", SRResources.ModelBinderUtil_ModelMetadataCannotBeNull);
            }

            ValueProviderResult valueProviderResult = ValueProviderResult.None;
            string modelName = ODataParameterValue.ParameterValuePrefix + bindingContext.ModelName;

            try
            {
                // Look in route data for a ODataParameterValue.
                object valueAsObject = null;
                if (!bindingContext.HttpContext.Request.ODataFeature().RoutingConventionsStore.TryGetValue(modelName, out valueAsObject))
                {
                    bindingContext.ActionContext.RouteData.Values.TryGetValue(modelName, out valueAsObject);
                }

                if (valueAsObject != null)
                {
                    StringValues stringValues = new StringValues(valueAsObject.ToString());
                    valueProviderResult = new ValueProviderResult(stringValues);
                    bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);

                    ODataParameterValue paramValue = valueAsObject as ODataParameterValue;
                    if (paramValue != null)
                    {
                        HttpRequest request = bindingContext.HttpContext.Request;
                        object      model   = ConvertTo(paramValue, bindingContext, request.GetRequestContainer());
                        bindingContext.Result = ModelBindingResult.Success(model);
                        return(Task.CompletedTask);
                    }
                }
                else
                {
                    // If not in the route data, ask the value provider.
                    valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
                    if (valueProviderResult == ValueProviderResult.None)
                    {
                        valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
                    }

                    if (valueProviderResult != ValueProviderResult.None)
                    {
                        bindingContext.ModelState.SetModelValue(bindingContext.ModelName, valueProviderResult);

                        object model = ODataModelBinderConverter.ConvertTo(valueProviderResult.FirstValue, bindingContext.ModelType);
                        if (model != null)
                        {
                            bindingContext.Result = ModelBindingResult.Success(model);
                            return(Task.CompletedTask);
                        }
                    }
                }

                // No matches, binding failed.
                bindingContext.Result = ModelBindingResult.Failed();
            }
            catch (ODataException ex)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex.Message);
                bindingContext.Result = ModelBindingResult.Failed();
            }
            catch (ValidationException ex)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, Error.Format(SRResources.ValueIsInvalid, valueProviderResult.FirstValue, ex.Message));
                bindingContext.Result = ModelBindingResult.Failed();
            }
            catch (FormatException ex)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, Error.Format(SRResources.ValueIsInvalid, valueProviderResult.FirstValue, ex.Message));
                bindingContext.Result = ModelBindingResult.Failed();
            }
            catch (Exception e)
            {
                bindingContext.ModelState.AddModelError(bindingContext.ModelName, e.Message);
                bindingContext.Result = ModelBindingResult.Failed();
            }

            return(Task.CompletedTask);
        }
        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);
        }
        public override string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext,
            ILookup<string, HttpActionDescriptor> actionMap)
        {
            if (odataPath == null)
            {
                throw Error.ArgumentNull("odataPath");
            }

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

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

            string actionName = null;
            DynamicPropertyPathSegment dynamicPropertSegment = null;

            switch (odataPath.PathTemplate)
            {
                case "~/entityset/key/dynamicproperty":
                case "~/entityset/key/cast/dynamicproperty":
                case "~/singleton/dynamicproperty":
                case "~/singleton/cast/dynamicproperty":
                    dynamicPropertSegment = odataPath.Segments[odataPath.Segments.Count - 1] as DynamicPropertyPathSegment;
                    if (dynamicPropertSegment == null)
                    {
                        return null;
                    }

                    if (controllerContext.Request.Method == HttpMethod.Get)
                    {
                        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[odataPath.Segments.Count - 1] as DynamicPropertyPathSegment;
                    if (dynamicPropertSegment == null)
                    {
                        return null;
                    }

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

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

                    if (controllerContext.Request.Method == HttpMethod.Get)
                    {
                        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))
                {
                    EntitySetPathSegment entitySetPathSegment = (EntitySetPathSegment)odataPath.Segments.First();
                    IEdmEntityType edmEntityType = entitySetPathSegment.EntitySetBase.EntityType();
                    KeyValuePathSegment keyValueSegment = (KeyValuePathSegment)odataPath.Segments[1];

                    controllerContext.AddKeyValueToRouteData(keyValueSegment, edmEntityType, ODataRouteConstants.Key);
                }

                controllerContext.RouteData.Values[ODataRouteConstants.DynamicProperty] = dynamicPropertSegment.PropertyName;
                var key = ODataParameterValue.ParameterValuePrefix + ODataRouteConstants.DynamicProperty;
                var value = new ODataParameterValue(dynamicPropertSegment.PropertyName, EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(string)));
                controllerContext.Request.ODataProperties().RoutingConventionsStore[key] = value;
                return actionName;
            }
            return null;
        }
        /// <inheritdoc/>
        public override string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext,
                                            ILookup <string, HttpActionDescriptor> actionMap)
        {
            if (odataPath == null)
            {
                throw Error.ArgumentNull("odataPath");
            }

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

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

            string actionName = null;
            DynamicPropertyPathSegment dynamicPropertSegment = null;

            switch (odataPath.PathTemplate)
            {
            case "~/entityset/key/dynamicproperty":
            case "~/entityset/key/cast/dynamicproperty":
            case "~/singleton/dynamicproperty":
            case "~/singleton/cast/dynamicproperty":
                dynamicPropertSegment = odataPath.Segments[odataPath.Segments.Count - 1] as DynamicPropertyPathSegment;
                if (dynamicPropertSegment == null)
                {
                    return(null);
                }

                if (controllerContext.Request.Method == HttpMethod.Get)
                {
                    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[odataPath.Segments.Count - 1] as DynamicPropertyPathSegment;
                if (dynamicPropertSegment == null)
                {
                    return(null);
                }

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

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

                if (controllerContext.Request.Method == HttpMethod.Get)
                {
                    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))
                {
                    KeyValuePathSegment keyValueSegment = odataPath.Segments[1] as KeyValuePathSegment;
                    controllerContext.RouteData.Values[ODataRouteConstants.Key] = keyValueSegment.Value;
                }

                controllerContext.RouteData.Values[ODataRouteConstants.DynamicProperty] = dynamicPropertSegment.PropertyName;
                var key   = ODataParameterValue.ParameterValuePrefix + ODataRouteConstants.DynamicProperty;
                var value = new ODataParameterValue(dynamicPropertSegment.PropertyName, EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(string)));
                controllerContext.RouteData.Values[key] = value;
                controllerContext.Request.ODataProperties().RoutingConventionsStore[key] = value;
                return(actionName);
            }
            return(null);
        }
        /// <inheritdoc />
        public override bool TryTranslate(ODataTemplateTranslateContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            RouteValueDictionary routeValues  = context.RouteValues;
            RouteValueDictionary updateValues = context.UpdatedValues;

            IDictionary <string, object> keysValues = new Dictionary <string, object>();

            foreach (var key in KeyMappings)
            {
                string keyName      = key.Key;
                string templateName = key.Value;
                if (routeValues.TryGetValue(templateName, out object rawValue))
                {
                    IEdmProperty keyProperty = KeyProperties.FirstOrDefault(k => k.Key == keyName).Value;
                    Contract.Assert(keyProperty != null);

                    IEdmTypeReference edmType     = keyProperty.Type;
                    string            strValue    = rawValue as string;
                    string            newStrValue = context.GetParameterAliasOrSelf(strValue);
                    newStrValue = Uri.UnescapeDataString(newStrValue);
                    if (newStrValue != strValue)
                    {
                        updateValues[templateName] = newStrValue;
                        strValue = newStrValue;
                    }

                    // If it's key as segment and the key type is Edm.String, we support non-single quoted string.
                    // Since we can't identify key as segment and key in parenthesis easy so far,
                    // we use the key literal with "/" to test in the whole route template.
                    // Why we can't create two key segment templates, one reason is that in attribute routing template,
                    // we can't identify key as segment or key in parenthesis also.
                    if (edmType.IsString() && context.IsPartOfRouteTemplate($"/{_keyLiteral}"))
                    {
                        if (!strValue.StartsWith('\'') && !strValue.EndsWith('\''))
                        {
                            strValue = $"'{strValue}'"; // prefix and suffix single quote
                        }
                    }

                    object newValue;
                    try
                    {
                        newValue = ODataUriUtils.ConvertFromUriLiteral(strValue, ODataVersion.V4, context.Model, edmType);
                    }
                    catch (ODataException ex)
                    {
                        string message = Error.Format(SRResources.InvalidKeyInUriFound, strValue, edmType.FullName());
                        throw new ODataException(message, ex);
                    }

                    // for non FromODataUri, so update it, for example, remove the single quote for string value.
                    updateValues[templateName] = newValue;

                    // For FromODataUri, let's refactor it later.
                    string prefixName = ODataParameterValue.ParameterValuePrefix + templateName;
                    updateValues[prefixName] = new ODataParameterValue(newValue, edmType);

                    keysValues[keyName] = newValue;
                }
            }

            context.Segments.Add(new KeySegment(keysValues, EntityType, NavigationSource));
            return(true);
        }
Exemple #15
0
        /// <inheritdoc />
        public override ODataPathSegment Translate(ODataTemplateTranslateContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            RouteValueDictionary routeValue = context.RouteValues;

            // TODO: process the parameter alias
            int skip = Function.IsBound ? 1 : 0;

            //if (!TestParameters(context, out IDictionary<string, string> actualParameters))
            //{
            //    return null;
            //}

            if (!IsAllParameters(routeValue))
            {
                if (!TestParameters(context, out IDictionary <string, string> actualParameters))
                {
                    return(null);
                }

                routeValue = new RouteValueDictionary();
                foreach (var item in context.RouteValues)
                {
                    routeValue.Add(item.Key, item.Value);
                }

                // Replace
                foreach (var item in actualParameters)
                {
                    routeValue[item.Key] = item.Value;
                }
            }

            IList <OperationSegmentParameter> parameters = new List <OperationSegmentParameter>();

            foreach (var parameter in Function.Parameters.Skip(skip))
            {
                if (routeValue.TryGetValue(parameter.Name, out object rawValue))
                {
                    // for resource or collection resource, this method will return "ODataResourceValue, ..." we should support it.
                    if (parameter.Type.IsResourceOrCollectionResource())
                    {
                        // For FromODataUri
                        string prefixName = ODataParameterValue.ParameterValuePrefix + parameter.Name;
                        routeValue[prefixName] = new ODataParameterValue(rawValue, parameter.Type);

                        parameters.Add(new OperationSegmentParameter(parameter.Name, rawValue));
                    }
                    else
                    {
                        string strValue = rawValue as string;
                        object newValue = ODataUriUtils.ConvertFromUriLiteral(strValue, ODataVersion.V4, context.Model, parameter.Type);

                        // for without FromODataUri, so update it, for example, remove the single quote for string value.
                        routeValue[parameter.Name] = newValue;

                        // For FromODataUri
                        string prefixName = ODataParameterValue.ParameterValuePrefix + parameter.Name;
                        routeValue[prefixName] = new ODataParameterValue(newValue, parameter.Type);

                        parameters.Add(new OperationSegmentParameter(parameter.Name, newValue));
                    }
                }
            }

            return(new OperationSegment(Function, parameters, NavigationSource as IEdmEntitySetBase));
        }
        /// <summary>
        /// Match the function parameter
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="function">The Edm function.</param>
        /// <param name="parameterMappings">The parameter mapping.</param>
        /// <returns></returns>
        public static IList <OperationSegmentParameter> Match(ODataTemplateTranslateContext context,
                                                              IEdmFunction function,
                                                              IDictionary <string, string> parameterMappings)
        {
            Contract.Assert(context != null);
            Contract.Assert(function != null);
            Contract.Assert(parameterMappings != null);

            RouteValueDictionary routeValues   = context.RouteValues;
            RouteValueDictionary updatedValues = context.UpdatedValues;

            IList <OperationSegmentParameter> parameters = new List <OperationSegmentParameter>();

            foreach (var parameter in parameterMappings)
            {
                string parameterName = parameter.Key;
                string parameterTemp = parameter.Value;

                IEdmOperationParameter edmParameter = function.Parameters.FirstOrDefault(p => p.Name == parameterName);
                Contract.Assert(edmParameter != null);

                // For a parameter mapping like: minSalary={min}
                // and a request like: ~/MyFunction(minSalary=2)
                // the routeValue includes the [min=2], so we should use the mapping name to retrieve the value.
                if (routeValues.TryGetValue(parameterTemp, out object rawValue))
                {
                    string strValue    = rawValue as string;
                    string newStrValue = context.GetParameterAliasOrSelf(strValue);
                    if (newStrValue != strValue)
                    {
                        updatedValues[parameterTemp] = newStrValue;
                        strValue = newStrValue;
                    }

                    string originalStrValue = strValue;

                    // for resource or collection resource, this method will return "ODataResourceValue, ..." we should support it.
                    if (edmParameter.Type.IsResourceOrCollectionResource())
                    {
                        // For FromODataUri
                        string prefixName = ODataParameterValue.ParameterValuePrefix + parameterTemp;
                        updatedValues[prefixName] = new ODataParameterValue(strValue, edmParameter.Type);

                        parameters.Add(new OperationSegmentParameter(parameterName, strValue));
                    }
                    else
                    {
                        if (edmParameter.Type.IsEnum() && strValue.StartsWith("'", StringComparison.Ordinal) && strValue.EndsWith("'", StringComparison.Ordinal))
                        {
                            // related implementation at: https://github.com/OData/odata.net/blob/master/src/Microsoft.OData.Core/UriParser/Resolver/StringAsEnumResolver.cs#L131
                            strValue = edmParameter.Type.FullName() + strValue;
                        }

                        object newValue;
                        try
                        {
                            newValue = ODataUriUtils.ConvertFromUriLiteral(strValue, ODataVersion.V4, context.Model, edmParameter.Type);
                        }
                        catch (ODataException ex)
                        {
                            string message = Error.Format(SRResources.InvalidParameterValueInUriFound, originalStrValue, edmParameter.Type.FullName());
                            throw new ODataException(message, ex);
                        }

                        // for without FromODataUri, so update it, for example, remove the single quote for string value.
                        updatedValues[parameterTemp] = newValue;

                        // For FromODataUri
                        string prefixName = ODataParameterValue.ParameterValuePrefix + parameterTemp;
                        updatedValues[prefixName] = new ODataParameterValue(newValue, edmParameter.Type);

                        parameters.Add(new OperationSegmentParameter(parameterName, newValue));
                    }
                }
                else
                {
                    return(null);
                }
            }

            return(parameters);
        }