Esempio n. 1
0
        /// <summary>
        /// Reads a value from the message reader.
        /// </summary>
        /// <param name="expectedClientType">The expected client type being materialized into.</param>
        /// <param name="expectedReaderType">The expected type for the underlying reader.</param>
        protected override void ReadWithExpectedType(IEdmTypeReference expectedClientType, IEdmTypeReference expectedReaderType)
        {
            ODataProperty property = this.messageReader.ReadProperty(expectedReaderType);
            Type          underlyingExpectedType = Nullable.GetUnderlyingType(this.ExpectedType) ?? this.ExpectedType;

            object propertyValue = property.Value;

            if (expectedClientType.IsCollection())
            {
                Debug.Assert(WebUtil.IsCLRTypeCollection(underlyingExpectedType, this.MaterializerContext.Model) || (SingleResult.HasValue && !SingleResult.Value), "expected type must be collection or single result must be false");

                // We are here for two cases:
                // (1) Something like Execute<ICollection<T>>, in which case the underlyingExpectedType is ICollection<T>
                // (2) Execute<T> with the bool singleValue = false, in which case underlyingExpectedType is T
                Type   collectionItemType        = underlyingExpectedType;
                Type   collectionICollectionType = ClientTypeUtil.GetImplementationType(underlyingExpectedType, typeof(ICollection <>));
                object collectionInstance;

                if (collectionICollectionType != null)
                {
                    // Case 1
                    collectionItemType = collectionICollectionType.GetGenericArguments()[0];
                    collectionInstance = this.CollectionValueMaterializationPolicy.CreateCollectionPropertyInstance(property, underlyingExpectedType);
                }
                else
                {
                    // Case 2
                    collectionICollectionType = typeof(ICollection <>).MakeGenericType(new Type[] { collectionItemType });
                    collectionInstance        = this.CollectionValueMaterializationPolicy.CreateCollectionPropertyInstance(property, collectionICollectionType);
                }

                bool isElementNullable = expectedClientType.AsCollection().ElementType().IsNullable;
                this.CollectionValueMaterializationPolicy.ApplyCollectionDataValues(
                    property,
                    collectionInstance,
                    collectionItemType,
                    ClientTypeUtil.GetAddToCollectionDelegate(collectionICollectionType),
                    isElementNullable);

                this.currentValue = collectionInstance;
            }
            else if (expectedClientType.IsComplex())
            {
                ODataComplexValue complexValue = propertyValue as ODataComplexValue;
                Debug.Assert(this.MaterializerContext.Model.GetOrCreateEdmType(underlyingExpectedType).ToEdmTypeReference(false).IsComplex(), "expectedType must be complex type");

                this.ComplexValueMaterializationPolicy.MaterializeComplexTypeProperty(underlyingExpectedType, complexValue);
                this.currentValue = complexValue.GetMaterializedValue();
            }
            else if (expectedClientType.IsEnum())
            {
                this.currentValue = this.EnumValueMaterializationPolicy.MaterializeEnumTypeProperty(underlyingExpectedType, property);
            }
            else
            {
                Debug.Assert(this.MaterializerContext.Model.GetOrCreateEdmType(underlyingExpectedType).ToEdmTypeReference(false).IsPrimitive(), "expectedType must be primitive type");
                this.currentValue = this.PrimitivePropertyConverter.ConvertPrimitiveValue(property.Value, this.ExpectedType);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Resolves the client type that should be used for materialization.
        /// </summary>
        /// <param name="expectedType">Expected client clr type based on the API called.</param>
        /// <param name="readerTypeName">
        /// The name surfaced by the ODataLib reader.
        /// If we have a server model, this will be a server type name that needs to be resolved.
        /// If not, then this will already be a client type name.</param>
        /// <returns>The resolved annotation for the client type to materialize into.</returns>
        internal ClientTypeAnnotation ResolveTypeForMaterialization(Type expectedType, string readerTypeName)
        {
            // If its a collection, get the collection item name
            string collectionItemTypeName = WebUtil.GetCollectionItemWireTypeName(readerTypeName);

            if (collectionItemTypeName == null)
            {
                // Resolve the primitive type first
                PrimitiveType primitiveType;
                if (PrimitiveType.TryGetPrimitiveType(readerTypeName, out primitiveType))
                {
                    return(this.clientEdmModel.GetClientTypeAnnotation(primitiveType.ClrType));
                }

                ClientTypeAnnotation resultType;
                if (this.edmTypeNameMap.TryGetValue(readerTypeName, out resultType))
                {
                    return(resultType);
                }

                if (this.serviceModel != null)
                {
                    var resolvedType = this.ResolveTypeFromName(readerTypeName, expectedType);
                    return(this.clientEdmModel.GetClientTypeAnnotation(resolvedType));
                }

                // If there was no type name specified in the payload, then the type resolver won't be invoked
                // and hence that edm type name might not be in the resolver cache. Hence look that up in the
                // ClientEdmModel cache. This lookup is more expensive and is unique across the app domain for the
                // given version.
                return(this.clientEdmModel.GetClientTypeAnnotation(readerTypeName));
            }

            Type collectionImplementationType = ClientTypeUtil.GetImplementationType(expectedType, typeof(ICollection <>));
            Type collectionElementType        = collectionImplementationType.GetGenericArguments()[0];

            // In case of collection, the expectedType might be collection of nullable types (for e.g. ICollection<int?>).
            // There is no way to know the nullability from the wireTypeName (For e.g. Collection(Edm.Int32)).
            // Hence in case of collections of primitives, we need to look at the element type of the expected type
            // and use that to create the instance otherwise we will not be able to assign the created ICollection<>
            // instance to the property on the user's entity (ICollection<int> cannot be assigned to ICollection<int?>).
            // There is also no need to invoke the resolver for primitives, so we just use the element type.
            if (!PrimitiveType.IsKnownType(collectionElementType))
            {
                collectionElementType = this.ResolveTypeForMaterialization(collectionElementType, collectionItemTypeName).ElementType;
            }

            Type clrCollectionType = WebUtil.GetBackingTypeForCollectionProperty(expectedType);

            return(this.clientEdmModel.GetClientTypeAnnotation(clrCollectionType));
        }
Esempio n. 3
0
        /// <summary>
        /// Reads a value from the message reader.
        /// </summary>
        /// <param name="expectedClientType">The expected client type being materialized into.</param>
        /// <param name="expectedReaderType">The expected type for the underlying reader.</param>
        protected override void ReadWithExpectedType(IEdmTypeReference expectedClientType, IEdmTypeReference expectedReaderType)
        {
            if (!expectedClientType.IsCollection())
            {
                throw new DataServiceClientException(DSClient.Strings.AtomMaterializer_TypeShouldBeCollectionError(expectedClientType.FullName()));
            }

            Type underlyingExpectedType = Nullable.GetUnderlyingType(this.ExpectedType) ?? this.ExpectedType;

            Debug.Assert(WebUtil.IsCLRTypeCollection(underlyingExpectedType, this.MaterializerContext.Model) ||
                         (SingleResult.HasValue && !SingleResult.Value), "expected type must be collection or single result must be false");

            // We are here for two cases:
            // (1) Something like Execute<ICollection<T>>, in which case the underlyingExpectedType is ICollection<T>
            // (2) Execute<T> with the bool singleValue = false, in which case underlyingExpectedType is T
            Type collectionItemType        = underlyingExpectedType;
            Type collectionICollectionType = ClientTypeUtil.GetImplementationType(underlyingExpectedType, typeof(ICollection <>));

            if (collectionICollectionType != null)
            {
                // Case 1 : Something like Execute<ICollection<T>>, in which case the underlyingExpectedType is ICollection<T>
                collectionItemType = collectionICollectionType.GetGenericArguments()[0];
            }
            else
            {
                // Case 2 : Execute<T> with the bool singleValue = false, in which case underlyingExpectedType is T
                collectionICollectionType = typeof(ICollection <>).MakeGenericType(new Type[] { collectionItemType });
            }

            Type   clrCollectionType  = WebUtil.GetBackingTypeForCollectionProperty(collectionICollectionType);
            object collectionInstance = this.CollectionValueMaterializationPolicy.CreateCollectionInstance((IEdmCollectionTypeReference)expectedClientType, clrCollectionType);

            // Enumerator over our collection reader was created, then ApplyDataCollections was refactored to
            // take an enumerable instead of a ODataCollectionValue. Enumerator is being used as a bridge
            ODataCollectionReader    collectionReader     = messageReader.CreateODataCollectionReader();
            NonEntityItemsEnumerable collectionEnumerable = new NonEntityItemsEnumerable(collectionReader);

            bool isElementNullable = expectedClientType.AsCollection().ElementType().IsNullable;

            this.CollectionValueMaterializationPolicy.ApplyCollectionDataValues(
                collectionEnumerable,
                null /*wireTypeName*/,
                collectionInstance,
                collectionItemType,
                ClientTypeUtil.GetAddToCollectionDelegate(collectionICollectionType),
                isElementNullable);

            this.currentValue = collectionInstance;
        }
Esempio n. 4
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);
 }
