Пример #1
0
        protected static bool MaterializePrimitiveDataValue(Type type, string wireTypeName, object value, System.Data.Services.Client.ResponseInfo responseInfo, Func <string> throwOnNullMessage, out object materializedValue)
        {
            PrimitiveType type3;
            Type          clrType = Nullable.GetUnderlyingType(type) ?? type;
            bool          flag    = PrimitiveType.TryGetPrimitiveType(clrType, out type3);

            if (!flag)
            {
                flag = PrimitiveType.TryGetPrimitiveType(responseInfo.TypeResolver.ResolveEdmTypeName(type, wireTypeName).ElementType, out type3);
            }
            if (flag)
            {
                if (value == null)
                {
                    if (!ClientTypeUtil.CanAssignNull(type))
                    {
                        throw new InvalidOperationException(throwOnNullMessage());
                    }
                    materializedValue = null;
                }
                else
                {
                    materializedValue = ConvertPrimitiveValue(value, clrType);
                }
                return(true);
            }
            materializedValue = null;
            return(false);
        }
Пример #2
0
        /// <summary>
        /// Creates an Edm property.
        /// </summary>
        /// <param name="declaringType">Type declaring this property.</param>
        /// <param name="propertyInfo">PropertyInfo instance for this property.</param>
        /// <returns>Returns a new instance of Edm property.</returns>
        private IEdmProperty CreateEdmProperty(IEdmStructuredType declaringType, PropertyInfo propertyInfo)
        {
            IEdmType propertyEdmType = this.GetOrCreateEdmType(propertyInfo.PropertyType);

            Debug.Assert(
                propertyEdmType.TypeKind == EdmTypeKind.Entity ||
                propertyEdmType.TypeKind == EdmTypeKind.Complex ||
                propertyEdmType.TypeKind == EdmTypeKind.Enum ||
                propertyEdmType.TypeKind == EdmTypeKind.Primitive ||
                propertyEdmType.TypeKind == EdmTypeKind.Collection,
                "Property kind should be Entity, Complex, Enum, Primitive or Collection.");

            IEdmProperty edmProperty        = null;
            bool         isPropertyNullable = ClientTypeUtil.CanAssignNull(propertyInfo.PropertyType);

            if (propertyEdmType.TypeKind == EdmTypeKind.Entity || (propertyEdmType.TypeKind == EdmTypeKind.Collection && ((IEdmCollectionType)propertyEdmType).ElementType.TypeKind() == EdmTypeKind.Entity))
            {
                if (declaringType.TypeKind == EdmTypeKind.Entity || declaringType.TypeKind == EdmTypeKind.Complex)
                {
                    if (declaringType as IEdmEntityType == null && declaringType as IEdmComplexType == null)
                    {
                        throw c.Error.InvalidOperation(c.Strings.ClientTypeCache_NonEntityTypeOrNonComplexTypeCannotContainEntityProperties(propertyInfo.Name, propertyInfo.DeclaringType.ToString()));
                    }

                    // Create a navigation property representing one side of an association.
                    // The partner representing the other side exists only inside this property and is not added to the target entity type,
                    // so it should not cause any name collisions.
                    edmProperty = EdmNavigationProperty.CreateNavigationPropertyWithPartner(
                        ClientTypeUtil.GetServerDefinedName(propertyInfo),
                        propertyEdmType.ToEdmTypeReference(isPropertyNullable),
                        /*dependentProperties*/ null,
                        /*principalProperties*/ null,
                        /*containsTarget*/ false,
                        EdmOnDeleteAction.None,
                        "Partner",
                        declaringType.ToEdmTypeReference(true),
                        /*partnerDependentProperties*/ null,
                        /*partnerPrincipalProperties*/ null,
                        /*partnerContainsTarget*/ false,
                        EdmOnDeleteAction.None);
                }
            }
            else
            {
                edmProperty = new EdmStructuralProperty(declaringType, ClientTypeUtil.GetServerDefinedName(propertyInfo), propertyEdmType.ToEdmTypeReference(isPropertyNullable));
            }

            edmProperty.SetClientPropertyAnnotation(new ClientPropertyAnnotation(edmProperty, propertyInfo, this));
            return(edmProperty);
        }
