/// <summary> /// Writes the 'atom:category' element with the specified attributes. /// </summary> /// <param name="atomPrefix">The prefix to use for the 'category' element.</param> /// <param name="term">The value for the 'term' attribute (required).</param> /// <param name="scheme">The value for the 'scheme' attribute (optional).</param> /// <param name="label">The value for the 'label' attribute (optional).</param> internal void WriteCategory(string atomPrefix, string term, string scheme, string label) { this.XmlWriter.WriteStartElement( atomPrefix, AtomConstants.AtomCategoryElementName, AtomConstants.AtomNamespace); if (term == null) { throw new ODataException(ODataErrorStrings.ODataAtomWriterMetadataUtils_CategoryMustSpecifyTerm); } this.XmlWriter.WriteAttributeString( AtomConstants.AtomCategoryTermAttributeName, ODataAtomWriterUtils.PrefixTypeName(term)); if (scheme != null) { this.XmlWriter.WriteAttributeString(AtomConstants.AtomCategorySchemeAttributeName, scheme); } if (label != null) { this.XmlWriter.WriteAttributeString(AtomConstants.AtomCategoryLabelAttributeName, label); } this.XmlWriter.WriteEndElement(); }
/// <summary> /// Writes an Xml element with the specified primitive value as content. /// </summary> /// <param name="prefix">The prefix for the element's namespace.</param> /// <param name="localName">The local name of the element.</param> /// <param name="ns">The namespace of the element.</param> /// <param name="textConstruct">The <see cref="AtomTextConstruct"/> value to be used as element content.</param> internal void WriteTextConstruct(string prefix, string localName, string ns, AtomTextConstruct textConstruct) { Debug.Assert(prefix != null, "prefix != null"); Debug.Assert(!string.IsNullOrEmpty(localName), "!string.IsNullOrEmpty(localName)"); Debug.Assert(!string.IsNullOrEmpty(ns), "!string.IsNullOrEmpty(ns)"); this.XmlWriter.WriteStartElement(prefix, localName, ns); if (textConstruct != null) { AtomTextConstructKind textKind = textConstruct.Kind; this.XmlWriter.WriteAttributeString(AtomConstants.AtomTypeAttributeName, AtomValueUtils.ToString(textConstruct.Kind)); string textValue = textConstruct.Text; if (textValue == null) { textValue = String.Empty; } if (textKind == AtomTextConstructKind.Xhtml) { ODataAtomWriterUtils.WriteRaw(this.XmlWriter, textValue); } else { ODataAtomWriterUtils.WriteString(this.XmlWriter, textValue); } } this.XmlWriter.WriteEndElement(); }
/// <summary> /// Writes a top-level error payload. /// </summary> /// <param name="error">The error instance to write.</param> /// <param name="includeDebugInformation">A flag indicating whether error details should be written (in debug mode only) or not.</param> internal void WriteTopLevelError(ODataError error, bool includeDebugInformation) { Debug.Assert(this.MessageWriterSettings != null, "this.MessageWriterSettings != null"); this.WritePayloadStart(); ODataAtomWriterUtils.WriteError(this.XmlWriter, error, includeDebugInformation, this.MessageWriterSettings.MessageQuotas.MaxNestingDepth); this.WritePayloadEnd(); }
/// <summary> /// Writes the m:type attribute for a property given the name of the type. /// </summary> /// <param name="typeName">The type name to write.</param> private void WritePropertyTypeAttribute(string typeName) { // m:type attribute this.XmlWriter.WriteAttributeString( AtomConstants.ODataMetadataNamespacePrefix, AtomConstants.AtomTypeAttributeName, AtomConstants.ODataMetadataNamespace, ODataAtomWriterUtils.PrefixTypeName(WriterUtils.RemoveEdmPrefixFromTypeName(typeName))); }
/// <summary> /// Writes an in-stream error. /// </summary> /// <param name="error">The error to write.</param> /// <param name="includeDebugInformation"> /// A flag indicating whether debug information (e.g., the inner error from the <paramref name="error"/>) should /// be included in the payload. This should only be used in debug scenarios. /// </param> private void WriteInStreamErrorImplementation(ODataError error, bool includeDebugInformation) { if (this.outputInStreamErrorListener != null) { this.outputInStreamErrorListener.OnInStreamError(); } ODataAtomWriterUtils.WriteError(this.xmlWriter, error, includeDebugInformation, this.MessageWriterSettings.MessageQuotas.MaxNestingDepth); }
/// <summary> /// Write the metadata of a link in ATOM format /// </summary> /// <param name="linkMetadata">The link metadata to write.</param> /// <param name="etag">The (optional) ETag for a link.</param> internal void WriteAtomLinkAttributes(AtomLinkMetadata linkMetadata, string etag) { Debug.Assert(linkMetadata != null, "Link metadata must not be null."); string linkHref = linkMetadata.Href == null ? null : this.UriToUrlAttributeValue(linkMetadata.Href); this.WriteAtomLinkMetadataAttributes(linkMetadata.Relation, linkHref, linkMetadata.HrefLang, linkMetadata.Title, linkMetadata.MediaType, linkMetadata.Length); if (etag != null) { ODataAtomWriterUtils.WriteETag(this.XmlWriter, etag); } }
/// <summary> /// Writes an Xml element with the specified primitive value as content. /// </summary> /// <param name="prefix">The prefix for the element's namespace.</param> /// <param name="localName">The local name of the element.</param> /// <param name="ns">The namespace of the element.</param> /// <param name="textContent">The value to be used as element content.</param> internal void WriteElementWithTextContent(string prefix, string localName, string ns, string textContent) { Debug.Assert(prefix != null, "prefix != null"); Debug.Assert(!string.IsNullOrEmpty(localName), "!string.IsNullOrEmpty(localName)"); Debug.Assert(!string.IsNullOrEmpty(ns), "!string.IsNullOrEmpty(ns)"); this.XmlWriter.WriteStartElement(prefix, localName, ns); if (textContent != null) { ODataAtomWriterUtils.WriteString(this.XmlWriter, textContent); } this.XmlWriter.WriteEndElement(); }
internal ODataAtomOutputContext( ODataFormat format, Stream messageStream, Encoding encoding, ODataMessageWriterSettings messageWriterSettings, bool writingResponse, bool synchronous, IEdmModel model, IODataUrlResolver urlResolver) : base(format, messageWriterSettings, writingResponse, synchronous, model, urlResolver) { Debug.Assert(messageStream != null, "stream != null"); try { this.messageOutputStream = messageStream; Stream outputStream; if (synchronous) { outputStream = messageStream; } else { this.asynchronousOutputStream = new AsyncBufferedStream(messageStream); outputStream = this.asynchronousOutputStream; } this.xmlWriter = ODataAtomWriterUtils.CreateXmlWriter(outputStream, messageWriterSettings, encoding); } catch (Exception e) { // Dispose the message stream if we failed to create the input context. if (ExceptionUtils.IsCatchableExceptionType(e) && messageStream != null) { messageStream.Dispose(); } throw; } }
/// <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 WriteFeedMetadata(AtomFeedMetadata feedMetadata, ODataFeed feed, string updatedTime, out bool authorWritten) { Debug.Assert(feedMetadata != null, "Feed metadata must not be null!"); // <atom:id>text</atom:id> // NOTE: this is the Id of the feed. For a regular feed this is stored on the feed itself; // if used in the context of an <atom:source> element it is stored in metadata Uri id = feed == null ? feedMetadata.SourceId : feed.Id; this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomIdElementName, AtomConstants.AtomNamespace, id == null ? null : UriUtils.UriToString(id)); // <atom:title>text</atom:title> // NOTE: write an empty element if no title is specified since the element is required this.WriteTextConstruct(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, feedMetadata.Title); if (feedMetadata.Subtitle != null) { // <atom:subtitle>text</atom:subtitle> this.WriteTextConstruct(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSubtitleElementName, AtomConstants.AtomNamespace, feedMetadata.Subtitle); } // <atom:updated>date</atom:updated> // NOTE: the <updated> element is required and if not specified we use a single 'default/current' date/time for the whole payload. string updated = feedMetadata.Updated.HasValue ? ODataAtomConvert.ToAtomString(feedMetadata.Updated.Value) : updatedTime; this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, updated); AtomLinkMetadata selfLinkMetadata = feedMetadata.SelfLink; if (selfLinkMetadata != null) { AtomLinkMetadata mergedSelfLinkMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata( selfLinkMetadata, AtomConstants.AtomSelfRelationAttributeValue, null /* href */, null /* title */, null /* media type */); this.WriteAtomLink(mergedSelfLinkMetadata, null /*etag*/); } IEnumerable <AtomLinkMetadata> links = feedMetadata.Links; if (links != null) { foreach (AtomLinkMetadata link in links) { // DeltaLink is written from ODataFeed, so it shouldn't be written again from AtomFeedMetadata. if (link.Relation != AtomConstants.AtomDeltaRelationAttributeValue) { // <atom:link>...</atom:link> this.WriteAtomLink(link, null /* etag */); } } } IEnumerable <AtomCategoryMetadata> categories = feedMetadata.Categories; if (categories != null) { foreach (AtomCategoryMetadata category in categories) { // <atom:category term="..." scheme="..." label="..."></atom:category> this.WriteCategory(category); } } Uri logo = feedMetadata.Logo; if (logo != null) { // <atom:logo>Uri</atom:logo> this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomLogoElementName, AtomConstants.AtomNamespace, this.UriToUrlAttributeValue(logo)); } if (feedMetadata.Rights != null) { // <atom:rights>rights</atom:rights> this.WriteTextConstruct( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomRightsElementName, AtomConstants.AtomNamespace, feedMetadata.Rights); } IEnumerable <AtomPersonMetadata> contributors = feedMetadata.Contributors; if (contributors != null) { foreach (AtomPersonMetadata contributor in contributors) { // <atom:contributor>contributor data</atom:contributor> this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContributorElementName, AtomConstants.AtomNamespace); this.WritePersonMetadata(contributor); this.XmlWriter.WriteEndElement(); } } AtomGeneratorMetadata generator = feedMetadata.Generator; if (generator != null) { // <atom:generator uri="..." version="...">name</atom:generator> this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomGeneratorElementName, AtomConstants.AtomNamespace); if (generator.Uri != null) { this.XmlWriter.WriteAttributeString(AtomConstants.AtomGeneratorUriAttributeName, this.UriToUrlAttributeValue(generator.Uri)); } if (!string.IsNullOrEmpty(generator.Version)) { this.XmlWriter.WriteAttributeString(AtomConstants.AtomGeneratorVersionAttributeName, generator.Version); } ODataAtomWriterUtils.WriteString(this.XmlWriter, generator.Name); this.XmlWriter.WriteEndElement(); } Uri icon = feedMetadata.Icon; if (icon != null) { // <atom:icon>Uri</atom:icon> this.WriteElementWithTextContent( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomIconElementName, AtomConstants.AtomNamespace, this.UriToUrlAttributeValue(icon)); } IEnumerable <AtomPersonMetadata> authors = feedMetadata.Authors; authorWritten = false; if (authors != null) { foreach (AtomPersonMetadata author in authors) { // <atom:author>author data</atom:author> authorWritten = true; this.XmlWriter.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomAuthorElementName, AtomConstants.AtomNamespace); this.WritePersonMetadata(author); this.XmlWriter.WriteEndElement(); } } }