Example #1
0
        /// <summary>
        /// Creates and returns an ODataResourceWrapper from the given value.
        /// </summary>
        /// <param name="complexType">The value type.</param>
        /// <param name="instance">The complex instance.</param>
        /// <param name="propertyName">If the value is a property, then it represents the name of the property. Can be null, for non-property.</param>
        /// <param name="visitedComplexTypeObjects">Set of instances of complex types encountered in the hierarchy. Used to detect cycles.</param>
        /// <returns>An ODataResourceWrapper representing the given value.</returns>
        internal ODataResourceWrapper CreateODataResourceWrapperForComplex(Type complexType, object instance, string propertyName, HashSet <object> visitedComplexTypeObjects)
        {
            Debug.Assert(complexType != null, "complexType != null");

            ClientEdmModel       model = this.requestInfo.Model;
            ClientTypeAnnotation complexTypeAnnotation = model.GetClientTypeAnnotation(complexType);

            Debug.Assert(complexTypeAnnotation != null, "complexTypeAnnotation != null");
            Debug.Assert(!complexTypeAnnotation.IsEntityType, "Unexpected entity");

            if (instance == null)
            {
                return(new ODataResourceWrapper()
                {
                    Resource = null
                });
            }

            if (visitedComplexTypeObjects == null)
            {
                visitedComplexTypeObjects = new HashSet <object>(ReferenceEqualityComparer <object> .Instance);
            }
            else if (visitedComplexTypeObjects.Contains(instance))
            {
                if (propertyName != null)
                {
                    throw Error.InvalidOperation(Strings.Serializer_LoopsNotAllowedInComplexTypes(propertyName));
                }
                else
                {
                    Debug.Assert(complexTypeAnnotation.ElementTypeName != null, "complexTypeAnnotation.ElementTypeName != null");
                    throw Error.InvalidOperation(Strings.Serializer_LoopsNotAllowedInNonPropertyComplexTypes(complexTypeAnnotation.ElementTypeName));
                }
            }

            visitedComplexTypeObjects.Add(instance);

            ODataResource resource = new ODataResource()
            {
                TypeName = complexTypeAnnotation.ElementTypeName
            };

            string serverTypeName = this.requestInfo.GetServerTypeName(complexTypeAnnotation);

            resource.TypeAnnotation = new ODataTypeAnnotation(serverTypeName);

            resource.Properties = this.PopulateProperties(instance, serverTypeName, complexTypeAnnotation.PropertiesToSerialize(), visitedComplexTypeObjects);

            var wrapper = new ODataResourceWrapper()
            {
                Resource = resource, Instance = instance
            };

            wrapper.NestedResourceInfoWrappers = this.PopulateNestedComplexProperties(instance, serverTypeName, complexTypeAnnotation.PropertiesToSerialize(), visitedComplexTypeObjects);

            visitedComplexTypeObjects.Remove(instance);

            return(wrapper);
        }
Example #2
0
        /// <summary>
        /// Creates and returns an ODataComplexValue from the given value.
        /// </summary>
        /// <param name="complexType">The value type.</param>
        /// <param name="value">The complex value.</param>
        /// <param name="propertyName">If the value is a property, then it represents the name of the property. Can be null, for non-property.</param>
        /// <param name="isCollectionItem">True, if the value is an item in a collection, false otherwise.</param>
        /// <param name="visitedComplexTypeObjects">Set of instances of complex types encountered in the hierarchy. Used to detect cycles.</param>
        /// <returns>An ODataComplexValue representing the given value.</returns>
        internal ODataComplexValue CreateODataComplexValue(Type complexType, object value, string propertyName, bool isCollectionItem, HashSet <object> visitedComplexTypeObjects)
        {
            Debug.Assert(complexType != null, "complexType != null");
            Debug.Assert(value != null || !isCollectionItem, "Collection items must not be null");

            ClientEdmModel       model = this.requestInfo.Model;
            ClientTypeAnnotation complexTypeAnnotation = model.GetClientTypeAnnotation(complexType);

            Debug.Assert(complexTypeAnnotation != null, "complexTypeAnnotation != null");
            Debug.Assert(!complexTypeAnnotation.IsEntityType, "Unexpected entity");

            // Handle null values for complex types by putting m:null="true"
            if (value == null)
            {
                Debug.Assert(!isCollectionItem, "Null collection items are not supported. Should have already been checked.");
                return(null);
            }

            if (visitedComplexTypeObjects == null)
            {
                visitedComplexTypeObjects = new HashSet <object>(ReferenceEqualityComparer <object> .Instance);
            }
            else if (visitedComplexTypeObjects.Contains(value))
            {
                if (propertyName != null)
                {
                    throw Error.InvalidOperation(Strings.Serializer_LoopsNotAllowedInComplexTypes(propertyName));
                }
                else
                {
                    Debug.Assert(complexTypeAnnotation.ElementTypeName != null, "complexTypeAnnotation.ElementTypeName != null");
                    throw Error.InvalidOperation(Strings.Serializer_LoopsNotAllowedInNonPropertyComplexTypes(complexTypeAnnotation.ElementTypeName));
                }
            }

            visitedComplexTypeObjects.Add(value);
            ODataComplexValue odataComplexValue = new ODataComplexValue();

            // When TypeName is set, it causes validation to occur when ODataLib writes out the collection. Part of the validation ensures that all items
            // in the collection are exactly the same type, no derived types are allowed. In the released WCF Data Services 5.0 implementation, we don't set
            // TypeName here, so that validation does not occur, therefore we will set this value only for JSON Light, so we don't break existing code.
            if (!this.requestInfo.Format.UsingAtom)
            {
                odataComplexValue.TypeName = complexTypeAnnotation.ElementTypeName;
            }

            // If this complex type is a collection item don't put type name on each item
            if (!isCollectionItem)
            {
                odataComplexValue.SetAnnotation(new SerializationTypeNameAnnotation {
                    TypeName = this.requestInfo.GetServerTypeName(complexTypeAnnotation)
                });
            }

            odataComplexValue.Properties = this.PopulateProperties(value, complexTypeAnnotation.PropertiesToSerialize(), visitedComplexTypeObjects);

            visitedComplexTypeObjects.Remove(value);
            return(odataComplexValue);
        }
