/// <summary>
        /// Creates an <see cref="ODataEnumValue"/> for the object represented by <paramref name="graph"/>.
        /// </summary>
        /// <param name="graph">The enum value.</param>
        /// <param name="enumType">The EDM enum type of the value.</param>
        /// <param name="writeContext">The serializer write context.</param>
        /// <returns>The created <see cref="ODataEnumValue"/>.</returns>
        public virtual Task<ODataEnumValue> CreateODataEnumValueAsync(object graph, IEdmEnumTypeReference enumType,
            ODataSerializerContext writeContext)
        {
            if (graph == null)
            {
                return null;
            }

            string value = null;
            if (graph.GetType().GetTypeInfo().IsEnum)
            {
                value = graph.ToString();
            }
            else
            {
                if (graph.GetType() == typeof(EdmEnumObject))
                {
                    value = ((EdmEnumObject)graph).Value;
                }
            }

            ODataEnumValue enumValue = new ODataEnumValue(value, enumType.FullName());

            ODataMetadataLevel metadataLevel = writeContext != null
                ? writeContext.MetadataLevel
                : ODataMetadataLevel.MinimalMetadata;
            AddTypeNameAnnotationAsNeeded(enumValue, enumType, metadataLevel);

            return Task.FromResult(enumValue);
        }
		/// <inheritdoc />
		public override async Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter,
			ODataSerializerContext writeContext)
		{
			if (messageWriter == null)
			{
				throw Error.ArgumentNull("messageWriter");
			}

			if (writeContext == null)
			{
				throw Error.ArgumentNull("writeContext");
			}

			IEdmNavigationSource navigationSource = writeContext.NavigationSource;
			if (navigationSource == null)
			{
				throw new SerializationException(SRResources.NavigationSourceMissingDuringSerialization);
			}

			var path = writeContext.Path;
			if (path == null)
			{
				throw new SerializationException(SRResources.ODataPathMissing);
			}

			ODataWriter writer = messageWriter.CreateODataEntryWriter(navigationSource, path.EdmType as IEdmEntityType);
			await WriteObjectInlineAsync(graph, navigationSource.EntityType().ToEdmTypeReference(isNullable: false), writer, writeContext);
		}
        /// <inheritdoc />
        public override async Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (messageWriter == null)
            {
                throw Error.ArgumentNull("messageWriter");
            }

            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            IEdmEntitySetBase entitySet = writeContext.NavigationSource as IEdmEntitySetBase;
            if (entitySet == null)
            {
                throw new SerializationException(SRResources.EntitySetMissingDuringSerialization);
            }

            IEdmTypeReference feedType = writeContext.GetEdmType(graph, type);
            Contract.Assert(feedType != null);

            IEdmEntityTypeReference entityType = GetEntityType(feedType);
            ODataWriter writer = messageWriter.CreateODataFeedWriter(entitySet, entityType.EntityDefinition());
            await WriteObjectInlineAsync(graph, feedType, writer, writeContext);
        }
        /// <inheritdoc/>
        public override Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (graph == null)
            {
                throw Error.ArgumentNull("graph");
            }
            if (messageWriter == null)
            {
                throw Error.ArgumentNull("messageWriter");
            }

            ODataError oDataError = graph as ODataError;
            if (oDataError == null)
            {
                HttpError httpError = graph as HttpError;
                if (httpError == null)
                {
                    string message = Error.Format(SRResources.ErrorTypeMustBeODataErrorOrHttpError, graph.GetType().FullName);
                    throw new SerializationException(message);
                }
                else
                {
                    oDataError = httpError.CreateODataError();
                }
            }

            bool includeDebugInformation = oDataError.InnerError != null;
            messageWriter.WriteError(oDataError, includeDebugInformation);

	        return Task.FromResult(true);
        }
        /// <inheritdoc />
        public override async Task WriteObjectInlineAsync(object graph, IEdmTypeReference expectedType, ODataWriter writer,
            ODataSerializerContext writeContext)
        {
            if (writer == null)
            {
                throw Error.ArgumentNull("writer");
            }
            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }
            if (expectedType == null)
            {
                throw Error.ArgumentNull("expectedType");
            }
            if (graph == null)
            {
                throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, Feed));
            }

            IEnumerable enumerable = graph as IEnumerable; // Data to serialize
            if (enumerable == null)
            {
                throw new SerializationException(
                    Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName));
            }

            await WriteFeedAsync(enumerable, expectedType, writer, writeContext);
        }
        /// <inheritdoc/>
        public override Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (messageWriter == null)
            {
                throw Error.ArgumentNull("messageWriter");
            }

            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            if (graph != null)
            {
                ODataEntityReferenceLink entityReferenceLink = graph as ODataEntityReferenceLink;
                if (entityReferenceLink == null)
                {
                    Uri uri = graph as Uri;
                    if (uri == null)
                    {
                        throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName));
                    }

                    entityReferenceLink = new ODataEntityReferenceLink { Url = uri };
                }

                messageWriter.WriteEntityReferenceLink(entityReferenceLink);
            }

	        return Task.FromResult(true);
        }
		protected override async Task CreatingEntityInstanceContextAsync(object entity, IEdmEntityTypeReference entityType, object graph, ODataSerializerContext writeContext)
		{
			if (entity is Customer)
			{
				await PreProcessCustomerAsync(entity as Customer);
			}
			await base.CreatingEntityInstanceContextAsync(entity, entityType, graph, writeContext);
		}
        private EntityInstanceContext(ODataSerializerContext serializerContext, IEdmEntityTypeReference entityType, IEdmEntityObject edmObject, string assemblyName)
        {
            if (serializerContext == null)
            {
                throw Error.ArgumentNull("serializerContext");
            }

	        AssemblyName = assemblyName;
            SerializerContext = serializerContext;
            EntityType = entityType.EntityDefinition();
            EdmObject = edmObject;
        }
        /// <inheritdoc/>
        /// <remarks>The metadata written is from the model set on the <paramref name="messageWriter"/>. The <paramref name="graph" />
        /// is not used.</remarks>
        public override Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (messageWriter == null)
            {
                throw Error.ArgumentNull("messageWriter");
            }

            // NOTE: ODataMessageWriter doesn't have a way to set the IEdmModel. So, there is an underlying assumption here that
            // the model received by this method and the model passed(from configuration) while building ODataMessageWriter is the same (clr object).
            messageWriter.WriteMetadataDocument();

	        return Task.FromResult(true);
        }
		/// <inheritdoc/>
		public sealed override async Task<ODataValue> CreateODataValueAsync(object graph, IEdmTypeReference expectedType, ODataSerializerContext writeContext)
		{
			if (!expectedType.IsPrimitive())
			{
				throw Error.InvalidOperation(SRResources.CannotWriteType, typeof(ODataPrimitiveSerializer), expectedType.FullName());
			}

			ODataPrimitiveValue value = await CreateODataPrimitiveValueAsync(graph, expectedType.AsPrimitive(), writeContext);
			if (value == null)
			{
				return new ODataNullValue();
			}

			return value;
		}
        /// <inheitdoc />
        public sealed override async Task<ODataValue> CreateODataValueAsync(object graph, IEdmTypeReference expectedType,
            ODataSerializerContext writeContext)
        {
            if (expectedType == null)
            {
                throw Error.ArgumentNull("expectedType");
            }

            if (!expectedType.IsComplex())
            {
                throw new SerializationException(
                    Error.Format(SRResources.CannotWriteType, GetType().Name, expectedType.FullName()));
            }

            return await CreateODataComplexValueAsync(graph, expectedType.AsComplex(), writeContext);
        }
		/// <inheritdoc/>
		public override async Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
		{
			if (messageWriter == null)
			{
				throw Error.ArgumentNull("messageWriter");
			}
			if (writeContext == null)
			{
				throw Error.ArgumentNull("writeContext");
			}
			if (writeContext.RootElementName == null)
			{
				throw Error.Argument("writeContext", SRResources.RootElementNameMissing, typeof(ODataSerializerContext).Name);
			}

			IEdmTypeReference edmType = writeContext.GetEdmType(graph, type);
			Contract.Assert(edmType != null);

			messageWriter.WriteProperty(await CreateProperty(graph, edmType, writeContext.RootElementName, writeContext));
		}
		/// <inheritdoc/>
		public override async Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter,
			ODataSerializerContext writeContext)
		{
			if (messageWriter == null)
			{
				throw Error.ArgumentNull("messageWriter");
			}

			if (writeContext == null)
			{
				throw Error.ArgumentNull("writeContext");
			}

			IEdmTypeReference collectionType = writeContext.GetEdmType(graph, type);
			Contract.Assert(collectionType != null);

			IEdmTypeReference elementType = GetElementType(collectionType);
			ODataCollectionWriter writer = messageWriter.CreateODataCollectionWriter(elementType);
			await WriteCollectionAsync(writer, graph, collectionType.AsCollection(), writeContext);
		}
        /// <inheritdoc/>
        public override Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (messageWriter == null)
            {
                throw Error.ArgumentNull("messageWriter");
            }
            if (graph == null)
            {
                throw Error.ArgumentNull("graph");
            }

            ODataServiceDocument serviceDocument = graph as ODataServiceDocument;
            if (serviceDocument == null)
            {
                throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, type.Name));
            }

            messageWriter.WriteServiceDocument(serviceDocument);

	        return Task.FromResult(true);
        }
        /// <inheritdoc/>
        public override Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (messageWriter == null)
            {
                throw Error.ArgumentNull("messageWriter");
            }
            if (graph == null)
            {
                throw Error.ArgumentNull("graph");
            }

            if (graph.GetType().GetTypeInfo().IsEnum)
            {
                messageWriter.WriteValue(graph.ToString());
            }
            else
            {
                messageWriter.WriteValue(ODataPrimitiveSerializer.ConvertUnsupportedPrimitives(graph));
            }
	        return Task.FromResult(true);
        }
		/// <inheritdoc />
		public override async Task WriteObjectInlineAsync(object graph, IEdmTypeReference expectedType, ODataWriter writer,
			ODataSerializerContext writeContext)
		{
			if (writer == null)
			{
				throw Error.ArgumentNull("writer");
			}

			if (writeContext == null)
			{
				throw Error.ArgumentNull("writeContext");
			}

			if (graph == null)
			{
				throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, Entry));
			}
			else
			{
				await WriteEntryAsync(graph, writer, writeContext);
			}
		}
        /// <inheridoc />
        public override Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (messageWriter == null)
            {
                throw Error.ArgumentNull("messageWriter");
            }

            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            if (graph != null)
            {
                ODataEntityReferenceLinks entityReferenceLinks = graph as ODataEntityReferenceLinks;
                if (entityReferenceLinks == null)
                {
                    IEnumerable<Uri> uris = graph as IEnumerable<Uri>;
                    if (uris == null)
                    {
                        throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName));
                    }

                    entityReferenceLinks = new ODataEntityReferenceLinks
                    {
                        Links = uris.Select(uri => new ODataEntityReferenceLink { Url = uri })
                    };

                    if (writeContext.Request != null)
                    {
                        entityReferenceLinks.Count = writeContext.Request.ODataProperties().TotalCount;
                    }
                }

                messageWriter.WriteEntityReferenceLinks(entityReferenceLinks);
            }

	        return Task.FromResult(true);
        }
		/// <inheritdoc/>
		public sealed override async Task<ODataValue> CreateODataValueAsync(object graph, IEdmTypeReference expectedType,
			ODataSerializerContext writeContext)
		{
			if (graph == null)
			{
				throw new SerializationException(Error.Format(SRResources.NullCollectionsCannotBeSerialized));
			}

			IEnumerable enumerable = graph as IEnumerable;
			if (enumerable == null)
			{
				throw Error.Argument("graph", SRResources.ArgumentMustBeOfType, typeof(IEnumerable).Name);
			}
			if (expectedType == null)
			{
				throw Error.ArgumentNull("expectedType");
			}

			IEdmTypeReference elementType = GetElementType(expectedType);

			return await CreateODataCollectionValueAsync(enumerable, elementType, writeContext);
		}
		/// <summary>
		/// Writes the given <paramref name="graph"/> using the given <paramref name="writer"/>.
		/// </summary>
		/// <param name="writer">The <see cref="ODataCollectionWriter"/> to use.</param>
		/// <param name="graph">The collection to write.</param>
		/// <param name="collectionType">The EDM type of the collection.</param>
		/// <param name="writeContext">The serializer context.</param>
		public virtual async Task WriteCollectionAsync(ODataCollectionWriter writer, object graph, IEdmTypeReference collectionType,
			ODataSerializerContext writeContext)
		{
			if (writer == null)
			{
				throw Error.ArgumentNull("writer");
			}

			ODataCollectionStart collectionStart = new ODataCollectionStart { Name = writeContext.RootElementName };

			if (writeContext.Request != null)
			{
				if (writeContext.Request.ODataProperties().NextLink != null)
				{
					collectionStart.NextPageLink = writeContext.Request.ODataProperties().NextLink;
				}

				if (writeContext.Request.ODataProperties().TotalCount != null)
				{
					collectionStart.Count = writeContext.Request.ODataProperties().TotalCount;
				}
			}

			writer.WriteStart(collectionStart);
			if (graph != null)
			{
				ODataCollectionValue collectionValue = await CreateODataValueAsync(graph, collectionType, writeContext) as ODataCollectionValue;
				if (collectionValue != null)
				{
					foreach (object item in collectionValue.Items)
					{
						writer.WriteItem(item);
					}
				}
			}

			writer.WriteEnd();
		}
        /// <summary>
        /// Writes the given deltaDeletedEntry specified by the parameter graph as a part of an existing OData message using the given
        /// messageWriter and the writeContext.
        /// </summary>
        /// <param name="graph">The object to be written.</param>
        /// <param name="writer">The <see cref="ODataDeltaWriter" /> to be used for writing.</param>
        /// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param>
        public virtual void WriteDeltaDeletedEntry(object graph, ODataDeltaWriter writer, ODataSerializerContext writeContext)
        {
            EdmDeltaDeletedEntityObject edmDeltaDeletedEntity = graph as EdmDeltaDeletedEntityObject;

            if (edmDeltaDeletedEntity == null)
            {
                throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName));
            }

            ODataDeltaDeletedEntry deltaDeletedEntry = new ODataDeltaDeletedEntry(
                edmDeltaDeletedEntity.Id, edmDeltaDeletedEntity.Reason);

            if (deltaDeletedEntry != null)
            {
                writer.WriteDeltaDeletedEntry(deltaDeletedEntry);
            }
        }
        /// <summary>
        /// Writes the given deltaDeletedEntry specified by the parameter graph as a part of an existing OData message using the given
        /// messageWriter and the writeContext.
        /// </summary>
        /// <param name="value">The object to be written.</param>
        /// <param name="writer">The <see cref="ODataDeltaWriter" /> to be used for writing.</param>
        /// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param>
        public virtual async Task WriteDeltaDeletedResourceAsync(object value, ODataWriter writer, ODataSerializerContext writeContext)
        {
            if (writer == null)
            {
                throw Error.ArgumentNull(nameof(writer));
            }

            ODataDeletedResource odataDeletedResource;

            if (value is EdmDeltaDeletedResourceObject edmDeltaDeletedEntity)
            {
                odataDeletedResource = new ODataDeletedResource(edmDeltaDeletedEntity.Id, edmDeltaDeletedEntity.Reason ?? DeltaDeletedEntryReason.Deleted);

                if (edmDeltaDeletedEntity.NavigationSource != null)
                {
                    ODataResourceSerializationInfo serializationInfo = new ODataResourceSerializationInfo
                    {
                        NavigationSourceName = edmDeltaDeletedEntity.NavigationSource.Name
                    };
                    odataDeletedResource.SetSerializationInfo(serializationInfo);
                }
            }
            else if (value is IDeltaDeletedResource deltaDeletedResource)
            {
                odataDeletedResource = new ODataDeletedResource(deltaDeletedResource.Id, deltaDeletedResource.Reason ?? DeltaDeletedEntryReason.Deleted);
            }
            else
            {
                throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, value?.GetType().FullName));
            }

            if (odataDeletedResource != null)
            {
                await writer.WriteStartAsync(odataDeletedResource).ConfigureAwait(false);

                await writer.WriteEndAsync().ConfigureAwait(false);
            }
        }
		internal async Task<List<ODataProperty>> AppendDynamicProperties(object source, IEdmStructuredTypeReference structuredType,
			ODataSerializerContext writeContext, List<ODataProperty> declaredProperties,
			string[] selectedDynamicProperties)
		{
			Contract.Assert(source != null);
			Contract.Assert(structuredType != null);
			Contract.Assert(writeContext != null);
			Contract.Assert(writeContext.Model != null);

			PropertyInfo dynamicPropertyInfo = EdmLibHelpers.GetDynamicPropertyDictionary(
				structuredType.StructuredDefinition(), writeContext.Model);

			IEdmStructuredObject structuredObject = source as IEdmStructuredObject;
			object value;
			IDelta delta = source as IDelta;
			if (delta == null)
			{
				if (dynamicPropertyInfo == null || structuredObject == null ||
					!structuredObject.TryGetPropertyValue(dynamicPropertyInfo.Name, out value) || value == null)
				{
					return null;
				}
			}
			else
			{
				value = ((EdmStructuredObject)structuredObject).TryGetDynamicProperties();
			}

			IDictionary<string, object> dynamicPropertyDictionary = (IDictionary<string, object>)value;

			// Build a HashSet to store the declared property names.
			// It is used to make sure the dynamic property name is different from all declared property names.
			HashSet<string> declaredPropertyNameSet = new HashSet<string>(declaredProperties.Select(p => p.Name));
			List<ODataProperty> dynamicProperties = new List<ODataProperty>();
			IEnumerable<KeyValuePair<string, object>> dynamicPropertiesToSelect =
				dynamicPropertyDictionary.Where(
					x => !selectedDynamicProperties.Any() || selectedDynamicProperties.Contains(x.Key));
			foreach (KeyValuePair<string, object> dynamicProperty in dynamicPropertiesToSelect)
			{
				if (String.IsNullOrEmpty(dynamicProperty.Key) || dynamicProperty.Value == null)
				{
					continue; // skip the null object
				}

				if (declaredPropertyNameSet.Contains(dynamicProperty.Key))
				{
					throw Error.InvalidOperation(SRResources.DynamicPropertyNameAlreadyUsedAsDeclaredPropertyName,
						dynamicProperty.Key, structuredType.FullName());
				}

				IEdmTypeReference edmTypeReference = writeContext.GetEdmType(dynamicProperty.Value,
					dynamicProperty.Value.GetType());
				if (edmTypeReference == null)
				{
					throw Error.NotSupported(SRResources.TypeOfDynamicPropertyNotSupported,
						dynamicProperty.Value.GetType().FullName, dynamicProperty.Key);
				}

				ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(edmTypeReference);
				if (propertySerializer == null)
				{
					throw Error.NotSupported(SRResources.DynamicPropertyCannotBeSerialized, dynamicProperty.Key,
						edmTypeReference.FullName());
				}

				dynamicProperties.Add(await propertySerializer.CreateProperty(
					dynamicProperty.Value, edmTypeReference, dynamicProperty.Key, writeContext, source, structuredType, null, null));
			}

			return dynamicProperties;
		}
        /// <inheritdoc/>
        public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (graph == null)
            {
                throw Error.ArgumentNull(nameof(graph));
            }

            if (messageWriter == null)
            {
                throw Error.ArgumentNull(nameof(messageWriter));
            }

            ODataError oDataError = graph as ODataError;

            if (oDataError == null)
            {
                if (!IsHttpError(graph))
                {
                    string message = Error.Format(SRResources.ErrorTypeMustBeODataErrorOrHttpError, graph.GetType().FullName);
                    throw new SerializationException(message);
                }
                else
                {
                    oDataError = CreateODataError(graph);
                }
            }

            // TODO: Call Async version?
            bool includeDebugInformation = oDataError.InnerError != null;

            messageWriter.WriteError(oDataError, includeDebugInformation);
        }
        private async Task WriteFeedAsync(IEnumerable enumerable, IEdmTypeReference feedType, ODataWriter writer,
            ODataSerializerContext writeContext)
        {
            Contract.Assert(writer != null);
            Contract.Assert(writeContext != null);
            Contract.Assert(enumerable != null);
            Contract.Assert(feedType != null);

            IEdmEntityTypeReference elementType = GetEntityType(feedType);
            ODataFeed feed = await CreateODataFeedAsync(enumerable, feedType.AsCollection(), writeContext);
            if (feed == null)
            {
                throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, Feed));
            }

            ODataEdmTypeSerializer entrySerializer = SerializerProvider.GetEdmTypeSerializer(elementType);
            if (entrySerializer == null)
            {
                throw new SerializationException(
                    Error.Format(SRResources.TypeCannotBeSerialized, elementType.FullName(), typeof(ODataOutputFormatter).Name));
            }

            // save this for later to support JSON odata.streaming.
            Uri nextPageLink = feed.NextPageLink;
            feed.NextPageLink = null;

            writer.WriteStart(feed);

            foreach (object entry in enumerable)
            {
                if (entry == null)
                {
                    throw new SerializationException(SRResources.NullElementInCollection);
                }

                await entrySerializer.WriteObjectInlineAsync(entry, elementType, writer, writeContext);
            }

            // Subtle and suprising behavior: If the NextPageLink property is set before calling WriteStart(feed),
            // the next page link will be written early in a manner not compatible with odata.streaming=true. Instead, if
            // the next page link is not set when calling WriteStart(feed) but is instead set later on that feed
            // object before calling WriteEnd(), the next page link will be written at the end, as required for
            // odata.streaming=true support.

            if (nextPageLink != null)
            {
                feed.NextPageLink = nextPageLink;
            }

            writer.WriteEnd();
        }