Esempio n. 5
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);
 }
Esempio n. 6
0
        /// <summary>
        /// Serializes an MemberExpression to a string
        /// </summary>
        /// <param name="m">Expression to serialize</param>
        /// <returns>MemberExpression</returns>
        internal override Expression VisitMemberAccess(MemberExpression m)
        {
            if (m.Member is FieldInfo)
            {
                throw new NotSupportedException(Strings.ALinq_CantReferToPublicField(m.Member.Name));
            }

            Expression e = this.Visit(m.Expression);

            // if this is a Nullable<T> instance, don't write out /Value since not supported by server
            if (m.Member.Name == "Value" && m.Member.DeclaringType.IsGenericType() &&
                m.Member.DeclaringType.GetGenericTypeDefinition() == typeof(Nullable <>))
            {
                return(m);
            }

            // if this is a GetValueAsync().Result call in async scenario, don't write out /Result
            MethodCallExpression methodCallExpression = m.Expression as MethodCallExpression;

            if (methodCallExpression != null && methodCallExpression.Method.Name == "GetValueAsync" && m.Member.Name == "Result")
            {
                return(m);
            }

            if (!this.IsImplicitInputReference(e) || writingFunctionsInQuery)
            {
                this.builder.Append(UriHelper.FORWARDSLASH);
            }

            // If the member is collection with count property, it will be parsed as $count segment
            var  parentType     = m.Member.DeclaringType;
            Type collectionType = ClientTypeUtil.GetImplementationType(parentType, typeof(ICollection <>));

            if (!PrimitiveType.IsKnownNullableType(parentType) && collectionType != null &&
                m.Member.Name.Equals(ReflectionUtil.COUNTPROPNAME, StringComparison.Ordinal))
            {
                this.builder.Append(UriHelper.DOLLARSIGN).Append(UriHelper.COUNT);
            }
            else
            {
                this.builder.Append(ClientTypeUtil.GetServerDefinedName(m.Member));
            }

            return(m);
        }