Example #3
0
        /// <summary>
        /// Write the entry element.
        /// </summary>
        /// <param name="entityDescriptor">The entity.</param>
        /// <param name="relatedLinks">Collection of links related to the entity.</param>
        /// <param name="requestMessage">The OData request message.</param>
        internal void WriteEntry(EntityDescriptor entityDescriptor, IEnumerable <LinkDescriptor> relatedLinks, ODataRequestMessageWrapper requestMessage)
        {
            ClientEdmModel       model      = this.requestInfo.Model;
            ClientTypeAnnotation entityType = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityDescriptor.Entity.GetType()));

            using (ODataMessageWriter messageWriter = Serializer.CreateMessageWriter(requestMessage, this.requestInfo, false /*isParameterPayload*/))
            {
                ODataWriterWrapper entryWriter = ODataWriterWrapper.CreateForEntry(messageWriter, this.requestInfo.Configurations.RequestPipeline);

                // Get the server type name using the type resolver or from the entity descriptor
                string serverTypeName = this.requestInfo.GetServerTypeName(entityDescriptor);

                var entry = CreateODataEntry(entityDescriptor, serverTypeName, entityType, this.requestInfo.Format);
                if (serverTypeName == null)
                {
                    serverTypeName = this.requestInfo.InferServerTypeNameFromServerModel(entityDescriptor);
                }

                IEnumerable <ClientPropertyAnnotation> properties;
                if ((!Util.IsFlagSet(this.options, SaveChangesOptions.ReplaceOnUpdate) &&
                     entityDescriptor.State == EntityStates.Modified &&
                     entityDescriptor.PropertiesToSerialize.Any()) ||
                    (Util.IsFlagSet(this.options, SaveChangesOptions.PostOnlySetProperties) &&
                     entityDescriptor.State == EntityStates.Added))
                {
                    properties = entityType.PropertiesToSerialize().Where(prop => entityDescriptor.PropertiesToSerialize.Contains(prop.PropertyName));
                }
                else
                {
                    properties = entityType.PropertiesToSerialize();
                }

                entry.Properties = this.propertyConverter.PopulateProperties(entityDescriptor.Entity, serverTypeName, properties);

                entryWriter.WriteStart(entry, entityDescriptor.Entity);

                this.WriteNestedComplexProperties(entityDescriptor.Entity, serverTypeName, properties, entryWriter);

                if (EntityStates.Added == entityDescriptor.State)
                {
                    this.WriteNestedResourceInfo(entityDescriptor, relatedLinks, entryWriter);
                }

                entryWriter.WriteEnd(entry, entityDescriptor.Entity);
            }
        }
Example #4
0
        /// <summary>
        /// Creates an ODataResource 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 ODataResource created.</returns>
        private ODataResourceWrapper CreateODataResourceFromEntityOperationParameter(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.CreateODataResourceWrapper(clientTypeAnnotation.ElementType, parameterValue, properties));
        }