Exemple #25
0
        private async Task <EntityInstanceContext> CreateEntityInstanceContextAsync(object graph, ODataSerializerContext writeContext, IEdmEntityTypeReference entityType)
        {
            var entity = graph;

            if (graph is ISelectExpandWrapper)
            {
                entity = (graph as ISelectExpandWrapper).Instance;
            }
            await CreatingEntityInstanceContextAsync(entity, entityType, graph, writeContext);

            return(new EntityInstanceContext(writeContext, entityType, graph, null));
        }
        /// <inheritdoc/>
        public sealed override ODataValue CreateODataValue(object graph, IEdmTypeReference expectedType, ODataSerializerContext writeContext)
        {
            if (!expectedType.IsPrimitive())
            {
                throw Error.InvalidOperation(SRResources.CannotWriteType, typeof(ODataPrimitiveSerializer), expectedType.FullName());
            }

            ODataPrimitiveValue value = CreateODataPrimitiveValue(graph, expectedType.AsPrimitive(), writeContext);

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

            return(value);
        }
Exemple #27
0
        /// <inheritdoc />
        public override async Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (messageWriter == null)
            {
                throw Error.ArgumentNull(nameof(messageWriter));
            }

            if (writeContext == null)
            {
                throw Error.ArgumentNull(nameof(writeContext));
            }

            IEdmEntitySetBase entitySet = writeContext.NavigationSource as IEdmEntitySetBase;

            IEdmTypeReference resourceSetType = writeContext.GetEdmType(graph, type);

            Contract.Assert(resourceSetType != null);

            IEdmStructuredTypeReference resourceType = GetResourceType(resourceSetType);

            ODataWriter writer = await messageWriter.CreateODataResourceSetWriterAsync(entitySet, resourceType.StructuredDefinition())
                                 .ConfigureAwait(false);

            await WriteObjectInlineAsync(graph, resourceSetType, writer, writeContext)
            .ConfigureAwait(false);
        }
 /// <inheritdoc/>
 public virtual async Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
 {
     await Task.Run(() => throw Error.NotSupported(SRResources.WriteObjectNotSupported, GetType().Name)).ConfigureAwait(false);
 }
        /// <inheritdoc/>
        public override void WriteObject(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (messageWriter == null)
            {
                throw Error.ArgumentNull("messageWriter");
            }
            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }
            if (writeContext.RootElementName == null)
            {
                throw Error.Argument("writeContext", SRResources.RootElementNameMissing, typeof(ODataSerializerContext).Name);
            }

            IEdmTypeReference edmType = writeContext.GetEdmType(graph, type);

            Contract.Assert(edmType != null);

            messageWriter.WriteProperty(CreateProperty(graph, edmType, writeContext.RootElementName, writeContext));
        }
 /// <summary>
 /// Creates an <see cref="ODataPrimitiveValue"/> for the object represented by <paramref name="graph"/>.
 /// </summary>
 /// <param name="graph">The primitive value.</param>
 /// <param name="primitiveType">The EDM primitive type of the value.</param>
 /// <param name="writeContext">The serializer write context.</param>
 /// <returns>The created <see cref="ODataPrimitiveValue"/>.</returns>
 public virtual ODataPrimitiveValue CreateODataPrimitiveValue(object graph, IEdmPrimitiveTypeReference primitiveType,
                                                              ODataSerializerContext writeContext)
 {
     return(CreatePrimitive(graph, primitiveType, writeContext));
 }
