private Expression GetPredicateBody(HttpRequestMessage request, ParameterExpression param) { Expression workingExpr = null; var type = param.Type; var queryPairs = request.GetQueryNameValuePairs(); foreach (var queryPair in queryPairs) { if (String.IsNullOrWhiteSpace(queryPair.Key)) { continue; } var prop = _modelManager.GetPropertyForJsonKey(type, queryPair.Key); if (prop != null) { var propertyType = prop.PropertyType; var queryValue = queryPair.Value; if (string.IsNullOrWhiteSpace(queryValue)) { queryValue = null; } Expression expr = null; if (propertyType == typeof(String)) { if (String.IsNullOrWhiteSpace(queryValue)) { Expression propertyExpr = Expression.Property(param, prop); expr = Expression.Equal(propertyExpr, Expression.Constant(null)); } else { Expression propertyExpr = Expression.Property(param, prop); expr = Expression.Equal(propertyExpr, Expression.Constant(queryValue)); } } else if (propertyType == typeof(Boolean)) { bool value; expr = bool.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(Boolean?)) { bool tmp; var value = bool.TryParse(queryValue, out tmp) ? tmp : (bool?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(SByte)) { SByte value; expr = SByte.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(SByte?)) { SByte tmp; var value = SByte.TryParse(queryValue, out tmp) ? tmp : (SByte?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(Byte)) { Byte value; expr = Byte.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(Byte?)) { Byte tmp; var value = Byte.TryParse(queryValue, out tmp) ? tmp : (Byte?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(Int16)) { Int16 value; expr = Int16.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(Int16?)) { Int16 tmp; var value = Int16.TryParse(queryValue, out tmp) ? tmp : (Int16?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(UInt16)) { UInt16 value; expr = UInt16.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(UInt16?)) { UInt16 tmp; var value = UInt16.TryParse(queryValue, out tmp) ? tmp : (UInt16?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(Int32)) { Int32 value; expr = Int32.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(Int32?)) { Int32 tmp; var value = Int32.TryParse(queryValue, out tmp) ? tmp : (Int32?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(UInt32)) { UInt32 value; expr = UInt32.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(UInt32?)) { UInt32 tmp; var value = UInt32.TryParse(queryValue, out tmp) ? tmp : (UInt32?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(Int64)) { Int64 value; expr = Int64.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(Int64?)) { Int64 tmp; var value = Int64.TryParse(queryValue, out tmp) ? tmp : (Int64?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(UInt64)) { UInt64 value; expr = UInt64.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(UInt64?)) { UInt64 tmp; var value = UInt64.TryParse(queryValue, out tmp) ? tmp : (UInt64?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(Single)) { Single value; expr = Single.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(Single?)) { Single tmp; var value = Single.TryParse(queryValue, out tmp) ? tmp : (Single?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(Double)) { Double value; expr = Double.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(Double?)) { Double tmp; var value = Double.TryParse(queryValue, out tmp) ? tmp : (Double?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(Decimal)) { Decimal value; expr = Decimal.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(Decimal?)) { Decimal tmp; var value = Decimal.TryParse(queryValue, out tmp) ? tmp : (Decimal?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(DateTime)) { DateTime value; expr = DateTime.TryParse(queryValue, out value) ? GetPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(DateTime?)) { DateTime tmp; var value = DateTime.TryParse(queryValue, out tmp) ? tmp : (DateTime?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType == typeof(DateTimeOffset)) { DateTimeOffset value; expr = DateTimeOffset.TryParse(queryValue, out value) ? GetPropertyExpression <DateTimeOffset>(value, prop, param) : Expression.Constant(false); } else if (propertyType == typeof(DateTimeOffset?)) { DateTimeOffset tmp; var value = DateTimeOffset.TryParse(queryValue, out tmp) ? tmp : (DateTimeOffset?)null; expr = GetPropertyExpression(value, prop, param); } else if (propertyType.IsEnum) { int value; expr = (int.TryParse(queryValue, out value) && Enum.IsDefined(propertyType, value)) ? GetEnumPropertyExpression(value, prop, param) : Expression.Constant(false); } else if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable <>) && propertyType.GenericTypeArguments[0].IsEnum) { int tmp; var value = int.TryParse(queryValue, out tmp) ? tmp : (int?)null; expr = GetEnumPropertyExpression(value, prop, param); } else { // See if it is a relationship property if (_modelManager.IsSerializedAsMany(propertyType)) { var elementType = _modelManager.GetElementType(propertyType); PropertyInfo relatedIdProperty; try { relatedIdProperty = _modelManager.GetIdProperty(elementType); } catch (InvalidOperationException) { relatedIdProperty = null; } if (relatedIdProperty != null) { var propertyExpr = Expression.Property(param, prop); if (string.IsNullOrWhiteSpace(queryValue)) { var leftExpr = Expression.Equal(propertyExpr, Expression.Constant(null)); var asQueryableCallExpr = Expression.Call( typeof(Queryable), "AsQueryable", new[] { elementType }, propertyExpr); var anyCallExpr = Expression.Call( typeof(Queryable), "Any", new[] { elementType }, asQueryableCallExpr); var rightExpr = Expression.Not(anyCallExpr); expr = Expression.OrElse(leftExpr, rightExpr); } else { var leftExpr = Expression.NotEqual(propertyExpr, Expression.Constant(null)); var idValue = queryValue.Trim(); var idExpr = Expression.Constant(idValue); var anyParam = Expression.Parameter(elementType); var relatedIdPropertyExpr = Expression.Property(anyParam, relatedIdProperty); var relatedIdPropertyEqualsIdExpr = Expression.Equal(relatedIdPropertyExpr, idExpr); var anyPredicateExpr = Expression.Lambda(relatedIdPropertyEqualsIdExpr, anyParam); var asQueryableCallExpr = Expression.Call( typeof(Queryable), "AsQueryable", new[] { elementType }, propertyExpr); var rightExpr = Expression.Call( typeof(Queryable), "Any", new[] { elementType }, asQueryableCallExpr, anyPredicateExpr); expr = Expression.AndAlso(leftExpr, rightExpr); } } } else { PropertyInfo relatedIdProperty; try { relatedIdProperty = _modelManager.GetIdProperty(propertyType); } catch (InvalidOperationException) { relatedIdProperty = null; } if (relatedIdProperty != null) { var propertyExpr = Expression.Property(param, prop); if (string.IsNullOrWhiteSpace(queryValue)) { expr = Expression.Equal(propertyExpr, Expression.Constant(null)); } else { var leftExpr = Expression.NotEqual(propertyExpr, Expression.Constant(null)); var idValue = queryValue.Trim(); var idExpr = Expression.Constant(idValue); var relatedIdPropertyExpr = Expression.Property(propertyExpr, relatedIdProperty); var rightExpr = Expression.Equal(relatedIdPropertyExpr, idExpr); expr = Expression.AndAlso(leftExpr, rightExpr); } } } } if (expr == null) { expr = Expression.Constant(true); } workingExpr = workingExpr == null ? expr : Expression.AndAlso(workingExpr, expr); } } return(workingExpr ?? Expression.Constant(true)); // No filters, so return everything }
public object Deserialize(Type objectType, Stream readStream, JsonReader reader, JsonSerializer serializer) { object retval = Activator.CreateInstance(objectType); if (reader.TokenType != JsonToken.StartObject) { throw new JsonReaderException(String.Format("Expected JsonToken.StartObject, got {0}", reader.TokenType.ToString())); } reader.Read(); // Burn the StartObject token do { if (reader.TokenType == JsonToken.PropertyName) { string value = (string)reader.Value; PropertyInfo prop; if (value == "links") { reader.Read(); // burn the PropertyName token //TODO: linked resources (Done??) DeserializeLinkedResources(retval, readStream, reader, serializer); } else if ((prop = _modelManager.GetPropertyForJsonKey(objectType, value)) != null) { reader.Read(); // burn the PropertyName token //TODO: Embedded would be dropped here! if (!CanWriteTypeAsPrimitive(prop.PropertyType)) { continue; // These aren't supposed to be here, they're supposed to be in "links"! } object propVal; if (prop.PropertyType == typeof(string) && prop.GetCustomAttributes().Any(attr => attr is SerializeStringAsRawJsonAttribute)) { if (reader.TokenType == JsonToken.Null) { propVal = null; } else { var token = JToken.Load(reader); var rawPropVal = token.ToString(); propVal = JsonHelpers.MinifyJson(rawPropVal); } } else { propVal = DeserializePrimitive(prop.PropertyType, reader); } prop.SetValue(retval, propVal, null); // Tell the MetadataManager that we deserialized this property MetadataManager.Instance.SetMetaForProperty(retval, prop, true); // pop the value off the reader, so we catch the EndObject token below!. reader.Read(); } else { // Unexpected/unknown property--Skip the propertyname and its value reader.Skip(); if (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject) { reader.Skip(); } else { reader.Read(); } } } } while (reader.TokenType != JsonToken.EndObject); reader.Read(); // burn the EndObject token before returning back up the call stack /* * // Suss out all the relationship members, and which ones have what cardinality... * IEnumerable<PropertyInfo> relations = ( * from prop in objectType.GetProperties() * where !CanWriteTypeAsPrimitive(prop.PropertyType) * && prop.GetCustomAttributes(true).Any(attribute => attribute is System.Runtime.Serialization.DataMemberAttribute) * select prop * ); * IEnumerable<PropertyInfo> hasManys = relations.Where(prop => typeof(IEnumerable<object>).IsAssignableFrom(prop.PropertyType)); * IEnumerable<PropertyInfo> belongsTos = relations.Where(prop => !typeof(IEnumerable<object>).IsAssignableFrom(prop.PropertyType)); * * JObject links = (JObject)jo["links"]; * * // Lets deal with belongsTos first, that should be simpler... * foreach (PropertyInfo prop in belongsTos) * { * if (links == null) break; // Well, apparently we don't have any data for the relationships! * * string btId = (string)links[_modelManager.GetJsonKeyForProperty(prop)]; * if (btId == null) * { * prop.SetValue(retval, null, null); // Important that we set--the value may have been cleared! * continue; // breaking early! * } * Type relType = prop.PropertyType; * //if (typeof(EntityObject).IsAssignableFrom(relType)) * if (resolver.CanIncludeTypeAsObject(relType)) * { * prop.SetValue(retval, resolver.GetById(relType, btId), null); * //throw new ApplicationException(String.Format("Could not assign BelongsTo property \"{0}\" on object of type {1} by ID {2} because no object of type {3} could be retrieved by that ID.", prop.Name, objectType, btId, prop.PropertyType)); * } * } */ return(retval); }