Esempio n. 7
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>
        internal void ApplyCollectionDataValues(ODataProperty collectionProperty, object collectionInstance, Type collectionItemType, Action <object, object> addValueToBackingICollectionInstance)
        {
            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(
                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");

            ODataCollectionValue collectionValue = collectionProperty.Value as ODataCollectionValue;

            this.ApplyCollectionDataValues(collectionValue.Items, collectionValue.TypeName, collectionInstance, collectionItemType, addValueToBackingICollectionInstance);

            collectionProperty.SetMaterializedValue(collectionInstance);
        }
Esempio n. 8
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)));
        }
Esempio n. 9
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);
        }
Esempio n. 10
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.TypeIsStructured(expectedType, model))
                    {
                        return(expectedType);
                    }
                }
            }

            implementationType = null;
            return(elementType);
        }
Esempio n. 11
0
        /// <summary>
        /// Resolves and creates if necessary a backing type for the <paramref name="collectionPropertyType"/>.
        /// </summary>
        /// <param name="collectionPropertyType">Type of a collection property as defined by the user - can be just an interface or generic type.</param>
        /// <returns>Resolved concrete type that can be instantiated and will back the collection property. Can be the <paramref name="collectionPropertyType"/> type.</returns>
        internal static Type GetBackingTypeForCollectionProperty(Type collectionPropertyType)
        {
            Debug.Assert(collectionPropertyType != null, "collectionPropertyType != null");
            Debug.Assert(ClientTypeUtil.GetImplementationType(collectionPropertyType, typeof(ICollection <>)) != null, "The type backing a collection has to implement ICollection<> interface.");

            Type collectionBackingType = null;

            // If the user's type is an interface we are using collectionItemType we have just resolved as the generic element type of the ICollection<T> instance (i.e. T).
            // Otherwise we can use directly the type defined by the user.
            // Note that we don't check here if the type we created can be assigned to the user's type. This should be done by the caller (if requested)
            if (collectionPropertyType.IsInterface())
            {
                collectionBackingType = typeof(ObservableCollection <>).MakeGenericType(collectionPropertyType.GetGenericArguments()[0]);
            }
            else
            {
                collectionBackingType = collectionPropertyType;
            }

            Debug.Assert(collectionBackingType != null, "The backing type for collection property must not be null at this point.");

            return(collectionBackingType);
        }
Esempio n. 12
0
        /// <summary>
        /// Returns MethodInfo instance for a generic type retrieved by using <paramref name="methodName"/> and gets
        /// element type for the provided <paramref name="genericTypeDefinition"/>.
        /// </summary>
        /// <param name="propertyType">starting type</param>
        /// <param name="genericTypeDefinition">the generic type definition to find</param>
        /// <param name="methodName">the method to search for</param>
        /// <param name="type">the element type for <paramref name="genericTypeDefinition" /> if found</param>
        /// <returns>element types</returns>
        internal static MethodInfo GetMethodForGenericType(Type propertyType, Type genericTypeDefinition, string methodName, out Type type)
        {
            Debug.Assert(propertyType != null, "null propertyType");
            Debug.Assert(genericTypeDefinition != null, "null genericTypeDefinition");
            Debug.Assert(genericTypeDefinition.IsGenericTypeDefinition(), "!IsGenericTypeDefinition");

            type = null;

            Type implementationType = ClientTypeUtil.GetImplementationType(propertyType, genericTypeDefinition);

            if (implementationType != null)
            {
                Type[]     genericArguments = implementationType.GetGenericArguments();
                MethodInfo methodInfo       = implementationType.GetMethod(methodName);
                Debug.Assert(methodInfo != null, "should have found the method");

#if DEBUG
                Debug.Assert(genericArguments != null, "null genericArguments");
                ParameterInfo[] parameters = methodInfo.GetParameters();
                if (parameters.Length > 0)
                {
                    // following assert was disabled for Contains which returns bool
                    //// Debug.Assert(typeof(void) == methodInfo.ReturnParameter.ParameterType, "method doesn't return void");

                    Debug.Assert(genericArguments.Length == parameters.Length, "genericArguments don't match parameters");
                    for (int i = 0; i < genericArguments.Length; ++i)
                    {
                        Debug.Assert(genericArguments[i] == parameters[i].ParameterType, "parameter doesn't match generic argument");
                    }
                }
#endif
                type = genericArguments[genericArguments.Length - 1];
                return(methodInfo);
            }

            return(null);
        }
Esempio n. 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))
                    {
                        if (model.MaxProtocolVersion <= DataServiceProtocolVersion.V2)
                        {
                            throw new InvalidOperationException(Strings.WebUtil_CollectionTypeNotSupportedInV2OrBelow(type.FullName));
                        }

                        return(true);
                    }
                }
            }

            return(false);
        }
Esempio n. 14
0
        protected override void ReadFromMessageReader(ODataMessageReader reader, IEdmTypeReference expectedType)
        {
            ODataProperty collectionProperty = reader.ReadProperty(expectedType);
            Type          type = Nullable.GetUnderlyingType(base.ExpectedType) ?? base.ExpectedType;
            object        obj2 = collectionProperty.Value;

            if (expectedType.IsCollection())
            {
                object obj3;
                Type   collectionItemType = type;
                Type   implementationType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>));
                if (implementationType != null)
                {
                    collectionItemType = implementationType.GetGenericArguments()[0];
                    obj3 = ODataMaterializer.CreateCollectionInstance(collectionProperty, type, base.ResponseInfo);
                }
                else
                {
                    implementationType = typeof(ICollection <>).MakeGenericType(new Type[] { collectionItemType });
                    obj3 = ODataMaterializer.CreateCollectionInstance(collectionProperty, implementationType, base.ResponseInfo);
                }
                ODataMaterializer.ApplyCollectionDataValues(collectionProperty, base.ResponseInfo.IgnoreMissingProperties, base.ResponseInfo, obj3, collectionItemType, ODataMaterializer.GetAddToCollectionDelegate(implementationType));
                this.currentValue = obj3;
            }
            else if (expectedType.IsComplex())
            {
                ODataComplexValue complexValue = obj2 as ODataComplexValue;
                ODataMaterializer.MaterializeComplexTypeProperty(type, complexValue, base.ResponseInfo.IgnoreMissingProperties, base.ResponseInfo);
                this.currentValue = complexValue.GetMaterializedValue();
            }
            else
            {
                ODataMaterializer.MaterializePrimitiveDataValue(base.ExpectedType, collectionProperty);
                this.currentValue = collectionProperty.GetMaterializedValue();
            }
        }
        /// <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);
                        }
                    }
                }
            }
        }