Exemple #31
0
        /// <summary>
        /// Creates an <see cref="ODataCollectionValue"/> for the enumerable represented by <paramref name="enumerable"/>.
        /// </summary>
        /// <param name="enumerable">The value of the collection to be created.</param>
        /// <param name="elementType">The element EDM type of the collection.</param>
        /// <param name="writeContext">The serializer context to be used while creating the collection.</param>
        /// <returns>The created <see cref="ODataCollectionValue"/>.</returns>
        public virtual async Task <ODataCollectionValue> CreateODataCollectionValueAsync(IEnumerable enumerable, IEdmTypeReference elementType,
                                                                                         ODataSerializerContext writeContext)
        {
            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }
            if (elementType == null)
            {
                throw Error.ArgumentNull("elementType");
            }

            var valueCollection = new List <object>();

            if (enumerable != null)
            {
                ODataEdmTypeSerializer itemSerializer = null;
                foreach (object item in enumerable)
                {
                    if (item == null)
                    {
                        if (elementType.IsNullable)
                        {
                            valueCollection.Add(null);
                            continue;
                        }

                        throw new SerializationException(SRResources.NullElementInCollection);
                    }

                    IEdmTypeReference actualType = writeContext.GetEdmType(item, item.GetType());
                    Contract.Assert(actualType != null);

                    itemSerializer = itemSerializer ?? SerializerProvider.GetEdmTypeSerializer(actualType);
                    if (itemSerializer == null)
                    {
                        throw new SerializationException(
                                  Error.Format(SRResources.TypeCannotBeSerialized, actualType.FullName(),
                                               typeof(ODataOutputFormatter).Name));
                    }

                    // ODataCollectionWriter expects the individual elements in the collection to be the underlying
                    // values and not ODataValues.
                    valueCollection.Add(
                        (await itemSerializer.CreateODataValueAsync(item, actualType, writeContext)).GetInnerValue());
                }
            }

            // Ideally, we'd like to do this:
            // string typeName = _edmCollectionType.FullName();
            // But ODataLib currently doesn't support .FullName() for collections. As a workaround, we construct the
            // collection type name the hard way.
            string typeName = "Collection(" + elementType.FullName() + ")";

            // ODataCollectionValue is only a V3 property, arrays inside Complex Types or Entity types are only supported in V3
            // if a V1 or V2 Client requests a type that has a collection within it ODataLib will throw.
            ODataCollectionValue value = new ODataCollectionValue
            {
                Items    = valueCollection,
                TypeName = typeName
            };

            AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel);
            return(value);
        }
