/// <summary> /// Creates the value for the named stream's link relation attribute. /// </summary> /// <param name="namedStream">The named stream to create the relation for.</param> /// <param name="forEditLink">'true' if the relation is computed for an edit link; otherwise 'false'.</param> /// <returns>The relation attribute value for the named stream's link relation.</returns> internal static string ComputeNamedStreamRelation(ODataMediaResource namedStream, bool forEditLink) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(namedStream != null, "namedStream != null"); Debug.Assert(!string.IsNullOrEmpty(namedStream.Name), "!string.IsNullOrEmpty(namedStream.Name)"); string segmentName = forEditLink ? AtomConstants.ODataNamedStreamsEditMediaSegmentName : AtomConstants.ODataNamedStreamsMediaResourceSegmentName; return string.Join("/", new string[] { AtomConstants.ODataNamespace, segmentName, namedStream.Name }); }
/// <summary> /// Creates the value for the named stream's link relation attribute. /// </summary> /// <param name="namedStream">The named stream to create the relation for.</param> /// <param name="forEditLink">'true' if the relation is computed for an edit link; otherwise 'false'.</param> /// <returns>The relation attribute value for the named stream's link relation.</returns> internal static string ComputeNamedStreamRelation(ODataMediaResource namedStream, bool forEditLink) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(namedStream != null, "namedStream != null"); Debug.Assert(!string.IsNullOrEmpty(namedStream.Name), "!string.IsNullOrEmpty(namedStream.Name)"); string segmentName = forEditLink ? AtomConstants.ODataNamedStreamsEditMediaSegmentName : AtomConstants.ODataNamedStreamsMediaResourceSegmentName; return(string.Join("/", new string[] { AtomConstants.ODataNamespace, segmentName, namedStream.Name })); }
/// <summary> /// Validates a named stream to ensure it's not null and it's name if correct. /// </summary> /// <param name="namedStream">The named stream to validate.</param> /// <param name="version">The version of the OData protocol used for checking.</param> internal static void ValidateNamedStream(ODataMediaResource namedStream, ODataVersion version) { DebugUtils.CheckNoExternalCallers(); ODataVersionChecker.CheckNamedStreams(version); if (namedStream == null) { throw new ODataException(Strings.ODataWriter_NamedStreamMustNotBeNull); } if (string.IsNullOrEmpty(namedStream.Name)) { throw new ODataException(Strings.ODataWriter_NamedStreamMustHaveNonEmptyName); } }
/// <summary> /// Validates an <see cref="ODataEntry"/> to ensure all required information is specified and valid. /// </summary> /// <param name="entry">The entry to validate.</param> internal static void ValidateEntry(ODataEntry entry) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entry != null, "entry != null"); // Verify non-empty ID (entries can have no (null) ID for insert scenarios; empty IDs are not allowed) if (entry.Id != null && entry.Id.Length == 0) { throw new ODataException(Strings.ODataWriter_EntriesMustHaveNonEmptyId); } // Type name is verified in the format writers since it's shared with other non-entity types // and verifying it here would mean doing it twice. // Verify the default stream if it's present ODataMediaResource defaultStream = entry.MediaResource; if (defaultStream != null) { if (defaultStream.Name != null) { throw new ODataException(Strings.ODataWriter_DefaultStreamMustNotHaveName); } if (string.IsNullOrEmpty(defaultStream.ContentType)) { throw new ODataException(Strings.ODataWriter_DefaultStreamMustHaveNonEmptyContentType); } if (defaultStream.ReadLink == null) { throw new ODataException(Strings.ODataWriter_DefaultStreamMustHaveReadLink); } if (defaultStream.EditLink == null && defaultStream.ETag != null) { throw new ODataException(Strings.ODataWriter_DefaultStreamMustHaveEditLinkToHaveETag); } } }
/// <summary> /// Writes a named stream to the ATOM payload including an /// </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="namedStream">The named stream to create the payload for.</param> internal static void WriteNamedStream(XmlWriter writer, Uri baseUri, ODataMediaResource namedStream) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(writer != null, "writer != null"); Debug.Assert(namedStream != null, "Named stream must not be null."); // <atom:link rel="...2007/08/dataservices/mediaresource/name"> writer.WriteStartElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomLinkElementName, AtomConstants.AtomNamespace); writer.WriteAttributeString( AtomConstants.AtomLinkRelationAttributeName, AtomUtils.ComputeNamedStreamRelation(namedStream, false)); writer.WriteAttributeString( AtomConstants.AtomTitleElementName, namedStream.Name); Uri readLink = namedStream.ReadLink; if (readLink != null) { // TODO, ckerer: should we throw when no source link is provided? writer.WriteAttributeString( AtomConstants.AtomHRefAttributeName, AtomUtils.ToUrlAttributeValue(readLink, baseUri)); } writer.WriteAttributeString( AtomConstants.AtomTypeAttributeName, namedStream.ContentType); writer.WriteEndElement(); if (namedStream.EditLink != null) { // <atom:link rel="...2007/08/dataservices/edit-media/name"> writer.WriteStartElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomLinkElementName, AtomConstants.AtomNamespace); writer.WriteAttributeString( AtomConstants.AtomLinkRelationAttributeName, AtomUtils.ComputeNamedStreamRelation(namedStream, true)); writer.WriteAttributeString( AtomConstants.AtomTitleElementName, namedStream.Name); Uri editLink = namedStream.EditLink; if (editLink != null) { writer.WriteAttributeString( AtomConstants.AtomHRefAttributeName, AtomUtils.ToUrlAttributeValue(editLink, baseUri)); } writer.WriteAttributeString( AtomConstants.AtomTypeAttributeName, namedStream.ContentType); string etag = namedStream.ETag; if (etag != null) { WriteETag(writer, etag); } writer.WriteEndElement(); } }
/// <summary> /// Writes the __metadata property and its content for an entry /// </summary> /// <param name="entry">The entry for which to write the metadata.</param> /// <returns>The resource type of the entry or null if no metadata is available.</returns> private ResourceType WriteEntryMetadata(ODataEntry entry) { Debug.Assert(entry != null, "entry != null"); // Write the "__metadata" for the entry this.jsonWriter.WriteName(JsonConstants.ODataMetadataName); this.jsonWriter.StartObjectScope(); // Write the "uri": "edit/read-link-uri" Uri uriValue = entry.EditLink; if (uriValue == null) { uriValue = entry.ReadLink; } if (uriValue != null) { this.jsonWriter.WriteName(JsonConstants.ODataMetadataUriName); this.jsonWriter.WriteValue(ODataJsonWriterUtils.UriToAbsoluteUriString(uriValue, this.BaseUri)); } // Write the "etag": "ETag value" // TODO: if this is a top-level entry also put the ETag into the headers. string etag = entry.ETag; if (etag != null) { this.jsonWriter.WriteName(JsonConstants.ODataMetadataETagName); this.jsonWriter.WriteValue(etag); } // Write the "type": "typename" string typeName = entry.TypeName; ResourceType entryType = ValidationUtils.ValidateTypeName(this.MetadataProvider, typeName, ResourceTypeKind.EntityType, false); if (typeName != null) { this.jsonWriter.WriteName(JsonConstants.ODataMetadataTypeName); this.jsonWriter.WriteValue(typeName); } // Write MLE metadata ODataMediaResource mediaResource = entry.MediaResource; if (mediaResource != null) { // Write the "edit_media": "url" Uri mediaEditLink = mediaResource.EditLink; if (mediaEditLink != null) { this.jsonWriter.WriteName(JsonConstants.ODataMetadataEditMediaName); this.jsonWriter.WriteValue(ODataJsonWriterUtils.UriToAbsoluteUriString(mediaEditLink, this.BaseUri)); } // Write the "media_src": "url" Debug.Assert(mediaResource.ReadLink != null, "The default stream read link should have been validated by now."); this.jsonWriter.WriteName(JsonConstants.ODataMetadataMediaUriName); this.jsonWriter.WriteValue(ODataJsonWriterUtils.UriToAbsoluteUriString(mediaResource.ReadLink, this.BaseUri)); // Write the "content_type": "type" Debug.Assert(!string.IsNullOrEmpty(mediaResource.ContentType), "The default stream content type should have been validated by now."); this.jsonWriter.WriteName(JsonConstants.ODataMetadataContentTypeName); this.jsonWriter.WriteValue(mediaResource.ContentType); // Write the "media_etag": "etag" string mediaETag = mediaResource.ETag; if (mediaETag != null) { Debug.Assert(mediaEditLink != null, "The default stream edit link and etag should have been validated by now."); this.jsonWriter.WriteName(JsonConstants.ODataMetadataMediaETagName); this.jsonWriter.WriteValue(mediaETag); } } // Write properties metadata // For now only association links are supported here IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks; if (associationLinks != null) { bool firstAssociationLink = true; foreach (ODataAssociationLink associationLink in associationLinks) { ValidationUtils.ValidateAssociationLink(associationLink, this.Version); if (firstAssociationLink) { // Write the "properties": { this.jsonWriter.WriteName(JsonConstants.ODataMetadataPropertiesName); this.jsonWriter.StartObjectScope(); firstAssociationLink = false; } // Write the "LinkName": { this.jsonWriter.WriteName(associationLink.Name); this.jsonWriter.StartObjectScope(); // Write the "__associationuri": "url" this.jsonWriter.WriteName(JsonConstants.ODataMetadataPropertiesAssociationUriName); this.jsonWriter.WriteValue(ODataJsonWriterUtils.UriToAbsoluteUriString(associationLink.Url, this.BaseUri)); // Close the "LinkName" object this.jsonWriter.EndObjectScope(); } if (!firstAssociationLink) { // Close the "properties" object this.jsonWriter.EndObjectScope(); } } // Close the __metadata object scope this.jsonWriter.EndObjectScope(); return(entryType); }
/// <summary> /// Write the content of the given entry. /// </summary> /// <param name="entry">The entry for which to write properties.</param> /// <param name="entryType">The <see cref="ResourceType"/> of the entry (or null if not metadata is available).</param> /// <param name="propertiesValueCache">The cache of properties.</param> /// <param name="rootSourcePathSegment">The root of the EPM source tree, if there's an EPM applied.</param> private void WriteEntryContent(ODataEntry entry, ResourceType entryType, EntryPropertiesValueCache propertiesValueCache, EpmSourcePathSegment rootSourcePathSegment) { Debug.Assert(entry != null, "entry != null"); Debug.Assert(propertiesValueCache != null, "propertiesValueCache != null"); ODataMediaResource mediaResource = entry.MediaResource; if (mediaResource == null) { // <content type="application/xml"> this.writer.WriteStartElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContentElementName, AtomConstants.AtomNamespace); this.writer.WriteAttributeString( AtomConstants.AtomTypeAttributeName, MimeConstants.MimeApplicationXml); // <m:properties> // we always write the <m:properties> element even if there are no properties this.writer.WriteStartElement( AtomConstants.ODataMetadataNamespacePrefix, AtomConstants.AtomPropertiesElementName, AtomConstants.ODataMetadataNamespace); ODataAtomWriterUtils.WriteProperties( this.writer, this.MetadataProvider, entryType, propertiesValueCache.EntryProperties, this.Version, false, propertiesValueCache, rootSourcePathSegment); // </m:properties> this.writer.WriteEndElement(); // </content> this.writer.WriteEndElement(); } else { Uri mediaEditLink = mediaResource.EditLink; if (mediaEditLink != null) { // <link rel="edit-media" href="href" /> this.writer.WriteStartElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomLinkElementName, AtomConstants.AtomNamespace); this.writer.WriteAttributeString( AtomConstants.AtomLinkRelationAttributeName, AtomConstants.AtomEditMediaRelationAttributeValue); this.writer.WriteAttributeString( AtomConstants.AtomHRefAttributeName, AtomUtils.ToUrlAttributeValue(mediaEditLink, this.BaseUri)); string mediaETag = mediaResource.ETag; if (mediaETag != null) { this.writer.WriteAttributeString( AtomConstants.ODataMetadataNamespacePrefix, AtomConstants.ODataETagAttributeName, AtomConstants.ODataMetadataNamespace, mediaETag); } // </link> this.writer.WriteEndElement(); } Debug.Assert(mediaEditLink != null || mediaResource.ETag == null, "The default stream edit link and etag should have been validated by now."); // <content type="type" src="src"> this.writer.WriteStartElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContentElementName, AtomConstants.AtomNamespace); Debug.Assert(!string.IsNullOrEmpty(mediaResource.ContentType), "The default stream content type should have been validated by now."); this.writer.WriteAttributeString( AtomConstants.AtomTypeAttributeName, mediaResource.ContentType); Debug.Assert(mediaResource.ReadLink != null, "The default stream read link should have been validated by now."); this.writer.WriteAttributeString( AtomConstants.MediaLinkEntryContentSourceAttributeName, AtomUtils.ToUrlAttributeValue(mediaResource.ReadLink, this.BaseUri)); // </content> this.writer.WriteEndElement(); // <m:properties> // we always write the <m:properties> element even if there are no properties this.writer.WriteStartElement( AtomConstants.ODataMetadataNamespacePrefix, AtomConstants.AtomPropertiesElementName, AtomConstants.ODataMetadataNamespace); ODataAtomWriterUtils.WriteProperties( this.writer, this.MetadataProvider, entryType, propertiesValueCache.EntryProperties, this.Version, false, propertiesValueCache, rootSourcePathSegment); // </m:properties> this.writer.WriteEndElement(); } }