Example #1
0
        /// <summary>
        /// Gets an entity metadata builder for the given entry.
        /// </summary>
        /// <param name="entryState">Entry state to use as reference for information needed by the builder.</param>
        /// <returns>An entity metadata builder.</returns>
        public ODataEntityMetadataBuilder GetEntityMetadataBuilderForReader(IODataJsonLightReaderEntryState entryState)
        {
            Debug.Assert(entryState != null, "entry != null");

            // Only apply the conventional template builder on response. On a request we would only report what's on the wire.
            if (entryState.MetadataBuilder == null)
            {
                ODataEntry entry = entryState.Entry;
                if (this.isResponse)
                {
                    ODataTypeAnnotation typeAnnotation = entry.GetAnnotation <ODataTypeAnnotation>();

                    Debug.Assert(typeAnnotation != null, "The JSON light reader should have already set the ODataTypeAnnotation.");
                    IEdmNavigationSource navigationSource = typeAnnotation.NavigationSource;

                    IEdmEntityType navigationSourceElementType         = this.edmTypeResolver.GetElementType(navigationSource);
                    IODataFeedAndEntryTypeContext typeContext          = ODataFeedAndEntryTypeContext.Create(/*serializationInfo*/ null, navigationSource, navigationSourceElementType, entryState.EntityType, this.model, /*throwIfMissingTypeInfo*/ true);
                    IODataEntryMetadataContext    entryMetadataContext = ODataEntryMetadataContext.Create(entry, typeContext, /*serializationInfo*/ null, (IEdmEntityType)entry.GetEdmType().Definition, this, entryState.SelectedProperties);

                    UrlConvention urlConvention            = UrlConvention.ForUserSettingAndTypeContext(/*keyAsSegment*/ null, typeContext);
                    ODataConventionalUriBuilder uriBuilder = new ODataConventionalUriBuilder(this.ServiceBaseUri, urlConvention);

                    entryState.MetadataBuilder = new ODataConventionalEntityMetadataBuilder(entryMetadataContext, this, uriBuilder);
                }
                else
                {
                    entryState.MetadataBuilder = new NoOpEntityMetadataBuilder(entry);
                }
            }

            return(entryState.MetadataBuilder);
        }
Example #2
0
        /// <summary>
        /// Creates a new instance of MaterializerEntry.
        /// </summary>
        /// <param name="entry">The entry.</param>
        /// <param name="format">The format the entry was read in.</param>
        /// <param name="isTracking">True if the contents of the entry will be tracked in the context, otherwise False.</param>
        /// <param name="model">The client model.</param>
        private MaterializerEntry(ODataEntry entry, ODataFormat format, bool isTracking, ClientEdmModel model)
        {
            Debug.Assert(entry != null, "entry != null");

            this.entry            = entry;
            this.Format           = format;
            this.entityDescriptor = new EntityDescriptor(model);

            this.isAtomOrTracking = isTracking || this.Format == ODataFormat.Atom;

            string serverTypeName = this.Entry.TypeName;
            SerializationTypeNameAnnotation serializationTypeNameAnnotation = entry.GetAnnotation <SerializationTypeNameAnnotation>();

            if (serializationTypeNameAnnotation != null)
            {
                // If the annotation has a value use it. Otherwise, in JSON-Light, the types can be inferred from the
                // metadata URI even if they are not present on the wire, so just use the type name from the entry.
                if (serializationTypeNameAnnotation.TypeName != null || this.Format != ODataFormat.Json)
                {
                    serverTypeName = serializationTypeNameAnnotation.TypeName;
                }
            }

            this.entityDescriptor.ServerTypeName = serverTypeName;
        }
Example #3
0
        private ResourceType GetEntryResourceType(ODataEntry entry, ResourceType expectedType)
        {
            ResourceType type;
            string       typeName = entry.TypeName;
            SerializationTypeNameAnnotation annotation = entry.GetAnnotation <SerializationTypeNameAnnotation>();

            if (annotation != null)
            {
                typeName = annotation.TypeName;
            }
            if (string.IsNullOrEmpty(typeName))
            {
                type = expectedType;
                if (base.Service.Provider.HasDerivedTypes(type))
                {
                    throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.BadRequest_TypeInformationMustBeSpecifiedForInhertiance);
                }
                return(type);
            }
            type = base.Service.Provider.TryResolveResourceType(typeName);
            if (type == null)
            {
                throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.BadRequest_InvalidTypeName(typeName));
            }
            if (!expectedType.IsAssignableFrom(type))
            {
                throw DataServiceException.CreateBadRequestError(System.Data.Services.Strings.BadRequest_InvalidTypeSpecified(typeName, expectedType.FullName));
            }
            return(type);
        }
Example #4
0
        /// <summary>
        /// Returns the new XmlWriter to cache the payload for firing WritingEntity event.
        /// </summary>
        /// <param name="entry">ODataEntry instance that is currently getting serialized.</param>
        /// <param name="entryWriter">XmlWriter that is used to write the payload.</param>
        /// <returns>XmlWriter instance that needs to be used to write the payload for the given odataentry.</returns>
        private static XmlWriter StartEntryXmlCustomizer(ODataEntry entry, XmlWriter entryWriter)
        {
            WritingEntityInfo writingEntityInfo = entry.GetAnnotation <WritingEntityInfo>();

            Debug.Assert(writingEntityInfo.RequestInfo.HasWritingEventHandlers, "this.requestInfo.HasWritingEventHandlers");
            return(writingEntityInfo.EntryPayload.CreateWriter());
        }
