示例#1
0
        /// <summary>
        /// If the source node is not of the specified type, then we check if type promotion is possible and inject a convert node.
        /// If the source node is the same type as the target type (or if the target type is null), we just return the source node as is.
        /// </summary>
        /// <param name="source">The source node to apply the convertion to.</param>
        /// <param name="targetTypeReference">The target primitive type. May be null - this method will do nothing in that case.</param>
        /// <returns>The converted query node, or the original source node unchanged.</returns>
        internal static SingleValueNode ConvertToTypeIfNeeded(SingleValueNode source, IEdmTypeReference targetTypeReference)
        {
            Debug.Assert(source != null, "source != null");

            if (targetTypeReference == null)
            {
                return(source);
            }

            if (source.TypeReference != null)
            {
                if (source.TypeReference.IsEquivalentTo(targetTypeReference))
                {
                    // For source is type definition, if source's underlying type == target type.
                    // We create a conversion node from source to its underlying type (target type)
                    // so that the service can convert value of source clr type to underlying clr type.
                    if (source.TypeReference.IsTypeDefinition())
                    {
                        return(new ConvertNode(source, targetTypeReference));
                    }

                    return(source);
                }

                if (!TypePromotionUtils.CanConvertTo(source, source.TypeReference, targetTypeReference))
                {
                    throw new ODataException(ODataErrorStrings.MetadataBinder_CannotConvertToType(source.TypeReference.ODataFullName(), targetTypeReference.ODataFullName()));
                }
                else
                {
                    ConstantNode constantNode = source as ConstantNode;

                    if (source.TypeReference.IsEnum() && constantNode != null)
                    {
                        return(new ConstantNode(constantNode.Value, ODataUriUtils.ConvertToUriLiteral(constantNode.Value, ODataVersion.V4), targetTypeReference));
                    }

                    object primitiveValue;
                    if (MetadataUtilsCommon.TryGetConstantNodePrimitiveLDMF(source, out primitiveValue) && (primitiveValue != null))
                    {
                        // L F D M types : directly create a ConvertNode.
                        // 1. NodeToExpressionTranslator.cs won't allow implicitly converting single/double to decimal, which should be done here at Node tree level.
                        // 2. And prevent losing precision in float -> double, e.g. (double)1.234f => 1.2339999675750732d not 1.234d
                        object primitiveValue2 = ODataUriConversionUtils.CoerceNumericType(primitiveValue, targetTypeReference.AsPrimitive().Definition as IEdmPrimitiveType);

                        if (string.IsNullOrEmpty(constantNode.LiteralText))
                        {
                            return(new ConstantNode(primitiveValue2));
                        }

                        return(new ConstantNode(primitiveValue2, constantNode.LiteralText));
                    }
                    else
                    {
                        // other type conversion : ConvertNode
                        return(new ConvertNode(source, targetTypeReference));
                    }
                }
            }
            else
            {
                // If the source doesn't have a type (possibly an open property), then it's possible to convert it
                // cause we don't know for sure.
                return(new ConvertNode(source, targetTypeReference));
            }
        }
示例#2
0
        public HttpResponseMessage Post(AssetValue val)
        {
            if (val == null)
            {
                return(Request.CreateResponse(HttpStatusCode.NotFound));
            }

            _rep.Create(val);
            var response = Request.CreateResponse(HttpStatusCode.Created, val);

            var odataPath = Request.GetODataPath();

            if (odataPath == null)
            {
                throw new InvalidOperationException("There is no ODataPath in the request.");
            }
            var entitySetPathSegment = odataPath.Segments.FirstOrDefault() as EntitySetPathSegment;

            if (entitySetPathSegment == null)
            {
                throw new InvalidOperationException("ODataPath doesn't start with EntitySetPathSegment.");
            }

            response.Headers.Location = new Uri(Url.ODataLink(entitySetPathSegment, new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(val.Id, ODataVersion.V3))));

            //response.Headers.Location = new Uri(Url.ODataLink(new EntitySetPathSegment("Governors"), new KeyValuePathSegment(gov.Id.ToString())));

            return(response);
        }
        public static HttpResponseMessage PostResponse <TEntity, TKey>(ApiController controller, TEntity createdEntity, TKey entityKey)
        {
            HttpResponseMessage response = null;
            HttpRequestMessage  request  = controller.Request;

            if (RequestPrefersReturnNoContent(request))
            {
                response = request.CreateResponse(HttpStatusCode.NoContent);
                response.Headers.Add(PreferenceAppliedHeaderName, ReturnNoContentHeaderValue);
            }
            else
            {
                response = request.CreateResponse(HttpStatusCode.Created, createdEntity);
            }

            ODataPath odataPath = request.ODataProperties().Path;

            if (odataPath == null)
            {
                throw Error.InvalidOperation(SRResources.LocationHeaderMissingODataPath);
            }

            EntitySetPathSegment entitySetSegment = odataPath.Segments.FirstOrDefault() as EntitySetPathSegment;

            if (entitySetSegment == null)
            {
                throw Error.InvalidOperation(SRResources.LocationHeaderDoesNotStartWithEntitySet);
            }

            UrlHelper urlHelper = controller.Url ?? new UrlHelper(request);

            response.Headers.Location = new Uri(urlHelper.CreateODataLink(entitySetSegment,
                                                                          new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(entityKey, ODataVersion.V3))));
            return(response);
        }
