/// <summary> /// Converts a <see cref="ODataResourceValue"/> to a string. /// </summary> /// <param name="resourceValue">Instance to convert.</param> /// <param name="model">Model to be used for validation. User model is optional. The EdmLib core model is expected as a minimum.</param> /// <param name="version">Version to be compliant with.</param> /// <returns>A string representation of <paramref name="resourceValue"/> to be added.</returns> internal static string ConvertToResourceLiteral(ODataResourceValue resourceValue, IEdmModel model, ODataVersion version) { ExceptionUtils.CheckArgumentNotNull(resourceValue, "resourceValue"); ExceptionUtils.CheckArgumentNotNull(model, "model"); StringBuilder builder = new StringBuilder(); using (TextWriter textWriter = new StringWriter(builder, CultureInfo.InvariantCulture)) { ODataMessageWriterSettings messageWriterSettings = new ODataMessageWriterSettings() { Version = version, Validations = ~ValidationKinds.ThrowOnUndeclaredPropertyForNonOpenType, // Should write instance annotations for the literal ShouldIncludeAnnotation = ODataUtils.CreateAnnotationFilter("*") }; WriteJsonLightLiteral( model, messageWriterSettings, textWriter, (serializer) => serializer.WriteResourceValue( resourceValue, /* resourceValue */ null, /* metadataTypeReference */ true, /* isOpenPropertyType */ serializer.CreateDuplicatePropertyNameChecker())); } return(builder.ToString()); }
/// <summary> /// Gets the type name from the given <paramref name="value"/>. /// </summary> /// <param name="value">The value to get the type name from. This can be an ODataPrimitiveValue, an ODataCollectionValue or a Clr primitive object.</param> /// <returns>The type name for the given <paramref name="value"/>.</returns> protected static string GetTypeNameFromValue(object value) { Debug.Assert(value != null, "value != null"); ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; if (primitiveValue != null) { // primitiveValueTypeReference == null means: the EDM type of the primitive value cannot be determined. // This could possibly be due to value being an unsigned int. // In this case, simply return null because: // - If the property is regular property, the type is not needed since service model knows its exact type. // - If the property is dynamic property, ODL does not support dynamic property containing unsigned int value // since we don't know its underlying type as well as how to serialize it. IEdmPrimitiveTypeReference primitiveValueTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(primitiveValue.Value.GetType()); return(primitiveValueTypeReference == null ? null : primitiveValueTypeReference.FullName()); } ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { return(enumValue.TypeName); } ODataResourceValue resourceValue = value as ODataResourceValue; if (resourceValue != null) { return(resourceValue.TypeName); } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { return(EdmLibraryExtensions.GetCollectionTypeFullName(collectionValue.TypeName)); } IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType()); if (primitiveTypeReference == null) { throw new ODataException(Strings.ValidationUtils_UnsupportedPrimitiveType(value.GetType().FullName)); } return(primitiveTypeReference.FullName()); }
/// <summary> /// Resolve a type name against the provided <paramref name="model"/>. If not payload type name is specified, /// derive the type from the model type (if available). /// </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="resourceValue">The value in question to resolve the type for.</param> /// <param name="isOpenPropertyType">True if the type name belongs to an open (dynamic) property.</param> /// <param name="writerValidator">The writer validator to use for validation.</param> /// <returns>A type for the <paramref name="resourceValue"/> or null if no type name is specified and no metadata is available.</returns> internal static IEdmTypeReference ResolveAndValidateTypeForResourceValue(IEdmModel model, IEdmTypeReference typeReferenceFromMetadata, ODataResourceValue resourceValue, bool isOpenPropertyType, IWriterValidator writerValidator) { Debug.Assert(model != null, "model != null"); Debug.Assert(resourceValue != null, "resourceValue != null"); var typeName = resourceValue.TypeName; ValidateIfTypeNameMissing(typeName, model, isOpenPropertyType); // It's ok to use "EdmTypeKind.Complex" because the validation will check "IsStructured()". IEdmType typeFromValue = typeName == null ? null : ResolveAndValidateTypeName(model, typeName, EdmTypeKind.Complex, true, writerValidator); if (typeReferenceFromMetadata != null) { // It's ok to use "EdmTypeKind.Complex" because the parameter "expectStructuredType" is set to "true". writerValidator.ValidateTypeKind(EdmTypeKind.Complex, typeReferenceFromMetadata.TypeKind(), true, typeFromValue); } return(ResolveTypeFromMetadataAndValue(typeReferenceFromMetadata, typeFromValue == null ? null : typeFromValue.ToTypeReference(), writerValidator)); }
public static string ConvertToUriLiteral(object value, ODataVersion version, IEdmModel model) { if (value == null) { value = new ODataNullValue(); } if (model == null) { model = Microsoft.OData.Edm.EdmCoreModel.Instance; } ODataNullValue nullValue = value as ODataNullValue; if (nullValue != null) { return(ExpressionConstants.KeywordNull); } ODataResourceValue resourceValue = value as ODataResourceValue; if (resourceValue != null) { return(ODataUriConversionUtils.ConvertToResourceLiteral(resourceValue, model, version)); } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { return(ODataUriConversionUtils.ConvertToUriCollectionLiteral(collectionValue, model, version)); } ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { return(ODataUriConversionUtils.ConvertToUriEnumLiteral(enumValue, version)); } ODataResourceBase resource = value as ODataResourceBase; if (resource != null) { return(ODataUriConversionUtils.ConvertToUriEntityLiteral(resource, model)); } ODataEntityReferenceLink link = value as ODataEntityReferenceLink; if (link != null) { return(ODataUriConversionUtils.ConvertToUriEntityReferenceLiteral(link, model)); } ODataEntityReferenceLinks links = value as ODataEntityReferenceLinks; if (links != null) { return(ODataUriConversionUtils.ConvertToUriEntityReferencesLiteral(links, model)); } IEnumerable <ODataResourceBase> list = value as IEnumerable <ODataResourceBase>; if (list != null) { return(ODataUriConversionUtils.ConvertToUriEntitiesLiteral(list, model)); } // Try to convert uints to their underlying type first according to the model. value = model.ConvertToUnderlyingTypeIfUIntValue(value); return(ODataUriConversionUtils.ConvertToUriPrimitiveLiteral(value, version)); }
/// <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); }