Beispiel #1
0
 /// <summary>
 /// Sets the single instance of <see cref="ClientTypeAnnotation"/> on the given instance of <paramref name="edmType"/>.
 /// </summary>
 /// <param name="model">The model the <paramref name="edmType"/> belongs to.</param>
 /// <param name="edmType">IEdmType instance to set the annotation on.</param>
 /// <param name="annotation">The annotation to set</param>
 internal static void SetClientTypeAnnotation(this IEdmModel model, IEdmType edmType, ClientTypeAnnotation annotation)
 {
     Debug.Assert(model != null, "model != null");
     Debug.Assert(edmType != null, "edmType != null");
     Debug.Assert(annotation != null, "annotation != null");
     model.SetAnnotationValue<ClientTypeAnnotation>(edmType, annotation);
 }
Beispiel #2
0
        /// <summary>
        /// Creates instance of EntityPropertyMappingInfo class.
        /// </summary>
        /// <param name="attribute">The <see cref="EntityPropertyMappingAttribute"/> corresponding to this object</param>
        /// <param name="definingType">Type the <see cref="EntityPropertyMappingAttribute"/> was defined on.</param>
        /// <param name="actualPropertyType">ClientType whose property is to be read.</param>
        public EntityPropertyMappingInfo(EntityPropertyMappingAttribute attribute, Type definingType, ClientTypeAnnotation actualPropertyType)
        {
#endif
            Debug.Assert(attribute != null, "attribute != null");
            Debug.Assert(definingType != null, "definingType != null");
            Debug.Assert(actualPropertyType != null, "actualPropertyType != null");

            this.attribute          = attribute;
            this.definingType       = definingType;
            this.actualPropertyType = actualPropertyType;

            Debug.Assert(!string.IsNullOrEmpty(attribute.SourcePath), "Invalid source path");
            this.propertyValuePath = attribute.SourcePath.Split('/');

            // Infer the mapping type from the attribute
            this.isSyndicationMapping = this.attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ClientEdmStructuredValue"/> class.
        /// </summary>
        /// <param name="structuredValue">The structured value.</param>
        /// <param name="model">The model.</param>
        /// <param name="clientTypeAnnotation">The client type annotation.</param>
        public ClientEdmStructuredValue(object structuredValue, ClientEdmModel model, ClientTypeAnnotation clientTypeAnnotation)
        {
            Debug.Assert(structuredValue != null, "entity != null");
            Debug.Assert(model != null, "model != null");
            Debug.Assert(clientTypeAnnotation != null, "clientTypeAnnotation != null");

            if (clientTypeAnnotation.EdmType.TypeKind == EdmTypeKind.Complex)
            {
                // TODO: nullable?
                this.Type = new EdmComplexTypeReference((IEdmComplexType)clientTypeAnnotation.EdmType, true);
            }
            else
            {
                Debug.Assert(clientTypeAnnotation.EdmType.TypeKind == EdmTypeKind.Entity, "Only complex and entity values supported");
                
                // TODO: nullable?
                this.Type = new EdmEntityTypeReference((IEdmEntityType)clientTypeAnnotation.EdmType, true);
            }

            this.structuredValue = structuredValue;
            this.typeAnnotation = clientTypeAnnotation;
            this.model = model;
        }
Beispiel #4
0
        /// <summary>
        /// Tries to resolve the server type corresponding to the client type.
        /// </summary>
        /// <param name="clientTypeAnnotation">The client type annotation.</param>
        /// <param name="serverType">The server type, if the server type could be resolved.</param>
        /// <returns>Whether or not the server type could be resolved.</returns>
        private bool TryToResolveServerType(ClientTypeAnnotation clientTypeAnnotation, out IEdmStructuredType serverType)
        {
            Debug.Assert(this.serviceModel != null, "this.serviceModel != null");
            Debug.Assert(clientTypeAnnotation != null, "clientTypeAnnotation != null");

            var serverTypeName = this.resolveNameFromType(clientTypeAnnotation.ElementType);
            if (serverTypeName == null)
            {
                serverType = null;
                return false;
            }

            serverType = this.serviceModel.FindType(serverTypeName) as IEdmStructuredType;
            return serverType != null;
        }
 public void Init()
 {
     var clientEdmModel = new ClientEdmModel(ODataProtocolVersion.V4);
     this.typeWithUnserializableProperties = new ClientTypeAnnotation(new EdmEntityType("NS", "Type1"), typeof(EntityWithUnserializableProperties), "NS.Type1", clientEdmModel);
     this.typeWithPropertiesInStrangeOrder = new ClientTypeAnnotation(new EdmEntityType("NS", "Type2"), typeof(EntityWithPropertiesInStrangeOrder), "NS.Type2", clientEdmModel);
 }
        /// <summary>
        /// Creates instance of EntityPropertyMappingInfo class.
        /// </summary>
        /// <param name="attribute">The <see cref="EntityPropertyMappingAttribute"/> corresponding to this object</param>
        /// <param name="definingType">Type the <see cref="EntityPropertyMappingAttribute"/> was defined on.</param>
        /// <param name="actualPropertyType">ClientType whose property is to be read.</param>
        public EntityPropertyMappingInfo(EntityPropertyMappingAttribute attribute, Type definingType, ClientTypeAnnotation actualPropertyType)
        {
#endif
            Debug.Assert(attribute != null, "attribute != null");
            Debug.Assert(definingType != null, "definingType != null");
            Debug.Assert(actualPropertyType != null, "actualPropertyType != null");

            this.attribute = attribute;
            this.definingType = definingType;
            this.actualPropertyType = actualPropertyType;

            Debug.Assert(!string.IsNullOrEmpty(attribute.SourcePath), "Invalid source path");
            this.propertyValuePath = attribute.SourcePath.Split('/');

            // Infer the mapping type from the attribute
            this.isSyndicationMapping = this.attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty;
        }
Beispiel #7
0
        /// <summary>
        /// Get the server type name - either from the entity descriptor or using the type resolver.
        /// </summary>
        /// <param name="clientTypeAnnotation">Client type annotation.</param>
        /// <returns>The server type name for the entity.</returns>
        internal string GetServerTypeName(ClientTypeAnnotation clientTypeAnnotation)
        {
            string serverTypeName = this.ResolveNameFromType(clientTypeAnnotation.ElementType);

            return serverTypeName;
        }
Beispiel #8
0
        /// <summary>
        /// Converts the object to ODataCollectionValue, ODataEntityReferenceLinks, or
        /// a list of ODataEntry.
        /// </summary>
        /// <param name="paramName">The name of the <see cref="UriOperationParameter"/>. Used for error reporting.</param>
        /// <param name="value">The value of the <see cref="UriOperationParameter"/>.</param>
        /// <param name="itemTypeAnnotation">The client type annotation of the value.</param>
        /// <param name="useEntityReference">If true, use entity reference, instead of entity to serialize the parameter.</param>
        /// <returns>The converted result.</returns>
        private object ConvertToCollectionValue(string paramName, object value, ClientTypeAnnotation itemTypeAnnotation, bool useEntityReference)
        {
            object valueInODataFormat;

            switch (itemTypeAnnotation.EdmType.TypeKind)
            {
                case EdmTypeKind.Primitive:
                case EdmTypeKind.Enum:
                case EdmTypeKind.Complex:
                    valueInODataFormat = this.propertyConverter.CreateODataCollection(itemTypeAnnotation.ElementType, null, value, null, false, false);
                    break;

                case EdmTypeKind.Entity:
                    if (useEntityReference)
                    {
                        var list = value as IEnumerable;
                        var links = (from object o in list
                            select new ODataEntityReferenceLink()
                            {
                                Url = this.requestInfo.EntityTracker.GetEntityDescriptor(o).GetLatestIdentity(),
                            }).ToList();

                        valueInODataFormat = new ODataEntityReferenceLinks()
                        {
                            Links = links,
                        };
                    }
                    else
                    {
                        valueInODataFormat = this.propertyConverter.CreateODataEntries(
                            itemTypeAnnotation.ElementType, value);
                    }

                    break;

                default:
                    throw new NotSupportedException(Strings.Serializer_InvalidCollectionParamterItemType(paramName, itemTypeAnnotation.EdmType.TypeKind));
            }

            return valueInODataFormat;
        }
        /// <summary>
        /// Applies the values of the specified <paramref name="properties"/> to a given <paramref name="instance"/>.
        /// </summary>
        /// <param name="type">Type to which properties will be applied.</param>
        /// <param name="properties">Properties to assign to the specified <paramref name="instance"/>.</param>
        /// <param name="instance">Instance on which values will be applied.</param>
        internal void ApplyDataValues(ClientTypeAnnotation type, IEnumerable<ODataProperty> properties, object instance)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(properties != null, "properties != null");
            Debug.Assert(instance != null, "instance != context");

            foreach (var p in properties)
            {
                this.ApplyDataValue(type, p, instance);
            }
        }
        public void Init()
        {
            this.serverModel = new EdmModel();
            this.serverEntityType = new EdmEntityType("Server.NS", "ServerEntityType");
            this.serverEntityTypeName = "Server.NS.ServerEntityType";
            this.serverModel.AddElement(this.serverEntityType);
            this.serverEntityType.AddKeys(this.serverEntityType.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32));
            
            var addressType = new EdmComplexType("Server.NS", "Address");
            addressType.AddStructuralProperty("Street", EdmPrimitiveTypeKind.String);
            this.serverEntityType.AddStructuralProperty("Address", new EdmComplexTypeReference(addressType, true));
            this.serverComplexTypeName = "Server.NS.Address";

            var homeAddressType = new EdmComplexType("Server.NS", "HomeAddress", addressType);
            homeAddressType.AddStructuralProperty("FamilyName", EdmPrimitiveTypeKind.String);
            this.serverComplexTypeName = "Server.NS.HomeAddress";

            var colorType = new EdmEnumType("Server.NS", "Color");
            colorType.AddMember(new EdmEnumMember(colorType, "Red", new EdmIntegerConstant(1)));
            colorType.AddMember(new EdmEnumMember(colorType, "Blue", new EdmIntegerConstant(2)));
            colorType.AddMember(new EdmEnumMember(colorType, "Green", new EdmIntegerConstant(3)));
            this.serverEntityType.AddStructuralProperty("Color", new EdmEnumTypeReference(colorType, false));

            this.serverEntityType.AddStructuralProperty("Nicknames", new EdmCollectionTypeReference(new EdmCollectionType(EdmCoreModel.Instance.GetInt32(false))));
            this.serverEntityType.AddStructuralProperty("OtherAddresses", new EdmCollectionTypeReference(new EdmCollectionType(new EdmComplexTypeReference(addressType, false))));

            this.clientModel = new ClientEdmModel(ODataProtocolVersion.V4);
            this.clientTypeAnnotation = this.clientModel.GetClientTypeAnnotation(typeof(TestClientEntityType));

            this.context = new DataServiceContext(new Uri("http://temp/"), ODataProtocolVersion.V4, this.clientModel);
            this.context.Format.UseJson(this.serverModel);

            this.testSubject = new ODataPropertyConverter(new RequestInfo(this.context));

            this.context.Format.UseJson(this.serverModel);
            this.context.ResolveName = t =>
                                       {
                                           if (t == typeof(TestClientEntityType))
                                           {
                                               return this.serverEntityTypeName;
                                           }

                                           if (t == typeof(Address))
                                           {
                                               return this.serverComplexTypeName;
                                           }

                                           return null;
                                       };
            this.entity = new TestClientEntityType
            {
                Id = 1, 
                Name = "foo", 
                Number = 1.23f, 
                Address = new Address(),
                OpenAddress = new Address(), 
                Nicknames = new string[0],
                OtherAddresses = new[] { new Address() },
                Color = 0
            };
            this.entityWithDerivedComplexProperty = new TestClientEntityType
            {
                Id = 1,
                Name = "foo",
                Number = 1.23f,
                Address = new HomeAddress(),
                OpenAddress = new Address(),
                Nicknames = new string[0],
                OtherAddresses = new[] { new Address() }
            };
            this.entityWithDerivedComplexInCollection = new TestClientEntityType
            {
                Id = 1,
                Name = "foo",
                Number = 1.23f,
                Address = new HomeAddress(),
                OpenAddress = new Address(),
                Nicknames = new string[0],
                OtherAddresses = new[] { new Address(), new HomeAddress() }
            };
        }