示例#4
0
        /// <summary>
        /// Generates a string to be used as the skip token value within the next link.
        /// </summary>
        /// <param name="lastMember"> Object based on which SkipToken value will be generated.</param>
        /// <param name="model">The edm model.</param>
        /// <param name="orderByNodes">List of orderByNodes used to generate the skiptoken value.</param>
        /// <returns>Value for the skiptoken to be used in the next link.</returns>
        private static string GenerateSkipTokenValue(Object lastMember, IEdmModel model, IList <OrderByNode> orderByNodes)
        {
            if (lastMember == null)
            {
                return(String.Empty);
            }

            IEnumerable <IEdmProperty> propertiesForSkipToken = GetPropertiesForSkipToken(lastMember, model, orderByNodes);
            StringBuilder skipTokenBuilder = new StringBuilder(String.Empty);

            if (propertiesForSkipToken == null)
            {
                return(skipTokenBuilder.ToString());
            }

            int    count = 0;
            string uriLiteral;
            object value;
            int    lastIndex         = propertiesForSkipToken.Count() - 1;
            IEdmStructuredObject obj = lastMember as IEdmStructuredObject;

            foreach (IEdmProperty edmProperty in propertiesForSkipToken)
            {
                bool   islast          = count == lastIndex;
                string clrPropertyName = EdmLibHelpers.GetClrPropertyName(edmProperty, model);
                if (obj != null)
                {
                    obj.TryGetPropertyValue(clrPropertyName, out value);
                }
                else
                {
                    value = lastMember.GetType().GetProperty(clrPropertyName).GetValue(lastMember);
                }

                if (value == null)
                {
                    uriLiteral = ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V401);
                }
                else if (edmProperty.Type.IsEnum())
                {
                    ODataEnumValue enumValue = new ODataEnumValue(value.ToString(), value.GetType().FullName);
                    uriLiteral = ODataUriUtils.ConvertToUriLiteral(enumValue, ODataVersion.V401, model);
                }
                else if (edmProperty.Type.IsDateTimeOffset() && value is DateTime)
                {
                    var dateTime            = (DateTime)value;
                    var dateTimeOffsetValue = TimeZoneInfoHelper.ConvertToDateTimeOffset(dateTime);
                    uriLiteral = ODataUriUtils.ConvertToUriLiteral(dateTimeOffsetValue, ODataVersion.V401, model);
                }
                else
                {
                    uriLiteral = ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V401, model);
                }

                var encodedUriLiteral = WebUtility.UrlEncode(uriLiteral);

                skipTokenBuilder.Append(edmProperty.Name).Append(propertyDelimiter).Append(encodedUriLiteral).Append(islast ? String.Empty : CommaDelimiter.ToString());
                count++;
            }

            return(skipTokenBuilder.ToString());
        }