Пример #3
0
        /// <summary>Materializes a primitive value. No op or non-primitive values.</summary>
        /// <param name="type">Type of value to set.</param>
        /// <param name="wireTypeName">Type name from the payload.</param>
        /// <param name="value">Value of primitive provided by ODL.</param>
        /// <param name="throwOnNullMessage">The exception message if the value is null.</param>
        /// <param name="materializedValue">The materialized value.</param>
        private void MaterializePrimitiveDataValue(Type type, string wireTypeName, object value, Func <string> throwOnNullMessage, out object materializedValue)
        {
            Debug.Assert(type != null, "type != null");

            ClientTypeAnnotation nestedElementType = null;
            Type underlyingType = Nullable.GetUnderlyingType(type) ?? type;

            PrimitiveType ptype;
            bool          knownType = PrimitiveType.TryGetPrimitiveType(underlyingType, out ptype);

            if (!knownType)
            {
                nestedElementType = this.context.ResolveTypeForMaterialization(type, wireTypeName);
                Debug.Assert(nestedElementType != null, "nestedElementType != null -- otherwise ReadTypeAttribute (or someone!) should throw");
                knownType = PrimitiveType.TryGetPrimitiveType(nestedElementType.ElementType, out ptype);
            }

            if (knownType)
            {
                if (value == null)
                {
                    if (!ClientTypeUtil.CanAssignNull(type))
                    {
                        throw new InvalidOperationException(throwOnNullMessage());
                    }

                    materializedValue = null;
                }
                else
                {
                    ODataUntypedValue untypedVal = value as ODataUntypedValue;
                    if ((untypedVal != null) &&
                        this.context.UndeclaredPropertyBehavior == UndeclaredPropertyBehavior.Support)
                    {
                        value = CommonUtil.ParseJsonToPrimitiveValue(untypedVal.RawValue);
                    }

                    materializedValue = this.PrimitivePropertyConverter.ConvertPrimitiveValue(value, underlyingType);
                }
            }
            else
            {
                materializedValue = null;
            }
        }
Пример #4
0
        /// <summary>Materializes a primitive value. No op or non-primitive values.</summary>
        /// <param name="type">Type of value to set.</param>
        /// <param name="wireTypeName">Type name from the payload.</param>
        /// <param name="value">Value of primitive provided by ODL.</param>
        /// <param name="throwOnNullMessage">The exception message if the value is null.</param>
        /// <param name="materializedValue">The materialized value.</param>
        /// <returns>true if the value was set; false if it wasn't (typically because it's a complex value).</returns>
        private bool MaterializePrimitiveDataValue(Type type, string wireTypeName, object value, Func <string> throwOnNullMessage, out object materializedValue)
        {
            Debug.Assert(type != null, "type != null");

            ClientTypeAnnotation nestedElementType = null;
            Type underlyingType = Nullable.GetUnderlyingType(type) ?? type;

            PrimitiveType ptype;
            bool          knownType = PrimitiveType.TryGetPrimitiveType(underlyingType, out ptype);

            if (!knownType)
            {
                nestedElementType = this.context.ResolveTypeForMaterialization(type, wireTypeName);
                Debug.Assert(nestedElementType != null, "nestedElementType != null -- otherwise ReadTypeAttribute (or someone!) should throw");
                knownType = PrimitiveType.TryGetPrimitiveType(nestedElementType.ElementType, out ptype);
            }

            if (knownType)
            {
                if (value == null)
                {
                    if (!ClientTypeUtil.CanAssignNull(type))
                    {
                        throw new InvalidOperationException(throwOnNullMessage());
                    }

                    materializedValue = null;
                }
                else
                {
                    materializedValue = this.PrimitivePropertyConverter.ConvertPrimitiveValue(value, underlyingType);
                }

                return(true);
            }
            else
            {
                materializedValue = null;
                return(false);
            }
        }
Пример #5
0
        private IEdmProperty CreateEdmProperty(IEdmStructuredType declaringType, PropertyInfo propertyInfo)
        {
            IEdmProperty property;
            IEdmType     edmType    = this.GetOrCreateEdmTypeInternal(propertyInfo.PropertyType).EdmType;
            bool         isNullable = ClientTypeUtil.CanAssignNull(propertyInfo.PropertyType);

            if ((edmType.TypeKind == EdmTypeKind.Entity) || ((edmType.TypeKind == EdmTypeKind.Collection) && (((IEdmCollectionType)edmType).ElementType.TypeKind() == EdmTypeKind.Entity)))
            {
                IEdmEntityType type2 = declaringType as IEdmEntityType;
                if (type2 == null)
                {
                    throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.ClientTypeCache_NonEntityTypeCannotContainEntityProperties(propertyInfo.Name, propertyInfo.DeclaringType.ToString()));
                }
                property = EdmNavigationProperty.CreateNavigationPropertyWithPartner(propertyInfo.Name, edmType.ToEdmTypeReference(isNullable), null, false, EdmOnDeleteAction.None, "Partner", type2.ToEdmTypeReference(true), null, false, EdmOnDeleteAction.None);
            }
            else
            {
                property = new EdmStructuralProperty(declaringType, propertyInfo.Name, edmType.ToEdmTypeReference(isNullable));
            }
            property.SetClientPropertyAnnotation(new ClientPropertyAnnotation(property, propertyInfo, this.protocolVersion));
            return(property);
        }
