/// <summary> /// Writes the edit link element for an entry. /// </summary> /// <param name="editLink">The edit link URL.</param> /// <param name="entryMetadata">The ATOM entry metatadata for the current entry.</param> internal void WriteEntryEditLink(Uri editLink, AtomEntryMetadata entryMetadata) { Debug.Assert(editLink != null, "editLink != null"); // we allow additional link metadata to specify the title, type, hreflang or length of the link AtomLinkMetadata editLinkMetadata = entryMetadata == null ? null : entryMetadata.EditLink; // <link rel="edit" href="LinkHRef" .../> this.WriteReadOrEditLink(editLink, editLinkMetadata, AtomConstants.AtomEditRelationAttributeValue); }
/// <summary> /// Writes the type name category element for the entry. /// </summary> /// <param name="typeName">The type name to write.</param> /// <param name="entryMetadata">The entry metadata if available.</param> internal void WriteEntryTypeName(string typeName, AtomEntryMetadata entryMetadata) { if (typeName != null) { AtomCategoryMetadata mergedCategoryMetadata = ODataAtomWriterMetadataUtils.MergeCategoryMetadata( entryMetadata == null ? null : entryMetadata.CategoryWithTypeName, typeName, AtomConstants.ODataSchemeNamespace); this.atomEntryMetadataSerializer.WriteCategory(mergedCategoryMetadata); } }
/// <summary> /// Writes the type name category element for the entry. /// </summary> /// <param name="typeName">The type name to write.</param> /// <param name="entryMetadata">The entry metadata if available.</param> internal void WriteEntryTypeName(string typeName, AtomEntryMetadata entryMetadata) { if (typeName != null) { AtomCategoryMetadata mergedCategoryMetadata = ODataAtomWriterMetadataUtils.MergeCategoryMetadata( entryMetadata == null ? null : entryMetadata.CategoryWithTypeName, typeName, AtomConstants.ODataSchemeNamespace); this.atomEntryMetadataSerializer.WriteCategory(mergedCategoryMetadata); } }
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; }
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); }
/// <summary> /// Writes the edit link element for an entry. /// </summary> /// <param name="editLink">The edit link URL.</param> /// <param name="entryMetadata">The ATOM entry metatadata for the current entry.</param> internal void WriteEntryEditLink(Uri editLink, AtomEntryMetadata entryMetadata) { Debug.Assert(editLink != null, "editLink != null"); // we allow additional link metadata to specify the title, type, hreflang or length of the link AtomLinkMetadata editLinkMetadata = entryMetadata == null ? null : entryMetadata.EditLink; // <link rel="edit" href="LinkHRef" .../> this.WriteReadOrEditLink(editLink, editLinkMetadata, AtomConstants.AtomEditRelationAttributeValue); }
private static void AddEntryMetadata(EntityInstance payloadElement, ODataEntry entry) { AtomEntryMetadata metadata = null; foreach (XmlTreeAnnotation epmTree in payloadElement.Annotations.OfType<XmlTreeAnnotation>()) { if (epmTree.NamespaceName == TestAtomConstants.AtomNamespace) { if (metadata == null) { metadata = new AtomEntryMetadata(); } string localName = epmTree.LocalName; if (localName == TestAtomConstants.AtomAuthorElementName) { Debug.Assert(!epmTree.IsAttribute); AtomPersonMetadata author = CreateAuthorMetadata(epmTree.Children); List<AtomPersonMetadata> authors; if (metadata.Authors == null) { authors = new List<AtomPersonMetadata>(); metadata.Authors = authors; } else { authors = (List<AtomPersonMetadata>)metadata.Authors; } authors.Add(author); } else if (localName == TestAtomConstants.AtomCategoryElementName) { Debug.Assert(!epmTree.IsAttribute); AtomCategoryMetadata category = CreateCategoryMetadata(epmTree.Children); List<AtomCategoryMetadata> categories; if (metadata.Categories == null) { categories = new List<AtomCategoryMetadata>(); metadata.Categories = categories; } else { categories = (List<AtomCategoryMetadata>)metadata.Categories; } categories.Add(category); } else if (localName == TestAtomConstants.AtomContributorElementName) { Debug.Assert(!epmTree.IsAttribute); AtomPersonMetadata contributor = CreateAuthorMetadata(epmTree.Children); List<AtomPersonMetadata> contributors; if (metadata.Contributors == null) { contributors = new List<AtomPersonMetadata>(); metadata.Contributors = contributors; } else { contributors = (List<AtomPersonMetadata>)metadata.Contributors; } contributors.Add(contributor); } else if (localName == TestAtomConstants.AtomIdElementName) { Debug.Assert(!epmTree.IsAttribute); entry.Id = string.IsNullOrEmpty(epmTree.PropertyValue) ? null : new Uri(epmTree.PropertyValue); } else if (localName == TestAtomConstants.AtomLinkElementName) { Debug.Assert(!epmTree.IsAttribute); AtomLinkMetadata link = CreateLinkMetadata(epmTree.Children); List<AtomLinkMetadata> links; if (metadata.Links == null) { links = new List<AtomLinkMetadata>(); metadata.Links = links; } else { links = (List<AtomLinkMetadata>)metadata.Links; } links.Add(link); } else if (localName == TestAtomConstants.AtomPublishedElementName) { Debug.Assert(!epmTree.IsAttribute); metadata.Published = string.IsNullOrEmpty(epmTree.PropertyValue) ? (DateTimeOffset?)null : DateTimeOffset.Parse(epmTree.PropertyValue); } else if (localName == TestAtomConstants.AtomRightsElementName) { Debug.Assert(!epmTree.IsAttribute); AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children); metadata.Rights = new AtomTextConstruct { Kind = atomConstructKind, Text = epmTree.PropertyValue }; } else if (localName == TestAtomConstants.AtomSourceElementName) { Debug.Assert(!epmTree.IsAttribute); metadata.Source = CreateFeedMetadata(epmTree.Children, null); } else if (localName == TestAtomConstants.AtomSummaryElementName) { Debug.Assert(!epmTree.IsAttribute); AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children); metadata.Summary = new AtomTextConstruct { Kind = atomConstructKind, Text = epmTree.PropertyValue }; } else if (localName == TestAtomConstants.AtomTitleElementName) { Debug.Assert(!epmTree.IsAttribute); AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children); metadata.Title = new AtomTextConstruct { Kind = atomConstructKind, Text = epmTree.PropertyValue }; } else if (localName == TestAtomConstants.AtomUpdatedElementName) { Debug.Assert(!epmTree.IsAttribute); metadata.Updated = string.IsNullOrEmpty(epmTree.PropertyValue) ? (DateTimeOffset?)null : DateTimeOffset.Parse(epmTree.PropertyValue); } else { throw new NotSupportedException("Unsupported atom metadata '" + localName + "' found for entry!"); } } } // Fix up metadata for baselining metadata = metadata.Fixup(); if (metadata != null) { entry.SetAnnotation<AtomEntryMetadata>(metadata); } }
/// <summary> /// Converts the Object Model representation of Atom metadata for entries into appropriate PayloadElement annotations /// </summary> /// <param name="entryMetadata">the Atom entry metadata, in Object Model representation, to convert</param> /// <param name="entry">the EntityInstance to annotate</param> private static void ConvertAtomEntryMetadata(AtomEntryMetadata entryMetadata, EntityInstance entry) { ExceptionUtilities.CheckArgumentNotNull(entryMetadata, "entryMetadata"); ExceptionUtilities.CheckArgumentNotNull(entry, "entry"); foreach (var author in entryMetadata.Authors) { entry.AtomAuthor(author.Name, author.Uri == null ? null : author.Uri.OriginalString, author.Email); } foreach (var category in entryMetadata.Categories) { entry.AtomCategory(category.Term, category.Scheme, category.Label); } foreach (var contributor in entryMetadata.Contributors) { entry.AtomContributor(contributor.Name, contributor.Uri == null? null : contributor.Uri.OriginalString, contributor.Email); } if (entryMetadata.EditLink != null) { AtomLinkMetadata editLink = entryMetadata.EditLink; entry.AtomEditLink(editLink.Href == null ? null : editLink.Href.OriginalString, editLink.MediaType, editLink.HrefLang, editLink.Title, ToString(editLink.Length)); } foreach (var link in entryMetadata.Links) { entry.AtomLink(link.Href == null ? null : link.Href.OriginalString, link.Relation, link.MediaType, link.HrefLang, link.Title, ToString(link.Length)); } if (entryMetadata.Published.HasValue) { entry.AtomPublished(ToString(entryMetadata.Published)); } if (entryMetadata.Rights != null) { entry.AtomRights(entryMetadata.Rights.Text, ToString(entryMetadata.Rights.Kind)); } if (entryMetadata.SelfLink != null) { AtomLinkMetadata selfLink = entryMetadata.SelfLink; entry.AtomSelfLink(selfLink.Href == null ? null : selfLink.Href.OriginalString, selfLink.MediaType, selfLink.HrefLang, selfLink.Title, ToString(selfLink.Length)); } if (entryMetadata.CategoryWithTypeName != null) { AtomCategoryMetadata categoryWithTypeName = entryMetadata.CategoryWithTypeName; entry.AtomCategoryWithTypeName(categoryWithTypeName.Term, categoryWithTypeName.Label); } if (entryMetadata.Source != null) { EntitySetInstance tempSourceFeed = new EntitySetInstance(); ConvertAtomFeedMetadata(entryMetadata.Source, tempSourceFeed); entry.AtomSource(tempSourceFeed); } if (entryMetadata.Summary != null) { entry.AtomSummary(entryMetadata.Summary.Text, ToString(entryMetadata.Summary.Kind)); } if (entryMetadata.Title != null) { entry.AtomTitle(entryMetadata.Title.Text, ToString(entryMetadata.Title.Kind)); } if (entryMetadata.Updated.HasValue) { entry.AtomUpdated(ToString(entryMetadata.Updated)); } }
internal void WriteEntryMetadata(AtomEntryMetadata entryMetadata, string updatedTime) { Debug.Assert(!string.IsNullOrEmpty(updatedTime), "!string.IsNullOrEmpty(updatedTime)"); #if DEBUG DateTimeOffset tempDateTimeOffset; Debug.Assert(DateTimeOffset.TryParse(updatedTime, out tempDateTimeOffset), "DateTimeOffset.TryParse(updatedTime, out tempDateTimeOffset)"); #endif // 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. if (entryMetadata == null) { // write all required metadata elements with default content // <atom:title></atom:title> this.WriteEmptyElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace); // <atom:updated>dateTimeOffset</atom:updated> // NOTE: the <updated> element is required and if not specified we use a single 'default/current' date/time for the whole payload. this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, updatedTime); this.WriteEmptyAuthor(); } else { // <atom:title>text</atom:title> // NOTE: writes an empty element even if no title was specified since the title is required this.WriteTextConstruct(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, entryMetadata.Title); AtomTextConstruct summary = entryMetadata.Summary; if (summary != null) { // <atom:summary>text</atom:summary> this.WriteTextConstruct(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSummaryElementName, AtomConstants.AtomNamespace, summary); } string published = entryMetadata.Published.HasValue ? ODataAtomConvert.ToAtomString(entryMetadata.Published.Value) : null; if (published != null) { // <atom:published>dateTimeOffset</atom:published> this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomPublishedElementName, AtomConstants.AtomNamespace, published); } // <atom:updated>date</atom:updated> string updated = entryMetadata.Updated.HasValue ? ODataAtomConvert.ToAtomString(entryMetadata.Updated.Value) : null; // NOTE: the <updated> element is required and if not specified we use a single 'default/current' date/time for the whole payload. updated = updated ?? updatedTime; this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, updated); bool wroteAuthor = false; IEnumerable<AtomPersonMetadata> authors = entryMetadata.Authors; if (authors != null) { foreach (AtomPersonMetadata author in authors) { if (author == null) { throw new ODataException(ODataErrorStrings.ODataAtomWriterMetadataUtils_AuthorMetadataMustNotContainNull); } // <atom:author>author data</atom:author> this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomAuthorElementName, AtomConstants.AtomNamespace); this.WritePersonMetadata(author); this.XmlWriter.WriteEndElement(); wroteAuthor = true; } } if (!wroteAuthor) { // write empty authors since they are required this.WriteEmptyAuthor(); } IEnumerable<AtomPersonMetadata> contributors = entryMetadata.Contributors; if (contributors != null) { foreach (AtomPersonMetadata contributor in contributors) { if (contributor == null) { throw new ODataException(ODataErrorStrings.ODataAtomWriterMetadataUtils_ContributorMetadataMustNotContainNull); } // <atom:contributor>contributor data</atom:contributor> this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContributorElementName, AtomConstants.AtomNamespace); this.WritePersonMetadata(contributor); this.XmlWriter.WriteEndElement(); } } IEnumerable<AtomLinkMetadata> links = entryMetadata.Links; if (links != null) { foreach (AtomLinkMetadata link in links) { if (link == null) { throw new ODataException(ODataErrorStrings.ODataAtomWriterMetadataUtils_LinkMetadataMustNotContainNull); } // <atom:link>...</atom:link> this.WriteAtomLink(link, null /*edit-link-etag*/); } } IEnumerable<AtomCategoryMetadata> categories = entryMetadata.Categories; if (categories != null) { foreach (AtomCategoryMetadata category in categories) { if (category == null) { throw new ODataException(ODataErrorStrings.ODataAtomWriterMetadataUtils_CategoryMetadataMustNotContainNull); } // <atom:category term="..." scheme="..." label="..."></atom:category> this.WriteCategory(category); } } if (entryMetadata.Rights != null) { // <atom:rights>rights</atom:rights> this.WriteTextConstruct( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomRightsElementName, AtomConstants.AtomNamespace, entryMetadata.Rights); } AtomFeedMetadata source = entryMetadata.Source; if (source != null) { // <atom:source> this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSourceElementName, AtomConstants.AtomNamespace); bool authorWritten; this.SourceMetadataSerializer.WriteFeedMetadata(source, null /* feed */, updatedTime, out authorWritten); // </atom:source> this.XmlWriter.WriteEndElement(); } } }
/// <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; } // <entry> this.atomOutputContext.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomEntryElementName, AtomConstants.AtomNamespace); if (this.IsTopLevel) { this.atomEntryAndFeedSerializer.WriteBaseUriAndDefaultNamespaceAttributes(); // Write metadata:context this.atomEntryAndFeedSerializer.TryWriteEntryContextUri(this.CurrentEntryScope.GetOrCreateTypeContext(this.atomOutputContext.Model, this.atomOutputContext.WritingResponse)); } 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. Uri entryId = entry.Id; bool isTransient = entry.IsTransient; if (entryId != null) { this.atomEntryAndFeedSerializer.WriteEntryId(entryId, isTransient); 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 = this.atomOutputContext.TypeNameOracle.GetEntryTypeNameForWriting(entry); 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. // If readlink is identical to editlink, don't write readlink. Uri readLink = entry.ReadLink; if (readLink != null) { if (readLink != editLink) { this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata); } currentEntryScope.SetWrittenElement(AtomElement.ReadLink); } this.WriteInstanceAnnotations(entry.InstanceAnnotations, currentEntryScope.InstanceAnnotationWriteTracker); }
internal void WriteEntryMetadata(AtomEntryMetadata entryMetadata, string updatedTime) { Debug.Assert(!string.IsNullOrEmpty(updatedTime), "!string.IsNullOrEmpty(updatedTime)"); #if DEBUG DateTimeOffset tempDateTimeOffset; Debug.Assert(DateTimeOffset.TryParse(updatedTime, out tempDateTimeOffset), "DateTimeOffset.TryParse(updatedTime, out tempDateTimeOffset)"); #endif // TODO: 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. if (entryMetadata == null) { // write all required metadata elements with default content // <atom:title></atom:title> this.WriteEmptyElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace); // <atom:updated>dateTimeOffset</atom:updated> // NOTE: the <updated> element is required and if not specified we use a single 'default/current' date/time for the whole payload. this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, updatedTime); this.WriteEmptyAuthor(); } else { // <atom:title>text</atom:title> // NOTE: writes an empty element even if no title was specified since the title is required this.WriteTextConstruct(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, entryMetadata.Title); AtomTextConstruct summary = entryMetadata.Summary; if (summary != null) { // <atom:summary>text</atom:summary> this.WriteTextConstruct(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSummaryElementName, AtomConstants.AtomNamespace, summary); } string published = entryMetadata.Published.HasValue ? ODataAtomConvert.ToAtomString(entryMetadata.Published.Value) : null; if (published != null) { // <atom:published>dateTimeOffset</atom:published> this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomPublishedElementName, AtomConstants.AtomNamespace, published); } // <atom:updated>date</atom:updated> string updated = entryMetadata.Updated.HasValue ? ODataAtomConvert.ToAtomString(entryMetadata.Updated.Value) : null; // NOTE: the <updated> element is required and if not specified we use a single 'default/current' date/time for the whole payload. updated = updated ?? updatedTime; this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, updated); bool wroteAuthor = false; IEnumerable <AtomPersonMetadata> authors = entryMetadata.Authors; if (authors != null) { foreach (AtomPersonMetadata author in authors) { if (author == null) { throw new ODataException(ODataErrorStrings.ODataAtomWriterMetadataUtils_AuthorMetadataMustNotContainNull); } // <atom:author>author data</atom:author> this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomAuthorElementName, AtomConstants.AtomNamespace); this.WritePersonMetadata(author); this.XmlWriter.WriteEndElement(); wroteAuthor = true; } } if (!wroteAuthor) { // write empty authors since they are required this.WriteEmptyAuthor(); } IEnumerable <AtomPersonMetadata> contributors = entryMetadata.Contributors; if (contributors != null) { foreach (AtomPersonMetadata contributor in contributors) { if (contributor == null) { throw new ODataException(ODataErrorStrings.ODataAtomWriterMetadataUtils_ContributorMetadataMustNotContainNull); } // <atom:contributor>contributor data</atom:contributor> this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContributorElementName, AtomConstants.AtomNamespace); this.WritePersonMetadata(contributor); this.XmlWriter.WriteEndElement(); } } IEnumerable <AtomLinkMetadata> links = entryMetadata.Links; if (links != null) { foreach (AtomLinkMetadata link in links) { if (link == null) { throw new ODataException(ODataErrorStrings.ODataAtomWriterMetadataUtils_LinkMetadataMustNotContainNull); } // <atom:link>...</atom:link> this.WriteAtomLink(link, null /*edit-link-etag*/); } } IEnumerable <AtomCategoryMetadata> categories = entryMetadata.Categories; if (categories != null) { foreach (AtomCategoryMetadata category in categories) { if (category == null) { throw new ODataException(ODataErrorStrings.ODataAtomWriterMetadataUtils_CategoryMetadataMustNotContainNull); } // <atom:category term="..." scheme="..." label="..."></atom:category> this.WriteCategory(category); } } if (entryMetadata.Rights != null) { // <atom:rights>rights</atom:rights> this.WriteTextConstruct( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomRightsElementName, AtomConstants.AtomNamespace, entryMetadata.Rights); } AtomFeedMetadata source = entryMetadata.Source; if (source != null) { // <atom:source> this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSourceElementName, AtomConstants.AtomNamespace); bool authorWritten; this.SourceMetadataSerializer.WriteFeedMetadata(source, null /* feed */, updatedTime, out authorWritten); // </atom:source> this.XmlWriter.WriteEndElement(); } } }
/// <summary> /// Creates an ODataEntry instance with the default values for 'Id', 'ReadLink' and 'Updated' /// that can be used and modified in tests. /// </summary> /// <param name="typeName">The optional type name for the default entry.</param> /// <param name="model">The product model to generate the type in (if not null).</param> /// <returns>The newly created ODataEntry instance.</returns> public static ODataEntry CreateDefaultEntryWithAtomMetadata(string entitySetName = null, string typeName = null, EdmModel model = null) { if (model != null && typeName != null) { EdmEntityType entityType = new EdmEntityType(DefaultNamespaceName, typeName); entityType.AddKeys(entityType.AddStructuralProperty("Id", EdmCoreModel.Instance.GetInt32(isNullable: false))); model.AddElement(entityType); typeName = entityType.FullName(); EdmEntityContainer container = new EdmEntityContainer(DefaultNamespaceName, "DefaultContainer"); model.AddElement(container); if (entitySetName != null) { container.AddEntitySet(entitySetName, entityType); } } ODataEntry entry = new ODataEntry() { Id = DefaultEntryId, ReadLink = DefaultEntryReadLink, TypeName = typeName, SerializationInfo = MySerializationInfo }; AtomEntryMetadata metadata = new AtomEntryMetadata() { Updated = DateTimeOffset.Parse(DefaultEntryUpdated) }; entry.SetAnnotation<AtomEntryMetadata>(metadata); return entry; }
/// <summary>Write the entry element.</summary> /// <param name="expanded">Expanded result provider for the specified <paramref name="element"/>.</param> /// <param name="element">Element representing the entry element.</param> /// <param name="resourceInstanceInFeed">true if the resource instance being serialized is inside a feed; false otherwise.</param> /// <param name="expectedType">Expected type of the entry element.</param> private void WriteEntry(IExpandedResult expanded, object element, bool resourceInstanceInFeed, ResourceType expectedType) { Debug.Assert(element != null, "element != null"); Debug.Assert(expectedType != null && expectedType.ResourceTypeKind == ResourceTypeKind.EntityType, "expectedType != null && expectedType.ResourceTypeKind == ResourceTypeKind.EntityType"); this.IncrementSegmentResultCount(); ODataEntry entry = new ODataEntry(); if (!resourceInstanceInFeed) { entry.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo { NavigationSourceName = this.CurrentContainer.Name, NavigationSourceEntityTypeName = this.CurrentContainer.ResourceType.FullName, ExpectedTypeName = expectedType.FullName }); } string title = expectedType.Name; #pragma warning disable 618 if (this.contentFormat == ODataFormat.Atom) #pragma warning restore 618 { AtomEntryMetadata entryAtom = new AtomEntryMetadata(); entryAtom.EditLink = new AtomLinkMetadata { Title = title }; entry.SetAnnotation(entryAtom); } ResourceType actualResourceType = WebUtil.GetNonPrimitiveResourceType(this.Provider, element); if (actualResourceType.ResourceTypeKind != ResourceTypeKind.EntityType) { // making sure that the actual resource type is an entity type throw new DataServiceException(500, Microsoft.OData.Service.Strings.BadProvider_InconsistentEntityOrComplexTypeUsage(actualResourceType.FullName)); } EntityToSerialize entityToSerialize = this.WrapEntity(element, actualResourceType); // populate the media resource, if the entity is a MLE. entry.MediaResource = this.GetMediaResource(entityToSerialize, title); // Write the type name this.PayloadMetadataPropertyManager.SetTypeName(entry, this.CurrentContainer.ResourceType.FullName, actualResourceType.FullName); // Write Id element this.PayloadMetadataPropertyManager.SetId(entry, () => entityToSerialize.SerializedKey.Identity); // Write "edit" link this.PayloadMetadataPropertyManager.SetEditLink(entry, () => entityToSerialize.SerializedKey.RelativeEditLink); // Write the etag property, if the type has etag properties this.PayloadMetadataPropertyManager.SetETag(entry, () => this.GetETagValue(element, actualResourceType)); IEnumerable<ProjectionNode> projectionNodes = this.GetProjections(); if (projectionNodes != null) { // Filter the projection nodes for the actual type of the entity // The projection node might refer to the property in a derived type. If the TargetResourceType of // the projection node is not a super type, then we do not want to serialize this property. projectionNodes = projectionNodes.Where(projectionNode => projectionNode.TargetResourceType.IsAssignableFrom(actualResourceType)); // Because we are going to enumerate through these multiple times, create a list. projectionNodes = projectionNodes.ToList(); // And add the annotation to tell ODataLib which properties to write into content (the projections) entry.SetAnnotation(new ProjectedPropertiesAnnotation(projectionNodes.Select(p => p.PropertyName))); } // Populate the advertised actions IEnumerable<ODataAction> actions; if (this.TryGetAdvertisedActions(entityToSerialize, resourceInstanceInFeed, out actions)) { foreach (ODataAction action in actions) { entry.AddAction(action); } } // Populate all the normal properties entry.Properties = this.GetEntityProperties(entityToSerialize, projectionNodes); // And start the entry var args = new DataServiceODataWriterEntryArgs(entry, element, this.Service.OperationContext); this.dataServicesODataWriter.WriteStart(args); // Now write all the navigation properties this.WriteNavigationProperties(expanded, entityToSerialize, resourceInstanceInFeed, projectionNodes); // And write the end of the entry this.dataServicesODataWriter.WriteEnd(args); #if ASTORIA_FF_CALLBACKS this.Service.InternalOnWriteItem(target, element); #endif }
/// <summary> /// Visits an ATOM entry metadata. /// </summary> /// <param name="atomEntryMetadata">The entry metadata to visit.</param> protected virtual void VisitAtomEntryMetadata(AtomEntryMetadata atomEntryMetadata) { IEnumerable<AtomPersonMetadata> authors = atomEntryMetadata.Authors; if (authors != null) { foreach (AtomPersonMetadata author in authors) { this.VisitAtomMetadata(author); } } IEnumerable<AtomCategoryMetadata> categories = atomEntryMetadata.Categories; if (categories != null) { foreach (AtomCategoryMetadata category in categories) { this.VisitAtomMetadata(category); } } IEnumerable<AtomPersonMetadata> contributors = atomEntryMetadata.Contributors; if (contributors != null) { foreach (AtomPersonMetadata contributor in contributors) { this.VisitAtomMetadata(contributor); } } IEnumerable<AtomLinkMetadata> links = atomEntryMetadata.Links; if (links != null) { foreach (AtomLinkMetadata link in links) { this.VisitAtomMetadata(link); } } this.VisitAtomMetadata(atomEntryMetadata.Rights); this.VisitAtomMetadata(atomEntryMetadata.EditLink); this.VisitAtomMetadata(atomEntryMetadata.SelfLink); this.VisitAtomMetadata(atomEntryMetadata.CategoryWithTypeName); this.VisitAtomMetadata(atomEntryMetadata.Source); this.VisitAtomMetadata(atomEntryMetadata.Summary); this.VisitAtomMetadata(atomEntryMetadata.Title); }
/// <summary> /// Write the ATOM metadata for an entry /// </summary> /// <param name="entryMetadata">The entry metadata to write.</param> /// <param name="updatedTime">Value for the atom:updated element.</param> internal void WriteEntryMetadata(AtomEntryMetadata entryMetadata, string updatedTime) { this.atomEntryMetadataSerializer.WriteEntryMetadata(entryMetadata, updatedTime); }
/// <summary> /// Reads an element in ATOM namespace in the content of the entry element. /// </summary> /// <param name="entryState">The reader entry state for the entry being read.</param> /// <remarks> /// Pre-Condition: XmlNodeType.Element (atom:*) - the ATOM element to read. /// Post-Condition: Any - the node after the ATOM element which was read. /// </remarks> internal void ReadAtomElementInEntryContent(IODataAtomReaderEntryState entryState) { Debug.Assert(entryState != null, "entryState != null"); this.AssertXmlCondition(XmlNodeType.Element); Debug.Assert(this.XmlReader.NamespaceURI == AtomConstants.AtomNamespace, "Only atom:* elements can be read by this method."); if (this.ReadAtomMetadata) { switch (this.XmlReader.LocalName) { case AtomConstants.AtomAuthorElementName: this.ReadAuthorElement(entryState); return; case AtomConstants.AtomContributorElementName: this.ReadContributorElement(entryState); return; case AtomConstants.AtomUpdatedElementName: { AtomEntryMetadata entryMetadata = entryState.AtomEntryMetadata; if (this.ShouldReadSingletonElement(entryMetadata.Updated.HasValue)) { entryMetadata.Updated = this.ReadAtomDateConstruct(); return; } } break; case AtomConstants.AtomPublishedElementName: { AtomEntryMetadata entryMetadata = entryState.AtomEntryMetadata; if (this.ShouldReadSingletonElement(entryMetadata.Published.HasValue)) { entryMetadata.Published = this.ReadAtomDateConstruct(); return; } } break; case AtomConstants.AtomRightsElementName: if (this.ShouldReadSingletonElement(entryState.AtomEntryMetadata.Rights != null)) { entryState.AtomEntryMetadata.Rights = this.ReadAtomTextConstruct(); return; } break; case AtomConstants.AtomSourceElementName: if (this.ShouldReadSingletonElement(entryState.AtomEntryMetadata.Source != null)) { entryState.AtomEntryMetadata.Source = this.ReadAtomSourceInEntryContent(); return; } break; case AtomConstants.AtomSummaryElementName: if (this.ShouldReadSingletonElement(entryState.AtomEntryMetadata.Summary != null)) { entryState.AtomEntryMetadata.Summary = this.ReadAtomTextConstruct(); return; } break; case AtomConstants.AtomTitleElementName: if (this.ShouldReadSingletonElement(entryState.AtomEntryMetadata.Title != null)) { entryState.AtomEntryMetadata.Title = this.ReadAtomTextConstruct(); return; } break; default: break; } } // Skip everything we didn't read. this.XmlReader.Skip(); }
/// <summary> /// Write the ATOM metadata for an entry /// </summary> /// <param name="entryMetadata">The entry metadata to write.</param> /// <param name="updatedTime">Value for the atom:updated element.</param> internal void WriteEntryMetadata(AtomEntryMetadata entryMetadata, string updatedTime) { this.atomEntryMetadataSerializer.WriteEntryMetadata(entryMetadata, updatedTime); }
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); // Get the projected properties annotation AtomEntryScope currentEntryScope = this.CurrentEntryScope; ProjectedPropertiesAnnotation projectedProperties = GetProjectedPropertiesAnnotation(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. bool isTransient = entry.IsTransient; this.atomEntryAndFeedSerializer.WriteEntryId(entry.Id, isTransient); } Uri editLink = entry.EditLink; if (editLink != null && !currentEntryScope.IsElementWritten(AtomElement.EditLink)) { this.atomEntryAndFeedSerializer.WriteEntryEditLink(editLink, entryMetadata); } Uri readLink = entry.ReadLink; if (readLink != null && readLink != editLink && !currentEntryScope.IsElementWritten(AtomElement.ReadLink)) { this.atomEntryAndFeedSerializer.WriteEntryReadLink(readLink, entryMetadata); } // write entry metadata this.atomEntryAndFeedSerializer.WriteEntryMetadata(entryMetadata, 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); } } // 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, projectedProperties); this.WriteInstanceAnnotations(entry.InstanceAnnotations, currentEntryScope.InstanceAnnotationWriteTracker); // </entry> this.atomOutputContext.XmlWriter.WriteEndElement(); this.CheckAndWriteParentNavigationLinkEndForInlineElement(); }
public void BaseUriErrorTest() { Uri baseUri = new Uri("http://odata.org"); Uri testUri = new Uri("http://odata.org/relative"); IEnumerable<Func<Uri, BaseUriErrorTestCase>> testCaseFuncs = new Func<Uri, BaseUriErrorTestCase>[] { relativeUri => new BaseUriErrorTestCase { // next page link ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataFeed feed = ObjectModelUtils.CreateDefaultFeed(); feed.NextPageLink = relativeUri; return new [] { feed }; }), Formats = new [] { ODataFormat.Atom, ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // entry read link ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataEntry entry = ObjectModelUtils.CreateDefaultEntry(); entry.ReadLink = relativeUri; return new [] { entry }; }), Formats = new [] { ODataFormat.Atom, ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // entry edit link ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataEntry entry = ObjectModelUtils.CreateDefaultEntry(); entry.EditLink = relativeUri; return new [] { entry }; }), Formats = new [] { ODataFormat.Atom, ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // media resource (default stream) read link ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataStreamReferenceValue mediaResource = new ODataStreamReferenceValue(); mediaResource.ContentType = "image/jpg"; mediaResource.ReadLink = relativeUri; ODataEntry entry = ObjectModelUtils.CreateDefaultEntry(); entry.MediaResource = mediaResource; return new [] { entry }; }), Formats = new [] { ODataFormat.Atom, ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // media resource (default stream) edit link ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataStreamReferenceValue mediaResource = new ODataStreamReferenceValue(); mediaResource.ContentType = "image/jpg"; // required mediaResource.ReadLink = testUri; // required mediaResource.EditLink = relativeUri; ODataEntry entry = ObjectModelUtils.CreateDefaultEntry(); entry.MediaResource = mediaResource; return new [] { entry }; }), Formats = new [] { ODataFormat.Atom, ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // link Url ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataNavigationLink link = ObjectModelUtils.CreateDefaultCollectionLink(); link.Url = relativeUri; ODataEntry entry = ObjectModelUtils.CreateDefaultEntry(); return new ODataItem[] { entry, link }; }), Formats = new [] { ODataFormat.Atom, ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // association link Url ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataNavigationLink link = ObjectModelUtils.CreateDefaultSingletonLink(); link.AssociationLinkUrl = relativeUri; ODataEntry entry = ObjectModelUtils.CreateDefaultEntry(); return new ODataItem[] { entry, link }; }), Formats = new [] { ODataFormat.Atom, ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // named stream read link ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataStreamReferenceValue namedStream = new ODataStreamReferenceValue() { ContentType = "image/jpg", ReadLink = relativeUri, }; ODataEntry entry = ObjectModelUtils.CreateDefaultEntry(); ODataProperty property = new ODataProperty() { Name = "NamedStream", Value = namedStream }; entry.Properties = new[] { property }; return new [] { entry }; }), Formats = new [] { ODataFormat.Atom, ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // named stream edit link ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataStreamReferenceValue namedStream = new ODataStreamReferenceValue() { ContentType = "image/jpg", ReadLink = testUri, EditLink = relativeUri }; ODataEntry entry = ObjectModelUtils.CreateDefaultEntry(); ODataProperty property = new ODataProperty() { Name = "NamedStream", Value = namedStream }; entry.Properties = new[] { property }; return new [] { entry }; }), Formats = new [] { ODataFormat.Atom, ODataFormat.Json } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: feed generator Uri ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataFeed feed = ObjectModelUtils.CreateDefaultFeed(); AtomFeedMetadata metadata = new AtomFeedMetadata() { Generator = new AtomGeneratorMetadata() { Uri = relativeUri } }; feed.SetAnnotation<AtomFeedMetadata>(metadata); return new [] { feed }; }), Formats = new [] { ODataFormat.Atom } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: feed logo ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataFeed feed = ObjectModelUtils.CreateDefaultFeed(); AtomFeedMetadata metadata = new AtomFeedMetadata() { Logo = relativeUri }; feed.SetAnnotation<AtomFeedMetadata>(metadata); return new [] { feed }; }), Formats = new [] { ODataFormat.Atom } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: feed icon ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataFeed feed = ObjectModelUtils.CreateDefaultFeed(); AtomFeedMetadata metadata = new AtomFeedMetadata() { Icon = relativeUri }; feed.SetAnnotation<AtomFeedMetadata>(metadata); return new [] { feed }; }), Formats = new [] { ODataFormat.Atom } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: feed author ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataFeed feed = ObjectModelUtils.CreateDefaultFeed(); AtomFeedMetadata metadata = new AtomFeedMetadata() { Authors = new [] { new AtomPersonMetadata() { Uri = relativeUri } } }; feed.SetAnnotation<AtomFeedMetadata>(metadata); return new [] { feed }; }), Formats = new [] { ODataFormat.Atom } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: feed contributor ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataFeed feed = ObjectModelUtils.CreateDefaultFeed(); AtomFeedMetadata metadata = new AtomFeedMetadata() { Contributors = new [] { new AtomPersonMetadata() { Uri = relativeUri } } }; feed.SetAnnotation<AtomFeedMetadata>(metadata); return new [] { feed }; }), Formats = new [] { ODataFormat.Atom } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: feed link ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataFeed feed = ObjectModelUtils.CreateDefaultFeed(); AtomFeedMetadata metadata = new AtomFeedMetadata() { Links = new [] { new AtomLinkMetadata() { Href = relativeUri } } }; feed.SetAnnotation<AtomFeedMetadata>(metadata); return new [] { feed }; }), Formats = new [] { ODataFormat.Atom } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: entry author ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataEntry entry = ObjectModelUtils.CreateDefaultEntry(); AtomEntryMetadata metadata = new AtomEntryMetadata() { Authors = new [] { new AtomPersonMetadata() { Uri = relativeUri } } }; entry.SetAnnotation<AtomEntryMetadata>(metadata); return new [] { entry }; }), Formats = new [] { ODataFormat.Atom } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: entry contributor ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataEntry entry = ObjectModelUtils.CreateDefaultEntry(); AtomEntryMetadata metadata = new AtomEntryMetadata() { Contributors = new [] { new AtomPersonMetadata() { Uri = relativeUri } } }; entry.SetAnnotation<AtomEntryMetadata>(metadata); return new [] { entry }; }), Formats = new [] { ODataFormat.Atom } }, relativeUri => new BaseUriErrorTestCase { // Atom metadata: entry link ItemFunc = new Func<IEnumerable<ODataItem>>(() => { ODataEntry entry = ObjectModelUtils.CreateDefaultEntry(); AtomEntryMetadata metadata = new AtomEntryMetadata() { Links = new [] { new AtomLinkMetadata() { Href = relativeUri } } }; entry.SetAnnotation<AtomEntryMetadata>(metadata); return new [] { entry }; }), Formats = new [] { ODataFormat.Atom } }, }; // ToDo: Fix places where we've lost JsonVerbose coverage to add JsonLight Uri testRelativeUri = baseUri.MakeRelativeUri(testUri); Uri invalidRelativeUri = new Uri("../invalid/relative/uri", UriKind.Relative); this.CombinatorialEngineProvider.RunCombinations( testCaseFuncs, this.WriterTestConfigurationProvider.ExplicitFormatConfigurations.Where(c => c.IsRequest == false && c.Format == ODataFormat.Atom), new Uri[] { testRelativeUri, invalidRelativeUri }, new bool[] { false, true }, (testCaseFunc, testConfiguration, uri, implementUrlResolver) => { var testCase = testCaseFunc(uri); var testDescriptor = new { Descriptor = new PayloadWriterTestDescriptor<ODataItem>( this.Settings, testCase.ItemFunc(), testConfig => new WriterTestExpectedResults(this.Settings.ExpectedResultSettings) { ExpectedException2 = ODataExpectedExceptions.ODataException("ODataWriter_RelativeUriUsedWithoutBaseUriSpecified", uri.OriginalString) }), Formats = testCase.Formats }; if (testDescriptor.Formats.Contains(testConfiguration.Format)) { PayloadWriterTestDescriptor<ODataItem> payloadTestDescriptor = testDescriptor.Descriptor; TestUrlResolver urlResolver = null; if (implementUrlResolver) { payloadTestDescriptor = new PayloadWriterTestDescriptor<ODataItem>(payloadTestDescriptor); urlResolver = new TestUrlResolver(); payloadTestDescriptor.UrlResolver = urlResolver; } testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(payloadTestDescriptor, testConfiguration, this.Assert, this.Logger); if (implementUrlResolver) { this.Assert.AreEqual(1, urlResolver.Calls.Where(call => call.Value.OriginalString == uri.OriginalString).Count(), "The resolver should be called exactly once for each URL."); } } }); }