Example #5
0
        /// <summary>
        /// Finish writing an entry.
        /// </summary>
        /// <param name="entry">The entry to write.</param>
        protected override void EndEntry(ODataEntry entry)
        {
            if (entry == null)
            {
                Debug.Assert(
                    this.ParentNavigationLink != null && !this.ParentNavigationLink.IsCollection.Value,
                    "when entry == null, it has to be and expanded single entry navigation");

                // this is a null expanded single entry and it is null, JSON null should be written as value in StartEntry()
                return;
            }

            // Get the projected properties
            ProjectedPropertiesAnnotation projectedProperties = entry.GetAnnotation <ProjectedPropertiesAnnotation>();

            // Write the properties
            this.jsonEntryAndFeedSerializer.AssertRecursionDepthIsZero();
            this.jsonEntryAndFeedSerializer.WriteProperties(
                this.EntryEntityType,
                entry.Properties,
                false /* isComplexValue */,
                this.DuplicatePropertyNamesChecker,
                projectedProperties);
            this.jsonEntryAndFeedSerializer.AssertRecursionDepthIsZero();

            // Close the object scope
            this.jsonOutputContext.JsonWriter.EndObjectScope();
        }
Example #6
0
        /// <summary>
        /// Converts the object to ODataEntry or ODataEntityReferenceLink.
        /// </summary>
        /// <param name="value">The value of the <see cref="UriOperationParameter"/>.</param>
        /// <param name="elementType">The type of the value</param>
        /// <param name="useEntityReference">If true, use entity reference, instead of entity to serialize the parameter.</param>
        /// <returns>The converted result.</returns>
        private object ConvertToEntityValue(object value, Type elementType, bool useEntityReference)
        {
            object valueInODataFormat;

            if (!useEntityReference)
            {
                valueInODataFormat = this.propertyConverter.CreateODataEntry(elementType, value);

                ODataEntry entry = (ODataEntry)valueInODataFormat;
                SerializationTypeNameAnnotation serializedTypeNameAnnotation =
                    entry.GetAnnotation <SerializationTypeNameAnnotation>();
                if (serializedTypeNameAnnotation == null ||
                    string.IsNullOrEmpty(serializedTypeNameAnnotation.TypeName))
                {
                    throw Error.InvalidOperation(Strings.DataServiceException_GeneralError);
                }
            }
            else
            {
                EntityDescriptor resource = this.requestInfo.EntityTracker.GetEntityDescriptor(value);
                Uri link = resource.GetLatestIdentity();
                valueInODataFormat = new ODataEntityReferenceLink()
                {
                    Url = link,
                };
            }

            return(valueInODataFormat);
        }
Example #7
0
        private MaterializerEntry(ODataEntry entry, DataServiceProtocolVersion maxProtocolVersion)
        {
            this.entry            = entry;
            this.entityDescriptor = new System.Data.Services.Client.EntityDescriptor(maxProtocolVersion);
            SerializationTypeNameAnnotation annotation = entry.GetAnnotation <SerializationTypeNameAnnotation>();

            this.entityDescriptor.ServerTypeName = (annotation != null) ? annotation.TypeName : (this.entityDescriptor.ServerTypeName = this.Entry.TypeName);
        }
Example #8
0
        private static void EndEntryXmlCustomizer(ODataEntry entry, XmlWriter entryWriter, XmlWriter parentWriter)
        {
            WritingEntityInfo annotation = entry.GetAnnotation <WritingEntityInfo>();

            entryWriter.Close();
            annotation.RequestInfo.FireWritingEntityEvent(annotation.Entity, annotation.EntryPayload.Root, null);
            annotation.EntryPayload.Root.WriteTo(parentWriter);
        }
Example #9
0
 protected override void EndEntry(ODataEntry entry)
 {
     if (entry != null)
     {
         ProjectedPropertiesAnnotation projectedProperties = entry.GetAnnotation <ProjectedPropertiesAnnotation>();
         this.jsonEntryAndFeedSerializer.WriteProperties(base.EntryEntityType, entry.Properties, false, base.DuplicatePropertyNamesChecker, projectedProperties);
         this.jsonOutputContext.JsonWriter.EndObjectScope();
     }
 }
Example #10
0
        private object CreateNestedEntityAndApplyProperties(System.Data.Services.SegmentInfo segmentInfo, ODataEntry entry)
        {
            ODataEntryAnnotation entryAnnotation = entry.GetAnnotation <ODataEntryAnnotation>();

            base.RecurseEnter();
            this.CreateEntityResource(segmentInfo, entry, entryAnnotation, false);
            this.ApplyEntityProperties(segmentInfo, entry, entryAnnotation);
            base.RecurseLeave();
            return(entryAnnotation.EntityResource);
        }