Пример #6
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);
        }
Пример #7
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);
        }
Пример #8
0
 protected sealed override bool ReadImplementation()
 {
     if (this.hasReadValue)
     {
         return(false);
     }
     try
     {
         ClientEdmModel    model        = ClientEdmModel.GetModel(base.ResponseInfo.MaxProtocolVersion);
         IEdmTypeReference expectedType = model.GetOrCreateEdmType(base.ExpectedType).ToEdmTypeReference(ClientTypeUtil.CanAssignNull(base.ExpectedType));
         if ((this.SingleResult.HasValue && !this.SingleResult.Value) && (expectedType.Definition.TypeKind != EdmTypeKind.Collection))
         {
             expectedType = model.GetOrCreateEdmType(typeof(ICollection <>).MakeGenericType(new Type[] { base.ExpectedType })).ToEdmTypeReference(false);
         }
         this.ReadFromMessageReader(this.messageReader, expectedType);
     }
     catch (ODataErrorException exception)
     {
         throw new DataServiceClientException(System.Data.Services.Client.Strings.Deserialize_ServerException(exception.Error.Message), exception);
     }
     catch (ODataException exception2)
     {
         throw new InvalidOperationException(exception2.Message, exception2);
     }
     catch (ArgumentException exception3)
     {
         throw new InvalidOperationException(exception3.Message, exception3);
     }
     finally
     {
         this.hasReadValue = true;
     }
     return(true);
 }
Пример #9
0
        /// <summary>
        /// Creates an Edm property.
        /// </summary>
        /// <param name="declaringType">Type declaring this property.</param>
        /// <param name="propertyInfo">PropertyInfo instance for this property.</param>
        /// <returns>Returns a new instance of Edm property.</returns>
        private IEdmProperty CreateEdmProperty(IEdmStructuredType declaringType, PropertyInfo propertyInfo)
        {
            IEdmType propertyEdmType = this.GetOrCreateEdmTypeInternal(propertyInfo.PropertyType).EdmType;

            Debug.Assert(
                propertyEdmType.TypeKind == EdmTypeKind.Entity ||
                propertyEdmType.TypeKind == EdmTypeKind.Complex ||
                propertyEdmType.TypeKind == EdmTypeKind.Primitive ||
                propertyEdmType.TypeKind == EdmTypeKind.Collection,
                "Property kind should be Entity, Complex, Primitive or Collection.");

            IEdmProperty edmProperty;
            bool         isPropertyNullable = ClientTypeUtil.CanAssignNull(propertyInfo.PropertyType);

            if (propertyEdmType.TypeKind == EdmTypeKind.Entity || (propertyEdmType.TypeKind == EdmTypeKind.Collection && ((IEdmCollectionType)propertyEdmType).ElementType.TypeKind() == EdmTypeKind.Entity))
            {
                IEdmEntityType declaringEntityType = declaringType as IEdmEntityType;
                if (declaringEntityType == null)
                {
                    throw c.Error.InvalidOperation(c.Strings.ClientTypeCache_NonEntityTypeCannotContainEntityProperties(propertyInfo.Name, propertyInfo.DeclaringType.ToString()));
                }

                // Create a navigation property representing one side of an association.
                // The partner representing the other side exists only inside this property and is not added to the target entity type,
                // so it should not cause any name collisions.
                edmProperty = EdmNavigationProperty.CreateNavigationPropertyWithPartner(
                    propertyInfo.Name,
                    propertyEdmType.ToEdmTypeReference(isPropertyNullable),
                    /*dependentProperties*/ null,
                    /*containsTarget*/ false,
                    EdmOnDeleteAction.None,
                    "Partner",
                    declaringEntityType.ToEdmTypeReference(true),
                    /*partnerDependentProperties*/ null,
                    /*partnerContainsTarget*/ false,
                    EdmOnDeleteAction.None);
            }
            else
            {
                edmProperty = new EdmStructuralProperty(declaringType, propertyInfo.Name, propertyEdmType.ToEdmTypeReference(isPropertyNullable));
            }

            FieldInfo backingField = null;

            if (this.ResolveBackingField != null)
            {
                // We only do this for "collections of entities" OR "complex properties"
                if (propertyEdmType.TypeKind == EdmTypeKind.Collection && !propertyEdmType.IsPrimitive() || propertyEdmType.TypeKind == EdmTypeKind.Complex)
                {
                    backingField = this.ResolveBackingField(propertyInfo);
                }

                if (backingField != null && backingField.FieldType != propertyInfo.PropertyType)
                {
                    backingField = null; // We disregard returned FieldInfo that has the wrong type.
                }
            }

            edmProperty.SetClientPropertyAnnotation(new ClientPropertyAnnotation(edmProperty, propertyInfo, backingField, this));
            return(edmProperty);
        }
