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); ODataEdmTypeSerializer resourceSerializer = SerializerProvider.GetEdmTypeSerializer(elementType); if (resourceSerializer == null) { throw new SerializationException( Error.Format(SRResources.TypeCannotBeSerialized, elementType.FullName())); } ODataResourceSet resourceSet = GetResourceSet(enumerable, resourceSetType, elementType, writeContext); // create the nextLinkGenerator for the current resourceSet and then set the nextpagelink to null to support JSON odata.streaming. Func <object, Uri> nextLinkGenerator = GetNextLinkGenerator(resourceSet, enumerable, writeContext); resourceSet.NextPageLink = null; await writer.WriteStartAsync(resourceSet); 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); await writer.WriteEndAsync(); } else { await resourceSerializer.WriteObjectInlineAsync(item, elementType, writer, writeContext); } } // 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(); }
public async Task WriteAsync(OeEntryFactory entryFactory, IAsyncEnumerator <Object> asyncEnumerator) { var resourceSet = new ODataResourceSet() { Count = _queryContext.TotalCountOfItems }; await _writer.WriteStartAsync(resourceSet).ConfigureAwait(false); Object?rawValue = null; int readCount = 0; Db.IOeDbEnumerator dbEnumerator = entryFactory.IsTuple ? (Db.IOeDbEnumerator) new Db.OeDbEnumerator(asyncEnumerator, entryFactory) : new Db.OeEntityDbEnumerator(asyncEnumerator, entryFactory); while (await dbEnumerator.MoveNextAsync().ConfigureAwait(false)) { await WriteEntry(dbEnumerator, dbEnumerator.Current).ConfigureAwait(false); readCount++; rawValue = dbEnumerator.RawValue; dbEnumerator.ClearBuffer(); } if (rawValue != null) { var nextPageLinkBuilder = new OeNextPageLinkBuilder(_queryContext); resourceSet.NextPageLink = nextPageLinkBuilder.GetNextPageLinkRoot(entryFactory, readCount, _queryContext.TotalCountOfItems, rawValue); } await _writer.WriteEndAsync().ConfigureAwait(false); }
/// <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 async Task WriteDeltaDeletedEntryAsync(object graph, ODataWriter writer, ODataSerializerContext writeContext) { if (writer == null) { throw Error.ArgumentNull(nameof(writer)); } EdmDeltaDeletedEntityObject edmDeltaDeletedEntity = graph as EdmDeltaDeletedEntityObject; if (edmDeltaDeletedEntity == null) { throw new SerializationException(Error.Format(SRResources.CannotWriteType, GetType().Name, graph?.GetType().FullName)); } Uri id = StringToUri(edmDeltaDeletedEntity.Id); ODataDeletedResource deletedResource = new ODataDeletedResource(id, edmDeltaDeletedEntity.Reason); if (edmDeltaDeletedEntity.NavigationSource != null) { ODataResourceSerializationInfo serializationInfo = new ODataResourceSerializationInfo { NavigationSourceName = edmDeltaDeletedEntity.NavigationSource.Name }; deletedResource.SetSerializationInfo(serializationInfo); } if (deletedResource != null) { await writer.WriteStartAsync(deletedResource).ConfigureAwait(false); await writer.WriteEndAsync().ConfigureAwait(false); } }
public async Task VerifyCanSendRequestPayloadAsyncTest() { var request = new ClientHttpRequestMessage(new Uri(TestDemoService.ServiceBaseUri, "Products")); request.Method = ODataConstants.MethodPost; using (ODataMessageWriter messageWriter = new ODataMessageWriter( request, new ODataMessageWriterSettings(), TestUtils.GetServiceModel(TestDemoService.ServiceBaseUri))) { ODataWriter writer = await messageWriter.CreateODataEntryWriterAsync(); await writer.WriteStartAsync(new ODataEntry() { TypeName = "DataServiceProviderDemo.Product", Properties = new ODataProperty[] { new ODataProperty { Name = "ID", Value = 42 } } }); await writer.WriteEndAsync(); await writer.FlushAsync(); } var response = await request.GetResponseAsync(); Assert.AreEqual(201, response.StatusCode); }
private async Task WriteNestedCollectionAsync(ODataWriter entryWriter, string entryName, ODataCollectionValue collection) { await entryWriter.WriteStartAsync(new ODataNestedResourceInfo() { Name = entryName, IsCollection = true, }).ConfigureAwait(false); await entryWriter.WriteStartAsync(new ODataResourceSet()); foreach (var item in collection.Items) { await WriteEntryPropertiesAsync(entryWriter, item as ODataResource, null); } await entryWriter.WriteEndAsync().ConfigureAwait(false); await entryWriter.WriteEndAsync().ConfigureAwait(false); }
/// <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 async Task WriteDeltaDeletedEntryAsync(object graph, ODataWriter writer, ODataSerializerContext writeContext) { ODataDeletedResource deletedResource = GetDeletedResource(graph); if (deletedResource != null) { await writer.WriteStartAsync(deletedResource); await writer.WriteEndAsync(); } }
private async Task WriteNestedEntryAsync(ODataWriter entryWriter, string entryName, ODataResource entry) { await entryWriter.WriteStartAsync(new ODataNestedResourceInfo() { Name = entryName, IsCollection = false, }).ConfigureAwait(false); await WriteEntryPropertiesAsync(entryWriter, entry, null); await entryWriter.WriteEndAsync().ConfigureAwait(false); }
private async Task WriteEntity(IEdmEntitySet entitySet, ODataResource entry, Stream stream) { IODataResponseMessage responseMessage = new Infrastructure.OeInMemoryMessage(stream, null); using (ODataMessageWriter messageWriter = new ODataMessageWriter(responseMessage, _settings, _model.GetEdmModel(entitySet))) { ODataUtils.SetHeadersForPayload(messageWriter, ODataPayloadKind.Resource); ODataWriter writer = await messageWriter.CreateODataResourceWriterAsync(entitySet, entitySet.EntityType()); await writer.WriteStartAsync(entry); await writer.WriteEndAsync(); } }
private async Task WriteLinkAsync(ODataWriter entryWriter, Microsoft.OData.Core.ODataEntry entry, string linkName, IEnumerable <ReferenceLink> links) { var navigationProperty = (_model.FindDeclaredType(entry.TypeName) as IEdmEntityType).NavigationProperties() .BestMatch(x => x.Name, linkName, _session.Pluralizer); bool isCollection = navigationProperty.Type.Definition.TypeKind == EdmTypeKind.Collection; var linkType = GetNavigationPropertyEntityType(navigationProperty); var linkTypeWithKey = linkType; while (linkTypeWithKey.DeclaredKey == null && linkTypeWithKey.BaseEntityType() != null) { linkTypeWithKey = linkTypeWithKey.BaseEntityType(); } await entryWriter.WriteStartAsync(new ODataNavigationLink() { Name = linkName, IsCollection = isCollection, Url = new Uri(ODataNamespace.Related + linkType, UriKind.Absolute), }).ConfigureAwait(false); foreach (var referenceLink in links) { var linkKey = linkTypeWithKey.DeclaredKey; var linkEntry = referenceLink.LinkData.ToDictionary(); var contentId = GetContentId(referenceLink); string linkUri; if (contentId != null) { linkUri = "$" + contentId; } else { bool isSingleton; var formattedKey = _session.Adapter.GetCommandFormatter().ConvertKeyValuesToUriLiteral( linkKey.ToDictionary(x => x.Name, x => linkEntry[x.Name]), true); var linkedCollectionName = _session.Metadata.GetLinkedCollectionName( referenceLink.LinkData.GetType().Name, linkTypeWithKey.Name, out isSingleton); linkUri = linkedCollectionName + (isSingleton ? string.Empty : formattedKey); } var link = new ODataEntityReferenceLink { Url = Utils.CreateAbsoluteUri(_session.Settings.BaseUri.AbsoluteUri, linkUri) }; await entryWriter.WriteEntityReferenceLinkAsync(link).ConfigureAwait(false); } await entryWriter.WriteEndAsync().ConfigureAwait(false); }
private async Task WriteLinkAsync(ODataWriter entryWriter, Microsoft.OData.Core.ODataEntry entry, string linkName, IEnumerable <ReferenceLink> links) { var navigationProperty = (_model.FindDeclaredType(entry.TypeName) as IEdmEntityType).NavigationProperties() .BestMatch(x => x.Name, linkName, _session.Pluralizer); bool isCollection = navigationProperty.Type.Definition.TypeKind == EdmTypeKind.Collection; var linkType = GetNavigationPropertyEntityType(navigationProperty); await entryWriter.WriteStartAsync(new ODataNavigationLink() { Name = linkName, IsCollection = isCollection, Url = new Uri("http://schemas.microsoft.com/ado/2007/08/dataservices/related/" + linkType, UriKind.Absolute), }); foreach (var referenceLink in links) { var linkKey = linkType.DeclaredKey; var linkEntry = referenceLink.LinkData.ToDictionary(); var contentId = GetContentId(referenceLink); string linkUri; if (contentId != null) { linkUri = "$" + contentId; } else { var linkSet = _model.SchemaElements .Where(x => x.SchemaElementKind == EdmSchemaElementKind.EntityContainer) .SelectMany(x => (x as IEdmEntityContainer).EntitySets()) .BestMatch(x => x.EntityType().Name, linkType.Name, _session.Pluralizer); var formattedKey = _session.Adapter.ConvertKeyValuesToUriLiteral( linkKey.ToDictionary(x => x.Name, x => linkEntry[x.Name]), true); linkUri = linkSet.Name + formattedKey; } var link = new ODataEntityReferenceLink { Url = Utils.CreateAbsoluteUri(_session.Settings.UrlBase, linkUri) }; await entryWriter.WriteEntityReferenceLinkAsync(link); } await entryWriter.WriteEndAsync(); }
private async Task WriteEntryPropertiesAsync(ODataWriter entryWriter, ODataResource entry, IDictionary <string, List <ReferenceLink> > links) { await entryWriter.WriteStartAsync(entry).ConfigureAwait(false); if (_resourceEntryMap.TryGetValue(entry, out var resourceEntry)) { if (resourceEntry.CollectionProperties != null) { foreach (var prop in resourceEntry.CollectionProperties) { if (prop.Value != null) { await WriteNestedCollectionAsync(entryWriter, prop.Key, prop.Value).ConfigureAwait(false); } } } if (resourceEntry.StructuralProperties != null) { foreach (var prop in resourceEntry.StructuralProperties) { if (prop.Value != null) { await WriteNestedEntryAsync(entryWriter, prop.Key, prop.Value).ConfigureAwait(false); } } } } if (links != null) { foreach (var link in links) { if (link.Value.Any(x => x.LinkData != null)) { await WriteLinkAsync(entryWriter, entry.TypeName, link.Key, link.Value) .ConfigureAwait(false); } } } await entryWriter.WriteEndAsync().ConfigureAwait(false); }
/// <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); } }
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); 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 deltaFeed = CreateODataDeltaFeed(enumerable, feedType.AsCollection(), writeContext); if (deltaFeed == null) { throw new SerializationException(Error.Format(SRResources.CannotSerializerNull, DeltaFeed)); } // save the next page link for later to support JSON odata.streaming. Func <object, Uri> nextLinkGenerator = GetNextLinkGenerator(deltaFeed, enumerable, writeContext); deltaFeed.NextPageLink = null; //Start writing of the Delta Feed await writer.WriteStartAsync(deltaFeed).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 entry in enumerable) { if (entry == null) { throw new SerializationException(SRResources.NullElementInCollection); } lastResource = entry; 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: await WriteDeltaDeletedEntryAsync(entry, writer, writeContext).ConfigureAwait(false); break; case EdmDeltaEntityKind.DeletedLinkEntry: await WriteDeltaDeletedLinkAsync(entry, writer, writeContext).ConfigureAwait(false); break; case EdmDeltaEntityKind.LinkEntry: await WriteDeltaLinkAsync(entry, writer, writeContext).ConfigureAwait(false); break; case EdmDeltaEntityKind.Entry: { ODataResourceSerializer entrySerializer = SerializerProvider.GetEdmTypeSerializer(elementType) as ODataResourceSerializer; if (entrySerializer == null) { throw new SerializationException( Error.Format(SRResources.TypeCannotBeSerialized, elementType.FullName())); } await entrySerializer.WriteDeltaObjectInlineAsync(entry, 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. deltaFeed.NextPageLink = nextLinkGenerator(lastResource); } //End Writing of the Delta Feed await writer.WriteEndAsync().ConfigureAwait(false); }