示例#5
0
        public void TestLongConvertFromUriLiteral(string value)
        {
            object longNumber = ODataUriUtils.ConvertFromUriLiteral(value, ODataVersion.V4);

            Assert.True(longNumber is long);
        }
        public override string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup <string, HttpActionDescriptor> actionMap)
        {
            if (odataPath.PathTemplate == "~/entityset/key")
            {
                KeyValuePathSegment segment = (KeyValuePathSegment)odataPath.Segments.Last();
                var keyValues = segment.Value.Split(',');
                if (keyValues.Length <= 1)
                {
                    return(null); // let other conventions to process
                }

                foreach (var item in keyValues)
                {
                    var keyValue = item.Split('=');
                    if (keyValue.Length != 2)
                    {
                        continue;
                    }
                    string key         = keyValue[0].Trim();
                    string valueString = keyValue[1].Trim();

                    object value = ODataUriUtils.ConvertFromUriLiteral(valueString, ODataVersion.V4);
                    controllerContext.RouteData.Values.Add("key" + key, value); // use a prefix
                }

                /*
                 * IEdmModel model = controllerContext.Request.ODataProperties().Model;
                 *
                 * string a = controllerContext.Request.GetUrlHelper().CreateODataLink(odataPath.Segments);
                 * //Uri b = new Uri();
                 *
                 * ODataUriParser parser = new ODataUriParser(model, new Uri(a, UriKind.Absolute));
                 * Sematic.ODataPath path = parser.ParsePath();
                 * Sematic.KeySegment keySegment = path.LastSegment as Sematic.KeySegment;
                 * foreach (var key in keySegment.Keys)
                 * {
                 *  controllerContext.RouteData.Values.Add("key" + key.Key, key.Value);
                 * }*/

                HttpMethod httpMethod = controllerContext.Request.Method;
                string     httpMethodName;

                switch (httpMethod.ToString().ToUpperInvariant())
                {
                case "GET":
                    httpMethodName = "Get";
                    break;

                case "PUT":
                    httpMethodName = "Put";
                    break;

                case "PATCH":
                case "MERGE":
                    httpMethodName = "Patch";
                    break;

                case "DELETE":
                    httpMethodName = "Delete";
                    break;

                default:
                    return(null);
                }

                IEdmEntityType entityType = odataPath.EdmType as IEdmEntityType;
                string         actionName = FindMatchingAction(actionMap,
                                                               httpMethodName + entityType.Name,
                                                               httpMethodName);

                return(actionName);
            }

            return(null);
        }
示例#7
0
        /// <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);
                    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);
        }
示例#8
0
        public void TestDoubleConvertFromUriLiteral(string value)
        {
            object doubleNumber = ODataUriUtils.ConvertFromUriLiteral(value, ODataVersion.V4);

            Assert.True(doubleNumber is double);
        }
示例#9
0
        public void ODataModelBinderProvider_Throws(object value, string action)
        {
            string url = String.Format("http://localhost/ODataModelBinderProviderThrowsTest/{0}({1})", action, Uri.EscapeDataString(ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V3)));
            HttpResponseMessage response = _client.GetAsync(url).Result;

            Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
        }
示例#10
0
        internal static object ConvertTo(string valueString, Type type, TimeZoneInfo timeZone, IEdmModel edmModel = null)
        {
            if (valueString == null)
            {
                return(null);
            }

            if (TypeHelper.IsNullable(type) && String.Equals(valueString, "null", StringComparison.Ordinal))
            {
                return(null);
            }

            // TODO 1668: ODL beta1's ODataUriUtils.ConvertFromUriLiteral does not support converting uri literal
            // to ODataEnumValue, but beta1's ODataUriUtils.ConvertToUriLiteral supports converting ODataEnumValue
            // to uri literal.
            if (TypeHelper.IsEnum(type))
            {
                string[] values = valueString.Split(new[] { '\'' }, StringSplitOptions.None);
                if (values.Length == 3 && String.IsNullOrEmpty(values[2]))
                {
                    // Remove the type name if the enum value is a fully qualified literal.
                    valueString = values[1];
                }

                Type     enumType     = TypeHelper.GetUnderlyingTypeOrSelf(type);
                object[] parameters   = new[] { valueString, Enum.ToObject(enumType, 0) };
                bool     isSuccessful = (bool)EnumTryParseMethod.MakeGenericMethod(enumType).Invoke(null, parameters);

                if (!isSuccessful)
                {
                    throw Error.InvalidOperation(SRResources.ModelBinderUtil_ValueCannotBeEnum, valueString, type.Name);
                }

                return(parameters[1]);
            }

            // The logic of "public static object ConvertFromUriLiteral(string value, ODataVersion version);" treats
            // the date value string (for example: 2015-01-02) as DateTimeOffset literal, and return a DateTimeOffset
            // object. However, the logic of
            // "object ConvertFromUriLiteral(string value, ODataVersion version, IEdmModel model, IEdmTypeReference typeReference);"
            // can return the correct Date object.
            if (type == typeof(Date) || type == typeof(Date?))
            {
                IEdmModel model = edmModel ?? EdmCoreModel.Instance;
                IEdmPrimitiveTypeReference dateTypeReference = model.GetEdmPrimitiveTypeReference(type);
                return(ODataUriUtils.ConvertFromUriLiteral(valueString, ODataVersion.V4, model, dateTypeReference));
            }

            object value;

            try
            {
                value = ODataUriUtils.ConvertFromUriLiteral(valueString, ODataVersion.V4);
            }
            catch
            {
                if (type == typeof(string))
                {
                    return(valueString);
                }

                throw;
            }

            bool isNonStandardEdmPrimitive;

            edmModel.IsNonstandardEdmPrimitive(type, out isNonStandardEdmPrimitive);

            if (isNonStandardEdmPrimitive)
            {
                // shall we get the timezone?
                return(EdmPrimitiveHelper.ConvertPrimitiveValue(value, type, timeZone));
            }
            else
            {
                type = Nullable.GetUnderlyingType(type) ?? type;
                return(System.Convert.ChangeType(value, type, CultureInfo.InvariantCulture));
            }
        }