Example #11
0
        /// <summary>
        /// Creates the materializer entry.
        /// </summary>
        /// <param name="entry">The entry.</param>
        /// <param name="format">The format the entry was read in.</param>
        /// <param name="isTracking">True if the contents of the entry will be tracked in the context, otherwise False.</param>
        /// <param name="model">The client model.</param>
        /// <returns>A new materializer entry.</returns>
        public static MaterializerEntry CreateEntry(ODataEntry entry, ODataFormat format, bool isTracking, ClientEdmModel model)
        {
            Debug.Assert(entry.GetAnnotation <MaterializerEntry>() == null, "MaterializerEntry has already been created.");

            MaterializerEntry materializerEntry = new MaterializerEntry(entry, format, isTracking, model);

            entry.SetAnnotation <MaterializerEntry>(materializerEntry);

            return(materializerEntry);
        }
Example #12
0
        public static AtomEntryMetadata Atom(this ODataEntry entry)
        {
            ExceptionUtils.CheckArgumentNotNull <ODataEntry>(entry, "entry");
            AtomEntryMetadata annotation = entry.GetAnnotation <AtomEntryMetadata>();

            if (annotation == null)
            {
                annotation = new AtomEntryMetadata();
                entry.SetAnnotation <AtomEntryMetadata>(annotation);
            }
            return(annotation);
        }
        private object CreateNestedEntityAndApplyProperties(ODataEntry entry, IEdmEntityTypeReference elementType, ODataDeserializerReadContext readContext)
        {
            ODataEntryAnnotation annotation = entry.GetAnnotation <ODataEntryAnnotation>();

            Contract.Assert(annotation != null);

            CreateEntityResource(annotation, elementType, readContext);

            ODataEntryDeserializer deserializer = DeserializerProvider.GetODataDeserializer(elementType);

            return(deserializer.ReadInline(entry, readContext));
        }
        /// <summary>
        /// Determines the entity type name to write to the payload.
        /// </summary>
        /// <param name="expectedTypeName">The expected type name, e.g. the base type of the set or the nav prop.</param>
        /// <param name="entry">The ODataEntry whose type is to be written.</param>
        /// <returns>Type name to write to the payload, or null if no type name should be written.</returns>
        internal override string GetEntryTypeNameForWriting(string expectedTypeName, ODataEntry entry)
        {
            Debug.Assert(entry != null, "entry != null");

            SerializationTypeNameAnnotation typeNameAnnotation = entry.GetAnnotation<SerializationTypeNameAnnotation>();
            if (typeNameAnnotation != null)
            {
                return typeNameAnnotation.TypeName;
            }

            return entry.TypeName;
        }
Example #15
0
        /// <summary>
        /// Fires the WritingEntity event, and then copies the payload into the parent writer.
        /// </summary>
        /// <param name="entry">ODataEntry that is currently getting serialized.</param>
        /// <param name="entryWriter">XmlWriter writer instance that got returned by StartEntryXmlCustomizer method.</param>
        /// <param name="parentWriter">Parent writer to which the payload needs to get copied to, after firing the event.</param>
        private static void EndEntryXmlCustomizer(ODataEntry entry, XmlWriter entryWriter, XmlWriter parentWriter)
        {
            WritingEntityInfo writingEntityInfo = entry.GetAnnotation <WritingEntityInfo>();

            Debug.Assert(writingEntityInfo.RequestInfo.HasWritingEventHandlers, "this.requestInfo.HasWritingEventHandlers");
#if PORTABLELIB
            entryWriter.Dispose();
#else
            entryWriter.Close();
#endif
            writingEntityInfo.RequestInfo.FireWritingEntityEvent(writingEntityInfo.Entity, (XElement)writingEntityInfo.EntryPayload.Root, null);
            writingEntityInfo.EntryPayload.Root.WriteTo(parentWriter);
        }
Example #16
0
        /// <summary>
        /// Determines the entity type name to write to the payload.
        /// </summary>
        /// <param name="expectedTypeName">The expected type name, e.g. the base type of the set or the nav prop.</param>
        /// <param name="entry">The ODataEntry whose type is to be written.</param>
        /// <returns>Type name to write to the payload, or null if no type name should be written.</returns>
        internal override string GetEntryTypeNameForWriting(string expectedTypeName, ODataEntry entry)
        {
            Debug.Assert(entry != null, "entry != null");

            SerializationTypeNameAnnotation typeNameAnnotation = entry.GetAnnotation <SerializationTypeNameAnnotation>();

            if (typeNameAnnotation != null)
            {
                return(typeNameAnnotation.TypeName);
            }

            return(entry.TypeName);
        }
Example #17
0
 protected override void StartEntry(ODataEntry entry)
 {
     if (entry == null)
     {
         this.jsonOutputContext.JsonWriter.WriteValue((string)null);
     }
     else
     {
         this.jsonOutputContext.JsonWriter.StartObjectScope();
         ProjectedPropertiesAnnotation projectedProperties = entry.GetAnnotation <ProjectedPropertiesAnnotation>();
         this.jsonEntryAndFeedSerializer.WriteEntryMetadata(entry, projectedProperties, base.EntryEntityType, base.DuplicatePropertyNamesChecker);
     }
 }
Example #18
0
        public static AtomEntryMetadata Atom(this ODataEntry entry)
        {
            ExceptionUtils.CheckArgumentNotNull(entry, "entry");

            AtomEntryMetadata entryMetadata = entry.GetAnnotation <AtomEntryMetadata>();

            if (entryMetadata == null)
            {
                entryMetadata = new AtomEntryMetadata();
                entry.SetAnnotation(entryMetadata);
            }

            return(entryMetadata);
        }
