/// <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)); }
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)); }
/// <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)); }
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); }
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); }
/// <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); }