/// <summary> /// Resolves and validates the Edm type for the given <paramref name="value"/>. /// </summary> /// <param name="model">The model to use.</param> /// <param name="typeReferenceFromMetadata">The type inferred from the model or null if the model is not a user model.</param> /// <param name="value">The value in question to resolve the type for.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>A type for the <paramref name="value"/> or null if no metadata is available.</returns> internal static IEdmTypeReference ResolveAndValidateTypeNameForValue(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ODataValue value, bool isOpenProperty) { Debug.Assert(model != null, "model != null"); Debug.Assert(value != null, "value != null"); ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; if (primitiveValue != null) { Debug.Assert(primitiveValue.Value != null, "primitiveValue.Value != null"); return EdmLibraryExtensions.GetPrimitiveTypeReference(primitiveValue.Value.GetType()); } ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { return ResolveAndValidateTypeFromNameAndMetadata(model, typeReferenceFromMetadata, complexValue.TypeName, EdmTypeKind.Complex, isOpenProperty); } ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { return ResolveAndValidateTypeFromNameAndMetadata(model, typeReferenceFromMetadata, enumValue.TypeName, EdmTypeKind.Enum, isOpenProperty); } ODataCollectionValue collectionValue = (ODataCollectionValue)value; return ResolveAndValidateTypeFromNameAndMetadata(model, typeReferenceFromMetadata, collectionValue.TypeName, EdmTypeKind.Collection, isOpenProperty); }
/// <summary> /// Constructs a new <see cref="ODataInstanceAnnotation"/> instance. /// </summary> /// <param name="name">The name of the instance annotation.</param> /// <param name="value">The value of the instance annotation.</param> public ODataInstanceAnnotation(string name, ODataValue value) { ValidateName(name); ValidateValue(value); this.Name = name; this.Value = value; }
public static void AssertODataValueAreEqual(ODataValue expected, ODataValue actual) { ODataPrimitiveValue expectedPrimitiveValue = expected as ODataPrimitiveValue; ODataPrimitiveValue actualPrimitiveValue = actual as ODataPrimitiveValue; if (expectedPrimitiveValue != null && actualPrimitiveValue != null) { AssertODataPrimitiveValueAreEqual(expectedPrimitiveValue, actualPrimitiveValue); } else { ODataComplexValue expectedComplexValue = expected as ODataComplexValue; ODataComplexValue actualComplexValue = actual as ODataComplexValue; if (expectedComplexValue != null && actualComplexValue != null) { AssertODataComplexValueAreEqual(expectedComplexValue, actualComplexValue); } else { ODataEnumValue expectedEnumValue = expected as ODataEnumValue; ODataEnumValue actualEnumValue = actual as ODataEnumValue; if (expectedEnumValue != null && actualEnumValue != null) { AssertODataEnumValueAreEqual(expectedEnumValue, actualEnumValue); } else { ODataCollectionValue expectedCollectionValue = (ODataCollectionValue)expected; ODataCollectionValue actualCollectionValue = (ODataCollectionValue)actual; AssertODataCollectionValueAreEqual(expectedCollectionValue, actualCollectionValue); } } } }
/// <summary> /// Validates the given <paramref name="value"/> is a valid instance annotation value. /// </summary> /// <param name="value">Value to validate.</param> internal static void ValidateValue(ODataValue value) { ExceptionUtils.CheckArgumentNotNull(value, "value"); if (value is ODataStreamReferenceValue) { throw new ArgumentException(Strings.ODataInstanceAnnotation_ValueCannotBeODataStreamReferenceValue, "value"); } }
/// <summary> /// Gets the type name based on the given odata value. /// </summary> /// <param name="value">The value.</param> /// <param name="model">The model used to handle unsigned int conversions.</param> /// <returns>The type name for the context URI.</returns> private static string GetTypeNameForValue(ODataValue value, IEdmModel model) { if (value == null) { return(null); } // special identifier for null values. if (value.IsNullValue) { return(ODataConstants.ContextUriFragmentNull); } var typeAnnotation = value.GetAnnotation <SerializationTypeNameAnnotation>(); if (typeAnnotation != null && !string.IsNullOrEmpty(typeAnnotation.TypeName)) { return(typeAnnotation.TypeName); } var complexValue = value as ODataComplexValue; if (complexValue != null) { return(complexValue.TypeName); } var collectionValue = value as ODataCollectionValue; if (collectionValue != null) { return(EdmLibraryExtensions.GetCollectionTypeFullName(collectionValue.TypeName)); } var enumValue = value as ODataEnumValue; if (enumValue != null) { return(enumValue.TypeName); } ODataPrimitiveValue primitive = value as ODataPrimitiveValue; if (primitive == null) { Debug.Assert(value is ODataStreamReferenceValue, "value is ODataStreamReferenceValue"); throw new ODataException(Strings.ODataContextUriBuilder_StreamValueMustBePropertiesOfODataEntry); } // Try convert to underlying type if the primitive value is unsigned int. IEdmTypeDefinitionReference typeDefinitionReference = model.ResolveUIntTypeDefinition(primitive.Value); if (typeDefinitionReference != null) { return(typeDefinitionReference.ODataFullName()); } IEdmPrimitiveTypeReference primitiveValueTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(primitive.Value.GetType()); return(primitiveValueTypeReference == null ? null : primitiveValueTypeReference.ODataFullName()); }
internal void SetTypeName(ODataValue value, ResourceType actualType) { Debug.Assert(value != null, "value != null"); #if DEBUG var complexValue = value as ODataComplexValue; if (complexValue != null) { Debug.Assert(!String.IsNullOrEmpty(complexValue.TypeName), "Type name must be specified in ODataComplexValue since ODL needs it for validation."); } else { var collectionValue = value as ODataCollectionValue; Debug.Assert(collectionValue == null || !String.IsNullOrEmpty(collectionValue.TypeName), "Type name must be specified in ODataCollectionValue since ODL needs it for validation."); } #endif string typeNameToWrite; if (this.interpreter.ShouldSpecifyTypeNameAnnotation(value, actualType, out typeNameToWrite)) { value.SetAnnotation(new SerializationTypeNameAnnotation { TypeName = typeNameToWrite }); } }
/// <summary> /// Resolves and validates the Edm type for the given <paramref name="value"/>. /// </summary> /// <param name="model">The model to use.</param> /// <param name="typeReferenceFromMetadata">The type inferred from the model or null if the model is not a user model.</param> /// <param name="value">The value in question to resolve the type for.</param> /// <param name="isOpenProperty">true if the type name belongs to an open property, false otherwise.</param> /// <returns>A type for the <paramref name="value"/> or null if no metadata is available.</returns> internal static IEdmTypeReference ResolveAndValidateTypeNameForValue(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ODataValue value, bool isOpenProperty) { Debug.Assert(model != null, "model != null"); Debug.Assert(value != null, "value != null"); ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; if (primitiveValue != null) { Debug.Assert(primitiveValue.Value != null, "primitiveValue.Value != null"); return(EdmLibraryExtensions.GetPrimitiveTypeReference(primitiveValue.Value.GetType())); } ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { return(ResolveAndValidateTypeFromNameAndMetadata(model, typeReferenceFromMetadata, complexValue.TypeName, EdmTypeKind.Complex, isOpenProperty)); } ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { return(ResolveAndValidateTypeFromNameAndMetadata(model, typeReferenceFromMetadata, enumValue.TypeName, EdmTypeKind.Enum, isOpenProperty)); } ODataCollectionValue collectionValue = (ODataCollectionValue)value; return(ResolveAndValidateTypeFromNameAndMetadata(model, typeReferenceFromMetadata, collectionValue.TypeName, EdmTypeKind.Collection, isOpenProperty)); }
/// <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.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() }); } }
public static void AssertODataValueAreEqual(ODataValue value1, ODataValue value2) { if (value1.IsNullValue && value2.IsNullValue) { return; } ODataPrimitiveValue primitiveValue1 = value1 as ODataPrimitiveValue; ODataPrimitiveValue primitiveValue2 = value2 as ODataPrimitiveValue; if (primitiveValue1 != null && primitiveValue2 != null) { AssertODataPrimitiveValueAreEqual(primitiveValue1, primitiveValue2); } else { ODataComplexValue complexValue1 = value1 as ODataComplexValue; ODataComplexValue complexValue2 = value2 as ODataComplexValue; if (complexValue1 != null && complexValue2 != null) { AssertODataComplexValueAreEqual(complexValue1, complexValue2); } else { ODataEnumValue enumValue1 = value1 as ODataEnumValue; ODataEnumValue enumValue2 = value2 as ODataEnumValue; if (enumValue1 != null && enumValue2 != null) { AssertODataEnumValueAreEqual(enumValue1, enumValue2); } else { ODataCollectionValue collectionValue1 = (ODataCollectionValue)value1; ODataCollectionValue collectionValue2 = (ODataCollectionValue)value2; AssertODataCollectionValueAreEqual(collectionValue1, collectionValue2); } } } }
private Uri CreateIndividualPropertyContextUri(ODataValue value, string resourcePath) { ODataContextUrlInfo info = ODataContextUrlInfo.Create(value, new ODataUri() { Path = new ODataUriParser(edmModel, new Uri(ServiceDocumentUriString), new Uri(ServiceDocumentUriString + resourcePath)).ParsePath() }); Uri contextUrl = this.responseContextUriBuilder.BuildContextUri(ODataPayloadKind.IndividualProperty, info); contextUrl.Should().NotBeNull(); return contextUrl; }
public void GetInnerValue_Returns_CorrectObject(ODataValue value, object expectedResult) { Assert.Equal(expectedResult, value.GetInnerValue()); }
/// <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; }
protected internal ODataValueAssertions(ODataValue value) : base(value) { }
/// <summary> /// Create ODataContextUrlInfo for OdataValue. /// </summary> /// <param name="value">The ODataValue to be used.</param> /// <param name="odataUri">The odata uri info for current query.</param> /// <param name="model">The model used to handle unsigned int conversions.</param> /// <returns>The generated ODataContextUrlInfo.</returns> internal static ODataContextUrlInfo Create(ODataValue value, ODataUri odataUri = null, IEdmModel model = null) { return new ODataContextUrlInfo() { TypeName = GetTypeNameForValue(value, model), odataUri = odataUri }; }
/// <summary> /// Writes an instance annotation. /// </summary> /// <param name="instanceAnnotation">The instance annotation to write.</param> /// <param name="ignoreFilter">Whether to ingore the filter in settings.</param> /// <param name="propertyName">The name of the property this instance annotation applies to</param> internal void WriteInstanceAnnotation(ODataInstanceAnnotation instanceAnnotation, bool ignoreFilter = false, string propertyName = null) { string name = instanceAnnotation.Name; ODataValue value = instanceAnnotation.Value; Debug.Assert(!string.IsNullOrEmpty(name), "name should not be null or empty"); Debug.Assert(!ODataAnnotationNames.IsODataAnnotationName(name), "A reserved name cannot be used as instance annotation key"); Debug.Assert(value != null, "value should not be null because we use ODataNullValue for null instead"); Debug.Assert(!(value is ODataStreamReferenceValue), "!(value is ODataStreamReferenceValue) -- ODataInstanceAnnotation and InstanceAnnotationCollection will throw if the value is a stream value."); Debug.Assert(this.valueSerializer.Model != null, "this.valueSerializer.Model != null"); if (!ignoreFilter && this.valueSerializer.Settings.ShouldSkipAnnotation(name)) { return; } IEdmTypeReference expectedType = MetadataUtils.LookupTypeOfValueTerm(name, this.valueSerializer.Model); if (value is ODataNullValue) { if (expectedType != null && !expectedType.IsNullable) { throw new ODataException(ODataErrorStrings.ODataAtomPropertyAndValueSerializer_NullValueNotAllowedForInstanceAnnotation(instanceAnnotation.Name, expectedType.ODataFullName())); } this.WriteInstanceAnnotationName(propertyName, name); this.valueSerializer.WriteNullValue(); return; } // If we didn't find an expected type from looking up the term in the model, treat this value the same way we would for open property values. // That is, write the type name (unless its a primitive value with a JSON-native type). If we did find an expected type, treat the annotation value like a // declared property with an expected type. This will still write out the type if the value type is more derived than the declared type, for example. bool treatLikeOpenProperty = expectedType == null; ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { this.WriteInstanceAnnotationName(propertyName, name); this.valueSerializer.WriteComplexValue(complexValue, expectedType, false /*isTopLevel*/, treatLikeOpenProperty, this.valueSerializer.CreateDuplicatePropertyNamesChecker()); return; } IEdmTypeReference typeFromValue = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.valueSerializer.Model, expectedType, value, treatLikeOpenProperty); ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { string collectionTypeNameToWrite = this.typeNameOracle.GetValueTypeNameForWriting(collectionValue, expectedType, typeFromValue, treatLikeOpenProperty); if (collectionTypeNameToWrite != null) { ODataJsonLightWriterUtils.WriteODataTypePropertyAnnotation(this.JsonWriter, name, collectionTypeNameToWrite); } this.WriteInstanceAnnotationName(propertyName, name); this.valueSerializer.WriteCollectionValue(collectionValue, expectedType, false /*isTopLevelProperty*/, false /*isInUri*/, treatLikeOpenProperty); return; } ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; Debug.Assert(primitiveValue != null, "Did we add a new subclass of ODataValue?"); string primitiveTypeNameToWrite = this.typeNameOracle.GetValueTypeNameForWriting(primitiveValue, expectedType, typeFromValue, treatLikeOpenProperty); if (primitiveTypeNameToWrite != null) { ODataJsonLightWriterUtils.WriteODataTypePropertyAnnotation(this.JsonWriter, name, primitiveTypeNameToWrite); } this.WriteInstanceAnnotationName(propertyName, name); this.valueSerializer.WritePrimitiveValue(primitiveValue.Value, expectedType); }
/// <summary> /// Gets the type name based on the given odata value. /// </summary> /// <param name="value">The value.</param> /// <param name="model">The model used to handle unsigned int conversions.</param> /// <returns>The type name for the context URI.</returns> private static string GetTypeNameForValue(ODataValue value, IEdmModel model) { if (value == null) { return null; } // special identifier for null values. if (value.IsNullValue) { return ODataConstants.ContextUriFragmentNull; } var typeAnnotation = value.GetAnnotation<SerializationTypeNameAnnotation>(); if (typeAnnotation != null && !string.IsNullOrEmpty(typeAnnotation.TypeName)) { return typeAnnotation.TypeName; } var complexValue = value as ODataComplexValue; if (complexValue != null) { return complexValue.TypeName; } var collectionValue = value as ODataCollectionValue; if (collectionValue != null) { return EdmLibraryExtensions.GetCollectionTypeFullName(collectionValue.TypeName); } var enumValue = value as ODataEnumValue; if (enumValue != null) { return enumValue.TypeName; } var untypedValue = value as ODataUntypedValue; if (untypedValue != null) { return ODataConstants.ContextUriFragmentUntyped; } ODataPrimitiveValue primitive = value as ODataPrimitiveValue; if (primitive == null) { Debug.Assert(value is ODataStreamReferenceValue, "value is ODataStreamReferenceValue"); throw new ODataException(Strings.ODataContextUriBuilder_StreamValueMustBePropertiesOfODataEntry); } // Try convert to underlying type if the primitive value is unsigned int. IEdmTypeDefinitionReference typeDefinitionReference = model.ResolveUIntTypeDefinition(primitive.Value); if (typeDefinitionReference != null) { return typeDefinitionReference.FullName(); } IEdmPrimitiveTypeReference primitiveValueTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(primitive.Value.GetType()); return primitiveValueTypeReference == null ? null : primitiveValueTypeReference.FullName(); }
/// <summary> /// Tries to convert the given value into an instance of <see cref="ODataValue"/>. /// </summary> /// <param name="property">The property being converted.</param> /// <param name="propertyValue">The property value to convert..</param> /// <param name="serverTypeName">The server type name of the entity whose properties are being populated.</param> /// <param name="visitedComplexTypeObjects">Set of instances of complex types encountered in the hierarchy. Used to detect cycles.</param> /// <param name="odataValue">The odata value if one was created.</param> /// <returns>Whether or not the value was converted.</returns> private bool TryConvertPropertyValue(ClientPropertyAnnotation property, object propertyValue, string serverTypeName, HashSet<object> visitedComplexTypeObjects, out ODataValue odataValue) { if (property.IsKnownType) { odataValue = CreateODataPrimitivePropertyValue(property, propertyValue); return true; } if (property.IsEnumType) { string enumValue; if (propertyValue == null) { enumValue = null; } else { enumValue = ClientTypeUtil.GetEnumValuesString(propertyValue.ToString(), property.PropertyType); } string typeNameInMetadata = this.requestInfo.ResolveNameFromType(property.PropertyType); odataValue = new ODataEnumValue(enumValue, typeNameInMetadata); return true; } if (property.IsPrimitiveOrEnumOrComplexCollection) { odataValue = this.CreateODataCollectionPropertyValue(property, propertyValue, serverTypeName, visitedComplexTypeObjects); return true; } if (!property.IsEntityCollection && !ClientTypeUtil.TypeIsEntity(property.PropertyType, this.requestInfo.Model)) { odataValue = this.CreateODataComplexPropertyValue(property, propertyValue, visitedComplexTypeObjects); return true; } odataValue = null; return false; }