Example #19
0
        private ResourceType GetEntryResourceType(ODataEntry entry, ResourceType expectedType)
        {
            Debug.Assert(entry != null, "entry != null");
            Debug.Assert(expectedType != null, "We must always have an expected type for entities.");
            Debug.Assert(expectedType.ResourceTypeKind == ResourceTypeKind.EntityType, "Expected type for entities must be an entity type.");

            ResourceType resourceType;

            // Note that we can't rely on the ODataLib handling in this case completely.
            // In the WCF DS Server mode the ODataLib uses the lax validation, which means that it doesn't actually
            // validate almost anything (to follow the same logic as used for complex types).
            // So we have to implement the validation logic here on top of ODataLib.
            // We also can't use the type name reported by the entry property always, as that is the resolved type name.
            // It's safer to use the actual type name from the payload if it's available.
            string payloadTypeName = entry.TypeName;
            SerializationTypeNameAnnotation serializationTypeNameAnnotation = entry.GetAnnotation <SerializationTypeNameAnnotation>();

            if (serializationTypeNameAnnotation != null)
            {
                payloadTypeName = serializationTypeNameAnnotation.TypeName;
            }

            // If the type is not specified in the payload, we assume the type to be the expected type.
            if (String.IsNullOrEmpty(payloadTypeName))
            {
                // Check if the expected type takes part in inheritance.
                resourceType = expectedType;
                if (this.Service.Provider.HasDerivedTypes(resourceType))
                {
                    throw DataServiceException.CreateBadRequestError(Microsoft.OData.Service.Strings.BadRequest_TypeInformationMustBeSpecifiedForInhertiance);
                }
            }
            else
            {
                // Otherwise, try and resolve the name specified in the payload.
                resourceType = this.Service.Provider.TryResolveResourceType(payloadTypeName);
                if (resourceType == null)
                {
                    throw DataServiceException.CreateBadRequestError(Microsoft.OData.Service.Strings.BadRequest_InvalidTypeName(payloadTypeName));
                }

                if (!expectedType.IsAssignableFrom(resourceType))
                {
                    throw DataServiceException.CreateBadRequestError(Microsoft.OData.Service.Strings.BadRequest_InvalidTypeSpecified(payloadTypeName, expectedType.FullName));
                }
            }

            return(resourceType);
        }
            /// <summary>
            /// Visits an entry item.
            /// </summary>
            /// <param name="entry">The entry item to visit.</param>
            /// <returns>An ODataPayloadElement representing the entry.</returns>
            protected override ODataPayloadElement VisitEntry(ODataEntry entry)
            {
                ExceptionUtilities.CheckArgumentNotNull(entry, "entry");

                EntityInstance entity = (EntityInstance)base.VisitEntry(entry);

                var atomMetadata = entry.GetAnnotation <AtomEntryMetadata>();

                if (atomMetadata != null)
                {
                    ConvertAtomEntryMetadata(atomMetadata, entity);
                }

                return(entity);
            }
Example #21
0
        /// <summary>
        /// Create the entity resource update token and applies properties and navigation links to the entity resource token instance
        /// based on the data from entry in the payload.
        /// </summary>
        /// <param name="segmentInfo">The segment info describing the entity in question.</param>
        /// <param name="entry">The OData entry instance read from the payload.</param>
        /// <returns>The entity resource update token for the created entity.</returns>
        /// <remarks>This method should only be called on nested entries!</remarks>
        private object CreateNestedEntityAndApplyProperties(SegmentInfo segmentInfo, ODataEntry entry)
        {
            Debug.Assert(segmentInfo != null, "segmentInfo != null");
            Debug.Assert(entry != null, "entry != null");

            ODataEntryAnnotation entryAnnotation = entry.GetAnnotation <ODataEntryAnnotation>();

            Debug.Assert(entryAnnotation != null, "Each entry we read must have our entry annotation.");

            this.RecurseEnter();
            this.CreateEntityResource(segmentInfo, entry, entryAnnotation, /*topLevel*/ false);
            this.ApplyEntityProperties(segmentInfo, entry, entryAnnotation);
            this.RecurseLeave();

            return(entryAnnotation.EntityResource);
        }
Example #22
0
 protected override void StartEntry(ODataEntry entry)
 {
     this.CheckAndWriteParentNavigationLinkStartForInlineElement();
     if (entry != null)
     {
         this.StartEntryXmlCustomization(entry);
         this.atomOutputContext.XmlWriter.WriteStartElement("", "entry", "http://www.w3.org/2005/Atom");
         if (base.IsTopLevel)
         {
             this.atomEntryAndFeedSerializer.WriteBaseUriAndDefaultNamespaceAttributes();
         }
         string eTag = entry.ETag;
         if (eTag != null)
         {
             ODataAtomWriterUtils.WriteETag(this.atomOutputContext.XmlWriter, eTag);
         }
         AtomEntryScope    currentEntryScope = this.CurrentEntryScope;
         AtomEntryMetadata entryMetadata     = entry.Atom();
         string            id = entry.Id;
         if (id != null)
         {
             this.atomEntryAndFeedSerializer.WriteEntryId(id);
             currentEntryScope.SetWrittenElement(AtomElement.Id);
         }
         string typeName = entry.TypeName;
         SerializationTypeNameAnnotation annotation = entry.GetAnnotation <SerializationTypeNameAnnotation>();
         if (annotation != null)
         {
             typeName = annotation.TypeName;
         }
         this.atomEntryAndFeedSerializer.WriteEntryTypeName(typeName, entryMetadata);
         Uri editLink = entry.EditLink;
         if (editLink != null)
         {
             this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata);
             currentEntryScope.SetWrittenElement(AtomElement.EditLink);
         }
         Uri readLink = entry.ReadLink;
         if (readLink != null)
         {
             this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata);
             currentEntryScope.SetWrittenElement(AtomElement.ReadLink);
         }
     }
 }