示例#11
0
        public void ODataModelBinderProvider_Works(object value, string action)
        {
            string url = String.Format("http://localhost/ODataModelBinderProviderTest/{0}({1})", action, Uri.EscapeDataString(ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V3)));
            HttpResponseMessage response = _client.GetAsync(url).Result;

            response.EnsureSuccessStatusCode();
            Assert.Equal(
                value,
                response.Content.ReadAsAsync(value.GetType(), _configuration.Formatters).Result);
        }
示例#12
0
        public static string GetUriRepresentationForDateTime(DateTime dateTime, TimeZoneInfo timeZoneInfo)
        {
            object value = ODataPrimitiveSerializer.ConvertUnsupportedDateTime(dateTime, timeZoneInfo);

            return(ODataUriUtils.ConvertToUriLiteral(value, ODataVersion.V4));
        }
示例#13
0
        private static IEdmModel GetEdmModel()
        {
            ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();

            modelBuilder.ContainerName = "WebApiCtx";

            //modelBuilder.EntitySet<TestDataObj>("Values");
            var holidays = modelBuilder.EntitySet <Model.WorkCalendar>("Holidays");

            holidays.EntityType.Property(h => h.Comment).IsOptional();
            holidays.EntityType.Ignore(h => h.DayType);
            holidays.EntityType.Ignore(h => h.BankDate);
            holidays.EntityType.Ignore(h => h.BankDate_Key);

            //var companies = modelBuilder.EntitySet<Model.Company>("Companies");
            var govs = modelBuilder.EntitySet <Model.Governor>("Governors");

            govs.HasEditLink(
                entityContext => entityContext.Url.ODataLink(
                    new EntitySetPathSegment(entityContext.EntitySet.Name),
                    new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(entityContext.EntityInstance.Id, ODataVersion.V3))),
                followsConventions: true);

            var c = modelBuilder.ComplexType <Model.Company>();

            c.Property(o => o.lawFormValue);
            c.Ignore(o => o.FullName);
            c.Ignore(o => o.LawForm);

            govs.EntityType.ComplexProperty(g => g.Company).IsRequired();

            var assets = modelBuilder.EntitySet <Model.AssetValue>("Assets");

            assets.HasEditLink(
                entityContext => entityContext.Url.ODataLink(
                    new EntitySetPathSegment(entityContext.EntitySet.Name),
                    new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(entityContext.EntityInstance.Id, ODataVersion.V3))),
                followsConventions: true);

            assets.HasRequiredBinding(a => a.Governor, govs);
            assets.EntityType.Property(a => a.InsuranceTypeValue).IsRequired();
            //assets.EntityType.ComplexProperty(a => a.Governor);
            assets.EntityType.Ignore(a => a.InsuranceType);
            assets.EntityType.Ignore(a => a.InsuranceTypeString);

            assets.HasNavigationPropertiesLink(
                assets.EntityType.NavigationProperties,
                (entityContext, navigationProperty) =>
                new Uri(entityContext.Url.ODataLink(
                            new EntitySetPathSegment(entityContext.EntitySet.Name),
                            new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(entityContext.EntityInstance.Id, ODataVersion.V3)),
                            new NavigationPathSegment(navigationProperty.Name))),
                followsConventions: true);

            govs.HasNavigationPropertiesLink(
                govs.EntityType.NavigationProperties,
                (entityContext, navigationProperty) =>
                new Uri(entityContext.Url.ODataLink(
                            new EntitySetPathSegment(entityContext.EntitySet.Name),
                            new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(entityContext.EntityInstance.Id, ODataVersion.V3)),
                            new NavigationPathSegment(navigationProperty.Name))),
                followsConventions: true);

            var actionRep = assets.EntityType.Collection.Action("Report");

            actionRep.Parameter <DateTime>("DateBegin");
            actionRep.Parameter <DateTime>("DateEnd");
            actionRep.Parameter <byte>("InsuranceType");
            actionRep.Parameter <Guid?>("GovernorId");
            actionRep.Returns <string>();

            var actionBatch = assets.EntityType.Collection.Action("CreateBatch");

            actionBatch.CollectionParameter <string>("Values");
            actionBatch.Returns <bool>();

            IEdmModel model = modelBuilder.GetEdmModel();

            return(model);
        }
