Пример #1
0
        /// <summary>Materializes the specified <paramref name="entry"/> as dynamic property.</summary>
        /// <param name="entry">Entry with object to materialize.</param>
        /// <param name="link">Nested resource link as parsed.</param>
        private void MaterializeDynamicProperty(MaterializerEntry entry, ODataNestedResourceInfo link)
        {
            Debug.Assert(entry != null, "entry != null");
            Debug.Assert(entry.ResolvedObject != null, "entry.ResolvedObject != null -- otherwise not resolved/created!");
            Debug.Assert(link != null, "link != null");

            ClientEdmModel model = this.MaterializerContext.Model;

            IDictionary <string, object> containerProperty;

            // Stop if owning type is not an open type
            // Or container property is not found
            // Or key with matching name already exists in the dictionary
            if (!ClientTypeUtil.IsInstanceOfOpenType(entry.ResolvedObject, model) ||
                !ClientTypeUtil.TryGetContainerProperty(entry.ResolvedObject, out containerProperty) ||
                containerProperty.ContainsKey(link.Name))
            {
                return;
            }

            MaterializerNavigationLink linkState = MaterializerNavigationLink.GetLink(link);

            if (linkState == null || (linkState.Entry == null && linkState.Feed == null))
            {
                return;
            }

            // NOTE: ODL (and OData WebApi) support navigational property on complex types
            // That support has not yet been implemented in OData client

            // An entity or entity collection as a dynamic property currently doesn't work as expected
            // due to the absence of a navigational property definition in the metadata
            // to express the relationship between that entity and the parent entity - unless they're the same type!
            // Only materialize a nested resource if its a complex or complex collection

            if (linkState.Feed != null)
            {
                string collectionTypeName     = linkState.Feed.TypeName; // TypeName represents a collection e.g. Collection(NS.Type)
                string collectionItemTypeName = CommonUtil.GetCollectionItemTypeName(collectionTypeName, false);

                // Highly unlikely, but the method return null if the typeName argument does not meet certain expectations
                if (collectionItemTypeName == null)
                {
                    return;
                }

                Type collectionItemType = ResolveClientTypeForDynamicProperty(collectionItemTypeName, entry.ResolvedObject);

                if (collectionItemType != null && ClientTypeUtil.TypeIsComplex(collectionItemType, model))
                {
                    Type  collectionType = typeof(System.Collections.ObjectModel.Collection <>).MakeGenericType(new Type[] { collectionItemType });
                    IList collection     = (IList)Util.ActivatorCreateInstance(collectionType);

                    IEnumerable <ODataResource> feedEntries = MaterializerFeed.GetFeed(linkState.Feed).Entries;
                    foreach (ODataResource feedEntry in feedEntries)
                    {
                        MaterializerEntry linkEntry = MaterializerEntry.GetEntry(feedEntry);
                        this.Materialize(linkEntry, collectionItemType, false /*includeLinks*/);
                        collection.Add(linkEntry.ResolvedObject);
                    }

                    containerProperty.Add(link.Name, collection);
                }
            }
            else
            {
                MaterializerEntry linkEntry = linkState.Entry;
                Type itemType = ResolveClientTypeForDynamicProperty(linkEntry.Entry.TypeName, entry.ResolvedObject);

                if (itemType != null && ClientTypeUtil.TypeIsComplex(itemType, model))
                {
                    this.Materialize(linkEntry, itemType, false /*includeLinks*/);
                    containerProperty.Add(link.Name, linkEntry.ResolvedObject);
                }
            }
        }
        /// <summary>
        /// Adds a data value to the dynamic properties dictionary (where it exists) on the specified <paramref name="instance"/>
        /// </summary>
        /// <param name="property">Property containing unmaterialzed value to apply</param>
        /// <param name="instance">Instance that may optionally contain the dynamic properties dictionary</param>
        internal void MaterializeDynamicProperty(ODataProperty property, object instance)
        {
            Debug.Assert(property != null, "property != null");
            Debug.Assert(instance != null, "instance != null");

            IDictionary <string, object> containerProperty;

            // Stop if owning type is not an open type
            // Or container property is not found
            // Or key with matching name already exists in the dictionary
            if (!ClientTypeUtil.IsInstanceOfOpenType(instance, this.MaterializerContext.Model) ||
                !ClientTypeUtil.TryGetContainerProperty(instance, out containerProperty) ||
                containerProperty.ContainsKey(property.Name))
            {
                return;
            }

            object value = property.Value;

            // Handles properties of known types returned with type annotations
            if (!(value is ODataValue) && PrimitiveType.IsKnownType(value.GetType()))
            {
                containerProperty.Add(property.Name, value);
                return;
            }

            // Handle untyped value
            ODataUntypedValue untypedVal = value as ODataUntypedValue;

            if (untypedVal != null)
            {
                value = CommonUtil.ParseJsonToPrimitiveValue(untypedVal.RawValue);
                containerProperty.Add(property.Name, value);
                return;
            }

            // Handle enum value
            ODataEnumValue enumVal = value as ODataEnumValue;

            if (enumVal != null)
            {
                Type clientType = ResolveClientTypeForDynamicProperty(enumVal.TypeName, instance);
                // Unable to resolve type for dynamic property
                if (clientType == null)
                {
                    return;
                }

                object materializedEnumValue;
                if (EnumValueMaterializationPolicy.TryMaterializeODataEnumValue(clientType, enumVal, out materializedEnumValue))
                {
                    containerProperty.Add(property.Name, materializedEnumValue);
                }

                return;
            }

            // Handle collection
            ODataCollectionValue collectionVal = value as ODataCollectionValue;

            if (collectionVal != null)
            {
                string collectionItemTypeName = CommonUtil.GetCollectionItemTypeName(collectionVal.TypeName, false);
                // Highly unlikely, but the method return null if the typeName argument does not meet certain expectations
                if (collectionItemTypeName == null)
                {
                    return;
                }

                Type collectionItemType;
                // ToNamedType will return true for primitive types
                if (!ClientConvert.ToNamedType(collectionItemTypeName, out collectionItemType))
                {
                    // Non-primitive collection
                    collectionItemType = ResolveClientTypeForDynamicProperty(collectionItemTypeName, instance);
                }

                if (collectionItemType == null)
                {
                    return;
                }

                object collectionInstance;
                if (this.CollectionValueMaterializationPolicy.TryMaterializeODataCollectionValue(collectionItemType, property, out collectionInstance))
                {
                    containerProperty.Add(property.Name, collectionInstance);
                }

                return;
            }
        }