/// <summary> /// Asynchronously writes an instance annotation. /// </summary> /// <param name="instanceAnnotation">The instance annotation to write.</param> /// <param name="ignoreFilter">Whether to ignore the filter in settings.</param> /// <param name="propertyName">The name of the property this instance annotation applies tos</param> internal async Task WriteInstanceAnnotationAsync( ODataInstanceAnnotation instanceAnnotation, bool ignoreFilter = false, string propertyName = null) { string annotationName = instanceAnnotation.Name; ODataValue annotationValue = instanceAnnotation.Value; Debug.Assert(!string.IsNullOrEmpty(annotationName), "annotationName should not be null or empty"); Debug.Assert(annotationValue != null, "annotationValue should not be null because we use ODataNullValue for null instead"); Debug.Assert(!(annotationValue is ODataStreamReferenceValue), "!(annotationValue 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.MessageWriterSettings.ShouldSkipAnnotation(annotationName)) { return; } IEdmTypeReference expectedType = MetadataUtils.LookupTypeOfTerm(annotationName, this.valueSerializer.Model); if (annotationValue is ODataNullValue) { if (expectedType != null && !expectedType.IsNullable) { throw new ODataException( ODataErrorStrings.JsonLightInstanceAnnotationWriter_NullValueNotAllowedForInstanceAnnotation( annotationName, expectedType.FullName())); } await this.WriteInstanceAnnotationNameAsync(propertyName, annotationName) .ConfigureAwait(false); await this.valueSerializer.WriteNullValueAsync() .ConfigureAwait(false); 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; ODataResourceValue resourceValue = annotationValue as ODataResourceValue; if (resourceValue != null) { IDuplicatePropertyNameChecker duplicatePropertyNameChecker = this.valueSerializer.GetDuplicatePropertyNameChecker(); await this.WriteInstanceAnnotationNameAsync(propertyName, annotationName) .ConfigureAwait(false); await this.valueSerializer.WriteResourceValueAsync(resourceValue, expectedType, treatLikeOpenProperty, duplicatePropertyNameChecker).ConfigureAwait(false); this.valueSerializer.ReturnDuplicatePropertyNameChecker(duplicatePropertyNameChecker); return; } ODataCollectionValue collectionValue = annotationValue as ODataCollectionValue; if (collectionValue != null) { IEdmTypeReference typeFromCollectionValue = (IEdmCollectionTypeReference)TypeNameOracle.ResolveAndValidateTypeForCollectionValue( this.valueSerializer.Model, expectedType, collectionValue, treatLikeOpenProperty, this.writerValidator); string collectionTypeNameToWrite = this.typeNameOracle.GetValueTypeNameForWriting(collectionValue, expectedType, typeFromCollectionValue, treatLikeOpenProperty); if (collectionTypeNameToWrite != null) { await this.asynchronousODataAnnotationWriter.WriteODataTypePropertyAnnotationAsync(annotationName, collectionTypeNameToWrite) .ConfigureAwait(false); } await this.WriteInstanceAnnotationNameAsync(propertyName, annotationName) .ConfigureAwait(false); await this.valueSerializer.WriteCollectionValueAsync( collectionValue, expectedType, typeFromCollectionValue, false /*isTopLevelProperty*/, false /*isInUri*/, treatLikeOpenProperty).ConfigureAwait(false); return; } ODataUntypedValue untypedValue = annotationValue as ODataUntypedValue; if (untypedValue != null) { await this.WriteInstanceAnnotationNameAsync(propertyName, annotationName) .ConfigureAwait(false); await this.valueSerializer.WriteUntypedValueAsync(untypedValue) .ConfigureAwait(false); return; } ODataEnumValue enumValue = annotationValue as ODataEnumValue; if (enumValue != null) { await this.WriteInstanceAnnotationNameAsync(propertyName, annotationName) .ConfigureAwait(false); await this.valueSerializer.WriteEnumValueAsync(enumValue, expectedType) .ConfigureAwait(false); return; } ODataPrimitiveValue primitiveValue = annotationValue as ODataPrimitiveValue; Debug.Assert(primitiveValue != null, "Did we add a new subclass of ODataValue?"); IEdmTypeReference typeFromPrimitiveValue = TypeNameOracle.ResolveAndValidateTypeForPrimitiveValue(primitiveValue); string primitiveTypeNameToWrite = this.typeNameOracle.GetValueTypeNameForWriting(primitiveValue, expectedType, typeFromPrimitiveValue, treatLikeOpenProperty); if (primitiveTypeNameToWrite != null) { await this.asynchronousODataAnnotationWriter.WriteODataTypePropertyAnnotationAsync(annotationName, primitiveTypeNameToWrite) .ConfigureAwait(false); } await this.WriteInstanceAnnotationNameAsync(propertyName, annotationName) .ConfigureAwait(false); await this.valueSerializer.WritePrimitiveValueAsync(primitiveValue.Value, typeFromPrimitiveValue, expectedType) .ConfigureAwait(false); }
/// <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); } if (value.TypeAnnotation != null && !string.IsNullOrEmpty(value.TypeAnnotation.TypeName)) { return(value.TypeAnnotation.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 resourceValue = value as ODataResourceValue; if (resourceValue != null) { return(resourceValue.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_StreamValueMustBePropertiesOfODataResource); } // 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> /// 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) : this(name, value, false) { }