Exemple #32
0
        /// <inheritdoc/>
        public override async Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (graph == null)
            {
                throw Error.ArgumentNull(nameof(graph));
            }

            if (messageWriter == null)
            {
                throw Error.ArgumentNull(nameof(messageWriter));
            }

            ODataServiceDocument serviceDocument = graph as ODataServiceDocument;

            if (serviceDocument == null)
            {
                throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, type?.Name));
            }

            // TODO: Call Async version?
            // messageWriter.WriteServiceDocumentAsync(serviceDocument);
            await messageWriter.WriteServiceDocumentAsync(serviceDocument).ConfigureAwait(false);
        }
		/// <summary>
		/// Creates an <see cref="ODataPrimitiveValue"/> for the object represented by <paramref name="graph"/>.
		/// </summary>
		/// <param name="graph">The primitive value.</param>
		/// <param name="primitiveType">The EDM primitive type of the value.</param>
		/// <param name="writeContext">The serializer write context.</param>
		/// <returns>The created <see cref="ODataPrimitiveValue"/>.</returns>
		public virtual Task<ODataPrimitiveValue> CreateODataPrimitiveValueAsync(object graph, IEdmPrimitiveTypeReference primitiveType,
			ODataSerializerContext writeContext)
		{
			// TODO: Bug 467598: validate the type of the object being passed in here with the underlying primitive type. 
			return Task.FromResult(CreatePrimitive(graph, primitiveType, writeContext));
		}
 /// <summary>
 /// Creates an <see cref="ODataPrimitiveValue"/> for the object represented by <paramref name="graph"/>.
 /// </summary>
 /// <param name="graph">The primitive value.</param>
 /// <param name="primitiveType">The EDM primitive type of the value.</param>
 /// <param name="writeContext">The serializer write context.</param>
 /// <returns>The created <see cref="ODataPrimitiveValue"/>.</returns>
 public virtual ODataPrimitiveValue CreateODataPrimitiveValue(object graph, IEdmPrimitiveTypeReference primitiveType,
                                                              ODataSerializerContext writeContext)
 {
     // TODO: Bug 467598: validate the type of the object being passed in here with the underlying primitive type.
     return(CreatePrimitive(graph, primitiveType, writeContext));
 }
Exemple #35
0
 /// <summary>
 /// Writes the given object specified by the parameter graph as a whole using the given messageWriter and writeContext.
 /// </summary>
 /// <param name="graph">The object to be written</param>
 /// <param name="type">The type of the object to be written.</param>
 /// <param name="messageWriter">The <see cref="ODataMessageWriter"/> to be used for writing.</param>
 /// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param>
 public virtual Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
 {
     throw Error.NotSupported(SRResources.WriteObjectNotSupported, GetType().Name);
 }