示例#14
0
        /// <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);
        }
        /// <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);
                    newStrValue = Uri.UnescapeDataString(newStrValue);
                    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);
        }
示例#16
0
        public void TestDateConvertFromUriLiteral()
        {
            Date dateValue = (Date)ODataUriUtils.ConvertFromUriLiteral("1997-07-01", ODataVersion.V4, HardCodedTestModel.TestModel, EdmCoreModel.Instance.GetDate(false));

            dateValue.Should().Be(new Date(1997, 7, 1));
        }
示例#17
0
        /// <summary>
        /// ConstantExpression visit method
        /// </summary>
        /// <param name="c">The ConstantExpression expression to visit</param>
        /// <returns>The visited ConstantExpression expression </returns>
        internal override Expression VisitConstant(ConstantExpression c)
        {
            if (c.Value == null)
            {
                this.builder.Append(UriHelper.NULL);
                return(c);
            }

            // DEVNOTE:
            // Rather than forcing every other codepath to have the 'Try...' pattern for formatting,
            // we catch the InvalidOperationException here to change the exception type.
            // This is exceedingly rare, and not a scenario where performance is meaningful, so the
            // reduced complexity in all other call sites is worth the extra logic here.
            string               result;
            BinaryExpression     b = this.parent as BinaryExpression;
            MethodCallExpression m = this.parent as MethodCallExpression;

            if ((b != null && HasEnumInBinaryExpression(b)) || (m != null && m.Method.Name == "HasFlag"))
            {
                c = this.ConvertConstantExpressionForEnum(c);
                ClientEdmModel       model          = this.context.Model;
                IEdmType             edmType        = model.GetOrCreateEdmType(c.Type.IsEnum() ? c.Type : c.Type.GetGenericArguments()[0]);
                ClientTypeAnnotation typeAnnotation = model.GetClientTypeAnnotation(edmType);
                string         typeNameInEdm        = this.context.ResolveNameFromTypeInternal(typeAnnotation.ElementType);
                MemberInfo     member      = typeAnnotation.ElementType.GetField(c.Value.ToString());
                string         memberValue = ClientTypeUtil.GetServerDefinedName(member);
                ODataEnumValue enumValue   = new ODataEnumValue(memberValue, typeNameInEdm ?? typeAnnotation.ElementTypeName);
                result = ODataUriUtils.ConvertToUriLiteral(enumValue, CommonUtil.ConvertToODataVersion(this.uriVersion), null);
            }
            else if (m != null && ReflectionUtil.IsSequenceMethod(m.Method, SequenceMethod.Contains))
            {
                StringBuilder listExpr = new StringBuilder();
                ODataVersion  version  = CommonUtil.ConvertToODataVersion(this.uriVersion);
                foreach (object item in (IEnumerable)c.Value)
                {
                    if (listExpr.Length != 0)
                    {
                        listExpr.Append(UriHelper.COMMA);
                    }

                    string uriLiteral = ODataUriUtils.ConvertToUriLiteral(item, version);
                    listExpr.Append(uriLiteral);
                }

                // Contains cannot be used with an empty static collection
                if (listExpr.Length == 0)
                {
                    throw new InvalidOperationException(Strings.ALinq_ContainsNotValidOnEmptyCollection);
                }

                listExpr.Insert(0, UriHelper.LEFTPAREN);
                listExpr.Append(UriHelper.RIGHTPAREN);

                result = listExpr.ToString();
            }
            else
            {
                try
                {
                    result = LiteralFormatter.ForConstants.Format(c.Value);
                }
                catch (InvalidOperationException)
                {
                    if (this.cantTranslateExpression)
                    {
                        // there's already a problem in the parents.
                        // we should just return here, because caller somewhere up the stack will throw a better exception
                        return(c);
                    }

                    throw new NotSupportedException(Strings.ALinq_CouldNotConvert(c.Value));
                }
            }

            Debug.Assert(result != null, "result != null");
            this.builder.Append(result);
            return(c);
        }
