Example #1
0
        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()));
            }
        }
Example #2
0
        /// <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&lt;T&gt; 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);
        }
Example #3
0
        /// <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);
                    }
                }
            }
        }
Example #4
0
        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);
        }
Example #5
0
        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));
        }
Example #6
0
        /// <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));
        }
Example #8
0
 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);
 }
Example #9
0
        /// <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()));
                }
            }
        }
Example #10
0
        /// <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);
        }
Example #11
0
 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);
 }
Example #12
0
        /// <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)));
        }
Example #13
0
        /// <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);
        }
Example #14
0
        /// <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);
        }
Example #15
0
        /// <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&lt;&gt;</param>
        /// <returns>Type of the instances that will be returned by materializer.</returns>
        /// <remarks>
        /// For collection navigation properties (i.e. ICollection&lt;T&gt; 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);
        }
Example #17
0
        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);
        }
Example #18
0
        /// <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);
        }
Example #19
0
        /// <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);
        }
Example #20
0
        /// <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);
        }
Example #21
0
        /// <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);
                    }
                }
            }
        }
Example #22
0
 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);
                        }
                    }
                }
            }
        }