Exemple #36
0
        /// <summary>
        ///  Creates an <see cref="ODataOperation" /> to be written for the given operation and the resourceSet instance.
        /// </summary>
        /// <param name="operation">The OData operation.</param>
        /// <param name="resourceSetContext">The context for the resourceSet instance being written.</param>
        /// <param name="writeContext">The serializer context.</param>
        /// <returns>The created operation or null if the operation should not be written.</returns>
        public virtual ODataOperation CreateODataOperation(IEdmOperation operation, ResourceSetContext resourceSetContext, ODataSerializerContext writeContext)
        {
            if (operation == null)
            {
                throw Error.ArgumentNull(nameof(operation));
            }

            if (resourceSetContext == null)
            {
                throw Error.ArgumentNull(nameof(resourceSetContext));
            }

            if (writeContext == null)
            {
                throw Error.ArgumentNull(nameof(writeContext));
            }

            ODataMetadataLevel metadataLevel = writeContext.MetadataLevel;
            IEdmModel          model         = writeContext.Model;

            if (metadataLevel != ODataMetadataLevel.Full)
            {
                return(null);
            }

            OperationLinkBuilder builder = model.GetOperationLinkBuilder(operation);

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

            Uri target = builder.BuildLink(resourceSetContext);

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

            Uri baseUri  = new Uri(writeContext.Request.CreateODataLink(MetadataSegment.Instance));
            Uri metadata = new Uri(baseUri, "#" + operation.FullName());

            ODataOperation odataOperation;
            IEdmAction     action = operation as IEdmAction;

            if (action != null)
            {
                odataOperation = new ODataAction();
            }
            else
            {
                odataOperation = new ODataFunction();
            }
            odataOperation.Metadata = metadata;

            // Always omit the title in minimal/no metadata modes.
            ODataResourceSerializer.EmitTitle(model, operation, odataOperation);

            // Omit the target in minimal/no metadata modes unless it doesn't follow conventions.
            if (metadataLevel == ODataMetadataLevel.Full || !builder.FollowsConventions)
            {
                odataOperation.Target = target;
            }

            return(odataOperation);
        }
Exemple #37
0
 protected virtual Task CreatingEntityInstanceContextAsync(object entity, IEdmEntityTypeReference entityType, object graph, ODataSerializerContext writeContext)
 {
     return(Task.FromResult(true));
 }
        /// <inheritdoc/>
        /// <remarks>The metadata written is from the model set on the <paramref name="messageWriter"/>. The <paramref name="graph" />
        /// is not used.</remarks>
        public override Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (messageWriter == null)
            {
                throw Error.ArgumentNull("messageWriter");
            }

            // NOTE: ODataMessageWriter doesn't have a way to set the IEdmModel. So, there is an underlying assumption here that
            // the model received by this method and the model passed(from configuration) while building ODataMessageWriter is the same (clr object).
            messageWriter.WriteMetadataDocument();

            return(Task.FromResult(true));
        }
        /// <summary>
        /// Writes the given deltaDeletedLink specified by the parameter graph as a part of an existing OData message using the given
        /// messageWriter and the writeContext.
        /// </summary>
        /// <param name="graph">The object to be written.</param>
        /// <param name="writer">The <see cref="ODataDeltaWriter" /> to be used for writing.</param>
        /// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param>
        public virtual void WriteDeltaDeletedLink(object graph, ODataDeltaWriter writer, ODataSerializerContext writeContext)
        {
            EdmDeltaDeletedLink edmDeltaDeletedLink = graph as EdmDeltaDeletedLink;

            if (edmDeltaDeletedLink == null)
            {
                throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph.GetType().FullName));
            }

            ODataDeltaDeletedLink deltaDeletedLink = new ODataDeltaDeletedLink(
                edmDeltaDeletedLink.Source,
                edmDeltaDeletedLink.Target,
                edmDeltaDeletedLink.Relationship);

            if (deltaDeletedLink != null)
            {
                writer.WriteDeltaDeletedLink(deltaDeletedLink);
            }
        }
		/// <summary>
		/// Creates an <see cref="ODataValue"/> for the object represented by <paramref name="graph"/>.
		/// </summary>
		/// <param name="graph">The value of the <see cref="ODataValue"/> to be created.</param>
		/// <param name="expectedType">The expected EDM type of the object represented by <paramref name="graph"/>.</param>
		/// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param>
		/// <returns>The <see cref="ODataValue"/> created.</returns>
		public virtual async Task<ODataValue> CreateODataValueAsync(object graph, IEdmTypeReference expectedType, ODataSerializerContext writeContext)
		{
			throw Error.NotSupported(SRResources.CreateODataValueNotSupported, GetType().Name);
		}
		private static object InterceptValue(object graph, IEdmTypeReference expectedType, string elementName,
			ODataSerializerContext writeContext, object declaringInstance, IEdmTypeReference declaringTypeReference,
			IEdmType declaringType, Type declaringClrType)
		{
			var modelBuilder = EdmModelHelperMethods.Configuration[writeContext.Model];
			var assemblyNames = writeContext.Request.HttpContext.RequestServices.GetService<AssembliesResolver>();
			var clrType = EdmLibHelpers.GetClrType(expectedType, writeContext.Model, assemblyNames);
			var serializers = modelBuilder.GetSerializeInterceptors(
				clrType).ToList();
			var isRoot = declaringInstance == null &&
						 declaringTypeReference == null &&
						 declaringType == null &&
						 declaringClrType == null;

			if (serializers.Any())
			{
				if (declaringClrType == null && declaringTypeReference != null)
				{
					declaringClrType = declaringType != null
						? EdmLibHelpers.GetClrType(declaringType, writeContext.Model, assemblyNames)
						: EdmLibHelpers.GetClrType(declaringTypeReference, writeContext.Model, assemblyNames);
				}
				var vp = new ValueInterceptor(
					graph, clrType, elementName, declaringInstance, declaringClrType, isRoot);
				foreach (var serializer in serializers)
				{
					if (!serializer.Process(vp))
					{
						break;
					}
				}
				graph = vp.Value;
			}
			return graph;
		}
		private async Task<ODataProperty> CreateProperty(object graph, IEdmTypeReference expectedType, string elementName,
			ODataSerializerContext writeContext, object declaringInstance,
			IEdmTypeReference declaringTypeReference,
			IEdmType declaringType,
			Type declaringClrType)
		{
			Contract.Assert(elementName != null);
			graph = InterceptValue(graph, expectedType, elementName, writeContext, declaringInstance, declaringTypeReference, declaringType, declaringClrType);
			return new ODataProperty
			{
				Name = elementName,
				Value = await CreateODataValueAsync(graph, expectedType, writeContext)
			};
		}
		/// <summary>
		/// Writes the given object specified by the parameter graph as a part of an existing OData message using the given
		/// messageWriter and the writeContext.
		/// </summary>
		/// <param name="graph">The object to be written.</param>
		/// <param name="expectedType">The expected EDM type of the object represented by <paramref name="graph"/>.</param>
		/// <param name="writer">The <see cref="ODataWriter" /> to be used for writing.</param>
		/// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param>
		public virtual async Task WriteObjectInlineAsync(object graph, IEdmTypeReference expectedType, ODataWriter writer,
			ODataSerializerContext writeContext)
		{
			throw Error.NotSupported(SRResources.WriteObjectInlineNotSupported, GetType().Name);
		}
        /// <inheritdoc />
        public override async Task WriteObjectAsync(object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
        {
            if (messageWriter == null)
            {
                throw Error.ArgumentNull("messageWriter");
            }

            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            if (graph == null)
            {
                throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, DeltaFeed));
            }

            IEdmEntitySetBase entitySet = writeContext.NavigationSource as IEdmEntitySetBase;

            if (entitySet == null)
            {
                throw new SerializationException(SRResources.EntitySetMissingDuringSerialization);
            }

            IEdmTypeReference feedType = writeContext.GetEdmType(graph, type);

            Contract.Assert(feedType != null);

            IEdmEntityTypeReference entityType = GetEntityType(feedType);
            ODataDeltaWriter        writer     = messageWriter.CreateODataDeltaWriter(entitySet, entityType.EntityDefinition());

            await WriteDeltaFeedInline(graph, feedType, writer, writeContext);

            writer.Flush();
        }
		internal async Task<ODataProperty> CreateProperty(object graph, IEdmTypeReference expectedType, string elementName,
			ODataSerializerContext writeContext)
		{
			return await CreateProperty(graph, expectedType, elementName, writeContext, null,
				null, null, null);
		}
