/// <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(); }
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); }
/// <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)); }
/// <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); }
/// <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)); }
/// <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); }
/// <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); }
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); }
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); } }
/// <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; }
/// <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)); }
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); }
/// <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); }
/// <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); }
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); } } }