Esempio n. 16
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);
                    }
                }
            }
        }
Esempio n. 17
0
        private EdmTypeCacheValue GetOrCreateEdmTypeInternal(IEdmStructuredType edmBaseType, Type type, PropertyInfo[] keyProperties, bool isEntity, bool?hasProperties)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(keyProperties != null, "keyProperties != null");

            EdmTypeCacheValue cachedEdmType;

            lock (this.clrToEdmTypeCache)
            {
                this.clrToEdmTypeCache.TryGetValue(type, out cachedEdmType);
            }

            if (cachedEdmType == null)
            {
                Type collectionType;
                if (PrimitiveType.IsKnownNullableType(type))
                {
                    PrimitiveType primitiveType;
                    PrimitiveType.TryGetPrimitiveType(type, out primitiveType);
                    Debug.Assert(primitiveType != null, "primitiveType != null");
                    cachedEdmType = new EdmTypeCacheValue(primitiveType.CreateEdmPrimitiveType(), hasProperties);
                }
                else if ((collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>))) != null && ClientTypeUtil.GetImplementationType(type, typeof(IDictionary <,>)) == null)
                {
                    // Collection Type
                    Type     elementType = collectionType.GetGenericArguments()[0];
                    IEdmType itemType    = this.GetOrCreateEdmType(elementType);

                    // Note that
                    // 1. throw here because collection of a collection is not allowed
                    // 2. will also throw during SaveChanges(), validated by unit test case 'SerializationOfCollection'in CollectionTests.cs.
                    if ((itemType.TypeKind == EdmTypeKind.Collection))
                    {
                        throw new ODataException(Strings.ClientType_CollectionOfCollectionNotSupported);
                    }

                    cachedEdmType = new EdmTypeCacheValue(new EdmCollectionType(itemType.ToEdmTypeReference(ClientTypeUtil.CanAssignNull(elementType))), hasProperties);
                }
                else
                {
                    Type enumTypeTmp = null;
                    if (isEntity)
                    {
                        Action <EdmEntityTypeWithDelayLoadedProperties> delayLoadEntityProperties = (entityType) =>
                        {
                            // Create properties without modifying the entityType.
                            // This will leave entityType intact in case of an exception during loading.
                            List <IEdmProperty>           loadedProperties    = new List <IEdmProperty>();
                            List <IEdmStructuralProperty> loadedKeyProperties = new List <IEdmStructuralProperty>();
                            foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name))
                            {
                                IEdmProperty edmProperty = this.CreateEdmProperty((EdmStructuredType)entityType, property);
                                loadedProperties.Add(edmProperty);

                                if (edmBaseType == null && keyProperties.Any(k => k.DeclaringType == type && k.Name == property.Name))
                                {
                                    Debug.Assert(edmProperty.PropertyKind == EdmPropertyKind.Structural, "edmProperty.PropertyKind == EdmPropertyKind.Structural");
                                    Debug.Assert(edmProperty.Type.TypeKind() == EdmTypeKind.Primitive, "edmProperty.Type.TypeKind() == EdmTypeKind.Primitive");
                                    loadedKeyProperties.Add((IEdmStructuralProperty)edmProperty);
                                }
                            }

                            // Now add properties to the entityType.
                            foreach (IEdmProperty property in loadedProperties)
                            {
                                entityType.AddProperty(property);
                            }

                            entityType.AddKeys(loadedKeyProperties);
                        };

                        // Creating an entity type
                        Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Entity, "baseType == null || baseType.TypeKind == EdmTypeKind.Entity");
                        bool hasStream = GetHasStreamValue((IEdmEntityType)edmBaseType, type);
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmEntityTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmEntityType)edmBaseType, c.PlatformHelper.IsAbstract(type), /*isOpen*/ false, hasStream, delayLoadEntityProperties),
                            hasProperties);
                    }
                    else if ((enumTypeTmp = Nullable.GetUnderlyingType(type) ?? type) != null &&
                             enumTypeTmp.IsEnum())
                    {
                        Action <EdmEnumTypeWithDelayLoadedMembers> delayLoadEnumMembers = (enumType) =>
                        {
#if WINRT
                            foreach (FieldInfo tmp in enumTypeTmp.GetFields().Where(fieldInfo => fieldInfo.IsStatic))
#else
                            foreach (FieldInfo tmp in enumTypeTmp.GetFields(BindingFlags.Static | BindingFlags.Public))
#endif
                            {
                                object memberValue = Enum.Parse(enumTypeTmp, tmp.Name, false);
                                enumType.AddMember(new EdmEnumMember(enumType, tmp.Name, new EdmIntegerConstant((long)Convert.ChangeType(memberValue, typeof(long), CultureInfo.InvariantCulture.NumberFormat))));
                            }
                        };

                        // underlying type may be Edm.Byte, Edm.SByte, Edm.Int16, Edm.Int32, or Edm.Int64.
                        Type underlyingType = Enum.GetUnderlyingType(enumTypeTmp);
                        IEdmPrimitiveType underlyingEdmType = (IEdmPrimitiveType)EdmCoreModel.Instance.FindDeclaredType("Edm." + underlyingType.Name);
                        Debug.Assert(underlyingEdmType != null, "underlyingEdmType != null");
                        bool isFlags = enumTypeTmp.GetCustomAttributes(false).Any(s => s is FlagsAttribute);
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmEnumTypeWithDelayLoadedMembers(CommonUtil.GetModelTypeNamespace(enumTypeTmp), CommonUtil.GetModelTypeName(enumTypeTmp), underlyingEdmType, isFlags, delayLoadEnumMembers),
                            null);
                    }
                    else
                    {
                        Action <EdmComplexTypeWithDelayLoadedProperties> delayLoadComplexProperties = (complexType) =>
                        {
                            // Create properties without modifying the complexType.
                            // This will leave complexType intact in case of an exception during loading.
                            List <IEdmProperty> loadedProperties = new List <IEdmProperty>();
                            foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name))
                            {
                                IEdmProperty edmProperty = this.CreateEdmProperty(complexType, property);
                                loadedProperties.Add(edmProperty);
                            }

                            // Now add properties to the complexType.
                            foreach (IEdmProperty property in loadedProperties)
                            {
                                complexType.AddProperty(property);
                            }
                        };

                        // Creating a complex type
                        Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Complex, "baseType == null || baseType.TypeKind == EdmTypeKind.Complex");
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmComplexTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmComplexType)edmBaseType, c.PlatformHelper.IsAbstract(type), /*isOpen*/ false, delayLoadComplexProperties),
                            hasProperties);
                    }
                }

                Debug.Assert(cachedEdmType != null, "cachedEdmType != null");

                IEdmType             edmType = cachedEdmType.EdmType;
                ClientTypeAnnotation clientTypeAnnotation = this.GetOrCreateClientTypeAnnotation(edmType, type);
                this.SetClientTypeAnnotation(edmType, clientTypeAnnotation);

                if (edmType.TypeKind == EdmTypeKind.Entity || edmType.TypeKind == EdmTypeKind.Complex)
                {
                    IEdmStructuredType edmStructuredType = edmType as IEdmStructuredType;
                    Debug.Assert(edmStructuredType != null, "edmStructuredType != null");
                    this.SetMimeTypeForProperties(edmStructuredType);
                }

                // Need to cache the type before loading the properties so we don't stack overflow because
                // loading the property can trigger calls to GetOrCreateEdmType on the same type.
                lock (this.clrToEdmTypeCache)
                {
                    EdmTypeCacheValue existing;
                    if (this.clrToEdmTypeCache.TryGetValue(type, out existing))
                    {
                        cachedEdmType = existing;
                    }
                    else
                    {
                        this.clrToEdmTypeCache.Add(type, cachedEdmType);
                    }
                }
            }

            return(cachedEdmType);
        }