示例#18
0
        public void TestCollectionConvertWithMismatchedBracket()
        {
            Action parse = () => ODataUriUtils.ConvertFromUriLiteral("[1,2,3)", ODataVersion.V4, HardCodedTestModel.TestModel, new EdmCollectionTypeReference(new EdmCollectionType(EdmCoreModel.Instance.GetInt32(false))));

            parse.Throws <ODataException>(Strings.ExpressionLexer_UnbalancedBracketExpression);
        }
示例#19
0
        private string ConvertToEscapedUriValue(string paramName, object value)
        {
            Debug.Assert(!string.IsNullOrEmpty(paramName), "!string.IsNullOrEmpty(paramName)");
            Object valueInODataFormat = null;

            // Literal values with single quotes need special escaping due to System.Uri changes in behavior between .NET 4.0 and 4.5.
            // We need to ensure that our escaped values do not change between those versions, so we need to escape values differently when they could contain single quotes.
            bool needsSpecialEscaping = false;

            if (value == null)
            {
                needsSpecialEscaping = true;
            }
            else
            {
                if (value.GetType() == typeof(ODataUriNullValue))
                {
                    valueInODataFormat   = value;
                    needsSpecialEscaping = true;
                }
                else
                {
                    ClientEdmModel model   = this.requestInfo.Model;
                    IEdmType       edmType = model.GetOrCreateEdmType(value.GetType());
                    Debug.Assert(edmType != null, "edmType != null");

                    switch (edmType.TypeKind)
                    {
                    case EdmTypeKind.Primitive:
                        valueInODataFormat   = value;
                        needsSpecialEscaping = true;
                        break;

                    case EdmTypeKind.Complex:
                        ClientTypeAnnotation typeAnnotation = model.GetClientTypeAnnotation(edmType);
                        Debug.Assert(typeAnnotation != null, "typeAnnotation != null");
                        valueInODataFormat = this.propertyConverter.CreateODataComplexValue(
                            typeAnnotation.ElementType,
                            value,
                            null /*propertyName*/,
                            false /*isCollectionItemType*/,
                            null /*visitedComplexTypeObjects*/);

                        // When using JsonVerbose to format query string parameters for Actions,
                        // we cannot write out Complex values in the URI without the type name of the complex type in the JSON payload.
                        // If this value is null, the client has to set the ResolveName property on the DataServiceContext instance.
                        ODataComplexValue complexValue = (ODataComplexValue)valueInODataFormat;
                        SerializationTypeNameAnnotation serializedTypeNameAnnotation = complexValue.GetAnnotation <SerializationTypeNameAnnotation>();
                        if (serializedTypeNameAnnotation == null || string.IsNullOrEmpty(serializedTypeNameAnnotation.TypeName))
                        {
                            throw Error.InvalidOperation(Strings.DataServiceException_GeneralError);
                        }

                        break;

                    case EdmTypeKind.Collection:
                        IEdmCollectionType edmCollectionType = edmType as IEdmCollectionType;
                        Debug.Assert(edmCollectionType != null, "edmCollectionType != null");
                        IEdmTypeReference itemTypeReference = edmCollectionType.ElementType;
                        Debug.Assert(itemTypeReference != null, "itemTypeReference != null");
                        ClientTypeAnnotation itemTypeAnnotation = model.GetClientTypeAnnotation(itemTypeReference.Definition);
                        Debug.Assert(itemTypeAnnotation != null, "itemTypeAnnotation != null");

                        switch (itemTypeAnnotation.EdmType.TypeKind)
                        {
                        // We only support primitive or complex type as a collection item type.
                        case EdmTypeKind.Primitive:
                        case EdmTypeKind.Complex:
                            break;

                        default:
                            throw new NotSupportedException(Strings.Serializer_InvalidCollectionParamterItemType(paramName, itemTypeAnnotation.EdmType.TypeKind));
                        }

                        valueInODataFormat = this.propertyConverter.CreateODataCollection(
                            itemTypeAnnotation.ElementType,
                            null /*propertyName*/,
                            value,
                            null /*visitedComplexTypeObjects*/);
                        break;

                    default:
                        // EdmTypeKind.Entity
                        // EdmTypeKind.Row
                        // EdmTypeKind.EntityReference
                        // EdmTypeKind.Enum.
                        throw new NotSupportedException(Strings.Serializer_InvalidParameterType(paramName, edmType.TypeKind));
                    }
                }

                Debug.Assert(valueInODataFormat != null, "valueInODataFormat != null");
            }

            // In the released WCF Data Services 5.0, we didn't pass the model for JSON Verbose literals, so continuing that behavior for backward compatibility
            ODataFormat literalFormat = this.requestInfo.Format.UriLiteralFormat;
            IEdmModel   edmModel      = literalFormat == ODataFormat.VerboseJson ? null : this.requestInfo.Model;

            // ODL can handle null values so we can send null values here.
            string literal = ODataUriUtils.ConvertToUriLiteral(valueInODataFormat, CommonUtil.ConvertToODataVersion(this.requestInfo.MaxProtocolVersionAsVersion), edmModel, literalFormat);

            // The value from ConvertToUriValue will not be escaped, but will already contain literal delimiters like single quotes, so we
            // need to use our own escape method that will preserve those characters instead of directly calling Uri.EscapeDataString that may escape them.
            // This is only necessary for primitives and nulls because the other structures are serialized using the JSON format and it uses double quotes
            // which have always been escaped.
            if (needsSpecialEscaping)
            {
                return(DataStringEscapeBuilder.EscapeDataString(literal));
            }

            return(Uri.EscapeDataString(literal));
        }
