/// <summary> /// 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 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(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.MessageWriterSettings.ShouldSkipAnnotation(name)) { return; } IEdmTypeReference expectedType = MetadataUtils.LookupTypeOfTerm(name, this.valueSerializer.Model); if (value is ODataNullValue) { if (expectedType != null && !expectedType.IsNullable) { throw new ODataException( ODataErrorStrings.JsonLightInstanceAnnotationWriter_NullValueNotAllowedForInstanceAnnotation( instanceAnnotation.Name, expectedType.FullName())); } 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; ODataCollectionValue collectionValue = value 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) { this.odataAnnotationWriter.WriteODataTypePropertyAnnotation(name, collectionTypeNameToWrite); } this.WriteInstanceAnnotationName(propertyName, name); this.valueSerializer.WriteCollectionValue(collectionValue, expectedType, typeFromCollectionValue, false /*isTopLevelProperty*/, false /*isInUri*/, treatLikeOpenProperty); return; } ODataUntypedValue untypedValue = value as ODataUntypedValue; if (untypedValue != null) { this.WriteInstanceAnnotationName(propertyName, name); this.valueSerializer.WriteUntypedValue(untypedValue); return; } ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { this.WriteInstanceAnnotationName(propertyName, name); this.valueSerializer.WriteEnumValue(enumValue, expectedType); return; } ODataPrimitiveValue primitiveValue = value 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) { this.odataAnnotationWriter.WriteODataTypePropertyAnnotation(name, primitiveTypeNameToWrite); } this.WriteInstanceAnnotationName(propertyName, name); this.valueSerializer.WritePrimitiveValue(primitiveValue.Value, typeFromPrimitiveValue, expectedType); }