Beispiel #11
0
        /// <summary>
        /// Figures out value to be written in OData-Version HTTP header for the given entity based on features used in this entity.
        /// </summary>
        /// <param name="clientType">Entity type for which data service version needs to be determined.</param>
        /// <returns>Data service version for the given entity and state.</returns>
        private static Version DetermineRequestVersion(ClientTypeAnnotation clientType)
        {
            Debug.Assert(clientType != null, "clientType != null");
            Debug.Assert(clientType.IsEntityType, "This method should be called only for entities");

            // Determine what the version is based on the client type.
            Version requestVersion = Util.ODataVersion4;

            WebUtil.RaiseVersion(ref requestVersion, clientType.GetMetadataVersion());
            return requestVersion;
        }
Beispiel #12
0
        /// <summary>
        /// Gets or creates client type annotation.
        /// </summary>
        /// <param name="edmType">The EdmType to use for creating client type annotation</param>
        /// <param name="type">The Clr type to create client type annotation for.</param>
        /// <returns>Client type annotation</returns>
        private ClientTypeAnnotation GetOrCreateClientTypeAnnotation(IEdmType edmType, Type type)
        {
            ClientTypeAnnotation clientTypeAnnotation;
            string qualifiedName = type.ToString();

            // all that are not built-in types need to be cached: enum, complex, entity
            if (edmType.TypeKind == EdmTypeKind.Enum || edmType.TypeKind == EdmTypeKind.Complex || edmType.TypeKind == EdmTypeKind.Entity)
            {
                lock (this.typeNameToClientTypeAnnotationCache)
                {
                    if (this.typeNameToClientTypeAnnotationCache.TryGetValue(qualifiedName, out clientTypeAnnotation) && clientTypeAnnotation.ElementType != type)
                    {
                        qualifiedName = type.AssemblyQualifiedName;
                        if (this.typeNameToClientTypeAnnotationCache.TryGetValue(qualifiedName, out clientTypeAnnotation) && clientTypeAnnotation.ElementType != type)
                        {
                            throw c.Error.InvalidOperation(Strings.ClientType_MultipleTypesWithSameName(qualifiedName));
                        }
                    }

                    if (clientTypeAnnotation == null)
                    {
                        clientTypeAnnotation = new ClientTypeAnnotation(edmType, type, qualifiedName, this);
                        this.typeNameToClientTypeAnnotationCache.Add(qualifiedName, clientTypeAnnotation);
                    }
                    else
                    {
                        Debug.Assert(clientTypeAnnotation.ElementType == type, "existing clientTypeAnnotation.ElementType == type");
                    }
                }
            }
            else
            {
                clientTypeAnnotation = new ClientTypeAnnotation(edmType, type, qualifiedName, this);
            }

            return clientTypeAnnotation;
        }
        /// <summary>
        /// Materializes the link properties if any with the url in the response payload
        /// </summary>
        /// <param name="actualType">Actual client type that is getting materialized.</param>
        /// <param name="entry">MaterializerEntry instance containing all the links that came in the response.</param>
        private static void ApplyLinkProperties(
            ClientTypeAnnotation actualType,
            MaterializerEntry entry)
        {
            Debug.Assert(actualType != null, "actualType != null");
            Debug.Assert(entry.Entry != null, "entry != null");

            if (entry.ShouldUpdateFromPayload)
            {
                foreach (var linkProperty in actualType.Properties().Where(p => p.PropertyType == typeof(DataServiceStreamLink)))
                {
                    string propertyName = linkProperty.PropertyName;
                    StreamDescriptor streamDescriptor;
                    if (entry.EntityDescriptor.TryGetNamedStreamInfo(propertyName, out streamDescriptor))
                    {
                        // At this time we have materialized the stream link onto the stream descriptor object
                        // we'll always make sure the stream link is the same instance on the entity and the descriptor
                        linkProperty.SetValue(entry.ResolvedObject, streamDescriptor.StreamLink, propertyName, true /*allowAdd*/);
                    }
                }
            }
        }
 /// <summary>
 /// Determines whether a given property should be serialized into an insert or update payload.
 /// </summary>
 /// <param name="type">The declaring type of the property.</param>
 /// <param name="property">The property.</param>
 /// <returns>Whether or not the property should be serialized.</returns>
 private static bool ShouldSerializeProperty(ClientTypeAnnotation type, ClientPropertyAnnotation property)
 {
     // don't write property if it is a dictionary
     // don't write mime data member or the mime type member for it
     // link properties need to be ignored
     return !property.IsDictionary
         && property != type.MediaDataMember
         && !property.IsStreamLinkProperty
         && (type.MediaDataMember == null || type.MediaDataMember.MimeTypeProperty != property);
 }
