/// <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); } }
/// <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)); }
/// <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; }
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); }
private static Type GetTypeForMaterializer(bool expectingPrimitiveValue, Type elementType, DataServiceProtocolVersion maxProtocolVersion, out Type implementationType) { if (!expectingPrimitiveValue && typeof(IEnumerable).IsAssignableFrom(elementType)) { implementationType = ClientTypeUtil.GetImplementationType(elementType, typeof(ICollection <>)); if (implementationType != null) { Type t = implementationType.GetGenericArguments()[0]; if (ClientTypeUtil.TypeIsEntity(t, maxProtocolVersion)) { return(t); } } } implementationType = null; return(elementType); }
/// <summary> /// 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); }
/// <summary> /// Applies collectionValue item to the provided <paramref name="collectionInstance"/>. /// </summary> /// <param name="collectionProperty">Atom property containing materialized Collection items.</param> /// <param name="collectionInstance">Collection instance. Must implement ICollection<T> where T is either primitive or complex type (not an entity).</param> /// <param name="collectionItemType">Type of items in the Collection. Note: this could be calculated from collectionInstance but we already have it in upstream methods.</param> /// <param name="addValueToBackingICollectionInstance">Action called actually add a Collection item to <paramref name="collectionInstance" /></param> 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); }
/// <summary> /// Creates Collection instance of store Collection items. /// </summary> /// <param name="collectionProperty">ODataProperty instance representing the Collection as seen in the atom payload.</param> /// <param name="userCollectionType">CLR type of the Collection as defined by the user.</param> /// <returns>Newly created Collection instance. Never null.</returns> internal object CreateCollectionPropertyInstance(ODataProperty collectionProperty, Type userCollectionType) { Debug.Assert(collectionProperty != null, "collectionProperty != null"); Debug.Assert(collectionProperty.Value != null, "Collection should have already been checked for nullness"); Debug.Assert(userCollectionType != null, "userCollectionType != null"); Debug.Assert(ClientTypeUtil.GetImplementationType(userCollectionType, typeof(ICollection <>)) != null, "Not a Collection - Collection types must implement ICollection<> interface."); Debug.Assert( !ClientTypeUtil.TypeIsEntity(ClientTypeUtil.GetImplementationType(userCollectionType, typeof(ICollection <>)).GetGenericArguments()[0], this.materializerContext.Model), "Not a Collection - Collections cannot contain entities"); Debug.Assert(!(collectionProperty.Value is ODataResourceSet) && !(collectionProperty.Value is ODataResource), "Collection properties should never materialized from entry or feed payload"); ODataCollectionValue collectionValue = collectionProperty.Value as ODataCollectionValue; // get a ClientType instance for the Collection property. This determines what type will be used later when creating the actual Collection instance ClientTypeAnnotation collectionClientType = this.materializerContext.ResolveTypeForMaterialization(userCollectionType, collectionValue.TypeName); return(this.CreateCollectionInstance(collectionClientType.EdmTypeReference as IEdmCollectionTypeReference, collectionClientType.ElementType, () => DSClient.Strings.AtomMaterializer_NoParameterlessCtorForCollectionProperty(collectionProperty.Name, collectionClientType.ElementTypeName))); }
/// <summary> /// Checks if the provided type is a collection type (i.e. it implements ICollection and the collection item type is not an entity). /// </summary> /// <param name="type">Type being checked.</param> /// <param name="model">The client model.</param> /// <returns>True if the CLR type is a collection compatible type. False otherwise.</returns> internal static bool IsCLRTypeCollection(Type type, ClientEdmModel model) { // char[] and byte[] implements ICollection<> but we should not threat them as collections since they are primitive types for us. if (!PrimitiveType.IsKnownNullableType(type)) { Type collectionType = ClientTypeUtil.GetImplementationType(type, typeof(ICollection <>)); if (collectionType != null) { // collectionType is ICollection so we know that the first generic parameter // is the collection item type if (!ClientTypeUtil.TypeIsEntity(collectionType.GetGenericArguments()[0], model)) { return(true); } } } return(false); }
/// <summary> /// Gets the type that of the instances that will be returned by materializer. /// </summary> /// <param name="expectingPrimitiveValue">Whether the expected is a primitive type.</param> /// <param name="elementType">Actual type on the client.</param> /// <param name="model">The client model used.</param> /// <param name="implementationType">The actual type that implements ICollection<></param> /// <returns>Type of the instances that will be returned by materializer.</returns> /// <remarks> /// For collection navigation properties (i.e. ICollection<T> where T is an entity the method returns T. Materializer will /// return single entity each time MoveNext() is called. However for collection properties we need the whole property instead of just a /// single collection item. /// </remarks> private static Type GetTypeForMaterializer(bool expectingPrimitiveValue, Type elementType, ClientEdmModel model, out Type implementationType) { if (!expectingPrimitiveValue && typeof(IEnumerable).IsAssignableFrom(elementType)) { implementationType = ClientTypeUtil.GetImplementationType(elementType, typeof(ICollection <>)); if (implementationType != null) { Type expectedType = implementationType.GetGenericArguments()[0]; // already know its ICollection<> // We should use the inner type only if this is a collection of entities (as opposed to a collection of primitive or complex types) if (ClientTypeUtil.TypeIsStructured(expectedType, model)) { return(expectedType); } } } implementationType = null; return(elementType); }
/// <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); }
/// <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); }
/// <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); }
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); } } } } }
/// <summary> /// Applies the collection data values to a collection instance. /// </summary> /// <param name="items">The items.</param> /// <param name="wireTypeName">Name of the wire type.</param> /// <param name="collectionInstance">The collection instance.</param> /// <param name="collectionItemType">Type of the collection item.</param> /// <param name="addValueToBackingICollectionInstance">The add value to backing I collection instance.</param> internal void ApplyCollectionDataValues(IEnumerable items, string wireTypeName, object collectionInstance, Type collectionItemType, Action <object, object> addValueToBackingICollectionInstance) { Debug.Assert(collectionInstance != null, "collectionInstance != null"); Debug.Assert(WebUtil.IsCLRTypeCollection(collectionInstance.GetType(), this.materializerContext.Model), "collectionInstance must be a CollectionValue"); Debug.Assert( ClientTypeUtil.GetImplementationType(collectionInstance.GetType(), typeof(ICollection <>)).GetGenericArguments()[0] == collectionItemType, "collectionItemType has to match the collectionInstance generic type."); Debug.Assert(!ClientTypeUtil.TypeIsEntity(collectionItemType, this.materializerContext.Model), "CollectionValues cannot contain entities"); Debug.Assert(addValueToBackingICollectionInstance != null, "AddValueToBackingICollectionInstance != null"); // is the Collection not empty ? if (items != null) { bool isCollectionItemTypePrimitive = PrimitiveType.IsKnownNullableType(collectionItemType); var edmModel = this.materializerContext.Model; foreach (object item in items) { if (item == null) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_NullCollectionItemsNotSupported); } ODataComplexValue complexValue = item as ODataComplexValue; // Is it a Collection of primitive types? if (isCollectionItemTypePrimitive) { // verify that the Collection does not contain complex type items if (complexValue != null || item is ODataCollectionValue) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_ComplexTypesInCollectionOfPrimitiveTypesNotAllowed); } object materializedValue = this.primitiveValueMaterializationPolicy.MaterializePrimitiveDataValueCollectionElement(collectionItemType, wireTypeName, item); addValueToBackingICollectionInstance(collectionInstance, materializedValue); } else { // verify that the Collection does not contain primitive values if (complexValue == null) { throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_PrimitiveTypesInCollectionOfComplexTypesNotAllowed); } // Derived complex types are not supported. We create the base type here and we will fail later when trying to materialize the value of a // property that is on the derived type but not on the base type (unless IgnoreMissingProperty setting is set to true). This is by design. ClientTypeAnnotation complexType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(collectionItemType)); object complexInstance = this.CreateNewInstance(complexType.EdmTypeReference, complexType.ElementType); // set properties with metarialized data values if there are any (note that for a payload that looks as follows <element xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices"/> // and represents an item that is a complex type there are no properties to be set) this.ComplexValueMaterializationPolicy.ApplyDataValues(complexType, complexValue.Properties, complexInstance); addValueToBackingICollectionInstance(collectionInstance, complexInstance); } } } }
private 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); }
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); }
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); }
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); }