示例#20
0
        /// <summary>
        /// Generates a model explicitly.
        /// </summary>
        static IEdmModel GetExplicitEdmModel()
        {
            ODataModelBuilder modelBuilder = new ODataModelBuilder();

            var products = modelBuilder.EntitySet <Product>("Products");

            products.HasIdLink(
                entityContext =>
            {
                object id;
                entityContext.EdmObject.TryGetPropertyValue("Id", out id);
                return(new Uri(entityContext.Url.CreateODataLink(
                                   new EntitySetPathSegment(entityContext.NavigationSource.Name),
                                   new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(id, ODataVersion.V4)))));
            },
                followsConventions: true);

            products.HasEditLink(
                entityContext =>
            {
                object id;
                entityContext.EdmObject.TryGetPropertyValue("Id", out id);
                return(new Uri(entityContext.Url.CreateODataLink(
                                   new EntitySetPathSegment(entityContext.NavigationSource.Name),
                                   new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(id, ODataVersion.V4)))));
            },
                followsConventions: true);

            var suppliers = modelBuilder.EntitySet <Supplier>("Suppliers");

            suppliers.HasIdLink(
                entityContext =>
            {
                object id;
                entityContext.EdmObject.TryGetPropertyValue("Id", out id);
                return(new Uri(entityContext.Url.CreateODataLink(
                                   new EntitySetPathSegment(entityContext.NavigationSource.Name),
                                   new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(id, ODataVersion.V4)))));
            },
                followsConventions: true);

            suppliers.HasEditLink(
                entityContext =>
            {
                object id;
                entityContext.EdmObject.TryGetPropertyValue("Id", out id);
                return(new Uri(entityContext.Url.CreateODataLink(
                                   new EntitySetPathSegment(entityContext.NavigationSource.Name),
                                   new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(id, ODataVersion.V4)))));
            },
                followsConventions: true);

            var families = modelBuilder.EntitySet <ProductFamily>("ProductFamilies");

            families.HasIdLink(
                entityContext =>
            {
                object id;
                entityContext.EdmObject.TryGetPropertyValue("Id", out id);
                return(new Uri(entityContext.Url.CreateODataLink(
                                   new EntitySetPathSegment(entityContext.NavigationSource.Name),
                                   new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(id, ODataVersion.V4)))));
            },
                followsConventions: true);

            families.HasEditLink(
                entityContext =>
            {
                object id;
                entityContext.EdmObject.TryGetPropertyValue("Id", out id);
                return(new Uri(entityContext.Url.CreateODataLink(
                                   new EntitySetPathSegment(entityContext.NavigationSource.Name),
                                   new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(id, ODataVersion.V4)))
                               ));
            },
                followsConventions: true);

            var product = products.EntityType;

            product.HasKey(p => p.Id);
            product.Property(p => p.Name);
            product.Property(p => p.ReleaseDate);
            product.Property(p => p.SupportedUntil);

            modelBuilder.EntityType <RatedProduct>().DerivesFrom <Product>().Property(rp => rp.Rating);

            var address = modelBuilder.ComplexType <Address>();

            address.Property(a => a.City);
            address.Property(a => a.Country);
            address.Property(a => a.State);
            address.Property(a => a.Street);
            address.Property(a => a.ZipCode);

            var supplier = suppliers.EntityType;

            supplier.HasKey(s => s.Id);
            supplier.Property(s => s.Name);
            supplier.ComplexProperty(s => s.Address);

            var productFamily = families.EntityType;

            productFamily.HasKey(pf => pf.Id);
            productFamily.Property(pf => pf.Name);
            productFamily.Property(pf => pf.Description);

            // Create relationships and bindings in one go
            products.HasRequiredBinding(p => p.Family, families);
            families.HasManyBinding(pf => pf.Products, products);
            families.HasOptionalBinding(pf => pf.Supplier, suppliers);
            suppliers.HasManyBinding(s => s.ProductFamilies, families);

            // Create navigation Link builders
            products.HasNavigationPropertiesLink(
                product.NavigationProperties,
                (entityContext, navigationProperty) =>
            {
                object id;
                entityContext.EdmObject.TryGetPropertyValue("Id", out id);
                return(new Uri(entityContext.Url.CreateODataLink(
                                   new EntitySetPathSegment(entityContext.NavigationSource.Name),
                                   new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(id, ODataVersion.V4)),
                                   new NavigationPathSegment(navigationProperty.Name))));
            },
                followsConventions: true);

            families.HasNavigationPropertiesLink(
                productFamily.NavigationProperties,
                (entityContext, navigationProperty) =>
            {
                object id;
                entityContext.EdmObject.TryGetPropertyValue("Id", out id);
                return(new Uri(entityContext.Url.CreateODataLink(
                                   new EntitySetPathSegment(entityContext.NavigationSource.Name),
                                   new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(id, ODataVersion.V4)),
                                   new NavigationPathSegment(navigationProperty.Name))));
            },
                followsConventions: true);

            suppliers.HasNavigationPropertiesLink(
                supplier.NavigationProperties,
                (entityContext, navigationProperty) =>
            {
                object id;
                entityContext.EdmObject.TryGetPropertyValue("Id", out id);
                return(new Uri(entityContext.Url.CreateODataLink(
                                   new EntitySetPathSegment(entityContext.NavigationSource.Name),
                                   new KeyValuePathSegment(ODataUriUtils.ConvertToUriLiteral(id, ODataVersion.V4)),
                                   new NavigationPathSegment(navigationProperty.Name))));
            },
                followsConventions: true);

            ActionConfiguration createProduct = productFamily.Action("CreateProduct");

            createProduct.Parameter <string>("Name");
            createProduct.Returns <int>();

            modelBuilder.Namespace = typeof(ProductFamily).Namespace;
            return(modelBuilder.GetEdmModel());
        }
示例#21
0
        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.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)
                    {
                        routeValues[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;
                        routeValues[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.
                        routeValues[parameterTemp] = newValue;

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

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

            return(parameters);
        }