private static IEnumerable <KeyValuePair <string, object> > ParseETagValue(IList <ResourceProperty> etagProperties, string ifMatchHeaderValue) { bool flag; if (ifMatchHeaderValue == "*") { return(WebUtil.EmptyKeyValuePairStringObject); } string stringToUnescape = ifMatchHeaderValue.Substring("W/\"".Length, (ifMatchHeaderValue.Length - "W/\"".Length) - 1); KeyInstance instance = null; Exception innerException = null; try { flag = KeyInstance.TryParseNullableTokens(Uri.UnescapeDataString(stringToUnescape), out instance); } catch (DataServiceException exception2) { flag = false; innerException = exception2; } if (!flag) { throw DataServiceException.CreatePreConditionFailedError(System.Data.Services.Strings.Serializer_ETagValueDoesNotMatch, innerException); } if (instance.PositionalValues.Count != etagProperties.Count) { throw DataServiceException.CreatePreConditionFailedError(System.Data.Services.Strings.Serializer_ETagValueDoesNotMatch); } KeyValuePair <string, object>[] pairArray = new KeyValuePair <string, object> [etagProperties.Count]; for (int i = 0; i < pairArray.Length; i++) { ResourceProperty property = etagProperties[i]; object targetValue = null; string text = (string)instance.PositionalValues[i]; if (text != "null") { try { flag = WebConvert.TryKeyStringToPrimitive(text, property.Type, out targetValue); } catch (OverflowException exception3) { flag = false; innerException = exception3; } if (!flag) { throw DataServiceException.CreatePreConditionFailedError(System.Data.Services.Strings.Serializer_ETagValueDoesNotMatch, innerException); } } pairArray[i] = new KeyValuePair <string, object>(etagProperties[i].Name, targetValue); } return(pairArray); }
private void ApplyStandardPaging(string skipToken) { if (!string.IsNullOrEmpty(skipToken)) { KeyInstance instance; if (!this.IsPageSizeDefined) { throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.RequestQueryProcessor_SkipTokenSupportedOnPagedSets); } WebUtil.CheckSyntaxValid(KeyInstance.TryParseNullableTokens(skipToken, out instance)); if (this.topLevelOrderingInfo.OrderingExpressions.Count != instance.PositionalValues.Count) { throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.DataService_SDP_SkipTokenNotMatchingOrdering(instance.PositionalValues.Count, skipToken, this.topLevelOrderingInfo.OrderingExpressions.Count)); } this.queryExpression = this.queryExpression.QueryableWhere(this.orderingParser.BuildSkipTokenFilter(this.topLevelOrderingInfo, instance)); this.description.VerifyProtocolVersion(RequestDescription.Version2Dot0, this.service); this.description.VerifyRequestVersion(RequestDescription.Version2Dot0, this.service); this.description.VerifyAndRaiseResponseVersion(RequestDescription.Version2Dot0, this.service); } }
private void ApplyCustomPaging(string skipToken) { if (!string.IsNullOrEmpty(skipToken)) { KeyInstance instance; WebUtil.CheckSyntaxValid(KeyInstance.TryParseNullableTokens(skipToken, out instance)); ParameterExpression parameterForIt = Expression.Parameter(this.description.LastSegmentInfo.TargetResourceType.InstanceType, "it"); RequestQueryParser.ExpressionParser parser = new RequestQueryParser.ExpressionParser(this.service, this.description, parameterForIt, string.Empty); object[] skipTokenValues = new object[instance.PositionalValues.Count]; int num = 0; foreach (object obj2 in instance.PositionalValues) { skipTokenValues[num++] = parser.ParseSkipTokenLiteral((string)obj2); } this.CheckAndApplyCustomPaging(skipTokenValues); this.description.VerifyProtocolVersion(RequestDescription.Version2Dot0, this.service); this.description.VerifyRequestVersion(RequestDescription.Version2Dot0, this.service); } else { this.CheckAndApplyCustomPaging(null); } }
/// <summary>Attempts to parse key values from the specified text.</summary> /// <param name='text'>Text to parse (not null).</param> /// <param name="allowNamedValues">Set to true if the parser should accept named values /// so syntax like Name='value'. If this is false, the parsing will fail on such constructs.</param> /// <param name="allowNull">Set to true if the parser should accept null values. /// If set to false, the parser will fail on null values.</param> /// <param name='instance'>After invocation, the parsed key instance.</param> /// <returns> /// true if the key instance was parsed; false if there was a /// syntactic error. /// </returns> /// <remarks> /// The returned instance contains only string values. To get typed values, a call to /// <see cref="TryConvertValues"/> is necessary. /// </remarks> private static bool TryParseFromUri(string text, bool allowNamedValues, bool allowNull, out KeyInstance instance) { Debug.Assert(text != null, "text != null"); Dictionary<string, object> namedValues = null; List<object> positionalValues = null; ExpressionLexer lexer = new ExpressionLexer(text); Token currentToken = lexer.CurrentToken; if (currentToken.Id == TokenId.End) { instance = Empty; return true; } instance = null; do { if (currentToken.Id == TokenId.Identifier && allowNamedValues) { // Name-value pair. if (positionalValues != null) { // We cannot mix named and non-named values. return false; } string identifier = lexer.CurrentToken.GetIdentifier(); lexer.NextToken(); if (lexer.CurrentToken.Id != TokenId.Equal) { return false; } lexer.NextToken(); if (!lexer.CurrentToken.IsKeyValueToken) { return false; } string namedValue = lexer.CurrentToken.Text; WebUtil.CreateIfNull(ref namedValues); if (namedValues.ContainsKey(identifier)) { // Duplicate name. return false; } namedValues.Add(identifier, namedValue); } else if (currentToken.IsKeyValueToken || (allowNull && currentToken.Id == TokenId.NullLiteral)) { // Positional value. if (namedValues != null) { // We cannot mix named and non-named values. return false; } WebUtil.CreateIfNull(ref positionalValues); positionalValues.Add(lexer.CurrentToken.Text); } else { return false; } // Read the next token. We should be at the end, or find // we have a comma followed by something. lexer.NextToken(); currentToken = lexer.CurrentToken; if (currentToken.Id == TokenId.Comma) { lexer.NextToken(); currentToken = lexer.CurrentToken; if (currentToken.Id == TokenId.End) { // Trailing comma. return false; } } } while (currentToken.Id != TokenId.End); instance = new KeyInstance(namedValues, positionalValues); return true; }
/// <summary>Attempts to parse nullable values (only positional values, no name-value pairs) from the specified text.</summary> /// <param name='text'>Text to parse (not null).</param> /// <param name='instance'>After invocation, the parsed key instance.</param> /// <returns> /// true if the given values were parsed; false if there was a /// syntactic error. /// </returns> /// <remarks> /// The returned instance contains only string values. To get typed values, a call to /// <see cref="TryConvertValues"/> is necessary. /// </remarks> internal static bool TryParseNullableTokens(string text, out KeyInstance instance) { return TryParseFromUri(text, false /*allowNamedValues*/, true /*allowNull*/, out instance); }
/// <summary> /// Parse the given etag value in the If-Match request header. /// </summary> /// <param name="etagProperties">List of etag properties for the type whose etag values we are parsing.</param> /// <param name="ifMatchHeaderValue">value of the If-Match header as specified in the request.</param> /// <returns>returns the etag value as a list containing the property name and its corresponding value. If the If-Match header value is '*', then returns an empty collection.</returns> private static IEnumerable <KeyValuePair <string, object> > ParseETagValue(IList <ResourceProperty> etagProperties, string ifMatchHeaderValue) { Debug.Assert(etagProperties != null && etagProperties.Count != 0, "There must be atleast one etag property specified"); Debug.Assert(!String.IsNullOrEmpty(ifMatchHeaderValue), "IfMatch header cannot be null"); if (ifMatchHeaderValue == XmlConstants.HttpAnyETag) { // if the value is '*', then we return an empty IEnumerable. return(new KeyValuePair <string, object> [0]); } Debug.Assert(ifMatchHeaderValue.StartsWith(XmlConstants.HttpWeakETagPrefix, StringComparison.Ordinal), "If-Match header must be properly formatted - this check is done in DataService.CheckETagValues method"); Debug.Assert(ifMatchHeaderValue.Length >= XmlConstants.HttpWeakETagPrefix.Length + 1, "If-Match header must be properly formatted - this check is done in DataService.CheckETagValues method"); // Just get the etag value - we need to ignore the 'W/"' and the last '"' character from the etag string strippedETag = ifMatchHeaderValue.Substring(XmlConstants.HttpWeakETagPrefix.Length, ifMatchHeaderValue.Length - XmlConstants.HttpWeakETagPrefix.Length - 1); KeyInstance keyInstance = null; bool success; Exception innerException = null; // In V1, when we didn't have IConcurrencyProvider interface, we always used to compute the // latest etag from the entity instance we got from IUpdatable.GetResource and then comparing // it with the If-Match request header. Hence all invalid cases always used to throw // DataServiceException with 412, since the etags didn't match. // In V1.5, we have added the support for IConcurrencyProvider, which means we need to parse // the etag values and parse it to the provider, if it has implement this interface. To avoid // breaking changes, we need to catch all parsing errors and report them as 412 instead of 400 // to avoid it from becoming a breaking change. try { success = KeyInstance.TryParseNullableTokens(Uri.UnescapeDataString(strippedETag), out keyInstance); } catch (DataServiceException e) { success = false; innerException = e; } if (!success) { // We could have throwed BadRequest here since the etag value is not properly formattted. But since // we used to do throw 412 in V1, keeping it that way to avoid breaking change. throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch, innerException); } if (keyInstance.PositionalValues.Count != etagProperties.Count) { // We could have throwed BadRequest here since the etag value is not properly formattted. But since // we used to do throw 412 in V1, keeping it that way to avoid breaking change. throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch); } KeyValuePair <string, object>[] etagPropertyInfo = new KeyValuePair <string, object> [etagProperties.Count]; for (int i = 0; i < etagPropertyInfo.Length; i++) { ResourceProperty etagProperty = etagProperties[i]; object propertyValue = null; string value = (string)keyInstance.PositionalValues[i]; if (value != XmlConstants.NullLiteralInETag) { // The reason we need to catch the Overflow Exception here is because of the Bug #679728. // In V1, when we didn't have IConcurrencyProvider interface, we always used to compute the // latest etag from the entity instance we got from IUpdatable.GetResource and then comparing // it with the If-Match request header. Hence all invalid cases always used to throw // DataServiceException with 412, since the etags didn't match. // In V1.5, we have added the support for IConcurrencyProvider, which means we need to parse // the etag values and parse it to the provider, if it has implement this interface. To avoid // breaking changes, we need to catch all parsing errors and report them as 412 instead of 400 // to avoid it from becoming a breaking change. try { success = System.Data.Services.Parsing.WebConvert.TryKeyStringToPrimitive(value, etagProperty.Type, out propertyValue); } catch (OverflowException e) { success = false; innerException = e; } if (!success) { // We could have throwed BadRequest here since the etag value is not properly formattted. But since // we used to do throw 412 in V1, keeping it that way to avoid breaking change. throw DataServiceException.CreatePreConditionFailedError(Strings.Serializer_ETagValueDoesNotMatch, innerException); } } etagPropertyInfo[i] = new KeyValuePair <string, object>(etagProperties[i].Name, propertyValue); } return(etagPropertyInfo); }
private static Expression SelectResourceByKey(Expression queryExpression, ResourceType resourceType, KeyInstance key) { for (int i = 0; i < resourceType.KeyProperties.Count; i++) { Expression expression2; ResourceProperty property = resourceType.KeyProperties[i]; object obj2 = key.AreValuesNamed ? key.NamedValues[property.Name] : key.PositionalValues[i]; ParameterExpression expression = Expression.Parameter(queryExpression.ElementType(), "element"); if (property.CanReflectOnInstanceTypeProperty) { expression2 = Expression.Property(expression, property.Name); } else { expression2 = Expression.Convert(Expression.Call(null, DataServiceProviderMethods.GetValueMethodInfo, expression, Expression.Constant(property)), property.Type); } LambdaExpression predicate = Expression.Lambda(Expression.Equal(expression2, Expression.Constant(obj2)), new ParameterExpression[] { expression }); queryExpression = queryExpression.QueryableWhere(predicate); } return queryExpression; }
/// <summary>Attempts to parse key values from the specified text.</summary> /// <param name='text'>Text to parse (not null).</param> /// <param name="allowNamedValues">Set to true if the parser should accept named values /// so syntax like Name='value'. If this is false, the parsing will fail on such constructs.</param> /// <param name="allowNull">Set to true if the parser should accept null values. /// If set to false, the parser will fail on null values.</param> /// <param name='instance'>After invocation, the parsed key instance.</param> /// <returns> /// true if the key instance was parsed; false if there was a /// syntactic error. /// </returns> /// <remarks> /// The returned instance contains only string values. To get typed values, a call to /// <see cref="TryConvertValues"/> is necessary. /// </remarks> private static bool TryParseFromUri(string text, bool allowNamedValues, bool allowNull, out KeyInstance instance) { Debug.Assert(text != null, "text != null"); Dictionary <string, object> namedValues = null; List <object> positionalValues = null; ExpressionLexer lexer = new ExpressionLexer(text); Token currentToken = lexer.CurrentToken; if (currentToken.Id == TokenId.End) { instance = Empty; return(true); } instance = null; do { if (currentToken.Id == TokenId.Identifier && allowNamedValues) { // Name-value pair. if (positionalValues != null) { // We cannot mix named and non-named values. return(false); } string identifier = lexer.CurrentToken.GetIdentifier(); lexer.NextToken(); if (lexer.CurrentToken.Id != TokenId.Equal) { return(false); } lexer.NextToken(); if (!lexer.CurrentToken.IsKeyValueToken) { return(false); } string namedValue = lexer.CurrentToken.Text; WebUtil.CreateIfNull(ref namedValues); if (namedValues.ContainsKey(identifier)) { // Duplicate name. return(false); } namedValues.Add(identifier, namedValue); } else if (currentToken.IsKeyValueToken || (allowNull && currentToken.Id == TokenId.NullLiteral)) { // Positional value. if (namedValues != null) { // We cannot mix named and non-named values. return(false); } WebUtil.CreateIfNull(ref positionalValues); positionalValues.Add(lexer.CurrentToken.Text); } else { return(false); } // Read the next token. We should be at the end, or find // we have a comma followed by something. lexer.NextToken(); currentToken = lexer.CurrentToken; if (currentToken.Id == TokenId.Comma) { lexer.NextToken(); currentToken = lexer.CurrentToken; if (currentToken.Id == TokenId.End) { // Trailing comma. return(false); } } }while (currentToken.Id != TokenId.End); instance = new KeyInstance(namedValues, positionalValues); return(true); }
/// <summary>Attempts to parse nullable values (only positional values, no name-value pairs) from the specified text.</summary> /// <param name='text'>Text to parse (not null).</param> /// <param name='instance'>After invocation, the parsed key instance.</param> /// <returns> /// true if the given values were parsed; false if there was a /// syntactic error. /// </returns> /// <remarks> /// The returned instance contains only string values. To get typed values, a call to /// <see cref="TryConvertValues"/> is necessary. /// </remarks> internal static bool TryParseNullableTokens(string text, out KeyInstance instance) { return(TryParseFromUri(text, false /*allowNamedValues*/, true /*allowNull*/, out instance)); }
private static bool TryParseFromUri(string text, bool allowNamedValues, bool allowNull, out KeyInstance instance) { Dictionary <string, object> dictionary = null; List <object> list = null; ExpressionLexer lexer = new ExpressionLexer(text); Token currentToken = lexer.CurrentToken; if (currentToken.Id == TokenId.End) { instance = Empty; return(true); } instance = null; do { if ((currentToken.Id == TokenId.Identifier) && allowNamedValues) { if (list != null) { return(false); } string identifier = lexer.CurrentToken.GetIdentifier(); lexer.NextToken(); if (lexer.CurrentToken.Id != TokenId.Equal) { return(false); } lexer.NextToken(); if (!lexer.CurrentToken.IsKeyValueToken) { return(false); } string str2 = lexer.CurrentToken.Text; WebUtil.CreateIfNull <Dictionary <string, object> >(ref dictionary); if (dictionary.ContainsKey(identifier)) { return(false); } dictionary.Add(identifier, str2); } else { if (!currentToken.IsKeyValueToken && (!allowNull || (currentToken.Id != TokenId.NullLiteral))) { return(false); } if (dictionary != null) { return(false); } WebUtil.CreateIfNull <List <object> >(ref list); list.Add(lexer.CurrentToken.Text); } lexer.NextToken(); currentToken = lexer.CurrentToken; if (currentToken.Id == TokenId.Comma) { lexer.NextToken(); currentToken = lexer.CurrentToken; if (currentToken.Id == TokenId.End) { return(false); } } }while (currentToken.Id != TokenId.End); instance = new KeyInstance(dictionary, list); return(true); }
internal static bool TryParseNullableTokens(string text, out KeyInstance instance) { return(TryParseFromUri(text, false, true, out instance)); }
internal static bool TryParseKeysFromUri(string text, out KeyInstance instance) { return(TryParseFromUri(text, true, false, out instance)); }
private static bool TryParseFromUri(string text, bool allowNamedValues, bool allowNull, out KeyInstance instance) { Dictionary<string, object> dictionary = null; List<object> list = null; ExpressionLexer lexer = new ExpressionLexer(text); Token currentToken = lexer.CurrentToken; if (currentToken.Id == TokenId.End) { instance = Empty; return true; } instance = null; do { if ((currentToken.Id == TokenId.Identifier) && allowNamedValues) { if (list != null) { return false; } string identifier = lexer.CurrentToken.GetIdentifier(); lexer.NextToken(); if (lexer.CurrentToken.Id != TokenId.Equal) { return false; } lexer.NextToken(); if (!lexer.CurrentToken.IsKeyValueToken) { return false; } string str2 = lexer.CurrentToken.Text; WebUtil.CreateIfNull<Dictionary<string, object>>(ref dictionary); if (dictionary.ContainsKey(identifier)) { return false; } dictionary.Add(identifier, str2); } else { if (!currentToken.IsKeyValueToken && (!allowNull || (currentToken.Id != TokenId.NullLiteral))) { return false; } if (dictionary != null) { return false; } WebUtil.CreateIfNull<List<object>>(ref list); list.Add(lexer.CurrentToken.Text); } lexer.NextToken(); currentToken = lexer.CurrentToken; if (currentToken.Id == TokenId.Comma) { lexer.NextToken(); currentToken = lexer.CurrentToken; if (currentToken.Id == TokenId.End) { return false; } } } while (currentToken.Id != TokenId.End); instance = new KeyInstance(dictionary, list); return true; }
internal static bool TryParseNullableTokens(string text, out KeyInstance instance) { return TryParseFromUri(text, false, true, out instance); }
internal static bool TryParseKeysFromUri(string text, out KeyInstance instance) { return TryParseFromUri(text, true, false, out instance); }