Exemple #1
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);
            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);
            }
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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();
            }
        }
Exemple #7
0
        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();
        }
Exemple #11
0
        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);
        }
Exemple #12
0
        /// <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);
        }