/// <summary>
        /// Gets or creates an <see cref="IEdmCollectionType"/> for the <paramref name="itemResourceType"/>.
        /// </summary>
        /// <param name="collectionResourceType">The collection resource type that the edm type is being created from.</param>
        /// <param name="itemResourceType">The item resource type to create an EDM collection type for.</param>
        /// <param name="customAnnotations">The optional annotations for the resource type; the annotations can contain facets that need to be applied to the type reference.</param>
        /// <returns>An <see cref="IEdmCollectionType"/> instance for the <paramref name="itemResourceType"/> item type.</returns>
        /// <remarks>
        /// Materialization state: none required. No change in materialization state.
        /// Cache state: none required. No change in cache state.
        /// </remarks>
        private IEdmCollectionType EnsureCollectionItemTypeIsPrimitiveOrComplex(CollectionResourceType collectionResourceType, ResourceType itemResourceType, List<KeyValuePair<string, object>> customAnnotations)
        {
            Debug.Assert(itemResourceType != null, "itemResourceType != null");

            IEdmCollectionType collectionType;
            if (this.primitiveOrComplexCollectionTypeCache.TryGetValue(itemResourceType, out collectionType))
            {
                return collectionType;
            }

            IEdmTypeReference elementTypeReference;
            switch (itemResourceType.ResourceTypeKind)
            {
                case ResourceTypeKind.ComplexType:
                    // WCF DS forces the item types of collection types to not be nullable. Only starting v3, can complex properties be nullable. 
                    // For providers, like reflection providers, we need to ensure complex items continue to be non-nullable.
                    elementTypeReference = this.EnsureTypeReference(itemResourceType, customAnnotations);
                    elementTypeReference = elementTypeReference.IsNullable != PrimitiveOrComplexCollectionItemTypeDefaultNullability
                        ? elementTypeReference.Clone(PrimitiveOrComplexCollectionItemTypeDefaultNullability)
                        : elementTypeReference;
                    break;
                case ResourceTypeKind.Primitive:
                    // WCF DS forces the item types of collection types to not be nullable
                    MetadataProviderUtils.GetAndRemoveNullableFacet(customAnnotations);
                    IEdmPrimitiveTypeReference primitiveTypeReference = MetadataProviderUtils.CreatePrimitiveTypeReference(itemResourceType, customAnnotations);
                    elementTypeReference = primitiveTypeReference.IsNullable != PrimitiveOrComplexCollectionItemTypeDefaultNullability
                        ? primitiveTypeReference.Clone(PrimitiveOrComplexCollectionItemTypeDefaultNullability)
                        : primitiveTypeReference;

                    break;
                case ResourceTypeKind.EntityType:       // fall through
                case ResourceTypeKind.Collection:       // fall through
                case ResourceTypeKind.EntityCollection: // fall through
                default:
                    throw new InvalidOperationException(Microsoft.OData.Service.Strings.MetadataProviderEdmModel_UnsupportedCollectionItemType_PrimitiveOrComplex(itemResourceType.ResourceTypeKind.ToString()));
            }

            collectionType = new MetadataProviderEdmCollectionType(collectionResourceType, elementTypeReference);
            this.primitiveOrComplexCollectionTypeCache.Add(itemResourceType, collectionType);
            return collectionType;
        }
Esempio n. 2
0
        /// <summary>Creates a server value from a client value.</summary>
        /// <param name="value">The value to convert.</param>
        /// <param name="resourceType">The resource type of the value.</param>
        /// <param name="createCollection">Optional func to create a new collection instance on the server.
        /// The first parameter is the collection resource type, the second is enumeration of server items to be added to the collection.</param>
        /// <param name="clientInstanceToResourceType">Func to resolve client resource to a server resource type.</param>
        /// <returns>The server representation of the client value</returns>
        public static object CreateServerValueFromClientValue(
            object value,
            providers.ResourceType resourceType,
            Func <providers.CollectionResourceType, IEnumerable <object>, object> createCollection,
            Func <object, providers.ResourceType> clientInstanceToResourceType)
        {
            if (value == null)
            {
                return(null);
            }

            Type valueType = value.GetType();

            if (valueType.IsValueType || (valueType.IsGenericParameter && valueType.GetGenericTypeDefinition() == typeof(Nullable <>)) || value is string)
            {
                // Primitive value
                return(value);
            }
            else if (value is IEnumerable)
            {
                // Collection
                providers.CollectionResourceType collectionResourceType = (providers.CollectionResourceType)resourceType;
                object        collection  = null;
                List <object> serverItems = new List <object>();
                foreach (object item in (IEnumerable)value)
                {
                    serverItems.Add(CreateServerValueFromClientValue(
                                        item,
                                        collectionResourceType == null ? null : collectionResourceType.ItemType,
                                        createCollection,
                                        clientInstanceToResourceType));
                }

                if (createCollection != null)
                {
                    collection = createCollection(collectionResourceType, serverItems);
                }
                if (collection == null)
                {
                    Type itemType = collectionResourceType == null?
                                    TypeSystem.GetIEnumerableElementType(value.GetType()) :
                                        collectionResourceType.ItemType.InstanceType;

                    if (itemType == null)
                    {
                        throw new Exception("Can't determine the item type of an open collection property.");
                    }

                    Type   listType             = typeof(List <>).MakeGenericType(itemType);
                    object serverItemsConverted = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(itemType).Invoke(null, new object[] { serverItems });
                    collection = Activator.CreateInstance(listType, serverItemsConverted);
                }

                return(collection);
            }
            else
            {
                // Complex type
                return(CreateServerResourceFromClientResource(value, createCollection, clientInstanceToResourceType));
            }
        }
Esempio n. 3
0
 /// <summary>Returns a read-only version of the specified collection.</summary>
 /// <param name="collection">The collection to convert to read-only.</param>
 /// <param name="resourceType">The resourceType of this collection property.</param>
 /// <returns>A read-only collection.</returns>
 internal static object GetReadOnlyCollection(IList collection, CollectionResourceType resourceType)
 {
     Debug.Assert(collection.GetType() == typeof(List<object>), "The collection was not created by CreateNewCollectionProperty.");
     return new CollectionPropertyValueEnumerable(collection, resourceType);
 }
        protected override void BeginCollectionPropertyValue(CollectionResourceType CollectionResourceType)
        {
            // {
            this.writer.StartObjectScope();
            // __metadata : { Type : "typename" }
            this.writer.WriteName(JsonMetadataString);
            this.writer.StartObjectScope();

            this.writer.WriteName(JsonTypeString);
            this.writer.WriteValue(CollectionResourceType.FullName);

            this.writer.EndScope();

            // "results":
            this.writer.WriteDataArrayName();
            // [
            this.writer.StartArrayScope();
        }
 protected override void BeginCollectionPropertyValue(CollectionResourceType CollectionResourceType)
 {
     // Do nothing
 }
 protected abstract void BeginCollectionPropertyValue(CollectionResourceType CollectionResourceType);