public void LocalDateTimeOffsetConversion() { var dto = DateTimeOffset.Now; var dt = WebUtil.ConvertDateTimeOffsetToDateTime(dto); dto.DateTime.ShouldBeEquivalentTo(dt, "For local DateTimeOffset values, the value of DateTime within DateTimeOffset must be equal to the result DateTime value"); }
/// <summary> /// Converts a primitive value read by ODataMessageReader into a primitive value acceptable by WCF DS. /// </summary> /// <param name="value">The value reported by ODataMessageReader.</param> /// <param name="resourceType">The resource type of the value to read, null if it is an open property value.</param> /// <returns>The value converted to the WCF DS value space.</returns> protected static object ConvertPrimitiveValue(object value, ref ResourceType resourceType) { Debug.Assert(resourceType == null || resourceType.ResourceTypeKind == ResourceTypeKind.Primitive, "Only primitive types are supported by this method."); // System.Xml.Linq.XElement and System.Data.Linq.Binaries primitive types are not supported by ODataLib directly, // so if the property is of one of those types, we need to convert the value to that type here. if (value != null) { Type instanceType; if (resourceType == null) { resourceType = ResourceType.GetPrimitiveResourceType(value.GetType()); instanceType = resourceType.InstanceType; } else { instanceType = resourceType.InstanceType; if (instanceType == typeof(System.Xml.Linq.XElement)) { string stringValue = value as string; Debug.Assert(stringValue != null, "If the property is of type System.Xml.Linq.XElement then ODataLib should ahve read it as string."); return(System.Xml.Linq.XElement.Parse(stringValue, System.Xml.Linq.LoadOptions.PreserveWhitespace)); } else if (instanceType == typeof(System.Data.Linq.Binary)) { byte[] byteArray = value as byte[]; Debug.Assert(byteArray != null, "If the property is of type System.Data.Linq.Binary then ODataLib should have read it as byte[]."); return(new System.Data.Linq.Binary(byteArray)); } } // It might be the case that store type is DateTime/DateTime? in which case the ResourceType is DateTimeOffset/DateTimeOffset?. if (instanceType == typeof(DateTime) || instanceType == typeof(DateTime?)) { Debug.Assert(value is DateTimeOffset, "Expecting DateTimeOffset for DateTime properties."); value = WebUtil.ConvertDateTimeOffsetToDateTime((DateTimeOffset)value); } } return(value); }
private Expression PromoteExpression(Expression expr, Type type, bool exact, bool isTypeCast = false) { Debug.Assert(expr != null, "expr != null"); Debug.Assert(type != null, "type != null"); if (expr.Type == type) { return(expr); } ConstantExpression ce = null; if (type == typeof(DateTime)) { // Sometimes if the property type is DateTime? in provider, we pass the type as DateTimeOffset? // to ODataLib and it puts a Convert node to convert DateTimeOffset to DateTimeOffset?. Hence // to reach to the constant value, we need to handle the Convert node. if (expr.Type == typeof(DateTimeOffset) || expr.Type == typeof(DateTimeOffset?)) { if (expr.NodeType == ExpressionType.Convert) { ce = ((UnaryExpression)expr).Operand as ConstantExpression; } } } if (ce == null) { ce = expr as ConstantExpression; } if (ce != null) { if (ce == ExpressionUtils.NullLiteral) { if (WebUtil.TypeAllowsNull(type)) { return(Expression.Constant(null, type)); } } else { string text; if (this.literals.TryGetValue(ce, out text)) { Type target = WebUtil.GetNonNullableType(type); object value = null; if (ce.Type == typeof(string) && (target == typeof(Type) || target == typeof(ResourceType))) { // No qoutes required when the function is a cast if (isTypeCast || WebConvert.TryRemoveQuotes(ref text)) { ResourceType resourceType = this.tryResolveResourceType(text); if (resourceType != null) { if (target == typeof(Type)) { if (resourceType.CanReflectOnInstanceType) { value = resourceType.InstanceType; } } else { if (resourceType.CanReflectOnInstanceType == false) { value = resourceType; } } } } } else if ((type == typeof(DateTime) || type == typeof(DateTime?)) && (expr.Type == typeof(DateTimeOffset) || expr.Type == typeof(DateTimeOffset?))) { // Since the URI parser in ODataLib will always convert Constants as DateTimeOffset, // and WCF DS Server supports DateTime clr type, we need to do the conversion whenever required. value = WebUtil.ConvertDateTimeOffsetToDateTime((DateTimeOffset)ce.Value); } else { switch (Type.GetTypeCode(ce.Type)) { case TypeCode.Int32: case TypeCode.Int64: value = ParseNumber(text, target); break; case TypeCode.Double: if (target == typeof(decimal)) { value = ParseNumber(text, target); } break; } } if (value != null) { return(Expression.Constant(value, type)); } } } } if (IsCompatibleWith(expr.Type, type)) { // (type != typeof(object) || expr.Type.IsValueType) part is added // to prevent cast to System.Object from non-value types (objects). if (type.IsValueType || exact && (type != typeof(object) || expr.Type.IsValueType)) { return(Expression.Convert(expr, type)); } return(expr); } // Allow promotion from nullable to non-nullable by directly accessing underlying value. if (WebUtil.IsNullableType(expr.Type) && type.IsValueType) { Expression valueAccessExpression = Expression.Property(expr, "Value"); valueAccessExpression = this.PromoteExpression(valueAccessExpression, type, exact, isTypeCast); return(valueAccessExpression); } return(null); }