Example #23
0
        private void WriteEntry(ODataWriter writer, ODataEntry entry)
        {
            writer.WriteStart(entry);
            var annotation = entry.GetAnnotation <ODataEntryNavigationLinksObjectModelAnnotation>();
            ODataNavigationLink navLink = null;

            if (annotation != null)
            {
                for (int i = 0; i < annotation.Count; ++i)
                {
                    bool found = annotation.TryGetNavigationLinkAt(i, out navLink);
                    ExceptionUtilities.Assert(found, "Navigation links should be ordered sequentially for writing");
                    this.WriteNavigationLink(writer, navLink);
                }
            }

            writer.WriteEnd();
        }
        /// <summary>
        /// Determines the entity type name to write to the payload.
        /// </summary>
        /// <param name="expectedTypeName">The expected type name, e.g. the base type of the set or the nav prop.</param>
        /// <param name="entry">The ODataEntry whose type is to be written.</param>
        /// <returns>Type name to write to the payload, or null if no type name should be written.</returns>
        internal override string GetEntryTypeNameForWriting(string expectedTypeName, ODataEntry entry)
        {
            Debug.Assert(entry != null, "entry != null");

            SerializationTypeNameAnnotation typeNameAnnotation = entry.GetAnnotation<SerializationTypeNameAnnotation>();
            if (typeNameAnnotation != null)
            {
                return typeNameAnnotation.TypeName;
            }

            // We only write entity type names in Json Light if it's more derived (different) from the expected type name.
            string entryTypeName = entry.TypeName;
            if (expectedTypeName != entryTypeName)
            {
                return entryTypeName;
            }

            return null;
        }
        public override object ReadInline(object item, ODataDeserializerReadContext readContext)
        {
            ODataEntry topLevelEntry = item as ODataEntry;

            if (item == null)
            {
                throw Error.Argument("item", SRResources.ItemMustBeOfType, typeof(ODataEntry).Name);
            }

            ODataEntryAnnotation topLevelEntryAnnotation = topLevelEntry.GetAnnotation <ODataEntryAnnotation>();

            Contract.Assert(topLevelEntryAnnotation != null);

            RecurseEnter(readContext);
            ApplyEntityProperties(topLevelEntry, topLevelEntryAnnotation, readContext);
            RecurseLeave(readContext);

            return(topLevelEntryAnnotation.EntityResource);
        }
        /// <summary>
        /// Determines the entity type name to write to the payload.
        /// </summary>
        /// <param name="expectedTypeName">The expected type name, e.g. the base type of the set or the nav prop.</param>
        /// <param name="entry">The ODataEntry whose type is to be written.</param>
        /// <returns>Type name to write to the payload, or null if no type name should be written.</returns>
        internal override string GetEntryTypeNameForWriting(string expectedTypeName, ODataEntry entry)
        {
            Debug.Assert(entry != null, "entry != null");

            SerializationTypeNameAnnotation typeNameAnnotation = entry.GetAnnotation <SerializationTypeNameAnnotation>();

            if (typeNameAnnotation != null)
            {
                return(typeNameAnnotation.TypeName);
            }

            // We only write entity type names in Json Light if it's more derived (different) from the expected type name.
            string entryTypeName = entry.TypeName;

            if (expectedTypeName != entryTypeName)
            {
                return(entryTypeName);
            }

            return(null);
        }
Example #27
0
        /// <summary>
        /// Start writing an entry.
        /// </summary>
        /// <param name="entry">The entry to write.</param>
        protected override void StartEntry(ODataEntry entry)
        {
            if (entry == null)
            {
                Debug.Assert(
                    this.ParentNavigationLink != null && !this.ParentNavigationLink.IsCollection.Value,
                    "when entry == null, it has to be and expanded single entry navigation");

                // this is a null expanded single entry and it is null, so write a JSON null as value.
                this.jsonOutputContext.JsonWriter.WriteValue(null);
                return;
            }

            // Write just the object start, nothing else, since we might not have complete information yet
            this.jsonOutputContext.JsonWriter.StartObjectScope();

            // Get the projected properties
            ProjectedPropertiesAnnotation projectedProperties = entry.GetAnnotation <ProjectedPropertiesAnnotation>();

            // Write the metadata
            this.jsonEntryAndFeedSerializer.WriteEntryMetadata(entry, projectedProperties, this.EntryEntityType, this.DuplicatePropertyNamesChecker);
        }