Esempio n. 18
0
        internal static object ProjectionValueForPath(ODataEntityMaterializer materializer, MaterializerEntry entry, Type expectedType, ProjectionPath path)
        {
            if ((path.Count == 0) || ((path.Count == 1) && (path[0].Member == null)))
            {
                if (!entry.EntityHasBeenResolved)
                {
                    materializer.Materialize(entry, expectedType, false);
                }
                return(entry.ResolvedObject);
            }
            object streamLink                = null;
            ODataNavigationLink link         = null;
            ODataProperty       atomProperty = null;
            ICollection <ODataNavigationLink> navigationLinks = entry.NavigationLinks;
            IEnumerable <ODataProperty>       properties      = entry.Entry.Properties;
            ClientEdmModel model = ClientEdmModel.GetModel(materializer.ResponseInfo.MaxProtocolVersion);

            for (int i = 0; i < path.Count; i++)
            {
                Func <StreamDescriptor, bool>    predicate = null;
                Func <ODataNavigationLink, bool> func2     = null;
                Func <ODataProperty, bool>       func3     = null;
                Func <ODataProperty, bool>       func4     = null;
                Func <ODataNavigationLink, bool> func5     = null;
                string propertyName;
                ProjectionPathSegment segment = path[i];
                if (segment.Member != null)
                {
                    bool flag = i == (path.Count - 1);
                    propertyName = segment.Member;
                    expectedType = segment.SourceTypeAs ?? expectedType;
                    ClientPropertyAnnotation property = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(expectedType)).GetProperty(propertyName, false);
                    if (property.IsStreamLinkProperty)
                    {
                        if (predicate == null)
                        {
                            predicate = sd => sd.Name == propertyName;
                        }
                        StreamDescriptor descriptor = entry.EntityDescriptor.StreamDescriptors.Where <StreamDescriptor>(predicate).SingleOrDefault <StreamDescriptor>();
                        if (descriptor == null)
                        {
                            if (segment.SourceTypeAs == null)
                            {
                                throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_PropertyMissing(propertyName, entry.Entry.Id));
                            }
                            return(WebUtil.GetDefaultValue <DataServiceStreamLink>());
                        }
                        streamLink = descriptor.StreamLink;
                    }
                    else
                    {
                        if (segment.SourceTypeAs != null)
                        {
                            if (func2 == null)
                            {
                                func2 = p => p.Name == propertyName;
                            }
                            if (!navigationLinks.Any <ODataNavigationLink>(func2))
                            {
                                if (func3 == null)
                                {
                                    func3 = p => p.Name == propertyName;
                                }
                                if (!properties.Any <ODataProperty>(func3) && flag)
                                {
                                    return(WebUtil.GetDefaultValue(property.PropertyType));
                                }
                            }
                        }
                        if (func4 == null)
                        {
                            func4 = p => p.Name == propertyName;
                        }
                        atomProperty = properties.Where <ODataProperty>(func4).FirstOrDefault <ODataProperty>();
                        if (func5 == null)
                        {
                            func5 = p => p.Name == propertyName;
                        }
                        link = ((atomProperty == null) && (navigationLinks != null)) ? navigationLinks.Where <ODataNavigationLink>(func5).FirstOrDefault <ODataNavigationLink>() : null;
                        if ((link == null) && (atomProperty == null))
                        {
                            throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_PropertyMissing(propertyName, entry.Entry.Id));
                        }
                        if (link != null)
                        {
                            ValidatePropertyMatch(property, link);
                            MaterializerNavigationLink link2 = MaterializerNavigationLink.GetLink(link);
                            if (link2.Feed != null)
                            {
                                MaterializerFeed feed = MaterializerFeed.GetFeed(link2.Feed);
                                Type             implementationType = ClientTypeUtil.GetImplementationType(segment.ProjectionType, typeof(ICollection <>));
                                if (implementationType == null)
                                {
                                    implementationType = ClientTypeUtil.GetImplementationType(segment.ProjectionType, typeof(IEnumerable <>));
                                }
                                Type nestedExpectedType = implementationType.GetGenericArguments()[0];
                                Type projectionType     = segment.ProjectionType;
                                if (projectionType.IsInterfaceEx() || ODataMaterializer.IsDataServiceCollection(projectionType))
                                {
                                    projectionType = typeof(Collection <>).MakeGenericType(new Type[] { nestedExpectedType });
                                }
                                IEnumerable list = (IEnumerable)Util.ActivatorCreateInstance(projectionType, new object[0]);
                                MaterializeToList(materializer, list, nestedExpectedType, feed.Entries);
                                if (ODataMaterializer.IsDataServiceCollection(segment.ProjectionType))
                                {
                                    list = (IEnumerable)Util.ActivatorCreateInstance(WebUtil.GetDataServiceCollectionOfT(new Type[] { nestedExpectedType }), new object[] { list, TrackingMode.None });
                                }
                                ProjectionPlan plan = CreatePlanForShallowMaterialization(nestedExpectedType);
                                materializer.FoundNextLinkForCollection(list, feed.Feed.NextPageLink, plan);
                                streamLink = list;
                            }
                            else if (link2.Entry != null)
                            {
                                MaterializerEntry entry2 = link2.Entry;
                                if (flag)
                                {
                                    if ((entry2.Entry != null) && !entry2.EntityHasBeenResolved)
                                    {
                                        materializer.Materialize(entry2, property.PropertyType, false);
                                    }
                                }
                                else
                                {
                                    CheckEntryToAccessNotNull(entry2, propertyName);
                                }
                                properties      = entry2.Properties;
                                navigationLinks = entry2.NavigationLinks;
                                streamLink      = entry2.ResolvedObject;
                                entry           = entry2;
                            }
                        }
                        else
                        {
                            if (atomProperty.Value is ODataStreamReferenceValue)
                            {
                                streamLink      = null;
                                navigationLinks = ODataMaterializer.EmptyLinks;
                                properties      = ODataMaterializer.EmptyProperties;
                                continue;
                            }
                            ValidatePropertyMatch(property, atomProperty);
                            if (ClientTypeUtil.TypeOrElementTypeIsEntity(property.PropertyType))
                            {
                                throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidEntityType(property.EntityCollectionItemType ?? property.PropertyType));
                            }
                            if (property.IsPrimitiveOrComplexCollection)
                            {
                                object instance = streamLink ?? (entry.ResolvedObject ?? Util.ActivatorCreateInstance(expectedType, new object[0]));
                                ODataMaterializer.ApplyDataValue(model.GetClientTypeAnnotation(model.GetOrCreateEdmType(instance.GetType())), atomProperty, materializer.ResponseInfo.IgnoreMissingProperties, materializer.ResponseInfo, instance);
                                navigationLinks = ODataMaterializer.EmptyLinks;
                                properties      = ODataMaterializer.EmptyProperties;
                            }
                            else if (atomProperty.Value is ODataComplexValue)
                            {
                                ODataComplexValue complexValue = atomProperty.Value as ODataComplexValue;
                                ODataMaterializer.MaterializeComplexTypeProperty(property.PropertyType, complexValue, materializer.ResponseInfo.IgnoreMissingProperties, materializer.ResponseInfo);
                                properties      = complexValue.Properties;
                                navigationLinks = ODataMaterializer.EmptyLinks;
                            }
                            else
                            {
                                if ((atomProperty.Value == null) && !ClientTypeUtil.CanAssignNull(property.NullablePropertyType))
                                {
                                    throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomMaterializer_CannotAssignNull(atomProperty.Name, property.NullablePropertyType));
                                }
                                ODataMaterializer.MaterializePrimitiveDataValue(property.NullablePropertyType, atomProperty);
                                navigationLinks = ODataMaterializer.EmptyLinks;
                                properties      = ODataMaterializer.EmptyProperties;
                            }
                            streamLink = atomProperty.GetMaterializedValue();
                        }
                    }
                    expectedType = property.PropertyType;
                }
            }
            return(streamLink);
        }