Beispiel #15
0
 /// <summary>
 /// Sets the single instance of <see cref="ClientTypeAnnotation"/> on the given instance of <paramref name="edmType"/>.
 /// </summary>
 /// <param name="model">The model the <paramref name="edmType"/> belongs to.</param>
 /// <param name="edmType">IEdmType instance to set the annotation on.</param>
 /// <param name="annotation">The annotation to set</param>
 internal static void SetClientTypeAnnotation(this IEdmModel model, IEdmType edmType, ClientTypeAnnotation annotation)
 {
     Debug.Assert(model != null, "model != null");
     Debug.Assert(edmType != null, "edmType != null");
     Debug.Assert(annotation != null, "annotation != null");
     model.SetAnnotationValue <ClientTypeAnnotation>(edmType, annotation);
 }
Beispiel #16
0
        /// <summary>
        /// Creates an ODataEntry for the given EntityDescriptor and fills in its ODataLib metadata.
        /// </summary>
        /// <param name="entityDescriptor">The entity descriptor.</param>
        /// <param name="serverTypeName">Name of the server type.</param>
        /// <param name="entityType">The client-side entity type.</param>
        /// <param name="clientFormat">The current client format.</param>
        /// <returns>An odata entry with its metadata filled in.</returns>
        internal static ODataEntry CreateODataEntry(EntityDescriptor entityDescriptor, string serverTypeName, ClientTypeAnnotation entityType, DataServiceClientFormat clientFormat)
        {
            ODataEntry entry = new ODataEntry();

            // If the client type name is different from the server type name, then add SerializationTypeNameAnnotation
            // which tells ODataLib to write the type name in the annotation in the payload.
            if (entityType.ElementTypeName != serverTypeName)
            {
                entry.SetAnnotation(new SerializationTypeNameAnnotation { TypeName = serverTypeName });
            }

            // We always need to write the client type name, since this is the type name used by ODataLib
            // to resolve the entity type using EdmModel.FindSchemaElement.
            entry.TypeName = entityType.ElementTypeName;

            // Continue to send the entry's ID in update payloads in Atom for compatibility with V1-V3,
            // but for JSON-Light we do not want the extra information on the wire.
            if (clientFormat.UsingAtom && EntityStates.Modified == entityDescriptor.State)
            {
                // <id>http://host/service/entityset(key)</id>
                entry.Id = entityDescriptor.GetLatestIdentity();
            }

            if (entityDescriptor.IsMediaLinkEntry || entityType.IsMediaLinkEntry)
            {
                // Since we are already enabled EnableWcfDataServicesClientBehavior in the writer settings,
                // setting the MediaResource value will tell ODataLib to write MLE payload, irrespective of
                // what the metadata says.
                entry.MediaResource = new ODataStreamReferenceValue();
            }

            return entry;
        }
        /// <summary>Applies a data value to the specified <paramref name="instance"/>.</summary>
        /// <param name="type">Type to which a property value will be applied.</param>
        /// <param name="property">Property with value to apply.</param>
        /// <param name="instance">Instance on which value will be applied.</param>
        internal void ApplyDataValue(ClientTypeAnnotation type, ODataProperty property, object instance)
        {
            Debug.Assert(type != null, "type != null");
            Debug.Assert(property != null, "property != null");
            Debug.Assert(instance != null, "instance != null");

            var prop = type.GetProperty(property.Name, this.MaterializerContext.IgnoreMissingProperties);
            if (prop == null)
            {
                return;
            }

            // Is it a collection? (note: property.Properties will be null if the Collection is empty (contains no elements))
            Type enumTypeTmp = null;
            if (prop.IsPrimitiveOrEnumOrComplexCollection)
            {
                // Collections must not be null
                if (property.Value == null)
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.Collection_NullCollectionNotSupported(property.Name));
                }

                // This happens if the payload contain just primitive value for a Collection property
                if (property.Value is string)
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_MixedTextWithComment);
                }

                if (property.Value is ODataComplexValue)
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidCollectionItem(property.Name));
                }

                // ODataLib already parsed the data and materialized all the primitive types. There is nothing more to materialize
                // anymore. Only complex type instance and collection instances need to be materialized, but those will be
                // materialized later on.
                // We need to materialize items before we change collectionInstance since this may throw. If we tried materializing
                // after the Collection is wiped or created we would leave the object in half constructed state.
                object collectionInstance = prop.GetValue(instance);
                if (collectionInstance == null)
                {
                    collectionInstance = this.CollectionValueMaterializationPolicy.CreateCollectionPropertyInstance(property, prop.PropertyType);

                    // allowAdd is false - we need to assign instance as the new property value
                    prop.SetValue(instance, collectionInstance, property.Name, false /* allowAdd? */);
                }
                else
                {
                    // Clear existing Collection
                    prop.ClearBackingICollectionInstance(collectionInstance);
                }

                bool isElementNullable = prop.EdmProperty.Type.AsCollection().ElementType().IsNullable;
                this.CollectionValueMaterializationPolicy.ApplyCollectionDataValues(
                    property,
                    collectionInstance,
                    prop.PrimitiveOrComplexCollectionItemType,
                    prop.AddValueToBackingICollectionInstance,
                    isElementNullable);
            }
            else if ((enumTypeTmp = Nullable.GetUnderlyingType(prop.NullablePropertyType) ?? prop.NullablePropertyType) != null
                && enumTypeTmp.IsEnum())
            {
                ODataEnumValue enumValue = property.Value as ODataEnumValue;
                object tmpValue = EnumValueMaterializationPolicy.MaterializeODataEnumValue(enumTypeTmp, enumValue);

                // TODO: 1. use EnumValueMaterializationPolicy 2. handle nullable enum property
                prop.SetValue(instance, tmpValue, property.Name, false /* allowAdd? */);
            }
            else
            {
                object propertyValue = property.Value;
                ODataComplexValue complexValue = propertyValue as ODataComplexValue;
                if (propertyValue != null && complexValue != null)
                {
                    if (!prop.EdmProperty.Type.IsComplex())
                    {
                        // The error message is a bit odd, but it's compatible with V1.
                        throw DSClient.Error.InvalidOperation(DSClient.Strings.Deserialize_ExpectingSimpleValue);
                    }

                    // Complex type.
                    bool needToSet = false;

                    ClientEdmModel edmModel = this.MaterializerContext.Model;
                    ClientTypeAnnotation complexType = edmModel.GetClientTypeAnnotation(edmModel.GetOrCreateEdmType(prop.PropertyType));
                    object complexInstance = prop.GetValue(instance);

                    // Validating property inheritance in complexvalue and instance
                    if (prop.PropertyType.Name != property.Name)
                    {
                        complexType = this.MaterializerContext.ResolveTypeForMaterialization(prop.PropertyType, complexValue.TypeName);

                        // recreate complexInstance with derived type
                        complexInstance = null;
                    }

                    if (complexValue.Properties.Any() || complexInstance == null)
                    {
                        complexInstance = this.CreateNewInstance(complexType.EdmTypeReference, complexType.ElementType);
                        needToSet = true;
                    }

                    this.MaterializeDataValues(complexType, complexValue.Properties, this.MaterializerContext.IgnoreMissingProperties);
                    this.ApplyDataValues(complexType, complexValue.Properties, complexInstance);

                    if (needToSet)
                    {
                        prop.SetValue(instance, complexInstance, property.Name, true /* allowAdd? */);
                    }

                    if (!this.MaterializerContext.Context.DisableInstanceAnnotationMaterialization)
                    {
                        // Set instance annotation for this complex instance
                        this.InstanceAnnotationMaterializationPolicy.SetInstanceAnnotations(property, complexInstance);
                    }
                }
                else
                {
                    this.MaterializePrimitiveDataValue(prop.NullablePropertyType, property);
                    prop.SetValue(instance, property.GetMaterializedValue(), property.Name, true /* allowAdd? */);
                }
            }

            if (!this.MaterializerContext.Context.DisableInstanceAnnotationMaterialization)
            {
                // Apply instance annotation for Property
                this.InstanceAnnotationMaterializationPolicy.SetInstanceAnnotations(property, type.ElementType, instance);
            }
        }