Example #28
0
        public void SetsAtomEntryMetadataAnnotation()
        {
            // Arrange
            var v2FeedPackage = new V2FeedPackage()
            {
                Id          = "SomePackageId",
                Version     = "1.0.0",
                Title       = "Title",
                Authors     = ".NET Foundation",
                LastUpdated = DateTime.UtcNow,
                Summary     = "Summary"
            };
            var annotationStrategy = new V2FeedPackageAnnotationStrategy(_contentType);
            var oDataEntry         = new ODataEntry();
            var request            = CreateHttpRequestMessage("https://localhost/api/v2/Packages");

            var expectedAtomEntryMetadataAnnotation = new AtomEntryMetadata()
            {
                Title   = v2FeedPackage.Id,
                Authors = new[] { new AtomPersonMetadata {
                                      Name = v2FeedPackage.Authors
                                  } },
                Updated = v2FeedPackage.LastUpdated,
                Summary = v2FeedPackage.Summary
            };

            // Act
            annotationStrategy.Annotate(request, oDataEntry, v2FeedPackage);

            var actualAtomEntryMetadataAnnotation = oDataEntry.GetAnnotation <AtomEntryMetadata>();

            // Assert
            Assert.Equal(expectedAtomEntryMetadataAnnotation.Title.Text, actualAtomEntryMetadataAnnotation.Title.Text);
            Assert.Equal(expectedAtomEntryMetadataAnnotation.Summary.Text, actualAtomEntryMetadataAnnotation.Summary.Text);
            Assert.Equal(expectedAtomEntryMetadataAnnotation.Authors.Single().Name, actualAtomEntryMetadataAnnotation.Authors.Single().Name);
            Assert.Equal(expectedAtomEntryMetadataAnnotation.Updated, actualAtomEntryMetadataAnnotation.Updated);
        }
Example #29
0
 public static MaterializerEntry GetEntry(ODataEntry entry)
 {
     return(entry.GetAnnotation <MaterializerEntry>());
 }
        /// <summary>
        /// Write the ATOM metadata for an entry
        /// </summary>
        /// <param name="writer">The Xml writer to write to.</param>
        /// <param name="baseUri">The base Uri of the document or null if none was specified.</param>
        /// <param name="entry">The entry for which to write the metadata.</param>
        /// <param name="epmEntryMetadata">The ATOM metadata for the entry which came from EPM.</param>
        internal static void WriteEntryMetadata(XmlWriter writer, Uri baseUri, ODataEntry entry, AtomEntryMetadata epmEntryMetadata)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(writer != null, "writer != null");

            // TODO, ckerer: implement the rule around authors (an entry has to have an author directly or in the <entry:source> unless the feed has an author).
            //               currently we make all entries have an author.
            AtomEntryMetadata customEntryMetadata = entry.GetAnnotation<AtomEntryMetadata>();
            AtomEntryMetadata entryMetadata = ODataAtomWriterMetadataEpmMergeUtils.MergeCustomAndEpmEntryMetadata(customEntryMetadata, epmEntryMetadata);
            if (entryMetadata == null)
            {
                // write all required metadata elements with default content

                // <atom:title></atom:title>
                ODataAtomWriterUtils.WriteEmptyElement(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace);

                // <atom:updated>dateTimeOffset</atom:updated>
                // NOTE: the <updated> element is required and if not specified the best we can do is to create a default
                //       one with the current date/time.
                ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, ODataAtomConvert.ToString(DateTimeOffset.UtcNow));

                WriteEmptyAuthor(writer);
            }
            else
            {
                // <atom:title>text</atom:title>
                // NOTE: writes an empty element even if no title was specified since the title is required
                ODataAtomWriterMetadataUtils.WriteTextConstruct(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, entryMetadata.Title);

                AtomTextConstruct summary = entryMetadata.Summary;
                if (summary != null)
                {
                    // <atom:summary>text</atom:summary>
                    ODataAtomWriterMetadataUtils.WriteTextConstruct(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSummaryElementName, AtomConstants.AtomNamespace, summary);
                }

                DateTimeOffset? published = entryMetadata.Published;
                if (published.HasValue)
                {
                    // <atom:published>dateTimeOffset</atom:published>
                    ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomPublishedElementName, AtomConstants.AtomNamespace, ODataAtomConvert.ToString(published.Value));
                }

                // <atom:updated>date</atom:updated>
                // NOTE: the <updated> element is required and if not specified the best we can do is to create a default
                //       one with the current date/time.
                DateTimeOffset updated = entryMetadata.Updated.HasValue ? entryMetadata.Updated.Value : DateTimeOffset.UtcNow;
                ODataAtomWriterUtils.WriteElementWithTextContent(
                    writer,
                    AtomConstants.AtomNamespacePrefix,
                    AtomConstants.AtomUpdatedElementName,
                    AtomConstants.AtomNamespace,
                    ODataAtomConvert.ToString(updated));

                bool wroteAuthor = false;
                IEnumerable<AtomPersonMetadata> authors = entryMetadata.Authors;
                if (authors != null)
                {
                    foreach (AtomPersonMetadata author in authors)
                    {
                        if (author == null)
                        {
                            throw new ODataException(Strings.ODataAtomWriterMetadataUtils_AuthorMetadataMustNotContainNull);
                        }

                        // <atom:author>author data</atom:author>
                        writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomAuthorElementName, AtomConstants.AtomNamespace);
                        WritePersonMetadata(writer, baseUri, author);
                        writer.WriteEndElement();
                        wroteAuthor = true;
                    }
                }

                if (!wroteAuthor)
                {
                    // write empty authors since they are required
                    WriteEmptyAuthor(writer);
                }

                IEnumerable<AtomPersonMetadata> contributors = entryMetadata.Contributors;
                if (contributors != null)
                {
                    foreach (AtomPersonMetadata contributor in contributors)
                    {
                        if (contributor == null)
                        {
                            throw new ODataException(Strings.ODataAtomWriterMetadataUtils_ContributorMetadataMustNotContainNull);
                        }

                        // <atom:contributor>contributor data</atom:contributor>
                        writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContributorElementName, AtomConstants.AtomNamespace);
                        WritePersonMetadata(writer, baseUri, contributor);
                        writer.WriteEndElement();
                    }
                }

                IEnumerable<AtomLinkMetadata> links = entryMetadata.Links;
                if (links != null)
                {
                    foreach (AtomLinkMetadata link in links)
                    {
                        if (link == null)
                        {
                            throw new ODataException(Strings.ODataAtomWriterMetadataUtils_LinkMetadataMustNotContainNull);
                        }

                        // <atom:link>...</atom:link>
                        WriteAtomLinkMetadata(writer, baseUri, link);
                    }
                }

                IEnumerable<AtomCategoryMetadata> categories = entryMetadata.Categories;
                if (categories != null)
                {
                    foreach (AtomCategoryMetadata category in categories)
                    {
                        if (category == null)
                        {
                            throw new ODataException(Strings.ODataAtomWriterMetadataUtils_CategoryMetadataMustNotContainNull);
                        }

                        // <atom:category term="..." scheme="..." label="..."></atom:category>
                        WriteCategory(writer, category);
                    }
                }

                if (entryMetadata.Rights != null)
                {
                    // <atom:rights>rights</atom:rights>
                    ODataAtomWriterMetadataUtils.WriteTextConstruct(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomRightsElementName, AtomConstants.AtomNamespace, entryMetadata.Rights);
                }

                Uri icon = entryMetadata.Icon;
                if (icon != null)
                {
                    // <atom:icon>Uri</atom:icon>
                    ODataAtomWriterUtils.WriteElementWithTextContent(
                        writer, 
                        AtomConstants.AtomNamespacePrefix, 
                        AtomConstants.AtomIconElementName, 
                        AtomConstants.AtomNamespace,
                        AtomUtils.ToUrlAttributeValue(icon, baseUri));
                }

                AtomFeedMetadata source = entryMetadata.Source;
                if (source != null)
                {
                    // <atom:source>
                    writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSourceElementName, AtomConstants.AtomNamespace);

                    WriteFeedMetadata(writer, baseUri, source, null);

                    // </atom:source>
                    writer.WriteEndElement();
                }
            }
        }
