internal static void ValidatePropertyMatch(ClientPropertyAnnotation property, ODataProperty atomProperty, ResponseInfo responseInfo, bool performEntityCheck) { ODataFeed feed = atomProperty.Value as ODataFeed; ODataEntry entry = atomProperty.Value as ODataEntry; if (property.IsKnownType && ((feed != null) || (entry != null))) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Deserialize_MismatchAtomLinkLocalSimple); } Type t = null; if (feed != null) { if (!property.IsEntityCollection) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Deserialize_MismatchAtomLinkFeedPropertyNotCollection(property.PropertyName)); } t = property.EntityCollectionItemType; } if (entry != null) { if (property.IsEntityCollection) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Deserialize_MismatchAtomLinkEntryPropertyIsCollection(property.PropertyName)); } t = property.PropertyType; } if (((t != null) && performEntityCheck) && !ClientTypeUtil.TypeIsEntity(t, responseInfo.MaxProtocolVersion)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidNonEntityType(t.ToString())); } }
/// <summary> /// Applies collectionValue item to the provided <paramref name="collectionInstance"/>. /// </summary> /// <param name="collectionProperty">Atom property containing materialized Collection items.</param> /// <param name="collectionInstance">Collection instance. Must implement ICollection<T> where T is either primitive or complex type (not an entity).</param> /// <param name="collectionItemType">Type of items in the Collection. Note: this could be calculated from collectionInstance but we already have it in upstream methods.</param> /// <param name="addValueToBackingICollectionInstance">Action called actually add a Collection item to <paramref name="collectionInstance" /></param> /// <param name="isElementNullable">If element type is nullable.</param> internal void ApplyCollectionDataValues( ODataProperty collectionProperty, object collectionInstance, Type collectionItemType, Action <object, object> addValueToBackingICollectionInstance, bool isElementNullable) { Debug.Assert(collectionProperty != null, "property != null"); Debug.Assert(collectionProperty.Value != null, "Collection should have already been checked for nullness"); Debug.Assert(collectionInstance != null, "collectionInstance != null"); Debug.Assert(WebUtil.IsCLRTypeCollection(collectionInstance.GetType(), this.materializerContext.Model), "collectionInstance must be a CollectionValue"); Debug.Assert(collectionItemType.IsAssignableFrom( ClientTypeUtil.GetImplementationType(collectionInstance.GetType(), typeof(ICollection <>)).GetGenericArguments()[0]), "collectionItemType has to match the collectionInstance generic type."); Debug.Assert(!ClientTypeUtil.TypeIsEntity(collectionItemType, this.materializerContext.Model), "CollectionValues cannot contain entities"); Debug.Assert(addValueToBackingICollectionInstance != null, "AddValueToBackingICollectionInstance != null"); ODataCollectionValue collectionValue = collectionProperty.Value as ODataCollectionValue; this.ApplyCollectionDataValues( collectionValue.Items, collectionValue.TypeName, collectionInstance, collectionItemType, addValueToBackingICollectionInstance, isElementNullable); collectionProperty.SetMaterializedValue(collectionInstance); }
/// <summary> /// Applies the collection data values to a collection instance. /// </summary> /// <param name="items">The items.</param> /// <param name="wireTypeName">Name of the wire type.</param> /// <param name="collectionInstance">The collection instance.</param> /// <param name="collectionItemType">Type of the collection item.</param> /// <param name="addValueToBackingICollectionInstance">The add value to backing I collection instance.</param> /// <param name="isElementNullable">If element type is nullable.</param> internal void ApplyCollectionDataValues( IEnumerable items, string wireTypeName, object collectionInstance, Type collectionItemType, Action <object, object> addValueToBackingICollectionInstance, bool isElementNullable) { Debug.Assert(collectionInstance != null, "collectionInstance != null"); Debug.Assert(WebUtil.IsCLRTypeCollection(collectionInstance.GetType(), this.materializerContext.Model), "collectionInstance must be a CollectionValue"); Debug.Assert(collectionItemType.IsAssignableFrom( ClientTypeUtil.GetImplementationType(collectionInstance.GetType(), typeof(ICollection <>)).GetGenericArguments()[0]), "collectionItemType has to match the collectionInstance generic type."); Debug.Assert(!ClientTypeUtil.TypeIsEntity(collectionItemType, this.materializerContext.Model), "CollectionValues cannot contain entities"); Debug.Assert(addValueToBackingICollectionInstance != null, "AddValueToBackingICollectionInstance != null"); // is the Collection not empty ? if (items != null) { bool isCollectionItemTypePrimitive = PrimitiveType.IsKnownNullableType(collectionItemType); foreach (object item in items) { if (!isElementNullable && item == null) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_NullCollectionItemsNotSupported); } ODataEnumValue enumVal = null; // Is it a Collection of primitive types? if (isCollectionItemTypePrimitive) { if (item is ODataCollectionValue) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_CollectionTypesInCollectionOfPrimitiveTypesNotAllowed); } object materializedValue = this.primitiveValueMaterializationPolicy.MaterializePrimitiveDataValueCollectionElement(collectionItemType, wireTypeName, item); addValueToBackingICollectionInstance(collectionInstance, materializedValue); } else if ((enumVal = item as ODataEnumValue) != null) { // TODO: use EnumValueMaterializationPolicy.MaterializeEnumDataValueCollectionElement() here object tmpValue = EnumValueMaterializationPolicy.MaterializeODataEnumValue(collectionItemType, enumVal); addValueToBackingICollectionInstance(collectionInstance, tmpValue); } else { if (item != null) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_PrimitiveTypesInCollectionOfComplexTypesNotAllowed); } addValueToBackingICollectionInstance(collectionInstance, null); } } } }
internal static Type ValidatePropertyMatch(ClientPropertyAnnotation property, ODataNavigationLink link, ResponseInfo responseInfo, bool performEntityCheck) { Type t = null; if (link.IsCollection.HasValue) { if (link.IsCollection.Value) { if (!property.IsEntityCollection) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Deserialize_MismatchAtomLinkFeedPropertyNotCollection(property.PropertyName)); } t = property.EntityCollectionItemType; } else { if (property.IsEntityCollection) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Deserialize_MismatchAtomLinkEntryPropertyIsCollection(property.PropertyName)); } t = property.PropertyType; } } if (((t != null) && performEntityCheck) && !ClientTypeUtil.TypeIsEntity(t, responseInfo.MaxProtocolVersion)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidNonEntityType(t.ToString())); } return(t); }
internal static bool IsDisallowedExpressionForMethodCall(Expression e, DataServiceProtocolVersion maxProtocolVersion) { MemberExpression expression = e as MemberExpression; if ((expression != null) && ClientTypeUtil.TypeIsEntity(expression.Expression.Type, maxProtocolVersion)) { return(false); } return(IsCollectionProducingExpression(e)); }
/// <summary> /// Returns true the specified entry represents an entity. /// </summary> /// <param name="entity">The resolved instance</param> /// <param name="model">The client model.</param> /// <returns>True if the entry represents an entity.</returns> private static bool IsEntity(object entity, ClientEdmModel model) { if (entity == null) { // you can set link to null, we need to track these values return(true); } return(ClientTypeUtil.TypeIsEntity(entity.GetType(), model)); }
/// <summary> /// Checks whether the specified expression is allowed in a MethodCall. Expressions that /// produce collections are not allowed. The only exception is when collection property /// belongs to an entity e.g. c.Orders.Select(o => o), where we allow c.Orders. /// </summary> /// <param name="e">Expression to check.</param> /// <param name="model">The client model used.</param> /// <returns>true if expression is disallowed, false otherwise.</returns> internal static bool IsDisallowedExpressionForMethodCall(Expression e, ClientEdmModel model) { // If this is a collection hanging off a Entity, then that is fine. MemberExpression me = e as MemberExpression; if (me != null && ClientTypeUtil.TypeIsEntity(me.Expression.Type, model)) { return(false); } // All collection producing expressions are disallowed. return(IsCollectionProducingExpression(e)); }
internal static bool IsCLRTypeCollection(Type type, DataServiceProtocolVersion maxProtocolVersion) { if (!PrimitiveType.IsKnownNullableType(type)) { Type implementationType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>)); if ((implementationType != null) && !ClientTypeUtil.TypeIsEntity(implementationType.GetGenericArguments()[0], maxProtocolVersion)) { if (maxProtocolVersion <= DataServiceProtocolVersion.V2) { throw new InvalidOperationException(System.Data.Services.Client.Strings.WebUtil_CollectionTypeNotSupportedInV2OrBelow(type.FullName)); } return(true); } } return(false); }
/// <summary> /// Validates the specified <paramref name="property"/> matches /// the parsed <paramref name="atomProperty"/>. /// </summary> /// <param name="property">Property as understood by the type system.</param> /// <param name="atomProperty">Property as parsed.</param> /// <param name="model">Client model.</param> /// <param name="performEntityCheck">whether to do the entity check or not.</param> internal static void ValidatePropertyMatch(ClientPropertyAnnotation property, ODataProperty atomProperty, ClientEdmModel model, bool performEntityCheck) { Debug.Assert(property != null, "property != null"); Debug.Assert(atomProperty != null, "atomProperty != null"); ODataResourceSet feed = atomProperty.Value as ODataResourceSet; ODataResource entry = atomProperty.Value as ODataResource; if (property.IsKnownType && (feed != null || entry != null)) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkLocalSimple); } Type propertyType = null; if (feed != null) { // We need to fail if the payload states that the property is a navigation collection property // and in the client, the property is not a collection property. if (!property.IsEntityCollection) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkFeedPropertyNotCollection(property.PropertyName)); } propertyType = property.EntityCollectionItemType; } if (entry != null) { if (property.IsEntityCollection) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkEntryPropertyIsCollection(property.PropertyName)); } propertyType = property.PropertyType; } // If the server type and the client type does not match, we need to throw. // This is a breaking change from V1/V2 where we allowed materialization of entities into non-entities and vice versa if (propertyType != null && performEntityCheck) { if (!ClientTypeUtil.TypeIsEntity(propertyType, model)) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidNonEntityType(propertyType.ToString())); } } }
/// <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="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, 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 { MemberInfo member = property.PropertyType.GetMember(propertyValue.ToString()).FirstOrDefault(); if (member == null) { throw new NotSupportedException(Strings.Serializer_InvalidEnumMemberValue(property.PropertyType.Name, propertyValue.ToString())); } enumValue = ClientTypeUtil.GetServerDefinedName(member); } string typeNameInMetadata = this.requestInfo.ResolveNameFromType(property.PropertyType); odataValue = new ODataEnumValue(enumValue, typeNameInMetadata); return(true); } if (property.IsPrimitiveOrEnumOrComplexCollection) { odataValue = this.CreateODataCollectionPropertyValue(property, propertyValue, 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); }
private static Type GetTypeForMaterializer(bool expectingPrimitiveValue, Type elementType, DataServiceProtocolVersion maxProtocolVersion, out Type implementationType) { if (!expectingPrimitiveValue && typeof(IEnumerable).IsAssignableFrom(elementType)) { implementationType = ClientTypeUtil.GetImplementationType(elementType, typeof(ICollection <>)); if (implementationType != null) { Type t = implementationType.GetGenericArguments()[0]; if (ClientTypeUtil.TypeIsEntity(t, maxProtocolVersion)) { return(t); } } } implementationType = null; return(elementType); }
/// <summary> /// Creates Collection instance of store Collection items. /// </summary> /// <param name="collectionProperty">ODataProperty instance representing the Collection as seen in the atom payload.</param> /// <param name="userCollectionType">CLR type of the Collection as defined by the user.</param> /// <returns>Newly created Collection instance. Never null.</returns> internal object CreateCollectionPropertyInstance(ODataProperty collectionProperty, Type userCollectionType) { Debug.Assert(collectionProperty != null, "collectionProperty != null"); Debug.Assert(collectionProperty.Value != null, "Collection should have already been checked for nullness"); Debug.Assert(userCollectionType != null, "userCollectionType != null"); Debug.Assert(ClientTypeUtil.GetImplementationType(userCollectionType, typeof(ICollection <>)) != null, "Not a Collection - Collection types must implement ICollection<> interface."); Debug.Assert( !ClientTypeUtil.TypeIsEntity(ClientTypeUtil.GetImplementationType(userCollectionType, typeof(ICollection <>)).GetGenericArguments()[0], this.materializerContext.Model), "Not a Collection - Collections cannot contain entities"); Debug.Assert(!(collectionProperty.Value is ODataResourceSet) && !(collectionProperty.Value is ODataResource), "Collection properties should never materialized from entry or feed payload"); ODataCollectionValue collectionValue = collectionProperty.Value as ODataCollectionValue; // get a ClientType instance for the Collection property. This determines what type will be used later when creating the actual Collection instance ClientTypeAnnotation collectionClientType = this.materializerContext.ResolveTypeForMaterialization(userCollectionType, collectionValue.TypeName); return(this.CreateCollectionInstance(collectionClientType.EdmTypeReference as IEdmCollectionTypeReference, collectionClientType.ElementType, () => DSClient.Strings.AtomMaterializer_NoParameterlessCtorForCollectionProperty(collectionProperty.Name, collectionClientType.ElementTypeName))); }
/// <summary> /// Checks if the provided type is a collection type (i.e. it implements ICollection and the collection item type is not an entity). /// </summary> /// <param name="type">Type being checked.</param> /// <param name="model">The client model.</param> /// <returns>True if the CLR type is a collection compatible type. False otherwise.</returns> internal static bool IsCLRTypeCollection(Type type, ClientEdmModel model) { // char[] and byte[] implements ICollection<> but we should not threat them as collections since they are primitive types for us. if (!PrimitiveType.IsKnownNullableType(type)) { Type collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>)); if (collectionType != null) { // collectionType is ICollection so we know that the first generic parameter // is the collection item type if (!ClientTypeUtil.TypeIsEntity(collectionType.GetGenericArguments()[0], model)) { return(true); } } } return(false); }
/// <summary> /// Validates the specified <paramref name="property"/> matches /// the parsed <paramref name="link"/>. /// </summary> /// <param name="property">Property as understood by the type system.</param> /// <param name="link">Property as parsed.</param> /// <param name="model">Client Model.</param> /// <param name="performEntityCheck">whether to do the entity check or not.</param> /// <returns>The type</returns> internal static Type ValidatePropertyMatch(ClientPropertyAnnotation property, ODataNavigationLink link, ClientEdmModel model, bool performEntityCheck) { Debug.Assert(property != null, "property != null"); Debug.Assert(link != null, "link != null"); Type propertyType = null; if (link.IsCollection.HasValue) { if (link.IsCollection.Value) { // We need to fail if the payload states that the property is a navigation collection property // and in the client, the property is not a collection property. if (!property.IsEntityCollection) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkFeedPropertyNotCollection(property.PropertyName)); } propertyType = property.EntityCollectionItemType; } else { if (property.IsEntityCollection) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MismatchAtomLinkEntryPropertyIsCollection(property.PropertyName)); } propertyType = property.PropertyType; } } // If the server type and the client type does not match, we need to throw. // This is a breaking change from V1/V2 where we allowed materialization of entities into non-entities and vice versa if (propertyType != null && performEntityCheck) { if (!ClientTypeUtil.TypeIsEntity(propertyType, model)) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidNonEntityType(propertyType.ToString())); } } return(propertyType); }
/// <summary> /// Gets the type that of the instances that will be returned by materializer. /// </summary> /// <param name="expectingPrimitiveValue">Whether the expected is a primitive type.</param> /// <param name="elementType">Actual type on the client.</param> /// <param name="model">The client model used.</param> /// <param name="implementationType">The actual type that implements ICollection<></param> /// <returns>Type of the instances that will be returned by materializer.</returns> /// <remarks> /// For collection navigation properties (i.e. ICollection<T> where T is an entity the method returns T. Materializer will /// return single entity each time MoveNext() is called. However for collection properties we need the whole property instead of just a /// single collection item. /// </remarks> private static Type GetTypeForMaterializer(bool expectingPrimitiveValue, Type elementType, ClientEdmModel model, out Type implementationType) { if (!expectingPrimitiveValue && typeof(IEnumerable).IsAssignableFrom(elementType)) { implementationType = ClientTypeUtil.GetImplementationType(elementType, typeof(ICollection <>)); if (implementationType != null) { Type expectedType = implementationType.GetGenericArguments()[0]; // already know its ICollection<> // We should use the inner type only if this is a collection of entities (as opposed to a collection of primitive or complex types) if (ClientTypeUtil.TypeIsEntity(expectedType, model)) { return(expectedType); } } } implementationType = null; return(elementType); }
/// <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); }
internal IEnumerable <ODataProperty> PopulateProperties(ClientTypeAnnotation type, object resource, List <object> visitedComplexTypeObjects) { List <ODataProperty> list = new List <ODataProperty>(); foreach (ClientPropertyAnnotation annotation in from p in type.Properties() orderby p.PropertyName select p) { if (((!annotation.IsDictionary && (annotation != type.MediaDataMember)) && !annotation.IsStreamLinkProperty) && ((type.MediaDataMember == null) || (type.MediaDataMember.MimeTypeProperty != annotation))) { object propertyValue = annotation.GetValue(resource); if (annotation.IsKnownType) { ODataProperty item = new ODataProperty { Name = annotation.EdmProperty.Name, Value = GetPrimitiveValue(propertyValue, annotation.PropertyType) }; list.Add(item); } else if (annotation.IsPrimitiveOrComplexCollection) { ODataProperty property2 = new ODataProperty { Name = annotation.EdmProperty.Name, Value = this.CreateODataCollectionPropertyValue(annotation, propertyValue, visitedComplexTypeObjects) }; list.Add(property2); } else if (!annotation.IsEntityCollection && !ClientTypeUtil.TypeIsEntity(annotation.PropertyType, this.requestInfo.MaxProtocolVersion)) { ODataProperty property3 = new ODataProperty { Name = annotation.EdmProperty.Name, Value = this.CreateODataComplexPropertyValue(annotation, propertyValue, visitedComplexTypeObjects) }; list.Add(property3); } } } return(list); }
/// <summary> /// Attach entity into the context in the Unchanged state. /// </summary> /// <param name="entityDescriptorFromMaterializer">entity descriptor from the response</param> /// <param name="failIfDuplicated">fail for public api else change existing relationship to unchanged</param> /// <remarks>Caller should validate descriptor instance.</remarks> /// <returns>The attached descriptor, if one already exists in the context and failIfDuplicated is set to false, then the existing instance is returned</returns> /// <exception cref="InvalidOperationException">if entity is already being tracked by the context</exception> /// <exception cref="InvalidOperationException">if identity is pointing to another entity</exception> internal override EntityDescriptor InternalAttachEntityDescriptor(EntityDescriptor entityDescriptorFromMaterializer, bool failIfDuplicated) { Debug.Assert(entityDescriptorFromMaterializer.Identity != null, "must have identity"); Debug.Assert(entityDescriptorFromMaterializer.Entity != null && ClientTypeUtil.TypeIsEntity(entityDescriptorFromMaterializer.Entity.GetType(), this.model), "must be entity type to attach"); this.EnsureIdentityToResource(); EntityDescriptor trackedEntityDescriptor; this.entityDescriptors.TryGetValue(entityDescriptorFromMaterializer.Entity, out trackedEntityDescriptor); EntityDescriptor existing; this.identityToDescriptor.TryGetValue(entityDescriptorFromMaterializer.Identity, out existing); // identity existing & pointing to something else if (failIfDuplicated && (trackedEntityDescriptor != null)) { throw Error.InvalidOperation(Strings.Context_EntityAlreadyContained); } else if (trackedEntityDescriptor != existing) { throw Error.InvalidOperation(Strings.Context_DifferentEntityAlreadyContained); } else if (trackedEntityDescriptor == null) { trackedEntityDescriptor = entityDescriptorFromMaterializer; // if resource doesn't exist... this.IncrementChange(entityDescriptorFromMaterializer); this.entityDescriptors.Add(entityDescriptorFromMaterializer.Entity, entityDescriptorFromMaterializer); this.identityToDescriptor.Add(entityDescriptorFromMaterializer.Identity, entityDescriptorFromMaterializer); } // DEVNOTE(pqian): // we used to mark the descriptor as Unchanged // but it's now up to the caller to do that return(trackedEntityDescriptor); }
/// <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="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, HashSet <object> visitedComplexTypeObjects, out ODataValue odataValue) { if (property.IsKnownType) { odataValue = CreateODataPrimitivePropertyValue(property, propertyValue); return(true); } if (property.IsPrimitiveOrComplexCollection) { odataValue = this.CreateODataCollectionPropertyValue(property, propertyValue, 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); }
/// <summary> /// Checks if the provided type is a collection type (i.e. it implements ICollection and the collection item type is not an entity). /// </summary> /// <param name="type">Type being checked.</param> /// <param name="model">The client model.</param> /// <returns>True if the CLR type is a collection compatible type. False otherwise.</returns> internal static bool IsCLRTypeCollection(Type type, ClientEdmModel model) { // char[] and byte[] implements ICollection<> but we should not threat them as collections since they are primitive types for us. if (!PrimitiveType.IsKnownNullableType(type)) { Type collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>)); if (collectionType != null) { // collectionType is ICollection so we know that the first generic parameter // is the collection item type if (!ClientTypeUtil.TypeIsEntity(collectionType.GetGenericArguments()[0], model)) { if (model.MaxProtocolVersion <= DataServiceProtocolVersion.V2) { throw new InvalidOperationException(Strings.WebUtil_CollectionTypeNotSupportedInV2OrBelow(type.FullName)); } return(true); } } } return(false); }
/// <summary> /// Applies the collection data values to a collection instance. /// </summary> /// <param name="items">The items.</param> /// <param name="wireTypeName">Name of the wire type.</param> /// <param name="collectionInstance">The collection instance.</param> /// <param name="collectionItemType">Type of the collection item.</param> /// <param name="addValueToBackingICollectionInstance">The add value to backing I collection instance.</param> internal void ApplyCollectionDataValues(IEnumerable items, string wireTypeName, object collectionInstance, Type collectionItemType, Action <object, object> addValueToBackingICollectionInstance) { Debug.Assert(collectionInstance != null, "collectionInstance != null"); Debug.Assert(WebUtil.IsCLRTypeCollection(collectionInstance.GetType(), this.materializerContext.Model), "collectionInstance must be a CollectionValue"); Debug.Assert( ClientTypeUtil.GetImplementationType(collectionInstance.GetType(), typeof(ICollection <>)).GetGenericArguments()[0] == collectionItemType, "collectionItemType has to match the collectionInstance generic type."); Debug.Assert(!ClientTypeUtil.TypeIsEntity(collectionItemType, this.materializerContext.Model), "CollectionValues cannot contain entities"); Debug.Assert(addValueToBackingICollectionInstance != null, "AddValueToBackingICollectionInstance != null"); // is the Collection not empty ? if (items != null) { bool isCollectionItemTypePrimitive = PrimitiveType.IsKnownNullableType(collectionItemType); var edmModel = this.materializerContext.Model; foreach (object item in items) { if (item == null) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_NullCollectionItemsNotSupported); } ODataComplexValue complexValue = item as ODataComplexValue; // Is it a Collection of primitive types? if (isCollectionItemTypePrimitive) { // verify that the Collection does not contain complex type items if (complexValue != null || item is ODataCollectionValue) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_ComplexTypesInCollectionOfPrimitiveTypesNotAllowed); } object materializedValue = this.primitiveValueMaterializationPolicy.MaterializePrimitiveDataValueCollectionElement(collectionItemType, wireTypeName, item); addValueToBackingICollectionInstance(collectionInstance, materializedValue); } else { // verify that the Collection does not contain primitive values if (complexValue == null) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_PrimitiveTypesInCollectionOfComplexTypesNotAllowed); } // Derived complex types are not supported. We create the base type here and we will fail later when trying to materialize the value of a // property that is on the derived type but not on the base type (unless IgnoreMissingProperty setting is set to true). This is by design. ClientTypeAnnotation complexType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(collectionItemType)); object complexInstance = this.CreateNewInstance(complexType.EdmTypeReference, complexType.ElementType); // set properties with metarialized data values if there are any (note that for a payload that looks as follows <element xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices"/> // and represents an item that is a complex type there are no properties to be set) this.ComplexValueMaterializationPolicy.ApplyDataValues(complexType, complexValue.Properties, complexInstance); addValueToBackingICollectionInstance(collectionInstance, complexInstance); } } } }
private static bool ShouldTrackWithContext(object entity, DataServiceProtocolVersion maxProtocolVersion) { return((entity == null) || ClientTypeUtil.TypeIsEntity(entity.GetType(), maxProtocolVersion)); }
/// <summary> /// Applies the collection data values to a collection instance. /// </summary> /// <param name="items">The items.</param> /// <param name="wireTypeName">Name of the wire type.</param> /// <param name="collectionInstance">The collection instance.</param> /// <param name="collectionItemType">Type of the collection item.</param> /// <param name="addValueToBackingICollectionInstance">The add value to backing I collection instance.</param> /// <param name="isElementNullable">If element type is nullable.</param> internal void ApplyCollectionDataValues( IEnumerable items, string wireTypeName, object collectionInstance, Type collectionItemType, Action <object, object> addValueToBackingICollectionInstance, bool isElementNullable) { Debug.Assert(collectionInstance != null, "collectionInstance != null"); Debug.Assert(WebUtil.IsCLRTypeCollection(collectionInstance.GetType(), this.materializerContext.Model), "collectionInstance must be a CollectionValue"); Debug.Assert(collectionItemType.IsAssignableFrom( ClientTypeUtil.GetImplementationType(collectionInstance.GetType(), typeof(ICollection <>)).GetGenericArguments()[0]), "collectionItemType has to match the collectionInstance generic type."); Debug.Assert(!ClientTypeUtil.TypeIsEntity(collectionItemType, this.materializerContext.Model), "CollectionValues cannot contain entities"); Debug.Assert(addValueToBackingICollectionInstance != null, "AddValueToBackingICollectionInstance != null"); // is the Collection not empty ? if (items != null) { bool isCollectionItemTypePrimitive = PrimitiveType.IsKnownNullableType(collectionItemType); foreach (object item in items) { if (!isElementNullable && item == null) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_NullCollectionItemsNotSupported); } ODataComplexValue complexValue = item as ODataComplexValue; ODataEnumValue enumVal = null; // Is it a Collection of primitive types? if (isCollectionItemTypePrimitive) { // verify that the Collection does not contain complex type items if (complexValue != null || item is ODataCollectionValue) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_ComplexTypesInCollectionOfPrimitiveTypesNotAllowed); } object materializedValue = this.primitiveValueMaterializationPolicy.MaterializePrimitiveDataValueCollectionElement(collectionItemType, wireTypeName, item); addValueToBackingICollectionInstance(collectionInstance, materializedValue); } else if ((enumVal = item as ODataEnumValue) != null) { // TODO: use EnumValueMaterializationPolicy.MaterializeEnumDataValueCollectionElement() here object tmpValue = EnumValueMaterializationPolicy.MaterializeODataEnumValue(collectionItemType, enumVal); addValueToBackingICollectionInstance(collectionInstance, tmpValue); } else { // verify that the Collection does not contain primitive values if (item != null && complexValue == null) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_PrimitiveTypesInCollectionOfComplexTypesNotAllowed); } if (item != null) { ClientTypeAnnotation complexType = this.materializerContext.ResolveTypeForMaterialization(collectionItemType, complexValue.TypeName); object complexInstance = this.CreateNewInstance(complexType.EdmTypeReference, complexType.ElementType); // set properties with metarialized data values if there are any (note that for a payload that looks as follows <element xmlns="http://docs.oasis-open.org/odata/ns/data"/> // and represents an item that is a complex type there are no properties to be set) this.ComplexValueMaterializationPolicy.ApplyDataValues(complexType, complexValue.Properties, complexInstance); addValueToBackingICollectionInstance(collectionInstance, complexInstance); // Apply instance annotation for complex type item if (!this.materializerContext.Context.DisableInstanceAnnotationMaterialization) { this.InstanceAnnotationMaterializationPolicy.SetInstanceAnnotations(complexValue, complexInstance); } } else { addValueToBackingICollectionInstance(collectionInstance, null); } } } } }