Exemple #46
0
        private async Task WriteDeltaEntryAsync(object graph, ODataDeltaWriter writer, ODataSerializerContext writeContext)
        {
            Contract.Assert(writeContext != null);

            IEdmEntityTypeReference entityType            = GetEntityType(graph, writeContext);
            EntityInstanceContext   entityInstanceContext =
                await CreateEntityInstanceContextAsync(graph, writeContext, entityType);

            SelectExpandNode selectExpandNode = await CreateSelectExpandNodeAsync(entityInstanceContext);

            if (selectExpandNode != null)
            {
                ODataEntry entry = await CreateEntryAsync(selectExpandNode, entityInstanceContext);

                if (entry != null)
                {
                    writer.WriteStart(entry);
                    //TODO: Need to add support to write Navigation Links using Delta Writer
                    //https://github.com/OData/odata.net/issues/155
                    writer.WriteEnd();
                }
            }
        }
        /// <summary>
        /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>.
        /// </summary>
        /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param>
        /// <param name="complexType">The EDM complex type of the object.</param>
        /// <param name="writeContext">The serializer context.</param>
        /// <returns>The created <see cref="ODataComplexValue"/>.</returns>
        public virtual async Task<ODataComplexValue> CreateODataComplexValueAsync(object graph, IEdmComplexTypeReference complexType,
            ODataSerializerContext writeContext)
        {
            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            if (graph == null || graph is NullEdmComplexObject)
            {
                return null;
            }

            IEdmComplexObject complexObject = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType, writeContext.Model);

            List<ODataProperty> propertyCollection = new List<ODataProperty>();
            foreach (IEdmProperty property in complexType.ComplexDefinition().Properties())
            {
                IEdmTypeReference propertyType = property.Type;
                ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType);
                if (propertySerializer == null)
                {
                    throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataOutputFormatter).Name);
                }

                object propertyValue;
                if (complexObject.TryGetPropertyValue(property.Name, out propertyValue))
                {
                    if (propertyType != null && propertyType.IsComplex())
                    {
                        IEdmTypeReference actualType = writeContext.GetEdmType(propertyValue, propertyValue.GetType());
                        if (actualType != null && propertyType != actualType)
                        {
                            propertyType = actualType;
                        }
                    }

                    propertyCollection.Add(
                        await propertySerializer.CreateProperty(propertyValue, propertyType, property.Name, writeContext));
                }
            }

            // Try to add the dynamic properties if the complex type is open.
            if (complexType.ComplexDefinition().IsOpen)
            {
                List<ODataProperty> dynamicProperties = 
                    await AppendDynamicProperties(complexObject, complexType, writeContext, propertyCollection, new string[0]);

                if (dynamicProperties != null)
                {
                    propertyCollection.AddRange(dynamicProperties);
                }
            }

            string typeName = complexType.FullName();

            ODataComplexValue value = new ODataComplexValue()
            {
                Properties = propertyCollection,
                TypeName = typeName
            };

            AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel);
            return value;
        }
        private async Task WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, ODataDeltaWriter writer,
                                     ODataSerializerContext writeContext)
        {
            Contract.Assert(writer != null);
            Contract.Assert(writeContext != null);
            Contract.Assert(enumerable != null);
            Contract.Assert(feedType != null);

            ODataDeltaResourceSet deltaFeed = CreateODataDeltaFeed(enumerable, feedType.AsCollection(), writeContext);

            if (deltaFeed == null)
            {
                throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, DeltaFeed));
            }

            // save this for later to support JSON odata.streaming.
            Uri nextPageLink = deltaFeed.NextPageLink;

            deltaFeed.NextPageLink = null;

            //Start writing of the Delta Feed
            writer.WriteStart(deltaFeed);

            //Iterate over all the entries present and select the appropriate write method.
            //Write method creates ODataDeltaDeletedEntry / ODataDeltaDeletedLink / ODataDeltaLink or ODataEntry.
            foreach (object entry in enumerable)
            {
                if (entry == null)
                {
                    throw new SerializationException(SRResources.NullElementInCollection);
                }

                IEdmChangedObject edmChangedObject = entry as IEdmChangedObject;
                if (edmChangedObject == null)
                {
                    throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, enumerable.GetType().FullName));
                }

                switch (edmChangedObject.DeltaKind)
                {
                case EdmDeltaEntityKind.DeletedEntry:
                    WriteDeltaDeletedEntry(entry, writer, writeContext);
                    break;

                case EdmDeltaEntityKind.DeletedLinkEntry:
                    WriteDeltaDeletedLink(entry, writer, writeContext);
                    break;

                case EdmDeltaEntityKind.LinkEntry:
                    WriteDeltaLink(entry, writer, writeContext);
                    break;

                case EdmDeltaEntityKind.Entry:
                {
                    IEdmEntityTypeReference elementType     = GetEntityType(feedType);
                    ODataResourceSerializer entrySerializer = SerializerProvider.GetEdmTypeSerializer(writeContext.Context, elementType) as ODataResourceSerializer;
                    if (entrySerializer == null)
                    {
                        throw new SerializationException(
                                  Error.Format(SRResources.TypeCannotBeSerialized, elementType.FullName(), typeof(ODataOutputFormatter).Name));
                    }
                    await entrySerializer.WriteDeltaObjectInline(entry, elementType, writer, writeContext);

                    break;
                }

                default:
                    break;
                }
            }

            // Subtle and surprising behavior: If the NextPageLink property is set before calling WriteStart(feed),
            // the next page link will be written early in a manner not compatible with odata.streaming=true. Instead, if
            // the next page link is not set when calling WriteStart(feed) but is instead set later on that feed
            // object before calling WriteEnd(), the next page link will be written at the end, as required for
            // odata.streaming=true support.
            if (nextPageLink != null)
            {
                deltaFeed.NextPageLink = nextPageLink;
            }

            //End Writing of the Delta Feed
            writer.WriteEnd();
        }
        /// <summary>
        /// Writes the given deltaLink specified by the parameter graph as a part of an existing OData message using the given
        /// messageWriter and the writeContext.
        /// </summary>
        /// <param name="value">The object to be written.</param>
        /// <param name="writer">The <see cref="ODataDeltaWriter" /> to be used for writing.</param>
        /// <param name="writeContext">The <see cref="ODataSerializerContext"/>.</param>
        public virtual async Task WriteDeltaLinkAsync(object value, ODataWriter writer, ODataSerializerContext writeContext)
        {
            if (value == null)
            {
                throw Error.ArgumentNull(nameof(value));
            }

            if (writer == null)
            {
                throw Error.ArgumentNull(nameof(writer));
            }

            ODataDeltaLink odataDeltaLink;

            if (value is EdmDeltaLink edmDeltaLink) // typeless
            {
                odataDeltaLink = new ODataDeltaLink(edmDeltaLink.Source, edmDeltaLink.Target, edmDeltaLink.Relationship);
            }
            else if (value is IDeltaLink deltaLink) // typed
            {
                odataDeltaLink = new ODataDeltaLink(deltaLink.Source, deltaLink.Target, deltaLink.Relationship);
            }
            else
            {
                throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, value.GetType().FullName));
            }

            if (odataDeltaLink != null)
            {
                await writer.WriteDeltaLinkAsync(odataDeltaLink).ConfigureAwait(false);
            }
        }
