/// <summary> /// Returns whether ODataLib should be explicitly instructed to include or omit a type name on the wire. /// </summary> /// <param name="value">The value to be serialized.</param> /// <param name="actualType">The type to be potentially serialized.</param> /// <param name="typeNameToWrite">The type name which ODataLib should be told to serialize. A value of null indicates the type name should be omitted.</param> /// <returns>true if an annotation should be created to override ODataLib's default type name serialization behavior; false if the ODataLib default behavior should be used.</returns> internal bool ShouldSpecifyTypeNameAnnotation(ODataValue value, ResourceType actualType, out string typeNameToWrite) { if (this.metadataParameterValueForTypeNames == MetadataParameterValue.Full) { ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; Debug.Assert(primitiveValue == null || actualType.ResourceTypeKind == ResourceTypeKind.Primitive, "If value is ODataPrimitiveValue, actualType must also be primitive."); if (primitiveValue != null && JsonSharedUtils.ValueTypeMatchesJsonType(primitiveValue, MetadataProviderUtils.CreatePrimitiveTypeReference(actualType))) { // Don't set the annotation and use the default ODataLib type name serialization behavior for basic JSON types. typeNameToWrite = null; return(false); } typeNameToWrite = actualType.FullName; return(true); } if (this.metadataParameterValueForTypeNames == MetadataParameterValue.None) { // Setting the type name to null explicitly tells ODataLib to not write a type name annotation on the wire. typeNameToWrite = null; return(true); } // Otherwise, don't set the annotation and use the default ODataLib type name serialization behavior. typeNameToWrite = null; return(false); }
/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="typeReferenceFromMetadata">The type as expected by the model.</param> /// <param name="typeReferenceFromValue">The type resolved from the value.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal override string GetValueTypeNameForWriting( ODataValue value, IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, bool isOpenProperty) { DebugUtils.CheckNoExternalCallers(); SerializationTypeNameAnnotation typeNameAnnotation = value.GetAnnotation <SerializationTypeNameAnnotation>(); if (typeNameAnnotation != null) { return(typeNameAnnotation.TypeName); } // Do not write type name when the type is native json type. if (typeReferenceFromValue != null && typeReferenceFromValue.IsPrimitive() && JsonSharedUtils.ValueTypeMatchesJsonType((ODataPrimitiveValue)value, typeReferenceFromValue.AsPrimitive())) { return(null); } return(GetTypeNameFromValue(value)); }
/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="propertyInfo">The serialization info of current property</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal override string GetValueTypeNameForWriting( ODataValue value, PropertySerializationInfo propertyInfo, bool isOpenProperty) { PropertyValueTypeInfo valueType = propertyInfo.ValueType; string typeNameToWrite; if (TypeNameOracle.TryGetTypeNameFromAnnotation(value, out typeNameToWrite)) { return(typeNameToWrite); } if (valueType.TypeReference != null) { // Do not write type name when the type is native json type. if (valueType.IsPrimitive && JsonSharedUtils.ValueTypeMatchesJsonType((ODataPrimitiveValue)value, valueType.PrimitiveTypeKind)) { return(null); } } return(GetTypeNameFromValue(value)); }
/// <summary> /// Adds a type annotation to the value if it is primitive and not defined on the server. /// </summary> /// <param name="serverTypeName">The server type name of the entity whose properties are being populated.</param> /// <param name="property">The current property.</param> /// <param name="odataValue">The already converted value of the property.</param> private void AddTypeAnnotationNotDeclaredOnServer(string serverTypeName, ClientPropertyAnnotation property, ODataValue odataValue) { Debug.Assert(property != null, "property != null"); Debug.Assert(property.EdmProperty != null, "property.EdmProperty != null"); #if DEBUG if (odataValue is ODataCollectionValue) { Debug.Assert( !this.requestInfo.TypeResolver.ShouldWriteClientTypeForOpenServerProperty(property.EdmProperty, serverTypeName), "Open collection properties are not yet supported. This method will need to be updated when they are."); } #endif var primitiveValue = odataValue as ODataPrimitiveValue; if (primitiveValue == null) { return; } if (!this.requestInfo.Format.UsingAtom && this.requestInfo.TypeResolver.ShouldWriteClientTypeForOpenServerProperty(property.EdmProperty, serverTypeName) && !JsonSharedUtils.ValueTypeMatchesJsonType(primitiveValue, property.EdmProperty.Type.AsPrimitive())) { // DEVNOTE: it is safe to use the property type name for primitive types because they do not generally support inheritance, // and spatial values always contain their specific type inside the GeoJSON/GML representation. primitiveValue.SetAnnotation(new SerializationTypeNameAnnotation { TypeName = property.EdmProperty.Type.FullName() }); } }
/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="propertyInfo">The serialization info of current property</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal override string GetValueTypeNameForWriting( ODataValue value, PropertySerializationInfo propertyInfo, bool isOpenProperty) { string fullTypeNameFromValue = null; PropertyValueTypeInfo valueType = propertyInfo.ValueType; PropertyMetadataTypeInfo modelType = propertyInfo.MetadataType; string typeNameToWrite; if (TypeNameOracle.TryGetTypeNameFromAnnotation(value, out typeNameToWrite)) { return(typeNameToWrite); } if (valueType.TypeReference != null) { fullTypeNameFromValue = valueType.FullName; // Write type name when the type in the payload is more derived than the type from metadata. if (modelType.TypeReference != null && modelType.FullName != fullTypeNameFromValue) { return(fullTypeNameFromValue); } // Do not write type name when the type is native json type. if (valueType.IsPrimitive && JsonSharedUtils.ValueTypeMatchesJsonType((ODataPrimitiveValue)value, valueType.PrimitiveTypeKind)) { return(null); } // Note: When writing derived complexType value in a payload, we don't have the expected type. // So always write @odata.type for top-level derived complex type. if (modelType.TypeReference == null && valueType.IsComplex) { if ((valueType.TypeReference as IEdmComplexTypeReference).ComplexDefinition().BaseType != null) { return(fullTypeNameFromValue); } } } if (!isOpenProperty) { // Do not write type name for non-open properties since we expect the reader to have an expected type (via API or context URI) and thus not need it. return(null); } return(fullTypeNameFromValue != null ? fullTypeNameFromValue : GetTypeNameFromValue(value)); }
/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="typeReferenceFromMetadata">The type as expected by the model.</param> /// <param name="typeReferenceFromValue">The type resolved from the value.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal override string GetValueTypeNameForWriting( ODataValue value, IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, bool isOpenProperty) { string fullTypeNameFromValue = null; string typeNameToWrite; if (TypeNameOracle.TryGetTypeNameFromAnnotation(value, out typeNameToWrite)) { return(typeNameToWrite); } if (typeReferenceFromValue != null) { fullTypeNameFromValue = typeReferenceFromValue.FullName(); // Write type name when the type in the payload is more derived than the type from metadata. if (typeReferenceFromMetadata != null && typeReferenceFromMetadata.Definition.AsActualType().FullTypeName() != fullTypeNameFromValue) { return(fullTypeNameFromValue); } // Do not write type name when the type is native json type. if (typeReferenceFromValue.IsPrimitive() && JsonSharedUtils.ValueTypeMatchesJsonType((ODataPrimitiveValue)value, typeReferenceFromValue.AsPrimitive())) { return(null); } // Note: When writing derived complexType value in a payload, we don't have the expected type. // So always write @odata.type for top-level derived complex type. if (typeReferenceFromMetadata == null && typeReferenceFromValue.IsComplex()) { if ((typeReferenceFromValue as IEdmComplexTypeReference).ComplexDefinition().BaseType != null) { return(fullTypeNameFromValue); } } } if (!isOpenProperty) { // Do not write type name for non-open properties since we expect the reader to have an expected type (via API or context URI) and thus not need it. return(null); } return(fullTypeNameFromValue != null ? fullTypeNameFromValue : GetTypeNameFromValue(value)); }
/// <summary> /// Adds a type annotation to the value if it is primitive and not defined on the server. /// </summary> /// <param name="serverTypeName">The server type name of the entity whose properties are being populated.</param> /// <param name="property">The current property.</param> /// <param name="odataValue">The already converted value of the property.</param> private void AddTypeAnnotationNotDeclaredOnServer(string serverTypeName, ClientPropertyAnnotation property, ODataValue odataValue) { Debug.Assert(property != null, "property != null"); Debug.Assert(property.EdmProperty != null, "property.EdmProperty != null"); var primitiveValue = odataValue as ODataPrimitiveValue; if (primitiveValue == null) { return; } if (this.requestInfo.TypeResolver.ShouldWriteClientTypeForOpenServerProperty(property.EdmProperty, serverTypeName) && !JsonSharedUtils.ValueTypeMatchesJsonType(primitiveValue, property.EdmProperty.Type.AsPrimitive())) { // DEVNOTE: it is safe to use the property type name for primitive types because they do not generally support inheritance, // and spatial values always contain their specific type inside the GeoJSON/GML representation. primitiveValue.TypeAnnotation = new ODataTypeAnnotation(property.EdmProperty.Type.FullName()); } }
/// <summary> /// Write a double value. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="value">Double value to be written.</param> internal static void WriteValue(TextWriter writer, double value) { Debug.Assert(writer != null, "writer != null"); if (JsonSharedUtils.IsDoubleValueSerializedAsString(value)) { WriteQuoted(writer, value.ToString(ODataNumberFormatInfo)); } else { // double.ToString() supports a max scale of 14, // whereas double.MinValue and double.MaxValue have 16 digits scale. Hence we need // to use XmlConvert in all other cases, except infinity string valueToWrite = XmlConvert.ToString(value); writer.Write(valueToWrite); if (valueToWrite.IndexOfAny(DoubleIndicatingCharacters) < 0) { writer.Write(".0"); } } }
/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="typeReferenceFromMetadata">The type as expected by the model.</param> /// <param name="typeReferenceFromValue">The type resolved from the value.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal override string GetValueTypeNameForWriting( ODataValue value, IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, bool isOpenProperty) { DebugUtils.CheckNoExternalCallers(); SerializationTypeNameAnnotation typeNameAnnotation = value.GetAnnotation <SerializationTypeNameAnnotation>(); if (typeNameAnnotation != null) { return(typeNameAnnotation.TypeName); } if (typeReferenceFromValue != null) { // Write type name when the type in the payload is more derived than the type from metadata. if (typeReferenceFromMetadata != null && typeReferenceFromMetadata.ODataFullName() != typeReferenceFromValue.ODataFullName()) { return(typeReferenceFromValue.ODataFullName()); } // Do not write type name when the type is native json type. if (typeReferenceFromValue.IsPrimitive() && JsonSharedUtils.ValueTypeMatchesJsonType((ODataPrimitiveValue)value, typeReferenceFromValue.AsPrimitive())) { return(null); } } if (!isOpenProperty) { // Do not write type name for non-open properties since we expect the reader to have an expected type (via API or metadata URI) and thus not need it. return(null); } return(GetTypeNameFromValue(value)); }
/// <summary> /// Determines the type name to write to the payload. Json Light type names are only written into the payload for open properties /// or if the payload type name is more derived than the model type name. /// </summary> /// <param name="value">The ODataValue whose type name is to be written.</param> /// <param name="typeReferenceFromMetadata">The type as expected by the model.</param> /// <param name="typeReferenceFromValue">The type resolved from the value.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>Type name to write to the payload, or null if no type should be written.</returns> internal override string GetValueTypeNameForWriting( ODataValue value, IEdmTypeReference typeReferenceFromMetadata, IEdmTypeReference typeReferenceFromValue, bool isOpenProperty) { string typeNameToWrite; if (TypeNameOracle.TryGetTypeNameFromAnnotation(value, out typeNameToWrite)) { return(typeNameToWrite); } // Do not write type name when the type is native json type. if (typeReferenceFromValue != null && typeReferenceFromValue.IsPrimitive() && JsonSharedUtils.ValueTypeMatchesJsonType((ODataPrimitiveValue)value, typeReferenceFromValue.AsPrimitive())) { return(null); } return(GetTypeNameFromValue(value)); }
/// <summary> /// Write a double value. /// </summary> /// <param name="writer">The text writer to write the output to.</param> /// <param name="value">Double value to be written.</param> /// <param name="mustIncludeDecimalPoint">If true, all double values will be written so that they either have an 'E' for scientific notation or contain a decimal point.</param> internal static void WriteValue(TextWriter writer, double value, bool mustIncludeDecimalPoint) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(writer != null, "writer != null"); if (JsonSharedUtils.IsDoubleValueSerializedAsString(value)) { WriteQuoted(writer, value.ToString(null, CultureInfo.InvariantCulture)); } else { // double.ToString() supports a max scale of 14, // whereas double.MinValue and double.MaxValue have 16 digits scale. Hence we need // to use XmlConvert in all other cases, except infinity string valueToWrite = XmlConvert.ToString(value); writer.Write(valueToWrite); if (mustIncludeDecimalPoint && valueToWrite.IndexOfAny(DoubleIndicatingCharacters) < 0) { writer.Write(".0"); } } }