Esempio n. 19
0
        private EdmTypeCacheValue GetOrCreateEdmTypeInternal(IEdmStructuredType edmBaseType, Type type, PropertyInfo[] keyProperties, bool isEntity, bool?hasProperties)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(keyProperties != null, "keyProperties != null");

            EdmTypeCacheValue cachedEdmType;

            lock (this.clrToEdmTypeCache)
            {
                this.clrToEdmTypeCache.TryGetValue(type, out cachedEdmType);
            }

            if (cachedEdmType == null)
            {
                Type collectionType;
                if (PrimitiveType.IsKnownNullableType(type))
                {
                    PrimitiveType primitiveType;
                    PrimitiveType.TryGetPrimitiveType(type, out primitiveType);
                    Debug.Assert(primitiveType != null, "primitiveType != null");
                    cachedEdmType = new EdmTypeCacheValue(primitiveType.CreateEdmPrimitiveType(), hasProperties);
                }
                else if ((collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>))) != null && ClientTypeUtil.GetImplementationType(type, typeof(IDictionary <,>)) == null)
                {
                    // Collection Type
                    Type     elementType = collectionType.GetGenericArguments()[0];
                    IEdmType itemType    = this.GetOrCreateEdmTypeInternal(elementType).EdmType;

                    // Note that while collection of a collection is not allowed, we cannot throw here since it's a breaking change.
                    // We will throw during SaveChanges() and we have unit test validating the error case.
                    Debug.Assert(
                        itemType.TypeKind == EdmTypeKind.Entity || itemType.TypeKind == EdmTypeKind.Complex || itemType.TypeKind == EdmTypeKind.Primitive || itemType.TypeKind == EdmTypeKind.Collection,
                        "itemType.TypeKind == EdmTypeKind.Entity || itemType.TypeKind == EdmTypeKind.Complex || itemType.TypeKind == EdmTypeKind.Primitive || itemType.TypeKind == EdmTypeKind.Collection");

                    cachedEdmType = new EdmTypeCacheValue(new EdmCollectionType(itemType.ToEdmTypeReference(ClientTypeUtil.CanAssignNull(elementType))), hasProperties);
                }
                else
                {
                    if (isEntity)
                    {
                        Action <EdmEntityTypeWithDelayLoadedProperties> delayLoadEntityProperties = (entityType) =>
                        {
                            // Create properties without modifying the entityType.
                            // This will leave entityType intact in case of an exception during loading.
                            List <IEdmProperty>           loadedProperties    = new List <IEdmProperty>();
                            List <IEdmStructuralProperty> loadedKeyProperties = new List <IEdmStructuralProperty>();
                            foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name))
                            {
                                IEdmProperty edmProperty = this.CreateEdmProperty((EdmStructuredType)entityType, property);
                                loadedProperties.Add(edmProperty);

                                if (edmBaseType == null && keyProperties.Any(k => k.DeclaringType == type && k.Name == property.Name))
                                {
                                    Debug.Assert(edmProperty.PropertyKind == EdmPropertyKind.Structural, "edmProperty.PropertyKind == EdmPropertyKind.Structural");
                                    Debug.Assert(edmProperty.Type.TypeKind() == EdmTypeKind.Primitive, "edmProperty.Type.TypeKind() == EdmTypeKind.Primitive");
                                    loadedKeyProperties.Add((IEdmStructuralProperty)edmProperty);
                                }
                            }

                            // Now add properties to the entityType.
                            foreach (IEdmProperty property in loadedProperties)
                            {
                                entityType.AddProperty(property);
                            }

                            entityType.AddKeys(loadedKeyProperties);
                        };

                        // Creating an entity type
                        Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Entity, "baseType == null || baseType.TypeKind == EdmTypeKind.Entity");
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmEntityTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmEntityType)edmBaseType, c.PlatformHelper.IsAbstract(type), false /*isOpen*/, delayLoadEntityProperties),
                            hasProperties);
                    }
                    else
                    {
                        Action <EdmComplexTypeWithDelayLoadedProperties> delayLoadComplexProperties = (complexType) =>
                        {
                            // Create properties without modifying the complexType.
                            // This will leave complexType intact in case of an exception during loading.
                            List <IEdmProperty> loadedProperties = new List <IEdmProperty>();
                            foreach (PropertyInfo property in ClientTypeUtil.GetPropertiesOnType(type, /*declaredOnly*/ edmBaseType != null).OrderBy(p => p.Name))
                            {
                                IEdmProperty edmProperty = this.CreateEdmProperty(complexType, property);
                                loadedProperties.Add(edmProperty);
                            }

                            // Now add properties to the complexType.
                            foreach (IEdmProperty property in loadedProperties)
                            {
                                complexType.AddProperty(property);
                            }
                        };

                        // Creating a complex type
                        Debug.Assert(edmBaseType == null || edmBaseType.TypeKind == EdmTypeKind.Complex, "baseType == null || baseType.TypeKind == EdmTypeKind.Complex");
                        cachedEdmType = new EdmTypeCacheValue(
                            new EdmComplexTypeWithDelayLoadedProperties(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmComplexType)edmBaseType, c.PlatformHelper.IsAbstract(type), delayLoadComplexProperties),
                            hasProperties);
                    }
                }

                Debug.Assert(cachedEdmType != null, "cachedEdmType != null");

                IEdmType             edmType = cachedEdmType.EdmType;
                ClientTypeAnnotation clientTypeAnnotation = this.GetOrCreateClientTypeAnnotation(edmType, type);
                this.SetClientTypeAnnotation(edmType, clientTypeAnnotation);

                if (edmType.TypeKind == EdmTypeKind.Entity || edmType.TypeKind == EdmTypeKind.Complex)
                {
                    IEdmStructuredType edmStructuredType = edmType as IEdmStructuredType;
                    Debug.Assert(edmStructuredType != null, "edmStructuredType != null");
                    this.SetMimeTypeForProperties(edmStructuredType);
                }

                // Need to cache the type before loading the properties so we don't stack overflow because
                // loading the property can trigger calls to GetOrCreateEdmType on the same type.
                lock (this.clrToEdmTypeCache)
                {
                    EdmTypeCacheValue existing;
                    if (this.clrToEdmTypeCache.TryGetValue(type, out existing))
                    {
                        cachedEdmType = existing;
                    }
                    else
                    {
                        this.clrToEdmTypeCache.Add(type, cachedEdmType);
                    }
                }
            }

            return(cachedEdmType);
        }