Пример #10
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);
        }
Пример #11
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);
        }
Пример #12
0
        /// <summary>
        /// Gets the CLR type based on the <see cref="IEdmTypeReference"/> and the current data service context.
        /// </summary>
        /// <param name="context">The data service context.</param>
        /// <param name="edmTypeReference">The specified edm type reference.</param>
        /// <param name="isBindingParameter">This flag indicates whether the edm type reference is used for a binding parameter.</param>
        /// <param name="clrType">The output parameter to return the CLR type.</param>
        /// <returns>True if the CLR type is found, or false.</returns>
        private static bool TryGetClrTypeFromEdmTypeReference(DataServiceContext context, IEdmTypeReference edmTypeReference, bool isBindingParameter, out Type clrType)
        {
            EdmTypeKind typeKind = edmTypeReference.Definition.TypeKind;

            if (typeKind == EdmTypeKind.None)
            {
                clrType = null;
                return(false);
            }

            if (typeKind == EdmTypeKind.Primitive)
            {
                PrimitiveType primitiveType = null;
                if (PrimitiveType.TryGetPrimitiveType(edmTypeReference.Definition.FullName(), out primitiveType))
                {
                    clrType = primitiveType.ClrType;

                    if (edmTypeReference.IsNullable && ClientTypeUtil.CanAssignNull(clrType))
                    {
                        clrType = typeof(Nullable <>).MakeGenericType(clrType);
                    }

                    return(true);
                }
            }

            if (typeKind == EdmTypeKind.Collection)
            {
                Type elementType;
                if (TryGetClrTypeFromEdmTypeReference(context, ((IEdmCollectionTypeReference)edmTypeReference).ElementType(), false, out elementType))
                {
                    if (isBindingParameter)
                    {
                        clrType = typeof(DataServiceQuery <>).MakeGenericType(elementType);
                    }
                    else
                    {
                        clrType = typeof(List <>).MakeGenericType(elementType);
                    }

                    return(true);
                }
            }

            if (typeKind == EdmTypeKind.Complex || typeKind == EdmTypeKind.Entity || typeKind == EdmTypeKind.Enum)
            {
                clrType = ResolveTypeFromName(context, edmTypeReference.FullName());
                if (clrType == null)
                {
                    return(false);
                }

                if (isBindingParameter)
                {
                    clrType = typeof(DataServiceQuerySingle <>).MakeGenericType(clrType);
                }

                return(true);
            }

            clrType = null;
            return(false);
        }
Пример #13
0
        /// <summary>
        /// Implementation of Read>.
        /// </summary>
        /// <returns>
        /// Return value of Read/>
        /// </returns>
        protected sealed override bool ReadImplementation()
        {
            if (!this.hasReadValue)
            {
                try
                {
                    ClientEdmModel    model              = this.MaterializerContext.Model;
                    Type              expectedType       = this.ExpectedType;
                    IEdmTypeReference expectedClientType = model.GetOrCreateEdmType(expectedType).ToEdmTypeReference(ClientTypeUtil.CanAssignNull(expectedType));
                    if ((this.SingleResult.HasValue && !this.SingleResult.Value) && expectedClientType.Definition.TypeKind != EdmTypeKind.Collection)
                    {
                        expectedType = typeof(ICollection <>).MakeGenericType(expectedType);

                        // we do not allow null values for collection
                        expectedClientType = model.GetOrCreateEdmType(expectedType).ToEdmTypeReference(false);
                    }

                    IEdmTypeReference expectedReaderType = this.MaterializerContext.ResolveExpectedTypeForReading(expectedType).ToEdmTypeReference(expectedClientType.IsNullable);

                    this.ReadWithExpectedType(expectedClientType, expectedReaderType);
                }
                catch (ODataErrorException e)
                {
                    throw new DataServiceClientException(ClientStrings.Deserialize_ServerException(e.Error.Message), e);
                }
                catch (ODataException e)
                {
                    throw new InvalidOperationException(e.Message, e);
                }
                catch (ArgumentException e)
                {
                    throw new InvalidOperationException(e.Message, e);
                }
                finally
                {
                    this.hasReadValue = true;
                }

                return(true);
            }
            else
            {
                return(false);
            }
        }