Beispiel #18
0
        /// <summary>
        /// Creates an ODataEntry using some properties extracted from an entity operation parameter.
        /// </summary>
        /// <param name="clientTypeAnnotation">The client type annotation of the entity.</param>
        /// <param name="parameterValue">The Clr value of the entity.</param>
        /// <returns>The ODataEntry created.</returns>
        private ODataEntry CreateODataEntryFromEntityOperationParameter(ClientTypeAnnotation clientTypeAnnotation, object parameterValue)
        {
            ClientPropertyAnnotation[] properties = new ClientPropertyAnnotation[0];
            if (sendOption == EntityParameterSendOption.SendOnlySetProperties)
            {
                try
                {
                    var descripter = this.requestInfo.Context.EntityTracker.GetEntityDescriptor(parameterValue);
                    properties = clientTypeAnnotation.PropertiesToSerialize().Where(p => descripter.PropertiesToSerialize.Contains(p.PropertyName)).ToArray();
                }
                catch (InvalidOperationException)
                {
                    throw Error.InvalidOperation(Strings.Context_MustBeUsedWith("EntityParameterSendOption.SendOnlySetProperties", "DataServiceCollection"));
                }
            }

            return this.propertyConverter.CreateODataEntry(clientTypeAnnotation.ElementType, parameterValue, properties);
        }
        /// <summary>
        /// Materializes the primitive data values in the given list of <paramref name="values"/>.
        /// </summary>
        /// <param name="actualType">Actual type for properties being materialized.</param>
        /// <param name="values">List of values to materialize.</param>
        /// <param name="ignoreMissingProperties">
        /// Whether properties missing from the client types should be ignored.
        /// </param>
        /// <remarks>
        /// Values are materialized in-place withi each <see cref="ODataProperty"/>
        /// instance.
        /// </remarks>
        internal void MaterializeDataValues(ClientTypeAnnotation actualType, IEnumerable<ODataProperty> values, bool ignoreMissingProperties)
        {
            Debug.Assert(actualType != null, "actualType != null");
            Debug.Assert(values != null, "values != null");

            foreach (var odataProperty in values)
            {
                if (odataProperty.Value is ODataStreamReferenceValue)
                {
                    continue;
                }

                string propertyName = odataProperty.Name;

                var property = actualType.GetProperty(propertyName, ignoreMissingProperties); // may throw
                if (property == null)
                {
                    continue;
                }

                // we should throw if the property type on the client does not match with the property type in the server
                // This is a breaking change from V1/V2 where we allowed materialization of entities into non-entities and vice versa
                if (ClientTypeUtil.TypeOrElementTypeIsEntity(property.PropertyType))
                {
                    throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidEntityType(property.EntityCollectionItemType ?? property.PropertyType));
                }

                if (property.IsKnownType)
                {
                    // Note: MaterializeDataValue materializes only properties of primitive types. Materialization specific 
                    // to complex types and collections is done later. 
                    this.MaterializePrimitiveDataValue(property.NullablePropertyType, odataProperty);
                }
            }
        }