Example #5
0
        /// <summary>
        /// Creates and returns an ODataResourceWrapper from the given value.
        /// </summary>
        /// <param name="entityType">The value type.</param>
        /// <param name="value">The resource value.</param>
        /// <param name="properties">The given properties to serialize.</param>
        /// <returns>An ODataResourceWrapper representing the given value.</returns>
        internal ODataResourceWrapper CreateODataResourceWrapper(Type entityType, object value, params ClientPropertyAnnotation[] properties)
        {
            Debug.Assert(entityType != null, "entityType != null");

            if (value == null)
            {
                return(null);
            }

            ClientEdmModel       model = this.requestInfo.Model;
            ClientTypeAnnotation entityTypeAnnotation = model.GetClientTypeAnnotation(value.GetType());

            Debug.Assert(entityTypeAnnotation != null, "entityTypeAnnotation != null");
            Debug.Assert(entityTypeAnnotation.IsStructuredType, "Unexpected type");

            ODataResource odataEntityValue = new ODataResource()
            {
                TypeName = entityTypeAnnotation.ElementTypeName,
            };

            string serverTypeName = this.requestInfo.GetServerTypeName(entityTypeAnnotation);

            odataEntityValue.TypeAnnotation = new ODataTypeAnnotation(serverTypeName);

            odataEntityValue.Properties = this.PopulateProperties(value, serverTypeName, properties.Any() ? properties : entityTypeAnnotation.PropertiesToSerialize(), null);

            var wrapper = new ODataResourceWrapper()
            {
                Resource = odataEntityValue
            };

            wrapper.NestedResourceInfoWrappers = PopulateNestedComplexProperties(value, serverTypeName, properties.Any() ? properties : entityTypeAnnotation.PropertiesToSerialize(), null);

            return(wrapper);
        }
Example #6
0
        /// <summary>
        /// Write the entry element.
        /// </summary>
        /// <param name="entityDescriptor">The entity.</param>
        /// <param name="relatedLinks">Collection of links related to the entity.</param>
        /// <param name="requestMessage">The OData request message.</param>
        internal void WriteEntry(EntityDescriptor entityDescriptor, IEnumerable <LinkDescriptor> relatedLinks, ODataRequestMessageWrapper requestMessage)
        {
            ClientEdmModel       model      = this.requestInfo.Model;
            ClientTypeAnnotation entityType = model.GetClientTypeAnnotation(model.GetOrCreateEdmType(entityDescriptor.Entity.GetType()));

            using (ODataMessageWriter messageWriter = Serializer.CreateMessageWriter(requestMessage, this.requestInfo, false /*isParameterPayload*/))
            {
                ODataWriterWrapper entryWriter = ODataWriterWrapper.CreateForEntry(messageWriter, this.requestInfo.Configurations.RequestPipeline);

                // Get the server type name using the type resolver or from the entity descriptor
                string serverTypeName = this.requestInfo.GetServerTypeName(entityDescriptor);

                var entry = CreateODataEntry(entityDescriptor, serverTypeName, entityType, this.requestInfo.Format);

                // Add the annotation required for writing the payload into an XElement
                // for firing WritingEntity events
                if (this.requestInfo.HasWritingEventHandlers)
                {
                    entry.SetAnnotation(new WritingEntityInfo(entityDescriptor.Entity, this.requestInfo));
                }

                if (serverTypeName == null)
                {
                    serverTypeName = this.requestInfo.InferServerTypeNameFromServerModel(entityDescriptor);
                }

                entry.Properties = this.propertyConverter.PopulateProperties(entityDescriptor.Entity, serverTypeName, entityType.PropertiesToSerialize());

                entryWriter.WriteStart(entry, entityDescriptor.Entity);

                if (EntityStates.Added == entityDescriptor.State)
                {
                    this.WriteNavigationLink(entityDescriptor, relatedLinks, entryWriter);
                }

                entryWriter.WriteEnd(entry, entityDescriptor.Entity);
            }
        }
        /// <summary>
        /// Creates and returns an ODataEntry from the given value.
        /// </summary>
        /// <param name="entityType">The value type.</param>
        /// <param name="value">The entry value.</param>
        /// <param name="properties">The given properties to serialize.</param>
        /// <returns>An ODataEntry representing the given value.</returns>
        internal ODataEntry CreateODataEntry(Type entityType, object value, params ClientPropertyAnnotation[] properties)
        {
            Debug.Assert(entityType != null, "entityType != null");
            Debug.Assert(value != null, "value != null");

            ClientEdmModel       model = this.requestInfo.Model;
            ClientTypeAnnotation entityTypeAnnotation = model.GetClientTypeAnnotation(entityType);

            Debug.Assert(entityTypeAnnotation != null, "entityTypeAnnotation != null");
            Debug.Assert(entityTypeAnnotation.IsEntityType, "Unexpected type");

            ODataEntry odataEntityValue = new ODataEntry()
            {
                TypeName = entityTypeAnnotation.ElementTypeName,
            };

            string serverTypeName = this.requestInfo.GetServerTypeName(entityTypeAnnotation);

            odataEntityValue.SetAnnotation(new SerializationTypeNameAnnotation {
                TypeName = serverTypeName
            });

            odataEntityValue.Properties = this.PopulateProperties(value, serverTypeName, properties.Any() ? properties : entityTypeAnnotation.PropertiesToSerialize(), null);

            return(odataEntityValue);
        }