Esempio n. 20
0
        private EdmTypeCacheValue GetOrCreateEdmTypeInternal(IEdmStructuredType edmBaseType, Type type, PropertyInfo[] keyProperties, bool isEntity, bool?hasProperties)
        {
            EdmTypeCacheValue value2;
            Action <MetadataProviderEdmEntityType>  action3 = null;
            Action <MetadataProviderEdmComplexType> action4 = null;

            lock (this.clrToEdmTypeCache)
            {
                this.clrToEdmTypeCache.TryGetValue(type, out value2);
            }
            if (value2 == null)
            {
                if (PrimitiveType.IsKnownNullableType(type))
                {
                    PrimitiveType type3;
                    PrimitiveType.TryGetPrimitiveType(type, out type3);
                    value2 = new EdmTypeCacheValue(type3.CreateEdmPrimitiveType(), hasProperties);
                }
                else
                {
                    Type type2;
                    if (((type2 = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>))) != null) && (ClientTypeUtil.GetImplementationType(type, typeof(IDictionary <,>)) == null))
                    {
                        Type type4 = type2.GetGenericArguments()[0];
                        value2 = new EdmTypeCacheValue(new EdmCollectionType(this.GetOrCreateEdmTypeInternal(type4).EdmType.ToEdmTypeReference(ClientTypeUtil.CanAssignNull(type4))), hasProperties);
                    }
                    else if (isEntity)
                    {
                        if (action3 == null)
                        {
                            action3 = delegate(MetadataProviderEdmEntityType entityType) {
                                List <IEdmProperty>           list  = new List <IEdmProperty>();
                                List <IEdmStructuralProperty> list1 = new List <IEdmStructuralProperty>();
                                using (IEnumerator <PropertyInfo> enumerator = (from p in ClientTypeUtil.GetPropertiesOnType(type, edmBaseType != null)
                                                                                orderby p.Name
                                                                                select p).GetEnumerator())
                                {
                                    Func <PropertyInfo, bool> predicate = null;
                                    while (enumerator.MoveNext())
                                    {
                                        PropertyInfo property = enumerator.Current;
                                        IEdmProperty item     = this.CreateEdmProperty(entityType, property);
                                        list.Add(item);
                                        if (edmBaseType == null)
                                        {
                                            if (predicate == null)
                                            {
                                                predicate = k => (k.DeclaringType == type) && (k.Name == property.Name);
                                            }
                                            if (keyProperties.Any <PropertyInfo>(predicate))
                                            {
                                                list1.Add((IEdmStructuralProperty)item);
                                            }
                                        }
                                    }
                                }
                                foreach (IEdmProperty property2 in list)
                                {
                                    entityType.AddProperty(property2);
                                }
                                entityType.AddKeys(list1);
                            };
                        }
                        Action <MetadataProviderEdmEntityType> propertyLoadAction = action3;
                        value2 = new EdmTypeCacheValue(new MetadataProviderEdmEntityType(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmEntityType)edmBaseType, type.IsAbstract(), false, propertyLoadAction), hasProperties);
                    }
                    else
                    {
                        if (action4 == null)
                        {
                            action4 = delegate(MetadataProviderEdmComplexType complexType) {
                                List <IEdmProperty> list = new List <IEdmProperty>();
                                foreach (PropertyInfo info in from p in ClientTypeUtil.GetPropertiesOnType(type, edmBaseType != null)
                                         orderby p.Name
                                         select p)
                                {
                                    IEdmProperty item = this.CreateEdmProperty(complexType, info);
                                    list.Add(item);
                                }
                                foreach (IEdmProperty property2 in list)
                                {
                                    complexType.AddProperty(property2);
                                }
                            };
                        }
                        Action <MetadataProviderEdmComplexType> action2 = action4;
                        value2 = new EdmTypeCacheValue(new MetadataProviderEdmComplexType(CommonUtil.GetModelTypeNamespace(type), CommonUtil.GetModelTypeName(type), (IEdmComplexType)edmBaseType, type.IsAbstract(), action2), hasProperties);
                    }
                }
                IEdmType             edmType = value2.EdmType;
                ClientTypeAnnotation orCreateClientTypeAnnotation = this.GetOrCreateClientTypeAnnotation(edmType, type);
                edmType.SetClientTypeAnnotation(orCreateClientTypeAnnotation);
                if ((edmType.TypeKind == EdmTypeKind.Entity) || (edmType.TypeKind == EdmTypeKind.Complex))
                {
                    IEdmStructuredType edmStructuredType = edmType as IEdmStructuredType;
                    this.SetMimeTypeForProperties(edmStructuredType);
                }
                lock (this.clrToEdmTypeCache)
                {
                    EdmTypeCacheValue value3;
                    if (this.clrToEdmTypeCache.TryGetValue(type, out value3))
                    {
                        return(value3);
                    }
                    this.clrToEdmTypeCache.Add(type, value2);
                }
            }
            return(value2);
        }