Example #31
0
        /// <summary>
        /// Start writing an entry.
        /// </summary>
        /// <param name="entry">The entry to write.</param>
        protected override void StartEntry(ODataEntry entry)
        {
            this.CheckAndWriteParentNavigationLinkStartForInlineElement();
            Debug.Assert(
                this.ParentNavigationLink == null || !this.ParentNavigationLink.IsCollection.Value,
                "We should have already verified that the IsCollection matches the actual content of the link (feed/entry).");

            if (entry == null)
            {
                Debug.Assert(this.ParentNavigationLink != null, "When entry == null, it has to be an expanded single entry navigation.");

                // this is a null expanded single entry and it is null, an empty <m:inline /> will be written.
                return;
            }

            this.StartEntryXmlCustomization(entry);

            // <entry>
            this.atomOutputContext.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomEntryElementName, AtomConstants.AtomNamespace);

            if (this.IsTopLevel)
            {
                this.atomEntryAndFeedSerializer.WriteBaseUriAndDefaultNamespaceAttributes();
            }

            string etag = entry.ETag;

            if (etag != null)
            {
                // TODO, ckerer: if this is a top-level entry also put the ETag into the headers.
                ODataAtomWriterUtils.WriteETag(this.atomOutputContext.XmlWriter, etag);
            }

            AtomEntryScope    currentEntryScope = this.CurrentEntryScope;
            AtomEntryMetadata entryMetadata     = entry.Atom();

            // Write the id if it's available here.
            // If it's not available here we will try to write it at the end of the entry again.
            string entryId = entry.Id;

            if (entryId != null)
            {
                this.atomEntryAndFeedSerializer.WriteEntryId(entryId);
                currentEntryScope.SetWrittenElement(AtomElement.Id);
            }

            // <category term="type" scheme="odatascheme"/>
            // If no type information is provided, don't include the category element for type at all
            // NOTE: the validation of the type name is done by the core writer.
            string typeName = entry.TypeName;
            SerializationTypeNameAnnotation serializationTypeNameAnnotation = entry.GetAnnotation <SerializationTypeNameAnnotation>();

            if (serializationTypeNameAnnotation != null)
            {
                typeName = serializationTypeNameAnnotation.TypeName;
            }

            this.atomEntryAndFeedSerializer.WriteEntryTypeName(typeName, entryMetadata);

            // Write the edit link if it's available here.
            // If it's not available here we will try to write it at the end of the entry again.
            Uri editLink = entry.EditLink;

            if (editLink != null)
            {
                this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata);
                currentEntryScope.SetWrittenElement(AtomElement.EditLink);
            }

            // Write the self link if it's available here.
            // If it's not available here we will try to write it at the end of the entry again.
            Uri readLink = entry.ReadLink;

            if (readLink != null)
            {
                this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata);
                currentEntryScope.SetWrittenElement(AtomElement.ReadLink);
            }
        }