Exemple #50
0
        /// <summary>
        /// Creates a function that takes in an object and generates nextlink uri.
        /// </summary>
        /// <param name="resourceSet">The resource set describing a collection of structured objects.</param>
        /// <param name="resourceSetInstance">The instance representing the resourceSet being written.</param>
        /// <param name="writeContext">The serializer context.</param>
        /// <returns>The function that generates the NextLink from an object.</returns>
        internal static Func <object, Uri> GetNextLinkGenerator(ODataResourceSetBase resourceSet, IEnumerable resourceSetInstance, ODataSerializerContext writeContext)
        {
            if (resourceSet != null && resourceSet.NextPageLink != null)
            {
                Uri defaultUri = resourceSet.NextPageLink;
                return((obj) => { return defaultUri; });
            }

            if (writeContext.ExpandedResource == null)
            {
                if (writeContext.Request != null && writeContext.QueryContext != null)
                {
                    SkipTokenHandler handler = writeContext.QueryContext.GetSkipTokenHandler();
                    return((obj) => { return handler.GenerateNextPageLink(new System.Uri(writeContext.Request.GetEncodedUrl()),
                                                                          (writeContext.Request.ODataFeature() as ODataFeature).PageSize, obj, writeContext); });
                }
            }
            else
            {
                // nested resourceSet
                ITruncatedCollection truncatedCollection = resourceSetInstance as ITruncatedCollection;
                if (truncatedCollection != null && truncatedCollection.IsTruncated)
                {
                    return((obj) => { return GetNestedNextPageLink(writeContext, truncatedCollection.PageSize, obj); });
                }
            }

            return((obj) => { return null; });
        }
		private static ODataPrimitiveValue CreatePrimitive(object value, IEdmPrimitiveTypeReference primitveType,
			ODataSerializerContext writeContext)
		{
			if (value == null)
			{
				return null;
			}

			object supportedValue = ConvertUnsupportedPrimitives(value);
			ODataPrimitiveValue primitive = new ODataPrimitiveValue(supportedValue);

			if (writeContext != null)
			{
				AddTypeNameAnnotationAsNeeded(primitive, primitveType, writeContext.MetadataLevel);
			}

			return primitive;
		}
Exemple #52
0
        /// <summary>
        /// Create the <see cref="ODataResourceSet"/> to be written for the given resourceSet instance.
        /// </summary>
        /// <param name="resourceSetInstance">The instance representing the resourceSet being written.</param>
        /// <param name="resourceSetType">The EDM type of the resourceSet being written.</param>
        /// <param name="writeContext">The serializer context.</param>
        /// <returns>The created <see cref="ODataResourceSet"/> object.</returns>
        public virtual ODataResourceSet CreateResourceSet(IEnumerable resourceSetInstance, IEdmCollectionTypeReference resourceSetType,
                                                          ODataSerializerContext writeContext)
        {
            if (writeContext == null)
            {
                throw Error.ArgumentNull(nameof(writeContext));
            }

            ODataResourceSet resourceSet = new ODataResourceSet
            {
                TypeName = resourceSetType.FullName()
            };

            IEdmStructuredTypeReference structuredType = GetResourceType(resourceSetType).AsStructured();

            if (writeContext.NavigationSource != null && structuredType.IsEntity())
            {
                ResourceSetContext resourceSetContext = ResourceSetContext.Create(writeContext, resourceSetInstance);
                IEdmEntityType     entityType         = structuredType.AsEntity().EntityDefinition();
                var operations      = writeContext.Model.GetAvailableOperationsBoundToCollection(entityType);
                var odataOperations = CreateODataOperations(operations, resourceSetContext, writeContext);
                foreach (var odataOperation in odataOperations)
                {
                    ODataAction action = odataOperation as ODataAction;
                    if (action != null)
                    {
                        resourceSet.AddAction(action);
                    }
                    else
                    {
                        resourceSet.AddFunction((ODataFunction)odataOperation);
                    }
                }
            }

            if (writeContext.ExpandedResource == null)
            {
                // If we have more OData format specific information apply it now, only if we are the root feed.
                PageResult odataResourceSetAnnotations = resourceSetInstance as PageResult;
                if (odataResourceSetAnnotations != null)
                {
                    resourceSet.Count        = odataResourceSetAnnotations.Count;
                    resourceSet.NextPageLink = odataResourceSetAnnotations.NextPageLink;
                }
                else if (writeContext.Request != null)
                {
                    IODataFeature odataFeature = writeContext.Request.ODataFeature();
                    resourceSet.NextPageLink = odataFeature.NextLink;
                    resourceSet.DeltaLink    = odataFeature.DeltaLink;

                    long?countValue = odataFeature.TotalCount;
                    if (countValue.HasValue)
                    {
                        resourceSet.Count = countValue.Value;
                    }
                }
            }
            else
            {
                ICountOptionCollection countOptionCollection = resourceSetInstance as ICountOptionCollection;
                if (countOptionCollection != null && countOptionCollection.TotalCount != null)
                {
                    resourceSet.Count = countOptionCollection.TotalCount;
                }
            }

            return(resourceSet);
        }
 /// <summary>
 /// Creates a function that takes in an object and generates nextlink uri.
 /// </summary>
 /// <param name="deltaResourceSet">The resource set describing a collection of structured objects.</param>
 /// <param name="enumerable">>The instance representing the resourceSet being written.</param>
 /// <param name="writeContext">The serializer context.</param>
 /// <returns>The function that generates the NextLink from an object.</returns>
 /// <returns></returns>
 internal static Func <object, Uri> GetNextLinkGenerator(ODataDeltaResourceSet deltaResourceSet, IEnumerable enumerable, ODataSerializerContext writeContext)
 {
     return(ODataResourceSetSerializer.GetNextLinkGenerator(deltaResourceSet, enumerable, writeContext));
 }
