internal static IEdmTypeReference ResolveAndValidateNonPrimitiveTargetType(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, EdmTypeKind payloadTypeKind, IEdmType payloadType, string payloadTypeName, IEdmModel model, ODataMessageReaderSettings messageReaderSettings, ODataVersion version, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { bool flag = (messageReaderSettings.ReaderBehavior.TypeResolver != null) && (payloadType != null); if (!flag) { ValidateTypeSupported(expectedTypeReference, version); if (model.IsUserModel() && ((expectedTypeReference == null) || !messageReaderSettings.DisableStrictMetadataValidation)) { VerifyPayloadTypeDefined(payloadTypeName, payloadType); } } else { ValidateTypeSupported((payloadType == null) ? null : payloadType.ToTypeReference(true), version); } if ((payloadTypeKind != EdmTypeKind.None) && (!messageReaderSettings.DisableStrictMetadataValidation || (expectedTypeReference == null))) { ValidationUtils.ValidateTypeKind(payloadTypeKind, expectedTypeKind, payloadTypeName); } serializationTypeNameAnnotation = null; if (!model.IsUserModel()) { return null; } if ((expectedTypeReference == null) || flag) { return ResolveAndValidateTargetTypeWithNoExpectedType(expectedTypeKind, payloadType, payloadTypeName, out serializationTypeNameAnnotation); } if (messageReaderSettings.DisableStrictMetadataValidation) { return ResolveAndValidateTargetTypeStrictValidationDisabled(expectedTypeKind, expectedTypeReference, payloadType, payloadTypeName, out serializationTypeNameAnnotation); } return ResolveAndValidateTargetTypeStrictValidationEnabled(expectedTypeKind, expectedTypeReference, payloadType, payloadTypeName, out serializationTypeNameAnnotation); }
internal string GetEntryTypeNameForWriting(ODataEntry entry) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entry != null, "entry != null"); SerializationTypeNameAnnotation typeNameAnnotation = entry.GetAnnotation <SerializationTypeNameAnnotation>(); if (typeNameAnnotation != null) { return(typeNameAnnotation.TypeName); } return(entry.TypeName); }
internal string GetValueTypeNameForWriting( object value, IEdmTypeReference typeReferenceFromValue, SerializationTypeNameAnnotation typeNameAnnotation, CollectionWithoutExpectedTypeValidator collectionValidator, out string collectionItemTypeName) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(value != null, "value != null"); collectionItemTypeName = null; // if no type name is specified we will use the type name inferred from metadata string typeName = GetTypeNameFromValue(value); if (typeName == null && typeReferenceFromValue != null) { typeName = typeReferenceFromValue.ODataFullName(); } if (typeName != null) { // If the type is the same as the one specified by the parent collection, omit the type name, since it's not needed. if (collectionValidator != null && string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, typeName) == 0) { typeName = null; } // If value is a collection value, get the item type name. if (typeName != null && value is ODataCollectionValue) { collectionItemTypeName = ValidationUtils.ValidateCollectionTypeName(typeName); } } if (typeNameAnnotation != null) { // If the value of TypeName is null, we'll flow it through here, thereby instructing the caller to write no type name. typeName = typeNameAnnotation.TypeName; } return(typeName); }
private ODataCollectionValue ReadCollectionValue(IEdmCollectionTypeReference collectionTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation) { this.IncreaseRecursionDepth(); ODataCollectionValue value2 = new ODataCollectionValue { TypeName = (collectionTypeReference == null) ? payloadTypeName : collectionTypeReference.ODataFullName() }; if (serializationTypeNameAnnotation != null) { value2.SetAnnotation<SerializationTypeNameAnnotation>(serializationTypeNameAnnotation); } base.XmlReader.MoveToElement(); List<object> sourceEnumerable = new List<object>(); if (!base.XmlReader.IsEmptyElement) { base.XmlReader.ReadStartElement(); IEdmTypeReference expectedTypeReference = (collectionTypeReference == null) ? null : collectionTypeReference.ElementType(); DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); CollectionWithoutExpectedTypeValidator collectionValidator = null; if (collectionTypeReference == null) { string itemTypeNameFromCollection = (payloadTypeName == null) ? null : EdmLibraryExtensions.GetCollectionItemTypeName(payloadTypeName); collectionValidator = new CollectionWithoutExpectedTypeValidator(itemTypeNameFromCollection); } do { switch (base.XmlReader.NodeType) { case XmlNodeType.Element: if (base.XmlReader.NamespaceEquals(base.XmlReader.ODataNamespace)) { if (!base.XmlReader.LocalNameEquals(this.ODataCollectionItemElementName)) { throw new ODataException(Microsoft.Data.OData.Strings.ODataAtomPropertyAndValueDeserializer_InvalidCollectionElement(base.XmlReader.LocalName, base.XmlReader.ODataNamespace)); } object item = this.ReadNonEntityValueImplementation(expectedTypeReference, duplicatePropertyNamesChecker, collectionValidator, true, false); base.XmlReader.Read(); ValidationUtils.ValidateCollectionItem(item, false); sourceEnumerable.Add(item); } else { base.XmlReader.Skip(); } break; case XmlNodeType.EndElement: break; default: base.XmlReader.Skip(); break; } } while (base.XmlReader.NodeType != XmlNodeType.EndElement); } value2.Items = new ReadOnlyEnumerable(sourceEnumerable); this.DecreaseRecursionDepth(); return value2; }
internal static IEdmTypeReference ResolvePayloadTypeNameAndComputeTargetType(EdmTypeKind expectedTypeKind, IEdmType defaultPrimitivePayloadType, IEdmTypeReference expectedTypeReference, string payloadTypeName, IEdmModel model, ODataMessageReaderSettings messageReaderSettings, ODataVersion version, Func<EdmTypeKind> typeKindFromPayloadFunc, out EdmTypeKind targetTypeKind, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { EdmTypeKind kind; IEdmTypeReference reference; serializationTypeNameAnnotation = null; IEdmType payloadType = ResolvePayloadTypeName(model, expectedTypeReference, payloadTypeName, EdmTypeKind.Complex, messageReaderSettings.ReaderBehavior, version, out kind); targetTypeKind = ComputeTargetTypeKind(expectedTypeReference, expectedTypeKind == EdmTypeKind.Entity, payloadTypeName, kind, messageReaderSettings, typeKindFromPayloadFunc); if (targetTypeKind == EdmTypeKind.Primitive) { reference = ResolveAndValidatePrimitiveTargetType(expectedTypeReference, kind, payloadType, payloadTypeName, defaultPrimitivePayloadType, model, messageReaderSettings, version); } else { reference = ResolveAndValidateNonPrimitiveTargetType(targetTypeKind, expectedTypeReference, kind, payloadType, payloadTypeName, model, messageReaderSettings, version, out serializationTypeNameAnnotation); } if ((expectedTypeKind != EdmTypeKind.None) && (reference != null)) { ValidationUtils.ValidateTypeKind(targetTypeKind, expectedTypeKind, payloadTypeName); } return reference; }
private ODataCollectionValue ReadCollectionValueImplementation(IEdmCollectionTypeReference collectionValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation) { ODataVersionChecker.CheckCollectionValue(base.Version); this.IncreaseRecursionDepth(); base.JsonReader.ReadStartObject(); ODataCollectionValue value2 = new ODataCollectionValue { TypeName = (collectionValueTypeReference != null) ? collectionValueTypeReference.ODataFullName() : payloadTypeName }; if (serializationTypeNameAnnotation != null) { value2.SetAnnotation<SerializationTypeNameAnnotation>(serializationTypeNameAnnotation); } List<object> sourceEnumerable = null; bool flag = false; while (base.JsonReader.NodeType == JsonNodeType.Property) { string strB = base.JsonReader.ReadPropertyName(); if (string.CompareOrdinal("__metadata", strB) == 0) { if (flag) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultiplePropertiesInCollectionWrapper("__metadata")); } flag = true; base.JsonReader.SkipValue(); } else { if (string.CompareOrdinal("results", strB) == 0) { if (sourceEnumerable != null) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultiplePropertiesInCollectionWrapper("results")); } sourceEnumerable = new List<object>(); base.JsonReader.ReadStartArray(); DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); IEdmTypeReference expectedTypeReference = null; if (collectionValueTypeReference != null) { expectedTypeReference = collectionValueTypeReference.CollectionDefinition().ElementType; } CollectionWithoutExpectedTypeValidator collectionValidator = null; while (base.JsonReader.NodeType != JsonNodeType.EndArray) { object item = this.ReadNonEntityValueImplementation(expectedTypeReference, duplicatePropertyNamesChecker, collectionValidator, true); ValidationUtils.ValidateCollectionItem(item, false); sourceEnumerable.Add(item); } base.JsonReader.ReadEndArray(); continue; } base.JsonReader.SkipValue(); } } base.JsonReader.ReadEndObject(); if (sourceEnumerable == null) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_CollectionWithoutResults); } value2.Items = new ReadOnlyEnumerable(sourceEnumerable); this.DecreaseRecursionDepth(); return value2; }
private object ReadNonEntityValueImplementation(IEdmTypeReference expectedTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, bool validateNullValue, bool epmPresent) { string itemTypeNameFromCollection; bool flag; SerializationTypeNameAnnotation annotation; EdmTypeKind kind2; this.ReadNonEntityValueAttributes(out itemTypeNameFromCollection, out flag); if (flag) { return this.ReadNullValue(expectedTypeReference, validateNullValue); } bool flag2 = false; if ((collectionValidator != null) && (itemTypeNameFromCollection == null)) { itemTypeNameFromCollection = collectionValidator.ItemTypeNameFromCollection; flag2 = collectionValidator.ItemTypeKindFromCollection != EdmTypeKind.None; } IEdmTypeReference type = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType(EdmTypeKind.None, edmStringType, expectedTypeReference, itemTypeNameFromCollection, base.Model, base.MessageReaderSettings, base.Version, new Func<EdmTypeKind>(this.GetNonEntityValueKind), out kind2, out annotation); if (flag2) { annotation = new SerializationTypeNameAnnotation { TypeName = null }; } if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(itemTypeNameFromCollection, kind2); } switch (kind2) { case EdmTypeKind.Primitive: return this.ReadPrimitiveValue(type.AsPrimitive()); case EdmTypeKind.Complex: return this.ReadComplexValue((type == null) ? null : type.AsComplex(), itemTypeNameFromCollection, annotation, duplicatePropertyNamesChecker, epmPresent); case EdmTypeKind.Collection: { IEdmCollectionTypeReference collectionTypeReference = ValidationUtils.ValidateCollectionType(type); return this.ReadCollectionValue(collectionTypeReference, itemTypeNameFromCollection, annotation); } } throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ODataAtomPropertyAndValueDeserializer_ReadNonEntityValue)); }
private ODataComplexValue CreateODataComplexValue(Type complexType, object value, string propertyName, bool isCollectionItem, List<object> visitedComplexTypeObjects) { ClientTypeAnnotation clientTypeAnnotation = ClientEdmModel.GetModel(this.requestInfo.MaxProtocolVersion).GetClientTypeAnnotation(complexType); if (visitedComplexTypeObjects == null) { visitedComplexTypeObjects = new List<object>(); } else if (visitedComplexTypeObjects.Contains(value)) { if (propertyName != null) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Serializer_LoopsNotAllowedInComplexTypes(propertyName)); } throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Serializer_LoopsNotAllowedInNonPropertyComplexTypes(clientTypeAnnotation.ElementTypeName)); } if (value == null) { return null; } visitedComplexTypeObjects.Add(value); ODataComplexValue value2 = new ODataComplexValue(); if (!isCollectionItem) { SerializationTypeNameAnnotation annotation = new SerializationTypeNameAnnotation { TypeName = this.requestInfo.GetServerTypeName(clientTypeAnnotation) }; value2.SetAnnotation<SerializationTypeNameAnnotation>(annotation); } value2.Properties = this.PopulateProperties(clientTypeAnnotation, value, visitedComplexTypeObjects); visitedComplexTypeObjects.Remove(value); return value2; }
/// <summary> /// Reads a collection value. /// </summary> /// <param name="collectionValueTypeReference">The collection type reference of the value.</param> /// <param name="payloadTypeName">The type name read from the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param> /// <returns>The value of the collection.</returns> /// <remarks> /// Pre-Condition: Fails if the current node is not a JsonNodeType.StartObject /// Post-Condition: almost anything - the node after the collection value (after the EndObject) /// </remarks> private ODataCollectionValue ReadCollectionValueImplementation( IEdmCollectionTypeReference collectionValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation) { DebugUtils.CheckNoExternalCallers(); Debug.Assert( collectionValueTypeReference == null || collectionValueTypeReference.IsNonEntityODataCollectionTypeKind(), "If the metadata is specified it must denote a Collection for this method to work."); this.JsonReader.AssertNotBuffering(); ODataVersionChecker.CheckCollectionValue(this.Version); this.IncreaseRecursionDepth(); // Read over the start object this.JsonReader.ReadStartObject(); ODataCollectionValue collectionValue = new ODataCollectionValue(); collectionValue.TypeName = collectionValueTypeReference != null ? collectionValueTypeReference.ODataFullName() : payloadTypeName; if (serializationTypeNameAnnotation != null) { collectionValue.SetAnnotation(serializationTypeNameAnnotation); } List<object> items = null; bool metadataPropertyFound = false; while (this.JsonReader.NodeType == JsonNodeType.Property) { string propertyName = this.JsonReader.ReadPropertyName(); if (string.CompareOrdinal(JsonConstants.ODataMetadataName, propertyName) == 0) { // __metadata property if (metadataPropertyFound) { throw new ODataException(o.Strings.ODataJsonPropertyAndValueDeserializer_MultiplePropertiesInCollectionWrapper(JsonConstants.ODataMetadataName)); } metadataPropertyFound = true; // Note that we don't need to read the type name again, as we've already read it above in FindTypeNameInPayload. // There's nothing else of interest in the __metadata for collections. this.JsonReader.SkipValue(); } else if (string.CompareOrdinal(JsonConstants.ODataResultsName, propertyName) == 0) { // results property if (items != null) { throw new ODataException(o.Strings.ODataJsonPropertyAndValueDeserializer_MultiplePropertiesInCollectionWrapper(JsonConstants.ODataResultsName)); } items = new List<object>(); this.JsonReader.ReadStartArray(); DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); IEdmTypeReference itemType = null; if (collectionValueTypeReference != null) { itemType = collectionValueTypeReference.CollectionDefinition().ElementType; } // NOTE: we do not support reading JSON without metadata right now so we always have an expected item type; // The collection validator is always null. CollectionWithoutExpectedTypeValidator collectionValidator = null; while (this.JsonReader.NodeType != JsonNodeType.EndArray) { object itemValue = this.ReadNonEntityValueImplementation( itemType, duplicatePropertyNamesChecker, collectionValidator, /*validateNullValue*/ true); // Validate the item (for example that it's not null) ValidationUtils.ValidateCollectionItem(itemValue, false /* isStreamable */); // Note that the ReadNonEntityValue already validated that the actual type of the value matches // the expected type (the itemType). items.Add(itemValue); } Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndArray, "The results value must end with an end array."); this.JsonReader.ReadEndArray(); } else { // Skip over any other property in the collection object this.JsonReader.SkipValue(); } } Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all properties of Collection wrapper are read the EndObject node is expected."); this.JsonReader.ReadEndObject(); if (items == null) { // We didn't find any results property. All collections must have the results property. throw new ODataException(o.Strings.ODataJsonPropertyAndValueDeserializer_CollectionWithoutResults); } collectionValue.Items = new ReadOnlyEnumerable(items); this.JsonReader.AssertNotBuffering(); this.DecreaseRecursionDepth(); return collectionValue; }
private static IEdmTypeReference ResolveAndValidateTargetTypeWithNoExpectedType(EdmTypeKind expectedTypeKind, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { serializationTypeNameAnnotation = null; if (payloadType == null) { if (expectedTypeKind == EdmTypeKind.Entity) { throw new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_EntryWithoutType); } throw new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_ValueWithoutType); } IEdmTypeReference targetTypeReference = payloadType.ToTypeReference(true); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference); return(targetTypeReference); }
internal static IEdmTypeReference ResolveAndValidateNonPrimitiveTargetType(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, EdmTypeKind payloadTypeKind, IEdmType payloadType, string payloadTypeName, IEdmModel model, ODataMessageReaderSettings messageReaderSettings, ODataVersion version, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { bool flag = (messageReaderSettings.ReaderBehavior.TypeResolver != null) && (payloadType != null); if (!flag) { ValidateTypeSupported(expectedTypeReference, version); if (model.IsUserModel() && ((expectedTypeReference == null) || !messageReaderSettings.DisableStrictMetadataValidation)) { VerifyPayloadTypeDefined(payloadTypeName, payloadType); } } else { ValidateTypeSupported((payloadType == null) ? null : payloadType.ToTypeReference(true), version); } if ((payloadTypeKind != EdmTypeKind.None) && (!messageReaderSettings.DisableStrictMetadataValidation || (expectedTypeReference == null))) { ValidationUtils.ValidateTypeKind(payloadTypeKind, expectedTypeKind, payloadTypeName); } serializationTypeNameAnnotation = null; if (!model.IsUserModel()) { return(null); } if ((expectedTypeReference == null) || flag) { return(ResolveAndValidateTargetTypeWithNoExpectedType(expectedTypeKind, payloadType, payloadTypeName, out serializationTypeNameAnnotation)); } if (messageReaderSettings.DisableStrictMetadataValidation) { return(ResolveAndValidateTargetTypeStrictValidationDisabled(expectedTypeKind, expectedTypeReference, payloadType, payloadTypeName, out serializationTypeNameAnnotation)); } return(ResolveAndValidateTargetTypeStrictValidationEnabled(expectedTypeKind, expectedTypeReference, payloadType, payloadTypeName, out serializationTypeNameAnnotation)); }
private static IEdmTypeReference ResolveAndValidateTargetTypeWithNoExpectedType(EdmTypeKind expectedTypeKind, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { serializationTypeNameAnnotation = null; if (payloadType == null) { if (expectedTypeKind == EdmTypeKind.Entity) { throw new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_EntryWithoutType); } throw new ODataException(Microsoft.Data.OData.Strings.ReaderValidationUtils_ValueWithoutType); } IEdmTypeReference targetTypeReference = payloadType.ToTypeReference(true); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference); return targetTypeReference; }
private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationDisabled(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { switch (expectedTypeKind) { case EdmTypeKind.Entity: { if (((payloadType == null) || (expectedTypeKind != payloadType.TypeKind)) || !expectedTypeReference.AsEntity().EntityDefinition().IsAssignableFrom(((IEdmEntityType)payloadType))) { break; } IEdmTypeReference targetTypeReference = payloadType.ToTypeReference(true); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference); return(targetTypeReference); } case EdmTypeKind.Complex: if ((payloadType != null) && (expectedTypeKind == payloadType.TypeKind)) { VerifyComplexType(expectedTypeReference, payloadType, false); } break; case EdmTypeKind.Collection: if ((payloadType != null) && (expectedTypeKind == payloadType.TypeKind)) { VerifyCollectionComplexItemType(expectedTypeReference, payloadType); } break; default: throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind)); } serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, expectedTypeReference); return(expectedTypeReference); }
private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationEnabled(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { switch (expectedTypeKind) { case EdmTypeKind.Entity: { if (payloadType == null) { break; } IEdmTypeReference targetTypeReference = payloadType.ToTypeReference(true); ValidationUtils.ValidateEntityTypeIsAssignable((IEdmEntityTypeReference) expectedTypeReference, (IEdmEntityTypeReference) targetTypeReference); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference); return targetTypeReference; } case EdmTypeKind.Complex: if (payloadType != null) { VerifyComplexType(expectedTypeReference, payloadType, true); } break; case EdmTypeKind.Collection: if ((payloadType != null) && (string.CompareOrdinal(payloadType.ODataFullName(), expectedTypeReference.ODataFullName()) != 0)) { VerifyCollectionComplexItemType(expectedTypeReference, payloadType); throw new ODataException(Microsoft.Data.OData.Strings.ValidationUtils_IncompatibleType(payloadType.ODataFullName(), expectedTypeReference.ODataFullName())); } break; default: throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind)); } serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, expectedTypeReference); return expectedTypeReference; }
private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationDisabled(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { switch (expectedTypeKind) { case EdmTypeKind.Entity: { if (((payloadType == null) || (expectedTypeKind != payloadType.TypeKind)) || !expectedTypeReference.AsEntity().EntityDefinition().IsAssignableFrom(((IEdmEntityType) payloadType))) { break; } IEdmTypeReference targetTypeReference = payloadType.ToTypeReference(true); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference); return targetTypeReference; } case EdmTypeKind.Complex: if ((payloadType != null) && (expectedTypeKind == payloadType.TypeKind)) { VerifyComplexType(expectedTypeReference, payloadType, false); } break; case EdmTypeKind.Collection: if ((payloadType != null) && (expectedTypeKind == payloadType.TypeKind)) { VerifyCollectionComplexItemType(expectedTypeReference, payloadType); } break; default: throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind)); } serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, expectedTypeReference); return expectedTypeReference; }
/// <summary> /// Read a collection from the reader. /// </summary> /// <param name="collectionTypeReference">The type of the collection to read (or null if no type is available).</param> /// <param name="payloadTypeName">The name of the collection type specified in the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param> /// <returns>The value read from the payload.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - the element to read the value for. /// XmlNodeType.Attribute - an attribute on the element to read the value for. /// Post-Condition: XmlNodeType.Element - the element was empty. /// XmlNodeType.EndElement - the element had some value. /// /// Note that this method will not read null values, those should be handled by the caller already. /// </remarks> private ODataCollectionValue ReadCollectionValue( IEdmCollectionTypeReference collectionTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation) { this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.Attribute); Debug.Assert( collectionTypeReference == null || collectionTypeReference.IsNonEntityODataCollectionTypeKind(), "If the metadata is specified it must denote a collection for this method to work."); this.IncreaseRecursionDepth(); ODataCollectionValue collectionValue = new ODataCollectionValue(); // If we have a metadata type for the collection, use that type name // otherwise use the type name from the payload (if there was any). collectionValue.TypeName = collectionTypeReference == null ? payloadTypeName : collectionTypeReference.ODataFullName(); if (serializationTypeNameAnnotation != null) { collectionValue.SetAnnotation(serializationTypeNameAnnotation); } // Move to the element (so that if we were on an attribute we can test the element for being empty) this.XmlReader.MoveToElement(); List<object> items = new List<object>(); // Empty collections are valid - they have no items if (!this.XmlReader.IsEmptyElement) { // Read over the collection element to its first child node (or end-element) this.XmlReader.ReadStartElement(); IEdmTypeReference itemTypeReference = collectionTypeReference == null ? null : collectionTypeReference.ElementType(); DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); CollectionWithoutExpectedTypeValidator collectionValidator = null; if (collectionTypeReference == null) { // Parse the type name from the payload (if any), extract the item type name and construct a collection validator string itemTypeName = payloadTypeName == null ? null : EdmLibraryExtensions.GetCollectionItemTypeName(payloadTypeName); collectionValidator = new CollectionWithoutExpectedTypeValidator(itemTypeName); } do { switch (this.XmlReader.NodeType) { case XmlNodeType.Element: if (this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace)) { if (!this.XmlReader.LocalNameEquals(this.ODataCollectionItemElementName)) { throw new ODataException(o.Strings.ODataAtomPropertyAndValueDeserializer_InvalidCollectionElement(this.XmlReader.LocalName, this.XmlReader.ODataNamespace)); } // We don't support EPM for collections so it is fine to say that EPM is not present object itemValue = this.ReadNonEntityValueImplementation( itemTypeReference, duplicatePropertyNamesChecker, collectionValidator, /*validateNullValue*/ true, /*epmPresent*/ false); // read over the end tag of the element or the start tag if the element was empty. this.XmlReader.Read(); // Validate the item (for example that it's not null) ValidationUtils.ValidateCollectionItem(itemValue, false /* isStreamable */); // Note that the ReadNonEntityValue already validated that the actual type of the value matches // the expected type (the itemType). items.Add(itemValue); } else { this.XmlReader.Skip(); } break; case XmlNodeType.EndElement: // End of the collection. break; default: // Non-element so for example a text node, just ignore this.XmlReader.Skip(); break; } } while (this.XmlReader.NodeType != XmlNodeType.EndElement); } collectionValue.Items = new ReadOnlyEnumerable(items); this.AssertXmlCondition(true, XmlNodeType.EndElement); Debug.Assert(collectionValue != null, "The method should never return null since it doesn't handle null values."); this.DecreaseRecursionDepth(); return collectionValue; }
/// <summary> /// Read a complex value from the reader. /// </summary> /// <param name="complexTypeReference">The type reference of the value to read (or null if no type is available).</param> /// <param name="payloadTypeName">The name of the type specified in the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the complex value (possibly null).</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use (cached), or null if new one should be created.</param> /// <param name="epmPresent">Whether any EPM mappings exist.</param> /// <returns>The value read from the payload.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - the element to read the value for. /// XmlNodeType.Attribute - an attribute on the element to read the value for. /// Post-Condition: XmlNodeType.EndElement - the element has been read. /// /// Note that this method will not read null values, those should be handled by the caller already. /// </remarks> private ODataComplexValue ReadComplexValue( IEdmComplexTypeReference complexTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool epmPresent) { this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.Attribute); this.IncreaseRecursionDepth(); ODataComplexValue complexValue = new ODataComplexValue(); IEdmComplexType complexType = complexTypeReference == null ? null : (IEdmComplexType)complexTypeReference.Definition; // If we have a metadata type for the complex value, use that type name // otherwise use the type name from the payload (if there was any). complexValue.TypeName = complexType == null ? payloadTypeName : complexType.ODataFullName(); if (serializationTypeNameAnnotation != null) { complexValue.SetAnnotation(serializationTypeNameAnnotation); } // Move to the element (so that if we were on an attribute we can test the element for being empty) this.XmlReader.MoveToElement(); if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> properties = new List<ODataProperty>(); this.ReadPropertiesImplementation(complexType, properties, duplicatePropertyNamesChecker, epmPresent); complexValue.Properties = new ReadOnlyEnumerable<ODataProperty>(properties); this.AssertXmlCondition(true, XmlNodeType.EndElement); Debug.Assert(complexValue != null, "The method should never return null since it doesn't handle null values."); this.DecreaseRecursionDepth(); return complexValue; }
/// <summary> /// Reads the primitive, complex or collection value. /// </summary> /// <param name="expectedTypeReference">The expected type reference of the value.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use (cached), or null if new one should be created.</param> /// <param name="collectionValidator">The collection validator instance if no expected item type has been specified; otherwise null.</param> /// <param name="validateNullValue">true to validate a null value; otherwise false.</param> /// <param name="epmPresent">Whether any EPM mappings exist.</param> /// <returns>The value read (null, primitive CLR value, ODataComplexValue or ODataCollectionValue).</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - The XML element containing the value to read (also the attributes will be read from it) /// Post-Condition: XmlNodeType.EndElement - The end tag of the element. /// XmlNodeType.Element - The empty element node. /// </remarks> private object ReadNonEntityValueImplementation( IEdmTypeReference expectedTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, bool validateNullValue, bool epmPresent) { this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert( expectedTypeReference == null || !expectedTypeReference.IsODataEntityTypeKind(), "Only primitive, complex or collection types can be read by this method."); Debug.Assert( expectedTypeReference == null || collectionValidator == null, "If an expected value type reference is specified, no collection validator must be provided."); this.XmlReader.AssertNotBuffering(); // Read the attributes looking for m:type and m:null string payloadTypeName; bool isNull; this.ReadNonEntityValueAttributes(out payloadTypeName, out isNull); object result; if (isNull) { result = this.ReadNullValue(expectedTypeReference, validateNullValue); } else { // If we could derive the item type name from the collection's type name and no type name was specified in the payload // fill it in now. EdmTypeKind payloadTypeKind; bool derivedItemTypeNameFromCollectionTypeName = false; if (collectionValidator != null && payloadTypeName == null) { payloadTypeName = collectionValidator.ItemTypeNameFromCollection; payloadTypeKind = collectionValidator.ItemTypeKindFromCollection; derivedItemTypeNameFromCollectionTypeName = payloadTypeKind != EdmTypeKind.None; } // Resolve the payload type name and compute the target type kind and target type reference. SerializationTypeNameAnnotation serializationTypeNameAnnotation; EdmTypeKind targetTypeKind; IEdmTypeReference targetTypeReference = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType( EdmTypeKind.None, /*defaultPrimitivePayloadType*/ edmStringType, expectedTypeReference, payloadTypeName, this.Model, this.MessageReaderSettings, this.Version, this.GetNonEntityValueKind, out targetTypeKind, out serializationTypeNameAnnotation); if (derivedItemTypeNameFromCollectionTypeName) { Debug.Assert( serializationTypeNameAnnotation == null, "If we derived the item type name from the collection type name we must not have created a serialization type name annotation."); serializationTypeNameAnnotation = new SerializationTypeNameAnnotation { TypeName = null }; } // If we have no expected type make sure the collection items are of the same kind and specify the same name. if (collectionValidator != null) { Debug.Assert(expectedTypeReference == null, "If a collection validator is specified there must not be an expected value type reference."); collectionValidator.ValidateCollectionItem(payloadTypeName, targetTypeKind); } switch (targetTypeKind) { case EdmTypeKind.Primitive: Debug.Assert(targetTypeReference != null && targetTypeReference.IsODataPrimitiveTypeKind(), "Expected an OData primitive type."); result = this.ReadPrimitiveValue(targetTypeReference.AsPrimitive()); break; case EdmTypeKind.Complex: Debug.Assert(targetTypeReference == null || targetTypeReference.IsComplex(), "Expected a complex type."); result = this.ReadComplexValue( targetTypeReference == null ? null : targetTypeReference.AsComplex(), payloadTypeName, serializationTypeNameAnnotation, duplicatePropertyNamesChecker, epmPresent); break; case EdmTypeKind.Collection: IEdmCollectionTypeReference collectionTypeReference = ValidationUtils.ValidateCollectionType(targetTypeReference); result = this.ReadCollectionValue( collectionTypeReference, payloadTypeName, serializationTypeNameAnnotation); break; default: throw new ODataException(o.Strings.General_InternalError(InternalErrorCodes.ODataAtomPropertyAndValueDeserializer_ReadNonEntityValue)); } } this.AssertXmlCondition(true, XmlNodeType.EndElement); this.XmlReader.AssertNotBuffering(); return result; }
private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationEnabled(EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { switch (expectedTypeKind) { case EdmTypeKind.Entity: { if (payloadType == null) { break; } IEdmTypeReference targetTypeReference = payloadType.ToTypeReference(true); ValidationUtils.ValidateEntityTypeIsAssignable((IEdmEntityTypeReference)expectedTypeReference, (IEdmEntityTypeReference)targetTypeReference); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, targetTypeReference); return(targetTypeReference); } case EdmTypeKind.Complex: if (payloadType != null) { VerifyComplexType(expectedTypeReference, payloadType, true); } break; case EdmTypeKind.Collection: if ((payloadType != null) && (string.CompareOrdinal(payloadType.ODataFullName(), expectedTypeReference.ODataFullName()) != 0)) { VerifyCollectionComplexItemType(expectedTypeReference, payloadType); throw new ODataException(Microsoft.Data.OData.Strings.ValidationUtils_IncompatibleType(payloadType.ODataFullName(), expectedTypeReference.ODataFullName())); } break; default: throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind)); } serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, expectedTypeReference); return(expectedTypeReference); }
/// <summary> /// Resolves and validates the payload type against the expected type and returns the target type. /// </summary> /// <param name="expectedTypeKind">The expected type kind for the value.</param> /// <param name="defaultPrimitivePayloadType">The default payload type if none is specified in the payload; /// for ATOM this is Edm.String, for JSON it is null since there is no payload type name for primitive types in the payload.</param> /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param> /// <param name="payloadTypeName">The payload type name, or null if no payload type was specified.</param> /// <param name="model">The model to use.</param> /// <param name="messageReaderSettings">The message reader settings to use.</param> /// <param name="version">The version of the payload being read.</param> /// <param name="typeKindFromPayloadFunc">A func to compute the type kind from the payload shape if it could not be determined from the expected type or the payload type.</param> /// <param name="targetTypeKind">The target type kind to be used to read the payload.</param> /// <param name="serializationTypeNameAnnotation">Potentially non-null instance of an annotation to put on the value reported from the reader.</param> /// <returns> /// The target type reference to use for parsing the value. /// If there is no user specified model, this will return null. /// If there is a user specified model, this method never returns null. /// </returns> /// <remarks> /// This method cannot be used for primitive type resolution. Primitive type resolution is format dependent and format specific methods should be used instead. /// </remarks> internal static IEdmTypeReference ResolvePayloadTypeNameAndComputeTargetType( EdmTypeKind expectedTypeKind, IEdmType defaultPrimitivePayloadType, IEdmTypeReference expectedTypeReference, string payloadTypeName, IEdmModel model, ODataMessageReaderSettings messageReaderSettings, ODataVersion version, Func<EdmTypeKind> typeKindFromPayloadFunc, out EdmTypeKind targetTypeKind, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(typeKindFromPayloadFunc != null, "typeKindFromPayloadFunc != null"); serializationTypeNameAnnotation = null; // Resolve the type name and get the payload type kind; that is the type kind of the payload // type if available or the expected type kind if no payload type could be resolved. Since // we always detect primitive and collection types the expected type for unrecognized payload // types is EdmTypeKind.Complex. EdmTypeKind payloadTypeKind; IEdmType payloadType = ResolvePayloadTypeName( model, expectedTypeReference, payloadTypeName, EdmTypeKind.Complex, messageReaderSettings.ReaderBehavior, version, out payloadTypeKind); // Compute the target type kind based on the expected type, the payload type kind // and a function to detect the target type kind from the shape of the payload. targetTypeKind = ComputeTargetTypeKind( expectedTypeReference, /*forEntityValue*/ expectedTypeKind == EdmTypeKind.Entity, payloadTypeName, payloadTypeKind, messageReaderSettings, typeKindFromPayloadFunc); // Resolve potential conflicts between payload and expected types and apply all the various behavior changing flags from settings IEdmTypeReference targetTypeReference; if (targetTypeKind == EdmTypeKind.Primitive) { targetTypeReference = ReaderValidationUtils.ResolveAndValidatePrimitiveTargetType( expectedTypeReference, payloadTypeKind, payloadType, payloadTypeName, defaultPrimitivePayloadType, model, messageReaderSettings, version); } else { targetTypeReference = ReaderValidationUtils.ResolveAndValidateNonPrimitiveTargetType( targetTypeKind, expectedTypeReference, payloadTypeKind, payloadType, payloadTypeName, model, messageReaderSettings, version, out serializationTypeNameAnnotation); } if (expectedTypeKind != EdmTypeKind.None && targetTypeReference != null) { ValidationUtils.ValidateTypeKind(targetTypeKind, expectedTypeKind, payloadTypeName); } return targetTypeReference; }
internal static IEdmTypeReference ResolvePayloadTypeNameAndComputeTargetType(EdmTypeKind expectedTypeKind, IEdmType defaultPrimitivePayloadType, IEdmTypeReference expectedTypeReference, string payloadTypeName, IEdmModel model, ODataMessageReaderSettings messageReaderSettings, ODataVersion version, Func <EdmTypeKind> typeKindFromPayloadFunc, out EdmTypeKind targetTypeKind, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { EdmTypeKind kind; IEdmTypeReference reference; serializationTypeNameAnnotation = null; IEdmType payloadType = ResolvePayloadTypeName(model, expectedTypeReference, payloadTypeName, EdmTypeKind.Complex, messageReaderSettings.ReaderBehavior, version, out kind); targetTypeKind = ComputeTargetTypeKind(expectedTypeReference, expectedTypeKind == EdmTypeKind.Entity, payloadTypeName, kind, messageReaderSettings, typeKindFromPayloadFunc); if (targetTypeKind == EdmTypeKind.Primitive) { reference = ResolveAndValidatePrimitiveTargetType(expectedTypeReference, kind, payloadType, payloadTypeName, defaultPrimitivePayloadType, model, messageReaderSettings, version); } else { reference = ResolveAndValidateNonPrimitiveTargetType(targetTypeKind, expectedTypeReference, kind, payloadType, payloadTypeName, model, messageReaderSettings, version, out serializationTypeNameAnnotation); } if ((expectedTypeKind != EdmTypeKind.None) && (reference != null)) { ValidationUtils.ValidateTypeKind(targetTypeKind, expectedTypeKind, payloadTypeName); } return(reference); }
/// <summary> /// Resolves the payload type versus the expected type and validates that such combination is allowed. /// </summary> /// <param name="expectedTypeKind">The expected type kind for the value.</param> /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param> /// <param name="payloadTypeKind">The payload type kind, this may be the one from the type itself, or one detected without resolving the type.</param> /// <param name="payloadType">The payload type, or null if the payload type was not specified, or it didn't resolve against the model.</param> /// <param name="payloadTypeName">The payload type name, or null if no payload type was specified.</param> /// <param name="model">The model to use.</param> /// <param name="messageReaderSettings">The message reader settings to use.</param> /// <param name="version">The version of the payload being read.</param> /// <param name="serializationTypeNameAnnotation">Potentially non-null instance of an annotation to put on the value reported from the reader.</param> /// <returns> /// The target type reference to use for parsing the value. /// If there is no user specified model, this will return null. /// If there is a user specified model, this method never returns null. /// </returns> /// <remarks> /// This method cannot be used for primitive type resolution. Primitive type resolution is format dependent and format specific methods should be used instead. /// </remarks> internal static IEdmTypeReference ResolveAndValidateNonPrimitiveTargetType( EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, EdmTypeKind payloadTypeKind, IEdmType payloadType, string payloadTypeName, IEdmModel model, ODataMessageReaderSettings messageReaderSettings, ODataVersion version, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(messageReaderSettings != null, "messageReaderSettings != null"); Debug.Assert( expectedTypeKind == EdmTypeKind.Complex || expectedTypeKind == EdmTypeKind.Entity || expectedTypeKind == EdmTypeKind.Collection, "The expected type kind must be one of Complex, Entity or Collection."); Debug.Assert( payloadTypeKind == EdmTypeKind.Complex || payloadTypeKind == EdmTypeKind.Entity || payloadTypeKind == EdmTypeKind.Collection || payloadTypeKind == EdmTypeKind.None || payloadTypeKind == EdmTypeKind.Primitive, "The payload type kind must be one of None, Primitive, Complex, Entity or Collection."); Debug.Assert( expectedTypeReference == null || expectedTypeReference.TypeKind() == expectedTypeKind, "The expected type kind must match the expected type reference if that is available."); Debug.Assert( payloadType == null || payloadType.TypeKind == payloadTypeKind, "The payload type kind must match the payload type if that is available."); Debug.Assert(payloadType == null || payloadTypeName != null, "If we have a payload type, we must have its name as well."); bool useExpectedTypeOnlyForTypeResolution = messageReaderSettings.ReaderBehavior.TypeResolver != null && payloadType != null; if (!useExpectedTypeOnlyForTypeResolution) { ValidateTypeSupported(expectedTypeReference, version); // We should validate that the payload type resolved before anything else to produce reasonable error messages // Otherwise we might report errors which are somewhat confusing (like "Type '' is Complex but Collection was expected."). if (model.IsUserModel() && (expectedTypeReference == null || !messageReaderSettings.DisableStrictMetadataValidation)) { // When using a type resolver (i.e., useExpectedTypeOnlyForTypeResolution == true) then we don't have to // call this method because the contract with the type resolver is to always resolve the type name and thus // we will always get a defined type. VerifyPayloadTypeDefined(payloadTypeName, payloadType); } } else { // Payload types are always nullable. ValidateTypeSupported(payloadType == null ? null : payloadType.ToTypeReference(/*nullable*/ true), version); } if (payloadTypeKind != EdmTypeKind.None && (!messageReaderSettings.DisableStrictMetadataValidation || expectedTypeReference == null)) { // Make sure that the type kinds match. ValidationUtils.ValidateTypeKind(payloadTypeKind, expectedTypeKind, payloadTypeName); } serializationTypeNameAnnotation = null; if (!model.IsUserModel()) { // If there's no model, it means we should not have the expected type either, and that there's no type to use, // no metadata validation to perform. Debug.Assert(expectedTypeReference == null, "If we don't have a model, we must not have expected type either."); return null; } if (expectedTypeReference == null || useExpectedTypeOnlyForTypeResolution) { return ResolveAndValidateTargetTypeWithNoExpectedType( expectedTypeKind, payloadType, payloadTypeName, out serializationTypeNameAnnotation); } if (messageReaderSettings.DisableStrictMetadataValidation) { return ResolveAndValidateTargetTypeStrictValidationDisabled( expectedTypeKind, expectedTypeReference, payloadType, payloadTypeName, out serializationTypeNameAnnotation); } return ResolveAndValidateTargetTypeStrictValidationEnabled( expectedTypeKind, expectedTypeReference, payloadType, payloadTypeName, out serializationTypeNameAnnotation); }
private ODataCollectionValue CreateODataCollection(Type collectionItemType, string propertyName, object value, List<object> visitedComplexTypeObjects) { PrimitiveType type; string edmType; Func<object, object> valueConverter = null; Func<object, ODataComplexValue> func2 = null; WebUtil.ValidateCollection(collectionItemType, value, propertyName); bool flag = PrimitiveType.TryGetPrimitiveType(collectionItemType, out type); ODataCollectionValue value2 = new ODataCollectionValue(); IEnumerable enumerable = (IEnumerable) value; if (flag) { edmType = ClientConvert.GetEdmType(Nullable.GetUnderlyingType(collectionItemType) ?? collectionItemType); if (valueConverter == null) { valueConverter = delegate (object val) { WebUtil.ValidateCollectionItem(val); WebUtil.ValidatePrimitiveCollectionItem(val, propertyName, collectionItemType); return GetPrimitiveValue(val, collectionItemType); }; } value2.Items = Util.GetEnumerable<object>(enumerable, valueConverter); } else { edmType = this.requestInfo.ResolveNameFromType(collectionItemType); if (func2 == null) { func2 = delegate (object val) { WebUtil.ValidateCollectionItem(val); WebUtil.ValidateComplexCollectionItem(val, propertyName, collectionItemType); return this.CreateODataComplexValue(collectionItemType, val, propertyName, true, visitedComplexTypeObjects); }; } value2.Items = Util.GetEnumerable<ODataComplexValue>(enumerable, func2); } string str2 = (edmType == null) ? null : string.Format(CultureInfo.InvariantCulture, "Collection({0})", new object[] { edmType }); SerializationTypeNameAnnotation annotation = new SerializationTypeNameAnnotation { TypeName = str2 }; value2.SetAnnotation<SerializationTypeNameAnnotation>(annotation); return value2; }
/// <summary> /// Resolves the payload type if there's no expected type. /// </summary> /// <param name="expectedTypeKind">The expected type kind for the value.</param> /// <param name="payloadType">The payload type, or null if the payload type was not specified, or it didn't resolve against the model.</param> /// <param name="payloadTypeName">The payload type name, or null if no payload type was specified.</param> /// <param name="serializationTypeNameAnnotation">Potentially non-null instance of an annotation to put on the value reported from the reader.</param> /// <returns>The target type reference to use for parsing the value.</returns> private static IEdmTypeReference ResolveAndValidateTargetTypeWithNoExpectedType( EdmTypeKind expectedTypeKind, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { Debug.Assert(payloadTypeName == null || payloadType != null, "The payload type must have resolved before we get here."); serializationTypeNameAnnotation = null; // No expected type (for example an open property, but other scenarios are possible) // We need some type to go on. We do have a model, so we must perform metadata validation and for that we need a type. if (payloadType == null) { if (expectedTypeKind == EdmTypeKind.Entity) { throw new ODataException(Strings.ReaderValidationUtils_EntryWithoutType); } throw new ODataException(Strings.ReaderValidationUtils_ValueWithoutType); } // Payload types are always nullable. IEdmTypeReference payloadTypeReference = payloadType.ToTypeReference(/*nullable*/ true); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, payloadTypeReference); // Use the payload type (since we don't have any other). return payloadTypeReference; }
internal void WriteEntry(EntityDescriptor entityDescriptor, IEnumerable<LinkDescriptor> relatedLinks, ODataRequestMessageWrapper requestMessage) { ClientEdmModel model = ClientEdmModel.GetModel(this.requestInfo.MaxProtocolVersion); ClientTypeAnnotation clientTypeAnnotation = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityDescriptor.Entity.GetType())); using (ODataMessageWriter writer = CreateMessageWriter(requestMessage, this.requestInfo)) { ODataWriter odataWriter = writer.CreateODataEntryWriter(); ODataEntry entry = new ODataEntry(); if (this.requestInfo.HasWritingEventHandlers) { entry.SetAnnotation<WritingEntityInfo>(new WritingEntityInfo(entityDescriptor.Entity, this.requestInfo)); } string serverTypeName = this.requestInfo.GetServerTypeName(entityDescriptor); if (clientTypeAnnotation.ElementTypeName != serverTypeName) { SerializationTypeNameAnnotation annotation = new SerializationTypeNameAnnotation { TypeName = serverTypeName }; entry.SetAnnotation<SerializationTypeNameAnnotation>(annotation); } entry.TypeName = clientTypeAnnotation.ElementTypeName; if (EntityStates.Modified == entityDescriptor.State) { entry.Id = entityDescriptor.GetLatestIdentity(); } if (entityDescriptor.IsMediaLinkEntry || clientTypeAnnotation.IsMediaLinkEntry) { entry.MediaResource = new ODataStreamReferenceValue(); } odataWriter.WriteStart(entry); if (EntityStates.Added == entityDescriptor.State) { this.WriteNavigationLink(entityDescriptor, relatedLinks, odataWriter); } entry.Properties = this.PopulateProperties(clientTypeAnnotation, entityDescriptor.Entity, null); odataWriter.WriteEnd(); } }
/// <summary> /// Resolves the payload type versus the expected type and validates that such combination is allowed when the strict validation is disabled. /// </summary> /// <param name="expectedTypeKind">The expected type kind for the value.</param> /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param> /// <param name="payloadType">The payload type, or null if the payload type was not specified, or it didn't resolve against the model.</param> /// <param name="payloadTypeName">The payload type name, or null if no payload type was specified.</param> /// <param name="serializationTypeNameAnnotation">Potentially non-null instance of an annotation to put on the value reported from the reader.</param> /// <returns>The target type reference to use for parsing the value.</returns> private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationDisabled( EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { // Lax validation logic switch (expectedTypeKind) { case EdmTypeKind.Complex: // if the expectedTypeKind is different from the payloadType.TypeKind the types are not related // in any way. In that case we will just use the expected type because we are in lax mode. if (payloadType != null && expectedTypeKind == payloadType.TypeKind) { // Just verify that it's not a derived complex type, in all other cases simply use the expected type. VerifyComplexType(expectedTypeReference, payloadType, /* failIfNotRelated */ false); } break; case EdmTypeKind.Entity: // if the expectedTypeKind is different from the payloadType.TypeKind the types are not related // in any way. In that case we will just use the expected type because we are in lax mode. if (payloadType != null && expectedTypeKind == payloadType.TypeKind) { // If the type is assignable (equal or derived) we will use the payload type, since we want to allow derived entities if (EdmLibraryExtensions.IsAssignableFrom(expectedTypeReference.AsEntity().EntityDefinition(), (IEdmEntityType)payloadType)) { IEdmTypeReference payloadTypeReference = payloadType.ToTypeReference(/*nullable*/ true); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, payloadTypeReference); return payloadTypeReference; } } break; case EdmTypeKind.Collection: // if the expectedTypeKind is different from the payloadType.TypeKind the types are not related // in any way. In that case we will just use the expected type because we are in lax mode. if (payloadType != null && expectedTypeKind == payloadType.TypeKind) { VerifyCollectionComplexItemType(expectedTypeReference, payloadType); } break; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind)); } serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, expectedTypeReference); // Either there's no payload type, in which case use the expected one, or the payload one and the expected one are equal. return expectedTypeReference; }
/// <summary> /// Reads a complex value. /// </summary> /// <param name="complexValueTypeReference">The expected type reference of the value.</param> /// <param name="payloadTypeName">The type name read from the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - if null the method should create a new one if necessary.</param> /// <returns>The value of the complex value.</returns> /// <remarks> /// Pre-Condition: Fails if the current node is not a JsonNodeType.StartObject or JsonNodeType.PrimitiveValue (with null value) /// Post-Condition: almost anything - the node after the complex value (after the EndObject) /// </remarks> private ODataComplexValue ReadComplexValueImplementation( IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.JsonReader.AssertNotBuffering(); this.IncreaseRecursionDepth(); // Read over the start object this.JsonReader.ReadStartObject(); ODataComplexValue complexValue = new ODataComplexValue(); complexValue.TypeName = complexValueTypeReference != null ? complexValueTypeReference.ODataFullName() : payloadTypeName; if (serializationTypeNameAnnotation != null) { complexValue.SetAnnotation(serializationTypeNameAnnotation); } if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> properties = new List<ODataProperty>(); bool metadataPropertyFound = false; while (this.JsonReader.NodeType == JsonNodeType.Property) { string propertyName = this.JsonReader.ReadPropertyName(); if (string.CompareOrdinal(JsonConstants.ODataMetadataName, propertyName) == 0) { // __metadata property. if (metadataPropertyFound) { throw new ODataException(o.Strings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue); } metadataPropertyFound = true; this.JsonReader.SkipValue(); } else { if (!ValidationUtils.IsValidPropertyName(propertyName)) { // We ignore properties with an invalid name since these are extension points for the future. this.JsonReader.SkipValue(); } else { // Any other property is data ODataProperty property = new ODataProperty(); property.Name = propertyName; // Lookup the property in metadata IEdmProperty edmProperty = null; bool ignoreProperty = false; if (complexValueTypeReference != null) { edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(propertyName, complexValueTypeReference.ComplexDefinition(), this.MessageReaderSettings, out ignoreProperty); } if (ignoreProperty) { this.JsonReader.SkipValue(); } else { ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null ? ODataNullValueBehaviorKind.Default : this.Model.NullValueReadBehaviorKind(edmProperty); // Read the property value object propertyValue = this.ReadNonEntityValueImplementation( edmProperty == null ? null : edmProperty.Type, /*duplicatePropertyNamesChecker*/ null, /*collectionValidator*/ null, nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default); if (nullValueReadBehaviorKind != ODataNullValueBehaviorKind.IgnoreValue || propertyValue != null) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); property.Value = propertyValue; properties.Add(property); } } } } } Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all the properties of a complex value are read the EndObject node is expected."); this.JsonReader.ReadEndObject(); complexValue.Properties = new ReadOnlyEnumerable<ODataProperty>(properties); this.JsonReader.AssertNotBuffering(); this.DecreaseRecursionDepth(); return complexValue; }
/// <summary> /// Resolves the payload type versus the expected type and validates that such combination is allowed when strict validation is enabled. /// </summary> /// <param name="expectedTypeKind">The expected type kind for the value.</param> /// <param name="expectedTypeReference">The expected type reference, or null if no expected type is available.</param> /// <param name="payloadType">The payload type, or null if the payload type was not specified, or it didn't resolve against the model.</param> /// <param name="payloadTypeName">The payload type name, or null if no payload type was specified.</param> /// <param name="serializationTypeNameAnnotation">Potentially non-null instance of an annotation to put on the value reported from the reader.</param> /// <returns>The target type reference to use for parsing the value.</returns> private static IEdmTypeReference ResolveAndValidateTargetTypeStrictValidationEnabled( EdmTypeKind expectedTypeKind, IEdmTypeReference expectedTypeReference, IEdmType payloadType, string payloadTypeName, out SerializationTypeNameAnnotation serializationTypeNameAnnotation) { Debug.Assert(payloadTypeName == null || payloadType != null, "The payload type must have resolved before we get here."); // Strict validation logic switch (expectedTypeKind) { case EdmTypeKind.Complex: if (payloadType != null) { VerifyComplexType(expectedTypeReference, payloadType, /* failIfNotRelated */ true); } break; case EdmTypeKind.Entity: if (payloadType != null) { // The payload type must be assignable to the expected type. IEdmTypeReference payloadTypeReference = payloadType.ToTypeReference(/*nullable*/ true); ValidationUtils.ValidateEntityTypeIsAssignable((IEdmEntityTypeReference)expectedTypeReference, (IEdmEntityTypeReference)payloadTypeReference); serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, payloadTypeReference); // Use the payload type return payloadTypeReference; } break; case EdmTypeKind.Collection: // The type must be exactly equal - note that we intentionally ignore nullability of the items here, since the payload type // can't specify that. if (payloadType != null && string.CompareOrdinal(payloadType.ODataFullName(), expectedTypeReference.ODataFullName()) != 0) { VerifyCollectionComplexItemType(expectedTypeReference, payloadType); throw new ODataException(Strings.ValidationUtils_IncompatibleType(payloadType.ODataFullName(), expectedTypeReference.ODataFullName())); } break; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.ReaderValidationUtils_ResolveAndValidateTypeName_Strict_TypeKind)); } serializationTypeNameAnnotation = CreateSerializationTypeNameAnnotation(payloadTypeName, expectedTypeReference); // Either there's no payload type, in which case use the expected one, or the payload one and the expected one are equal. return expectedTypeReference; }
private ODataComplexValue ReadComplexValueImplementation(IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.IncreaseRecursionDepth(); base.JsonReader.ReadStartObject(); ODataComplexValue value2 = new ODataComplexValue { TypeName = (complexValueTypeReference != null) ? complexValueTypeReference.ODataFullName() : payloadTypeName }; if (serializationTypeNameAnnotation != null) { value2.SetAnnotation<SerializationTypeNameAnnotation>(serializationTypeNameAnnotation); } if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> sourceList = new List<ODataProperty>(); bool flag = false; while (base.JsonReader.NodeType == JsonNodeType.Property) { string strB = base.JsonReader.ReadPropertyName(); if (string.CompareOrdinal("__metadata", strB) == 0) { if (flag) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue); } flag = true; base.JsonReader.SkipValue(); } else if (!ValidationUtils.IsValidPropertyName(strB)) { base.JsonReader.SkipValue(); } else { ODataProperty property = new ODataProperty { Name = strB }; IEdmProperty property2 = null; bool ignoreProperty = false; if (complexValueTypeReference != null) { property2 = ReaderValidationUtils.ValidateValuePropertyDefined(strB, complexValueTypeReference.ComplexDefinition(), base.MessageReaderSettings, out ignoreProperty); } if (ignoreProperty) { base.JsonReader.SkipValue(); continue; } ODataNullValueBehaviorKind kind = (base.ReadingResponse || (property2 == null)) ? ODataNullValueBehaviorKind.Default : base.Model.NullValueReadBehaviorKind(property2); object obj2 = this.ReadNonEntityValueImplementation((property2 == null) ? null : property2.Type, null, null, kind == ODataNullValueBehaviorKind.Default); if ((kind != ODataNullValueBehaviorKind.IgnoreValue) || (obj2 != null)) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); property.Value = obj2; sourceList.Add(property); } } } base.JsonReader.ReadEndObject(); value2.Properties = new ReadOnlyEnumerable<ODataProperty>(sourceList); this.DecreaseRecursionDepth(); return value2; }
private ODataComplexValue ReadComplexValue(IEdmComplexTypeReference complexTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool epmPresent) { this.IncreaseRecursionDepth(); ODataComplexValue value2 = new ODataComplexValue(); IEdmComplexType type = (complexTypeReference == null) ? null : ((IEdmComplexType) complexTypeReference.Definition); value2.TypeName = (type == null) ? payloadTypeName : type.ODataFullName(); if (serializationTypeNameAnnotation != null) { value2.SetAnnotation<SerializationTypeNameAnnotation>(serializationTypeNameAnnotation); } base.XmlReader.MoveToElement(); if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> properties = new List<ODataProperty>(); this.ReadPropertiesImplementation(type, properties, duplicatePropertyNamesChecker, epmPresent); value2.Properties = new ReadOnlyEnumerable<ODataProperty>(properties); this.DecreaseRecursionDepth(); return value2; }