Example #32
0
 private static XmlWriter StartEntryXmlCustomizer(ODataEntry entry, XmlWriter entryWriter)
 {
     return(entry.GetAnnotation <WritingEntityInfo>().EntryPayload.CreateWriter());
 }
Example #33
0
        protected override void EndEntry(ODataEntry entry)
        {
            Debug.Assert(
                this.ParentNavigationLink == null || !this.ParentNavigationLink.IsCollection.Value,
                "We should have already verified that the IsCollection matches the actual content of the link (feed/entry).");

            if (entry == null)
            {
                Debug.Assert(this.ParentNavigationLink != null, "When entry == null, it has to be an expanded single entry navigation.");

                // this is a null expanded single entry and it is null, an empty <m:inline /> will be written.
                this.CheckAndWriteParentNavigationLinkEndForInlineElement();
                return;
            }

            IEdmEntityType entryType = this.EntryEntityType;

            // Initialize the property value cache and cache the entry properties.
            EntryPropertiesValueCache propertyValueCache = new EntryPropertiesValueCache(entry);

            // NOTE: when writing, we assume the model has been validated already and thus pass int.MaxValue for the maxMappingCount.
            ODataEntityPropertyMappingCache epmCache = this.atomOutputContext.Model.EnsureEpmCache(entryType, /*maxMappingCount*/ int.MaxValue);

            // Populate the property value cache based on the EPM source tree information.
            // We do this since we need to write custom EPM after the properties below and don't
            // want to cache all properties just for the case that they are used in a custom EPM.
            if (epmCache != null)
            {
                EpmWriterUtils.CacheEpmProperties(propertyValueCache, epmCache.EpmSourceTree);
            }

            // Get the projected properties annotation
            ProjectedPropertiesAnnotation projectedProperties = entry.GetAnnotation <ProjectedPropertiesAnnotation>();

            AtomEntryScope    currentEntryScope = this.CurrentEntryScope;
            AtomEntryMetadata entryMetadata     = entry.Atom();

            if (!currentEntryScope.IsElementWritten(AtomElement.Id))
            {
                // NOTE: We write even null id, in that case we generate an empty atom:id element.
                this.atomEntryAndFeedSerializer.WriteEntryId(entry.Id);
            }

            Uri editLink = entry.EditLink;

            if (editLink != null && !currentEntryScope.IsElementWritten(AtomElement.EditLink))
            {
                this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata);
            }

            Uri readLink = entry.ReadLink;

            if (readLink != null && !currentEntryScope.IsElementWritten(AtomElement.ReadLink))
            {
                this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata);
            }

            // write entry metadata including syndication EPM
            AtomEntryMetadata epmEntryMetadata = null;

            if (epmCache != null)
            {
                ODataVersionChecker.CheckEntityPropertyMapping(this.atomOutputContext.Version, entryType, this.atomOutputContext.Model);

                epmEntryMetadata = EpmSyndicationWriter.WriteEntryEpm(
                    epmCache.EpmTargetTree,
                    propertyValueCache,
                    entryType.ToTypeReference().AsEntity(),
                    this.atomOutputContext);
            }

            this.atomEntryAndFeedSerializer.WriteEntryMetadata(entryMetadata, epmEntryMetadata, this.updatedTime);

            // stream properties
            IEnumerable <ODataProperty> streamProperties = propertyValueCache.EntryStreamProperties;

            if (streamProperties != null)
            {
                foreach (ODataProperty streamProperty in streamProperties)
                {
                    this.atomEntryAndFeedSerializer.WriteStreamProperty(
                        streamProperty,
                        entryType,
                        this.DuplicatePropertyNamesChecker,
                        projectedProperties);
                }
            }

            // association links
            IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks;

            if (associationLinks != null)
            {
                foreach (ODataAssociationLink associationLink in associationLinks)
                {
                    this.atomEntryAndFeedSerializer.WriteAssociationLink(
                        associationLink,
                        entryType,
                        this.DuplicatePropertyNamesChecker,
                        projectedProperties);
                }
            }

            // actions
            IEnumerable <ODataAction> actions = entry.Actions;

            if (actions != null)
            {
                foreach (ODataAction action in actions)
                {
                    ValidationUtils.ValidateOperationNotNull(action, true);
                    this.atomEntryAndFeedSerializer.WriteOperation(action);
                }
            }

            // functions
            IEnumerable <ODataFunction> functions = entry.Functions;

            if (functions != null)
            {
                foreach (ODataFunction function in functions)
                {
                    ValidationUtils.ValidateOperationNotNull(function, false);
                    this.atomEntryAndFeedSerializer.WriteOperation(function);
                }
            }

            // write the content
            this.WriteEntryContent(
                entry,
                entryType,
                propertyValueCache,
                epmCache == null ? null : epmCache.EpmSourceTree.Root,
                projectedProperties);

            // write custom EPM
            if (epmCache != null)
            {
                EpmCustomWriter.WriteEntryEpm(
                    this.atomOutputContext.XmlWriter,
                    epmCache.EpmTargetTree,
                    propertyValueCache,
                    entryType.ToTypeReference().AsEntity(),
                    this.atomOutputContext);
            }

            // </entry>
            this.atomOutputContext.XmlWriter.WriteEndElement();

            this.EndEntryXmlCustomization(entry);

            this.CheckAndWriteParentNavigationLinkEndForInlineElement();
        }