Exemple #54
0
        private async Task WriteResourceSetAsync(IEnumerable enumerable, IEdmTypeReference resourceSetType, ODataWriter writer,
                                                 ODataSerializerContext writeContext)
        {
            Contract.Assert(writer != null);
            Contract.Assert(writeContext != null);
            Contract.Assert(enumerable != null);
            Contract.Assert(resourceSetType != null);

            IEdmStructuredTypeReference elementType = GetResourceType(resourceSetType);
            ODataResourceSet            resourceSet = CreateResourceSet(enumerable, resourceSetType.AsCollection(), writeContext);

            Func <object, Uri> nextLinkGenerator = GetNextLinkGenerator(resourceSet, enumerable, writeContext);

            if (resourceSet == null)
            {
                throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, ResourceSet));
            }

            IEdmEntitySetBase entitySet = writeContext.NavigationSource as IEdmEntitySetBase;

            if (entitySet == null)
            {
                resourceSet.SetSerializationInfo(new ODataResourceSerializationInfo
                {
                    IsFromCollection = true,
                    NavigationSourceEntityTypeName = elementType.FullName(),
                    NavigationSourceKind           = EdmNavigationSourceKind.UnknownEntitySet,
                    NavigationSourceName           = null
                });
            }

            ODataEdmTypeSerializer resourceSerializer = SerializerProvider.GetEdmTypeSerializer(elementType);

            if (resourceSerializer == null)
            {
                throw new SerializationException(
                          Error.Format(SRResources.TypeCannotBeSerialized, elementType.FullName()));
            }

            // set the nextpagelink to null to support JSON odata.streaming.
            resourceSet.NextPageLink = null;
            await writer.WriteStartAsync(resourceSet).ConfigureAwait(false);

            object lastResource = null;

            foreach (object item in enumerable)
            {
                lastResource = item;
                if (item == null || item is NullEdmComplexObject)
                {
                    if (elementType.IsEntity())
                    {
                        throw new SerializationException(SRResources.NullElementInCollection);
                    }

                    // for null complex element, it can be serialized as "null" in the collection.
                    await writer.WriteStartAsync(resource : null).ConfigureAwait(false);

                    await writer.WriteEndAsync().ConfigureAwait(false);
                }
                else
                {
                    await resourceSerializer.WriteObjectInlineAsync(item, elementType, writer, writeContext).ConfigureAwait(false);
                }
            }

            // Subtle and surprising behavior: If the NextPageLink property is set before calling WriteStart(resourceSet),
            // the next page link will be written early in a manner not compatible with odata.streaming=true. Instead, if
            // the next page link is not set when calling WriteStart(resourceSet) but is instead set later on that resourceSet
            // object before calling WriteEnd(), the next page link will be written at the end, as required for
            // odata.streaming=true support.

            resourceSet.NextPageLink = nextLinkGenerator(lastResource);

            await writer.WriteEndAsync().ConfigureAwait(false);
        }
        private async Task WriteDeltaResourceSetAsync(IEnumerable enumerable, IEdmTypeReference feedType, ODataWriter writer,
                                                      ODataSerializerContext writeContext)
        {
            Contract.Assert(writer != null);
            Contract.Assert(writeContext != null);
            Contract.Assert(enumerable != null);
            Contract.Assert(feedType != null);

            IEdmStructuredTypeReference elementType = GetResourceType(feedType);

            if (elementType.IsComplex())
            {
                ODataResourceSet resourceSet = new ODataResourceSet()
                {
                    TypeName = feedType.FullName()
                };

                await writer.WriteStartAsync(resourceSet).ConfigureAwait(false);

                ODataResourceSerializer entrySerializer = SerializerProvider.GetEdmTypeSerializer(elementType) as ODataResourceSerializer;
                if (entrySerializer == null)
                {
                    throw new SerializationException(
                              Error.Format(SRResources.TypeCannotBeSerialized, elementType.FullName()));
                }

                foreach (object entry in enumerable)
                {
                    await entrySerializer.WriteDeltaObjectInlineAsync(entry, elementType, writer, writeContext).ConfigureAwait(false);
                }
            }
            else
            {
                ODataDeltaResourceSet deltaResourceSet = CreateODataDeltaResourceSet(enumerable, feedType.AsCollection(), writeContext);
                if (deltaResourceSet == null)
                {
                    throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, DeltaResourceSet));
                }

                // save the next page link for later to support JSON odata.streaming.
                Func <object, Uri> nextLinkGenerator = GetNextLinkGenerator(deltaResourceSet, enumerable, writeContext);
                deltaResourceSet.NextPageLink = null;

                //Start writing of the Delta Feed
                await writer.WriteStartAsync(deltaResourceSet).ConfigureAwait(false);

                object lastResource = null;
                //Iterate over all the entries present and select the appropriate write method.
                //Write method creates ODataDeltaDeletedEntry / ODataDeltaDeletedLink / ODataDeltaLink or ODataEntry.
                foreach (object item in enumerable)
                {
                    if (item == null)
                    {
                        throw new SerializationException(SRResources.NullElementInCollection);
                    }

                    lastResource = item;
                    DeltaItemKind kind = GetDelteItemKind(item);
                    switch (kind)
                    {
                    case DeltaItemKind.DeletedResource:
                        await WriteDeltaDeletedResourceAsync(item, writer, writeContext).ConfigureAwait(false);

                        break;

                    case DeltaItemKind.DeltaDeletedLink:
                        await WriteDeltaDeletedLinkAsync(item, writer, writeContext).ConfigureAwait(false);

                        break;

                    case DeltaItemKind.DeltaLink:
                        await WriteDeltaLinkAsync(item, writer, writeContext).ConfigureAwait(false);

                        break;

                    case DeltaItemKind.Resource:
                    {
                        ODataResourceSerializer entrySerializer = SerializerProvider.GetEdmTypeSerializer(elementType) as ODataResourceSerializer;
                        if (entrySerializer == null)
                        {
                            throw new SerializationException(
                                      Error.Format(SRResources.TypeCannotBeSerialized, elementType.FullName()));
                        }
                        await entrySerializer.WriteDeltaObjectInlineAsync(item, elementType, writer, writeContext)
                        .ConfigureAwait(false);

                        break;
                    }

                    default:
                        break;
                    }
                }

                // Subtle and surprising behavior: If the NextPageLink property is set before calling WriteStart(feed),
                // the next page link will be written early in a manner not compatible with odata.streaming=true. Instead, if
                // the next page link is not set when calling WriteStart(feed) but is instead set later on that feed
                // object before calling WriteEnd(), the next page link will be written at the end, as required for
                // odata.streaming=true support.

                deltaResourceSet.NextPageLink = nextLinkGenerator(lastResource);
            }

            //End Writing of the Delta Feed
            await writer.WriteEndAsync().ConfigureAwait(false);
        }
Exemple #56
0
        /// <inheritdoc/>
        public sealed override async Task <ODataValue> CreateODataValueAsync(object graph, IEdmTypeReference expectedType, ODataSerializerContext writeContext)
        {
            if (!expectedType.IsEnum())
            {
                throw Error.InvalidOperation(SRResources.CannotWriteType, typeof(ODataEnumSerializer).Name, expectedType.FullName());
            }

            ODataEnumValue value = await CreateODataEnumValueAsync(graph, expectedType.AsEnum(), writeContext);

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

            return(value);
        }
Exemple #57
0
        /// <summary>
        /// Creates an <see cref="ODataComplexValue"/> for the object represented by <paramref name="graph"/>.
        /// </summary>
        /// <param name="graph">The value of the <see cref="ODataComplexValue"/> to be created.</param>
        /// <param name="complexType">The EDM complex type of the object.</param>
        /// <param name="writeContext">The serializer context.</param>
        /// <returns>The created <see cref="ODataComplexValue"/>.</returns>
        public virtual ODataComplexValue CreateODataComplexValue(object graph, IEdmComplexTypeReference complexType,
                                                                 ODataSerializerContext writeContext)
        {
            if (writeContext == null)
            {
                throw Error.ArgumentNull("writeContext");
            }

            if (graph == null || graph is NullEdmComplexObject)
            {
                return(null);
            }

            IEdmComplexObject complexObject = graph as IEdmComplexObject ?? new TypedEdmComplexObject(graph, complexType, writeContext.Model);

            List <ODataProperty> propertyCollection = new List <ODataProperty>();

            foreach (IEdmProperty property in complexType.ComplexDefinition().Properties())
            {
                IEdmTypeReference      propertyType       = property.Type;
                ODataEdmTypeSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType);
                if (propertySerializer == null)
                {
                    throw Error.NotSupported(SRResources.TypeCannotBeSerialized, propertyType.FullName(), typeof(ODataOutputFormatter).Name);
                }

                object propertyValue;
                if (complexObject.TryGetPropertyValue(property.Name, out propertyValue))
                {
                    if (propertyType != null && propertyType.IsComplex())
                    {
                        IEdmTypeReference actualType = writeContext.GetEdmType(propertyValue, propertyValue.GetType());
                        if (actualType != null && propertyType != actualType)
                        {
                            propertyType = actualType;
                        }
                    }

                    propertyCollection.Add(
                        propertySerializer.CreateProperty(propertyValue, propertyType, property.Name, writeContext));
                }
            }

            // Try to add the dynamic properties if the complex type is open.
            if (complexType.ComplexDefinition().IsOpen)
            {
                List <ODataProperty> dynamicProperties =
                    AppendDynamicProperties(complexObject, complexType, writeContext, propertyCollection, new string[0]);

                if (dynamicProperties != null)
                {
                    propertyCollection.AddRange(dynamicProperties);
                }
            }

            string typeName = complexType.FullName();

            ODataComplexValue value = new ODataComplexValue()
            {
                Properties = propertyCollection,
                TypeName   = typeName
            };

            AddTypeNameAnnotationAsNeeded(value, writeContext.MetadataLevel);
            return(value);
        }
Exemple #58
0
        private IEnumerable <ODataOperation> CreateODataOperations(IEnumerable <IEdmOperation> operations, ResourceSetContext resourceSetContext, ODataSerializerContext writeContext)
        {
            Contract.Assert(operations != null);
            Contract.Assert(resourceSetContext != null);
            Contract.Assert(writeContext != null);

            foreach (IEdmOperation operation in operations)
            {
                ODataOperation oDataOperation = CreateODataOperation(operation, resourceSetContext, writeContext);
                if (oDataOperation != null)
                {
                    yield return(oDataOperation);
                }
            }
        }