/// <summary> /// Writes a single Uri in response to a $links query. /// </summary> /// <param name="entityReferenceLink">The entity reference link to write out.</param> private void WriteEntityReferenceLinkImplementation(ODataEntityReferenceLink entityReferenceLink) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entityReferenceLink != null, "entityReferenceLink != null"); WriterValidationUtils.ValidateEntityReferenceLink(entityReferenceLink); this.JsonWriter.StartObjectScope(); this.JsonWriter.WriteName(JsonConstants.ODataUriName); this.JsonWriter.WriteValue(this.UriToAbsoluteUriString(entityReferenceLink.Url)); this.JsonWriter.EndObjectScope(); }
/// <summary> /// Writes a set of links (Uris) in response to a $links query; includes optional count and next-page-link information. /// </summary> /// <param name="entityReferenceLinks">The set of entity reference links to write out.</param> /// <param name="includeResultsWrapper">true if the 'results' wrapper should be included into the payload; otherwise false.</param> private void WriteEntityReferenceLinksImplementation(ODataEntityReferenceLinks entityReferenceLinks, bool includeResultsWrapper) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entityReferenceLinks != null, "entityReferenceLinks != null"); if (includeResultsWrapper) { // { this.JsonWriter.StartObjectScope(); } if (entityReferenceLinks.Count.HasValue) { Debug.Assert(includeResultsWrapper, "Expected 'includeResultsWrapper' to be true if a count is specified."); this.JsonWriter.WriteName(JsonConstants.ODataCountName); this.JsonWriter.WriteValue(entityReferenceLinks.Count.Value); } if (includeResultsWrapper) { // "results": this.JsonWriter.WriteDataArrayName(); } this.JsonWriter.StartArrayScope(); IEnumerable <ODataEntityReferenceLink> entityReferenceLinksEnumerable = entityReferenceLinks.Links; if (entityReferenceLinksEnumerable != null) { foreach (ODataEntityReferenceLink entityReferenceLink in entityReferenceLinksEnumerable) { WriterValidationUtils.ValidateEntityReferenceLinkNotNull(entityReferenceLink); this.WriteEntityReferenceLinkImplementation(entityReferenceLink); } } this.JsonWriter.EndArrayScope(); if (entityReferenceLinks.NextPageLink != null) { // "__next": ... Debug.Assert(includeResultsWrapper, "Expected 'includeResultsWrapper' to be true if a next page link is specified."); this.JsonWriter.WriteName(JsonConstants.ODataNextLinkName); this.JsonWriter.WriteValue(this.UriToAbsoluteUriString(entityReferenceLinks.NextPageLink)); } if (includeResultsWrapper) { this.JsonWriter.EndObjectScope(); } }
/// <summary> /// Writes a primitive property. /// </summary> /// <param name="primitiveValue">The primitive value to be written</param> /// <param name="isOpenPropertyType">If the property is open.</param> private void WritePrimitiveProperty( ODataPrimitiveValue primitiveValue, bool isOpenPropertyType) { ResolvePrimitiveValueTypeName(primitiveValue, isOpenPropertyType); WriterValidationUtils.ValidatePropertyDerivedTypeConstraint(this.currentPropertyInfo); this.WritePropertyTypeName(); this.JsonWriter.WriteName(this.currentPropertyInfo.WireName); this.JsonLightValueSerializer.WritePrimitiveValue(primitiveValue.Value, this.currentPropertyInfo.ValueType.TypeReference, this.currentPropertyInfo.MetadataType.TypeReference); }
private void WriteEntityReferenceLink(ODataEntityReferenceLink entityReferenceLink, bool isTopLevel) { WriterValidationUtils.ValidateEntityReferenceLink(entityReferenceLink); string ns = (base.UseClientFormatBehavior && isTopLevel) ? "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" : base.MessageWriterSettings.WriterBehavior.ODataNamespace; base.XmlWriter.WriteStartElement(string.Empty, "uri", ns); if (isTopLevel) { base.XmlWriter.WriteAttributeString("xmlns", ns); } base.XmlWriter.WriteString(base.UriToUrlAttributeValue(entityReferenceLink.Url)); base.XmlWriter.WriteEndElement(); }
private void WriteCollectionValue(ODataCollectionValue collectionValue, IEdmTypeReference propertyTypeReference, bool isOpenPropertyType, bool isWritingCollection) { this.IncreaseRecursionDepth(); string typeName = collectionValue.TypeName; IEdmCollectionTypeReference type = (IEdmCollectionTypeReference)WriterValidationUtils.ResolveTypeNameForWriting(base.Model, propertyTypeReference, ref typeName, EdmTypeKind.Collection, isOpenPropertyType); string itemTypeNameFromCollection = null; if (typeName != null) { itemTypeNameFromCollection = ValidationUtils.ValidateCollectionTypeName(typeName); } SerializationTypeNameAnnotation annotation = collectionValue.GetAnnotation <SerializationTypeNameAnnotation>(); if (annotation != null) { typeName = annotation.TypeName; } if (typeName != null) { this.WritePropertyTypeAttribute(typeName); } IEdmTypeReference metadataTypeReference = (type == null) ? null : type.ElementType(); CollectionWithoutExpectedTypeValidator collectionValidator = new CollectionWithoutExpectedTypeValidator(itemTypeNameFromCollection); IEnumerable items = collectionValue.Items; if (items != null) { DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = null; foreach (object obj2 in items) { ValidationUtils.ValidateCollectionItem(obj2, false); base.XmlWriter.WriteStartElement("d", "element", base.MessageWriterSettings.WriterBehavior.ODataNamespace); ODataComplexValue complexValue = obj2 as ODataComplexValue; if (complexValue != null) { if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); } this.WriteComplexValue(complexValue, metadataTypeReference, false, isWritingCollection, null, null, duplicatePropertyNamesChecker, collectionValidator, null, null, null); duplicatePropertyNamesChecker.Clear(); } else { this.WritePrimitiveValue(obj2, collectionValidator, metadataTypeReference); } base.XmlWriter.WriteEndElement(); } } this.DecreaseRecursionDepth(); }
/// <summary> /// Start writing a navigation link with content. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> protected override void StartNavigationLinkWithContent(ODataNavigationLink navigationLink) { Debug.Assert(navigationLink != null, "navigationLink != null"); Debug.Assert(!string.IsNullOrEmpty(navigationLink.Name), "The navigation link name should have been verified by now."); if (this.jsonLightOutputContext.WritingResponse) { // Write the navigation link metadata first. The rest is written by the content entry or feed. this.jsonLightEntryAndFeedSerializer.WriteNavigationLinkMetadata(navigationLink, this.DuplicatePropertyNamesChecker); } else { WriterValidationUtils.ValidateNavigationLinkHasCardinality(navigationLink); } }
private void WriteNullPropertyValue(IEdmProperty edmProperty, string propertyName, bool isTopLevel, bool isWritingCollection, Action beforePropertyAction) { WriterValidationUtils.ValidateNullPropertyValue(edmProperty, base.MessageWriterSettings.WriterBehavior, base.Model); this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); if ((edmProperty != null) && !base.UseDefaultFormatBehavior) { string typeName = edmProperty.Type.ODataFullName(); if ((typeName != "Edm.String") && (edmProperty.Type.IsODataPrimitiveTypeKind() || base.UseServerFormatBehavior)) { this.WritePropertyTypeAttribute(typeName); } } this.WriteNullAttribute(); this.WritePropertyEnd(); }
/// <summary> /// Writes the property information for a property. /// </summary> /// <param name="propertyInfo">The property info to write out.</param> /// <param name="owningType">The owning type for the <paramref name="propertyInfo"/> or null if no metadata is available.</param> /// <param name="isTopLevel">true when writing a top-level property; false for nested properties.</param> /// <param name="duplicatePropertyNameChecker">The DuplicatePropertyNameChecker to use.</param> /// <param name="metadataBuilder">The metadatabuilder for the resource</param> internal void WritePropertyInfo( ODataPropertyInfo propertyInfo, IEdmStructuredType owningType, bool isTopLevel, IDuplicatePropertyNameChecker duplicatePropertyNameChecker, ODataResourceMetadataBuilder metadataBuilder) { WriterValidationUtils.ValidatePropertyNotNull(propertyInfo); string propertyName = propertyInfo.Name; if (this.JsonLightOutputContext.MessageWriterSettings.Validations != ValidationKinds.None) { WriterValidationUtils.ValidatePropertyName(propertyName); } if (!this.JsonLightOutputContext.PropertyCacheHandler.InResourceSetScope()) { this.currentPropertyInfo = new PropertySerializationInfo(this.JsonLightOutputContext.Model, propertyName, owningType) { IsTopLevel = isTopLevel }; } else { this.currentPropertyInfo = this.JsonLightOutputContext.PropertyCacheHandler.GetProperty(this.JsonLightOutputContext.Model, propertyName, owningType); } WriterValidationUtils.ValidatePropertyDefined(this.currentPropertyInfo, this.MessageWriterSettings.ThrowOnUndeclaredPropertyForNonOpenType); duplicatePropertyNameChecker.ValidatePropertyUniqueness(propertyInfo); if (currentPropertyInfo.MetadataType.IsUndeclaredProperty) { WriteODataTypeAnnotation(propertyInfo, isTopLevel); } WriteInstanceAnnotation(propertyInfo, isTopLevel, currentPropertyInfo.MetadataType.IsUndeclaredProperty); ODataStreamPropertyInfo streamInfo = propertyInfo as ODataStreamPropertyInfo; if (streamInfo != null && !(this.JsonLightOutputContext.MetadataLevel is JsonNoMetadataLevel)) { Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level."); WriteStreamValue(streamInfo, propertyInfo.Name, metadataBuilder); } }
/// <summary> /// Writes an operation (an action or a function). /// </summary> /// <param name="operation">The association link to write.</param> internal void WriteOperation(ODataOperation operation) { DebugUtils.CheckNoExternalCallers(); // checks for null and validates its properties WriterValidationUtils.ValidateCanWriteOperation(operation, this.WritingResponse); ValidationUtils.ValidateOperationMetadataNotNull(operation); ValidationUtils.ValidateOperationTargetNotNull(operation); string elementName; if (operation is ODataAction) { elementName = AtomConstants.ODataActionElementName; } else { Debug.Assert(operation is ODataFunction, "operation is either an ODataAction or an ODataFunction"); elementName = AtomConstants.ODataFunctionElementName; } // <m:action ... or <m:function ... this.XmlWriter.WriteStartElement( AtomConstants.ODataMetadataNamespacePrefix, elementName, AtomConstants.ODataMetadataNamespace); // write the attributes of the action/function // The metadata URI of an ODataOperation can be relative. string metadataAttributeValue = this.UriToUrlAttributeValue(operation.Metadata, /*failOnRelativeUriWithoutBaseUri*/ false); this.XmlWriter.WriteAttributeString(AtomConstants.ODataOperationMetadataAttribute, metadataAttributeValue); if (operation.Title != null) { this.XmlWriter.WriteAttributeString(AtomConstants.ODataOperationTitleAttribute, operation.Title); } string targetAttribute = this.UriToUrlAttributeValue(operation.Target); this.XmlWriter.WriteAttributeString(AtomConstants.ODataOperationTargetAttribute, targetAttribute); // </m:action> or </m:function> this.XmlWriter.WriteEndElement(); }
/// <summary> /// Writes a set of links (Uris) in response to a $ref query; includes optional count and next-page-link information. /// </summary> /// <param name="entityReferenceLinks">The set of entity reference links to write out.</param> internal void WriteEntityReferenceLinks(ODataEntityReferenceLinks entityReferenceLinks) { Debug.Assert(entityReferenceLinks != null, "entityReferenceLinks != null"); this.WritePayloadStart(); // COMPAT 25: Should $link payloads use the default 'd' namespace prefix for data service elements (instead of no prefix)? // <feed> ... this.XmlWriter.WriteStartElement(string.Empty, AtomConstants.AtomFeedElementName, AtomConstants.AtomNamespace); // xmlns:metadata= this.XmlWriter.WriteAttributeString(AtomConstants.XmlnsNamespacePrefix, AtomConstants.ODataMetadataNamespacePrefix, null, AtomConstants.ODataMetadataNamespace); // metadata:context this.WriteContextUriProperty(this.contextUriBuilder.BuildContextUri(ODataPayloadKind.EntityReferenceLinks)); if (entityReferenceLinks.Count.HasValue) { // <m:count> this.WriteCount(entityReferenceLinks.Count.Value); } IEnumerable <ODataEntityReferenceLink> entityReferenceLinkEnumerable = entityReferenceLinks.Links; if (entityReferenceLinkEnumerable != null) { foreach (ODataEntityReferenceLink entityReferenceLink in entityReferenceLinkEnumerable) { WriterValidationUtils.ValidateEntityReferenceLinkNotNull(entityReferenceLink); this.WriteEntityReferenceLink(entityReferenceLink, false); } } if (entityReferenceLinks.NextPageLink != null) { // <d:next> string nextLink = this.UriToUrlAttributeValue(entityReferenceLinks.NextPageLink); this.XmlWriter.WriteElementString(string.Empty, AtomConstants.ODataNextLinkElementName, AtomConstants.ODataNamespace, nextLink); } // </feed> this.XmlWriter.WriteEndElement(); this.WritePayloadEnd(); }
/// <summary> /// Writes a single Uri in response to a $ref query. /// </summary> /// <param name="entityReferenceLink">The entity reference link to write out.</param> /// <param name="isTopLevel">true if the entity reference link being written is at the top level of the payload.</param> private void WriteEntityReferenceLinkImplementation(ODataEntityReferenceLink entityReferenceLink, bool isTopLevel) { Debug.Assert(entityReferenceLink != null, "entityReferenceLink != null"); WriterValidationUtils.ValidateEntityReferenceLink(entityReferenceLink); this.JsonWriter.StartObjectScope(); if (isTopLevel) { this.WriteContextUriProperty(ODataPayloadKind.EntityReferenceLink); } this.JsonWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataId); this.JsonWriter.WriteValue(this.UriToString(entityReferenceLink.Url)); this.JsonWriter.EndObjectScope(); }
/// <summary> /// Writes "actions" or "functions" metadata. /// </summary> /// <param name="operations">The operations to write.</param> /// <param name="operationName">The name of the property used for the operations.</param> /// <param name="isAction">true when writing the entry's actions; false when writing the entry's functions.</param> /// <param name="writingJsonLight">true if we're writing JSON lite, false if we're writing verbose JSON.</param> internal void WriteOperations(IEnumerable <ODataOperation> operations, string operationName, bool isAction, bool writingJsonLight) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(operationName != null, "operationName != null"); bool firstOperation = true; // we cannot compare two URI's directly because the 'Equals' method on the 'Uri' class compares two 'Uri' instances without regard to the // fragment part of the URI. (E.G: For 'http://someuri/index.htm#EC.action1' and http://someuri/index.htm#EC.action2', the 'Equals' method // will return true. var metadataGroups = operations.GroupBy(o => { // We need to validate here to ensure that the metadata is not null, otherwise call to the method 'UriToString' will throw. ValidationUtils.ValidateOperationNotNull(o, isAction); WriterValidationUtils.ValidateCanWriteOperation(o, this.VerboseJsonOutputContext.WritingResponse); ValidationUtils.ValidateOperationMetadataNotNull(o); if (!writingJsonLight) { ValidationUtils.ValidateOperationTargetNotNull(o); } return(this.UriToUriString(o.Metadata, /*makeAbsolute*/ false)); }); foreach (IGrouping <string, ODataOperation> metadataGroup in metadataGroups) { if (firstOperation) { // write the the object only if there is any operations. this.VerboseJsonOutputContext.JsonWriter.WriteName(operationName); this.VerboseJsonOutputContext.JsonWriter.StartObjectScope(); firstOperation = false; } this.WriteOperationMetadataGroup(metadataGroup); } // close the object if there is any operations. if (!firstOperation) { this.VerboseJsonOutputContext.JsonWriter.EndObjectScope(); } }
/// <summary> /// Writes "actions" or "functions" metadata. /// </summary> /// <param name="operations">The operations to write.</param> /// <param name="isAction">true when writing the resource's actions; false when writing the resource's functions.</param> internal void WriteOperations(IEnumerable <ODataOperation> operations, bool isAction) { // We cannot compare two URIs directly because the 'Equals' method on the 'Uri' class compares two 'Uri' instances without regard to the // fragment part of the URI. (E.G: For 'http://someuri/index.htm#EC.action1' and http://someuri/index.htm#EC.action2', the 'Equals' method // will return true. IEnumerable <IGrouping <string, ODataOperation> > metadataGroups = operations.GroupBy(o => { // We need to validate here to ensure that the metadata is not null, otherwise call to the method 'UriToString' will throw. ValidationUtils.ValidateOperationNotNull(o, isAction); WriterValidationUtils.ValidateCanWriteOperation(o, this.JsonLightOutputContext.WritingResponse); ODataJsonLightValidationUtils.ValidateOperation(this.MetadataDocumentBaseUri, o); return(this.GetOperationMetadataString(o)); }); foreach (IGrouping <string, ODataOperation> metadataGroup in metadataGroups) { this.WriteOperationMetadataGroup(metadataGroup); } }
/// <summary> /// Writes a set of links (Uris) in response to a $links query; includes optional count and next-page-link information. /// </summary> /// <param name="entityReferenceLinks">The entity reference links to write.</param> internal void WriteEntityReferenceLinks(ODataEntityReferenceLinks entityReferenceLinks) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entityReferenceLinks != null, "entityReferenceLinks != null"); this.WritePayloadStart(); // <links> ... this.XmlWriter.WriteStartElement(string.Empty, AtomConstants.ODataLinksElementName, this.MessageWriterSettings.WriterBehavior.ODataNamespace); // xmlns= this.XmlWriter.WriteAttributeString(AtomConstants.XmlnsNamespacePrefix, this.MessageWriterSettings.WriterBehavior.ODataNamespace); if (entityReferenceLinks.Count.HasValue) { // <m:count> this.WriteCount(entityReferenceLinks.Count.Value, true); } IEnumerable <ODataEntityReferenceLink> entityReferenceLinkEnumerable = entityReferenceLinks.Links; if (entityReferenceLinkEnumerable != null) { foreach (ODataEntityReferenceLink entityReferenceLink in entityReferenceLinkEnumerable) { WriterValidationUtils.ValidateEntityReferenceLinkNotNull(entityReferenceLink); this.WriteEntityReferenceLink(entityReferenceLink, false); } } if (entityReferenceLinks.NextPageLink != null) { // <d:next> string nextLink = this.UriToUrlAttributeValue(entityReferenceLinks.NextPageLink); this.XmlWriter.WriteElementString(string.Empty, AtomConstants.ODataNextLinkElementName, this.MessageWriterSettings.WriterBehavior.ODataNamespace, nextLink); } // </links> this.XmlWriter.WriteEndElement(); this.WritePayloadEnd(); }
/// <summary> /// Writes a single Uri in response to a $links query. /// </summary> /// <param name="entityReferenceLink">The entity reference link to write out.</param> /// <param name="entitySet">The entity set of the navigation property</param> /// <param name="navigationProperty">The navigation property for which the entity reference link is being written, or null if none is available.</param> /// <param name="isTopLevel">true if the entity reference link being written is at the top level of the payload.</param> private void WriteEntityReferenceLinkImplementation(ODataEntityReferenceLink entityReferenceLink, IEdmEntitySet entitySet, IEdmNavigationProperty navigationProperty, bool isTopLevel) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entityReferenceLink != null, "entityReferenceLink != null"); WriterValidationUtils.ValidateEntityReferenceLink(entityReferenceLink); this.JsonWriter.StartObjectScope(); if (isTopLevel) { Uri metadataUri; if (this.metadataUriBuilder.TryBuildEntityReferenceLinkMetadataUri(entityReferenceLink.SerializationInfo, entitySet, navigationProperty, out metadataUri)) { this.WriteMetadataUriProperty(metadataUri); } } this.JsonWriter.WriteName(JsonLightConstants.ODataEntityReferenceLinkUrlName); this.JsonWriter.WriteValue(this.UriToString(entityReferenceLink.Url)); this.JsonWriter.EndObjectScope(); }
private void WriteEntityReferenceLinksImplementation(ODataEntityReferenceLinks entityReferenceLinks, bool includeResultsWrapper) { if (includeResultsWrapper) { base.JsonWriter.StartObjectScope(); } if (entityReferenceLinks.Count.HasValue) { base.JsonWriter.WriteName("__count"); base.JsonWriter.WriteValue(entityReferenceLinks.Count.Value); } if (includeResultsWrapper) { base.JsonWriter.WriteDataArrayName(); } base.JsonWriter.StartArrayScope(); IEnumerable <ODataEntityReferenceLink> links = entityReferenceLinks.Links; if (links != null) { foreach (ODataEntityReferenceLink link in links) { WriterValidationUtils.ValidateEntityReferenceLinkNotNull(link); this.WriteEntityReferenceLinkImplementation(link); } } base.JsonWriter.EndArrayScope(); if (entityReferenceLinks.NextPageLink != null) { base.JsonWriter.WriteName("__next"); base.JsonWriter.WriteValue(base.UriToAbsoluteUriString(entityReferenceLinks.NextPageLink)); } if (includeResultsWrapper) { base.JsonWriter.EndObjectScope(); } }
internal void WriteStreamProperty(ODataProperty streamProperty, IEdmEntityType owningType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { WriterValidationUtils.ValidatePropertyNotNull(streamProperty); string name = streamProperty.Name; if (!projectedProperties.ShouldSkipProperty(name)) { WriterValidationUtils.ValidateProperty(streamProperty); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(streamProperty); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(streamProperty.Name, owningType); WriterValidationUtils.ValidateStreamReferenceProperty(streamProperty, edmProperty, base.Version, base.WritingResponse); ODataStreamReferenceValue value2 = (ODataStreamReferenceValue)streamProperty.Value; if (((owningType != null) && owningType.IsOpen) && (edmProperty == null)) { ValidationUtils.ValidateOpenPropertyValue(streamProperty.Name, value2); } AtomStreamReferenceMetadata annotation = value2.GetAnnotation <AtomStreamReferenceMetadata>(); string contentType = value2.ContentType; string title = streamProperty.Name; Uri readLink = value2.ReadLink; if (readLink != null) { string relation = AtomUtils.ComputeStreamPropertyRelation(streamProperty, false); AtomLinkMetadata metadata = (annotation == null) ? null : annotation.SelfLink; AtomLinkMetadata linkMetadata = ODataAtomWriterMetadataUtils.MergeLinkMetadata(metadata, relation, readLink, title, contentType); this.atomEntryMetadataSerializer.WriteAtomLink(linkMetadata, null); } Uri editLink = value2.EditLink; if (editLink != null) { string str5 = AtomUtils.ComputeStreamPropertyRelation(streamProperty, true); AtomLinkMetadata metadata4 = (annotation == null) ? null : annotation.EditLink; AtomLinkMetadata metadata5 = ODataAtomWriterMetadataUtils.MergeLinkMetadata(metadata4, str5, editLink, title, contentType); this.atomEntryMetadataSerializer.WriteAtomLink(metadata5, value2.ETag); } } }
private void WriteOperations(IEnumerable <ODataOperation> operations, bool isAction) { bool flag = true; string name = isAction ? "actions" : "functions"; foreach (IGrouping <string, ODataOperation> grouping in operations.GroupBy <ODataOperation, string>(delegate(ODataOperation o) { ValidationUtils.ValidateOperationNotNull(o, isAction); WriterValidationUtils.ValidateOperation(o, this.WritingResponse); return(this.UriToUriString(o.Metadata, false)); })) { if (flag) { base.JsonWriter.WriteName(name); base.JsonWriter.StartObjectScope(); flag = false; } this.WriteOperationMetadataGroup(grouping); } if (!flag) { base.JsonWriter.EndObjectScope(); } }
/// <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="IEdmEntityType"/> 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> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> private void WriteEntryContent( ODataEntry entry, IEdmEntityType entryType, EntryPropertiesValueCache propertiesValueCache, EpmSourcePathSegment rootSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { Debug.Assert(entry != null, "entry != null"); Debug.Assert(propertiesValueCache != null, "propertiesValueCache != null"); ODataStreamReferenceValue mediaResource = entry.MediaResource; if (mediaResource == null) { // <content type="application/xml"> this.atomOutputContext.XmlWriter.WriteStartElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContentElementName, AtomConstants.AtomNamespace); this.atomOutputContext.XmlWriter.WriteAttributeString( AtomConstants.AtomTypeAttributeName, MimeConstants.MimeApplicationXml); this.atomEntryAndFeedSerializer.AssertRecursionDepthIsZero(); this.atomEntryAndFeedSerializer.WriteProperties( entryType, propertiesValueCache.EntryProperties, false /* isWritingCollection */, this.atomEntryAndFeedSerializer.WriteEntryPropertiesStart, this.atomEntryAndFeedSerializer.WriteEntryPropertiesEnd, this.DuplicatePropertyNamesChecker, propertiesValueCache, rootSourcePathSegment, projectedProperties); this.atomEntryAndFeedSerializer.AssertRecursionDepthIsZero(); // </content> this.atomOutputContext.XmlWriter.WriteEndElement(); } else { WriterValidationUtils.ValidateStreamReferenceValue(mediaResource, true); this.atomEntryAndFeedSerializer.WriteEntryMediaEditLink(mediaResource); if (mediaResource.ReadLink != null) { // <content type="type" src="src"> this.atomOutputContext.XmlWriter.WriteStartElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContentElementName, AtomConstants.AtomNamespace); Debug.Assert(!string.IsNullOrEmpty(mediaResource.ContentType), "The default stream content type should have been validated by now. If we have a read link we must have a non-empty content type as well."); this.atomOutputContext.XmlWriter.WriteAttributeString( AtomConstants.AtomTypeAttributeName, mediaResource.ContentType); this.atomOutputContext.XmlWriter.WriteAttributeString( AtomConstants.MediaLinkEntryContentSourceAttributeName, this.atomEntryAndFeedSerializer.UriToUrlAttributeValue(mediaResource.ReadLink)); // </content> this.atomOutputContext.XmlWriter.WriteEndElement(); } this.atomEntryAndFeedSerializer.AssertRecursionDepthIsZero(); this.atomEntryAndFeedSerializer.WriteProperties( entryType, propertiesValueCache.EntryProperties, false /* isWritingCollection */, this.atomEntryAndFeedSerializer.WriteEntryPropertiesStart, this.atomEntryAndFeedSerializer.WriteEntryPropertiesEnd, this.DuplicatePropertyNamesChecker, propertiesValueCache, rootSourcePathSegment, projectedProperties); this.atomEntryAndFeedSerializer.AssertRecursionDepthIsZero(); } }
/// <summary> /// Writes a single property in ATOM format. /// </summary> /// <param name="property">The property to write out.</param> /// <param name="owningType">The owning type for the <paramref name="property"/> or null if no metadata is available.</param> /// <param name="isTopLevel">true if writing a top-level property payload; otherwise false.</param> /// <param name="isWritingCollection">true if we are writing a top-level collection instead of an entry.</param> /// <param name="beforePropertyAction">Action which is called before the property is written, if it's going to be written.</param> /// <param name="epmValueCache">Cache of values used in EPM so that we avoid multiple enumerations of properties/items. (can be null)</param> /// <param name="epmParentSourcePathSegment">The EPM source path segment which points to the property which sub-property we're writing. (can be null)</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> /// <returns>true if the property was actually written, false otherwise.</returns> private bool WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool isWritingCollection, Action beforePropertyAction, EpmValueCache epmValueCache, EpmSourcePathSegment epmParentSourcePathSegment, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); WriterValidationUtils.ValidatePropertyNotNull(property); object value = property.Value; string propertyName = property.Name; EpmSourcePathSegment epmSourcePathSegment = EpmWriterUtils.GetPropertySourcePathSegment(epmParentSourcePathSegment, propertyName); //// TODO: If we implement type conversions the value needs to be converted here //// since the next method call needs to know if the value is a string or not in some cases. ODataComplexValue complexValue = value as ODataComplexValue; ProjectedPropertiesAnnotation complexValueProjectedProperties = null; if (!this.ShouldWritePropertyInContent(owningType, projectedProperties, propertyName, value, epmSourcePathSegment)) { // If ShouldWritePropertyInContent returns false for a comlex value we have to continue // writing the property but set the projectedProperties to an empty array. The reason for this // is that we might find EPM on a nested property that has a null value and thus must be written // in content (in which case the parent property also has to be written). // This only applies if we have EPM information for the property. if (epmSourcePathSegment != null && complexValue != null) { Debug.Assert(!projectedProperties.IsPropertyProjected(propertyName), "ShouldWritePropertyInContent must not return false for a projected complex property."); complexValueProjectedProperties = ProjectedPropertiesAnnotation.EmptyProjectedPropertiesInstance; } else { return(false); } } WriterValidationUtils.ValidatePropertyName(propertyName); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds); IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; if (value is ODataStreamReferenceValue) { throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } // If the property is of Geography or Geometry type or the value is of Geography or Geometry type // make sure to check that the version is 3.0 or above. if ((propertyTypeReference != null && propertyTypeReference.IsSpatial()) || (propertyTypeReference == null && value is System.Spatial.ISpatial)) { ODataVersionChecker.CheckSpatialValue(this.Version); } // Null property value. if (value == null) { this.WriteNullPropertyValue(propertyTypeReference, propertyName, isTopLevel, isWritingCollection, beforePropertyAction); return(true); } bool isOpenPropertyType = owningType != null && owningType.IsOpen && propertyTypeReference == null; if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value, this.MessageWriterSettings.UndeclaredPropertyBehaviorKinds); } if (complexValue != null) { return(this.WriteComplexValueProperty( complexValue, propertyName, isTopLevel, isWritingCollection, beforePropertyAction, epmValueCache, propertyTypeReference, isOpenPropertyType, epmSourcePathSegment, complexValueProjectedProperties)); } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { this.WriteCollectionValueProperty( collectionValue, propertyName, isTopLevel, isWritingCollection, beforePropertyAction, propertyTypeReference, isOpenPropertyType); return(true); } // If the value isn't one of the value types tested for already, it must be a non-null primitive. this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); SerializationTypeNameAnnotation serializationTypeNameAnnotation = property.ODataValue.GetAnnotation <SerializationTypeNameAnnotation>(); this.WritePrimitiveValue(value, /*collectionValidator*/ null, propertyTypeReference, serializationTypeNameAnnotation); this.WritePropertyEnd(); return(true); }
/// <summary> /// Writes the navigation link's start element and atom metadata. /// </summary> /// <param name="navigationLink">The navigation link to write.</param> /// <param name="navigationLinkUrlOverride">Url to use for the navigation link. If this is specified the Url property on the <paramref name="navigationLink"/> /// will be ignored. If this parameter is null, the Url from the navigation link is used.</param> private void WriteNavigationLinkStart(ODataNavigationLink navigationLink, Uri navigationLinkUrlOverride) { WriterValidationUtils.ValidateNavigationLinkHasCardinality(navigationLink); WriterValidationUtils.ValidateNavigationLinkUrlPresent(navigationLink); this.atomEntryAndFeedSerializer.WriteNavigationLinkStart(navigationLink, navigationLinkUrlOverride); }
private bool WriteProperty(ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool isWritingCollection, Action beforePropertyAction, EpmValueCache epmValueCache, EpmSourcePathSegment epmParentSourcePathSegment, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { Action beforeValueAction = null; Action afterValueAction = null; WriterValidationUtils.ValidatePropertyNotNull(property); object propertyValue = property.Value; string propertyName = property.Name; EpmSourcePathSegment propertySourcePathSegment = EpmWriterUtils.GetPropertySourcePathSegment(epmParentSourcePathSegment, propertyName); ODataComplexValue complexValue = propertyValue as ODataComplexValue; ProjectedPropertiesAnnotation emptyProjectedPropertiesMarker = null; if (!this.ShouldWritePropertyInContent(owningType, projectedProperties, propertyName, propertyValue, propertySourcePathSegment)) { if ((propertySourcePathSegment == null) || (complexValue == null)) { return(false); } emptyProjectedPropertiesMarker = ProjectedPropertiesAnnotation.EmptyProjectedPropertiesMarker; } WriterValidationUtils.ValidateProperty(property); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType); if (propertyValue is ODataStreamReferenceValue) { throw new ODataException(Microsoft.Data.OData.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } if (((edmProperty != null) && edmProperty.Type.IsSpatial()) || ((edmProperty == null) && (propertyValue is ISpatial))) { ODataVersionChecker.CheckSpatialValue(base.Version); } if (propertyValue == null) { this.WriteNullPropertyValue(edmProperty, propertyName, isTopLevel, isWritingCollection, beforePropertyAction); return(true); } bool isOpenPropertyType = ((owningType != null) && owningType.IsOpen) && (edmProperty == null); if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(propertyName, propertyValue); } IEdmTypeReference metadataTypeReference = (edmProperty == null) ? null : edmProperty.Type; if (complexValue != null) { DuplicatePropertyNamesChecker checker = base.CreateDuplicatePropertyNamesChecker(); if (isTopLevel) { this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); this.WriteComplexValue(complexValue, metadataTypeReference, isOpenPropertyType, isWritingCollection, null, null, checker, null, epmValueCache, propertySourcePathSegment, null); this.WritePropertyEnd(); return(true); } if (beforeValueAction == null) { beforeValueAction = delegate { this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); }; } if (afterValueAction == null) { afterValueAction = delegate { this.WritePropertyEnd(); }; } return(this.WriteComplexValue(complexValue, metadataTypeReference, isOpenPropertyType, isWritingCollection, beforeValueAction, afterValueAction, checker, null, epmValueCache, propertySourcePathSegment, emptyProjectedPropertiesMarker)); } ODataCollectionValue collectionValue = propertyValue as ODataCollectionValue; if (collectionValue != null) { ODataVersionChecker.CheckCollectionValueProperties(base.Version, propertyName); this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); this.WriteCollectionValue(collectionValue, metadataTypeReference, isOpenPropertyType, isWritingCollection); this.WritePropertyEnd(); return(true); } this.WritePropertyStart(beforePropertyAction, propertyName, isWritingCollection, isTopLevel); this.WritePrimitiveValue(propertyValue, null, metadataTypeReference); this.WritePropertyEnd(); return(true); }
private void WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool allowStreamProperty, IDuplicatePropertyNameChecker duplicatePropertyNameChecker) { WriterValidationUtils.ValidatePropertyNotNull(property); string propertyName = property.Name; if (this.JsonLightOutputContext.MessageWriterSettings.Validations != ValidationKinds.None) { WriterValidationUtils.ValidatePropertyName(propertyName); } if (!this.JsonLightOutputContext.PropertyCacheHandler.InResourceSetScope()) { this.currentPropertyInfo = new PropertySerializationInfo(propertyName, owningType) { IsTopLevel = isTopLevel }; } else { this.currentPropertyInfo = this.JsonLightOutputContext.PropertyCacheHandler.GetProperty(propertyName, owningType); } WriterValidationUtils.ValidatePropertyDefined(this.currentPropertyInfo, this.MessageWriterSettings.ThrowOnUndeclaredPropertyForNonOpenType); duplicatePropertyNameChecker.ValidatePropertyUniqueness(property); if (currentPropertyInfo.MetadataType.IsUndeclaredProperty) { WriteODataTypeAnnotation(property, isTopLevel); } WriteInstanceAnnotation(property, isTopLevel, currentPropertyInfo.MetadataType.IsUndeclaredProperty); ODataValue value = property.ODataValue; // handle ODataUntypedValue ODataUntypedValue untypedValue = value as ODataUntypedValue; if (untypedValue != null) { WriteUntypedValue(untypedValue); return; } ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue; if (streamReferenceValue != null) { if (!allowStreamProperty) { throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataResource(propertyName)); } Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type."); Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level."); WriterValidationUtils.ValidateStreamReferenceProperty(property, currentPropertyInfo.MetadataType.EdmProperty, this.WritingResponse); this.WriteStreamReferenceProperty(propertyName, streamReferenceValue); return; } if (value is ODataNullValue || value == null) { this.WriteNullProperty(property); return; } bool isOpenPropertyType = this.IsOpenProperty(property); ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; if (primitiveValue != null) { this.WritePrimitiveProperty(primitiveValue, isOpenPropertyType); return; } ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { this.WriteEnumProperty(enumValue, isOpenPropertyType); return; } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { this.WriteCollectionProperty(collectionValue, isOpenPropertyType); return; } }
/// <summary> /// Writes out the value of a collection property. /// </summary> /// <param name="collectionValue">The collection value to write.</param> /// <param name="metadataTypeReference">The metadata type reference for the collection.</param> /// <param name="isOpenPropertyType">true if the type name belongs to an open property.</param> /// <remarks>The current recursion depth is measured by the number of complex and collection values between /// this one and the top-level payload, not including this one.</remarks> internal void WriteCollectionValue( ODataCollectionValue collectionValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(collectionValue != null, "collectionValue != null"); this.IncreaseRecursionDepth(); // Start the object scope which will represent the entire CollectionValue instance this.JsonWriter.StartObjectScope(); // "__metadata": { "type": "typename" } // If the CollectionValue has type information write out the metadata and the type in it. string typeName = collectionValue.TypeName; // resolve the type name to the type; if no type name is specified we will use the // type inferred from metadata IEdmCollectionTypeReference collectionTypeReference = (IEdmCollectionTypeReference)WriterValidationUtils.ResolveTypeNameForWriting(this.Model, metadataTypeReference, ref typeName, EdmTypeKind.Collection, isOpenPropertyType); string collectionItemTypeName = null; if (typeName != null) { collectionItemTypeName = ValidationUtils.ValidateCollectionTypeName(typeName); } SerializationTypeNameAnnotation serializationTypeNameAnnotation = collectionValue.GetAnnotation <SerializationTypeNameAnnotation>(); if (serializationTypeNameAnnotation != null) { typeName = serializationTypeNameAnnotation.TypeName; } if (typeName != null) { // Write the __metadata object this.JsonWriter.WriteName(JsonConstants.ODataMetadataName); this.JsonWriter.StartObjectScope(); // "type": "typename" this.JsonWriter.WriteName(JsonConstants.ODataMetadataTypeName); this.JsonWriter.WriteValue(typeName); // End the __metadata this.JsonWriter.EndObjectScope(); } // "results": [ // This represents the array of items in the CollectionValue this.JsonWriter.WriteDataArrayName(); this.JsonWriter.StartArrayScope(); // Iterate through the CollectionValue items and write them out (treat null Items as an empty enumeration) IEnumerable items = collectionValue.Items; if (items != null) { IEdmTypeReference expectedItemTypeReference = collectionTypeReference == null ? null : collectionTypeReference.ElementType(); CollectionWithoutExpectedTypeValidator collectionValidator = new CollectionWithoutExpectedTypeValidator(collectionItemTypeName); DuplicatePropertyNamesChecker duplicatePropertyNamesChecker = null; foreach (object item in items) { ValidationUtils.ValidateCollectionItem(item, false /* isStreamable */); ODataComplexValue itemAsComplexValue = item as ODataComplexValue; if (itemAsComplexValue != null) { if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); } this.WriteComplexValue( itemAsComplexValue, expectedItemTypeReference, false, duplicatePropertyNamesChecker, collectionValidator); duplicatePropertyNamesChecker.Clear(); } else { Debug.Assert(!(item is ODataCollectionValue), "!(item is ODataCollectionValue)"); Debug.Assert(!(item is ODataStreamReferenceValue), "!(item is ODataStreamReferenceValue)"); this.WritePrimitiveValue(item, collectionValidator, expectedItemTypeReference); } } } // End the array scope which holds the items this.JsonWriter.EndArrayScope(); // End the object scope which holds the entire collection this.JsonWriter.EndObjectScope(); this.DecreaseRecursionDepth(); }
/// <summary> /// Writes the __metadata property and its content for an entry /// </summary> /// <param name="entry">The entry for which to write the metadata.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> /// <param name="entryEntityType">The entity type of the entry to write.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use.</param> internal void WriteEntryMetadata( ODataEntry entry, ProjectedPropertiesAnnotation projectedProperties, IEdmEntityType entryEntityType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entry != null, "entry != null"); // Write the "__metadata" for the entry this.JsonWriter.WriteName(JsonConstants.ODataMetadataName); this.JsonWriter.StartObjectScope(); // Write the "id": "Entity Id" string id = entry.Id; if (id != null) { this.JsonWriter.WriteName(JsonConstants.ODataEntryIdName); this.JsonWriter.WriteValue(id); } // Write the "uri": "edit/read-link-uri" Uri uriValue = entry.EditLink ?? entry.ReadLink; if (uriValue != null) { this.JsonWriter.WriteName(JsonConstants.ODataMetadataUriName); this.JsonWriter.WriteValue(this.UriToAbsoluteUriString(uriValue)); } // 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.WriteETag(JsonConstants.ODataMetadataETagName, etag); } // Write the "type": "typename" string typeName = this.VerboseJsonOutputContext.TypeNameOracle.GetEntryTypeNameForWriting(entry); if (typeName != null) { this.JsonWriter.WriteName(JsonConstants.ODataMetadataTypeName); this.JsonWriter.WriteValue(typeName); } // Write MLE metadata ODataStreamReferenceValue mediaResource = entry.MediaResource; if (mediaResource != null) { WriterValidationUtils.ValidateStreamReferenceValue(mediaResource, true); this.WriteStreamReferenceValueContent(mediaResource); } // write "actions" metadata IEnumerable <ODataAction> actions = entry.Actions; if (actions != null) { this.WriteOperations(actions.Cast <ODataOperation>(), JsonConstants.ODataActionsMetadataName, /*isAction*/ true, /*writingJsonLight*/ false); } // write "functions" metadata IEnumerable <ODataFunction> functions = entry.Functions; if (functions != null) { this.WriteOperations(functions.Cast <ODataOperation>(), JsonConstants.ODataFunctionsMetadataName, /*isAction*/ false, /*writingJsonLight*/ false); } // 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.ValidateAssociationLinkNotNull(associationLink); if (projectedProperties.ShouldSkipProperty(associationLink.Name)) { continue; } if (firstAssociationLink) { // Write the "properties": { this.JsonWriter.WriteName(JsonConstants.ODataMetadataPropertiesName); this.JsonWriter.StartObjectScope(); firstAssociationLink = false; } this.ValidateAssociationLink(associationLink, entryEntityType); this.WriteAssociationLink(associationLink, duplicatePropertyNamesChecker); } if (!firstAssociationLink) { // Close the "properties" object this.JsonWriter.EndObjectScope(); } } // Close the __metadata object scope this.JsonWriter.EndObjectScope(); }
/// <summary> /// Writes a single property in ATOM format. /// </summary> /// <param name="property">The property to write out.</param> /// <param name="owningType">The owning type for the <paramref name="property"/> or null if no metadata is available.</param> /// <param name="isTopLevel">true if writing a top-level property payload; otherwise false.</param> /// <param name="isWritingCollection">true if we are writing a top-level collection instead of an entry.</param> /// <param name="beforePropertyAction">Action which is called before the property is written, if it's going to be written.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> /// <returns>true if the property was actually written, false otherwise.</returns> private bool WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool isWritingCollection, Action beforePropertyAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { WriterValidationUtils.ValidatePropertyNotNull(property); object value = property.Value; string propertyName = property.Name; //// TODO: If we implement type conversions the value needs to be converted here //// since the next method call needs to know if the value is a string or not in some cases. ODataComplexValue complexValue = value as ODataComplexValue; ProjectedPropertiesAnnotation complexValueProjectedProperties = null; if (!ShouldWritePropertyInContent(projectedProperties, propertyName)) { return(false); } WriterValidationUtils.ValidatePropertyName(propertyName); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(propertyName, owningType); IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; if (value is ODataStreamReferenceValue) { throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } // Null property value. if (value == null) { this.WriteNullPropertyValue(propertyTypeReference, propertyName, isTopLevel, isWritingCollection, beforePropertyAction); return(true); } bool isOpenPropertyType = owningType != null && owningType.IsOpen && propertyTypeReference == null; if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value); } if (complexValue != null) { return(this.WriteComplexValueProperty( complexValue, propertyName, isTopLevel, isWritingCollection, beforePropertyAction, propertyTypeReference, isOpenPropertyType, complexValueProjectedProperties)); } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { this.WriteCollectionValueProperty( collectionValue, propertyName, isTopLevel, isWritingCollection, beforePropertyAction, propertyTypeReference, isOpenPropertyType); return(true); } // If the value isn't one of the value types tested for already, it must be a non-null primitive or enum type. this.WritePropertyStart(beforePropertyAction, property, isWritingCollection, isTopLevel); SerializationTypeNameAnnotation serializationTypeNameAnnotation = property.ODataValue.GetAnnotation <SerializationTypeNameAnnotation>(); ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { this.WriteEnumValue(enumValue, /*collectionValidator*/ null, propertyTypeReference, serializationTypeNameAnnotation); } else { this.WritePrimitiveValue(value, /*collectionValidator*/ null, propertyTypeReference, serializationTypeNameAnnotation); } this.WritePropertyEnd(); return(true); }
/// <summary> /// Writes out the value of a complex property. /// </summary> /// <param name="complexValue">The complex value to write.</param> /// <param name="propertyTypeReference">The metadata type for the complex value.</param> /// <param name="isOpenPropertyType">true if the type name belongs to an open property.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="collectionValidator">The collection validator instance to validate the type names and type kinds of collection items; null if no validation is needed.</param> /// <remarks>The current recursion depth should be a value, measured by the number of complex and collection values between /// this complex value and the top-level payload, not including this one.</remarks> internal void WriteComplexValue( ODataComplexValue complexValue, IEdmTypeReference propertyTypeReference, bool isOpenPropertyType, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(complexValue != null, "complexValue != null"); this.IncreaseRecursionDepth(); // Start the object scope which will represent the entire complex instance this.JsonWriter.StartObjectScope(); // Write the "__metadata" : { "type": "typename" } // But only if we actually have a typename to write, otherwise we need the __metadata to be omitted entirely string typeName = complexValue.TypeName; if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex); } // resolve the type name to the type; if no type name is specified we will use the // type inferred from metadata IEdmComplexTypeReference complexValueTypeReference = WriterValidationUtils.ResolveTypeNameForWriting(this.Model, propertyTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull(); // If the type is the same as the one specified by the parent collection, omit the type name, since it's not needed. if (typeName != null && collectionValidator != null) { string expectedItemTypeName = collectionValidator.ItemTypeNameFromCollection; if (string.CompareOrdinal(expectedItemTypeName, typeName) == 0) { typeName = null; } } SerializationTypeNameAnnotation serializationTypeNameAnnotation = complexValue.GetAnnotation <SerializationTypeNameAnnotation>(); if (serializationTypeNameAnnotation != null) { typeName = serializationTypeNameAnnotation.TypeName; } if (typeName != null) { // Write the __metadata object this.JsonWriter.WriteName(JsonConstants.ODataMetadataName); this.JsonWriter.StartObjectScope(); // "type": "typename" this.JsonWriter.WriteName(JsonConstants.ODataMetadataTypeName); this.JsonWriter.WriteValue(typeName); // End the __metadata this.JsonWriter.EndObjectScope(); } // Write the properties of the complex value as usual. Note we do not allow complex types to contain named stream properties. this.WriteProperties( complexValueTypeReference == null ? null : complexValueTypeReference.ComplexDefinition(), complexValue.Properties, true /* isComplexValue */, duplicatePropertyNamesChecker, null /*projectedProperties */); // End the object scope which represents the complex instance this.JsonWriter.EndObjectScope(); this.DecreaseRecursionDepth(); }
internal bool WriteComplexValue(ODataComplexValue complexValue, IEdmTypeReference metadataTypeReference, bool isOpenPropertyType, bool isWritingCollection, Action beforeValueAction, Action afterValueAction, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, EpmValueCache epmValueCache, EpmSourcePathSegment epmSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { Action action2 = null; string typeName = complexValue.TypeName; if (collectionValidator != null) { collectionValidator.ValidateCollectionItem(typeName, EdmTypeKind.Complex); } this.IncreaseRecursionDepth(); IEdmComplexTypeReference reference = WriterValidationUtils.ResolveTypeNameForWriting(base.Model, metadataTypeReference, ref typeName, EdmTypeKind.Complex, isOpenPropertyType).AsComplexOrNull(); if (((typeName != null) && (collectionValidator != null)) && (string.CompareOrdinal(collectionValidator.ItemTypeNameFromCollection, typeName) == 0)) { typeName = null; } SerializationTypeNameAnnotation annotation = complexValue.GetAnnotation <SerializationTypeNameAnnotation>(); if (annotation != null) { typeName = annotation.TypeName; } Action beforePropertiesAction = beforeValueAction; if (typeName != null) { if (beforeValueAction != null) { if (action2 == null) { action2 = delegate { beforeValueAction(); this.WritePropertyTypeAttribute(typeName); }; } beforePropertiesAction = action2; } else { this.WritePropertyTypeAttribute(typeName); } } if (((base.MessageWriterSettings.WriterBehavior != null) && base.MessageWriterSettings.WriterBehavior.UseV1ProviderBehavior) && !object.ReferenceEquals(projectedProperties, ProjectedPropertiesAnnotation.EmptyProjectedPropertiesMarker)) { IEdmComplexType definition = (IEdmComplexType)reference.Definition; if (base.Model.EpmCachedKeepPrimitiveInContent(definition) == null) { List <string> keptInContentPropertyNames = null; foreach (IEdmProperty property in from p in definition.Properties() where p.Type.IsODataPrimitiveTypeKind() select p) { EntityPropertyMappingAttribute entityPropertyMapping = EpmWriterUtils.GetEntityPropertyMapping(epmSourcePathSegment, property.Name); if ((entityPropertyMapping != null) && entityPropertyMapping.KeepInContent) { if (keptInContentPropertyNames == null) { keptInContentPropertyNames = new List <string>(); } keptInContentPropertyNames.Add(property.Name); } } base.Model.SetAnnotationValue <CachedPrimitiveKeepInContentAnnotation>(definition, new CachedPrimitiveKeepInContentAnnotation(keptInContentPropertyNames)); } } bool flag = this.WriteProperties((reference == null) ? null : reference.ComplexDefinition(), EpmValueCache.GetComplexValueProperties(epmValueCache, complexValue, true), isWritingCollection, beforePropertiesAction, afterValueAction, duplicatePropertyNamesChecker, epmValueCache, epmSourcePathSegment, projectedProperties); this.DecreaseRecursionDepth(); return(flag); }
/// <summary> /// Writes a name/value pair for a property. /// </summary> /// <param name="property">The property to write out.</param> /// <param name="owningType">The type owning the property (or null if no metadata is available).</param> /// <param name="allowStreamProperty">Should pass in true if we are writing a property of an ODataEntry instance, false otherwise. /// Named stream properties should only be defined on ODataEntry instances.</param> /// <param name="duplicatePropertyNamesChecker">The checker instance for duplicate property names.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> private void WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool allowStreamProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { DebugUtils.CheckNoExternalCallers(); WriterValidationUtils.ValidatePropertyNotNull(property); if (projectedProperties.ShouldSkipProperty(property.Name)) { return; } WriterValidationUtils.ValidateProperty(property); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined(property.Name, owningType); // If the property is of Geography or Geometry type or the value is of Geography or Geometry type // make sure to check that the version is 3.0 or above. if ((edmProperty != null && edmProperty.Type.IsSpatial()) || (edmProperty == null && property.Value is System.Spatial.ISpatial)) { ODataVersionChecker.CheckSpatialValue(this.Version); } this.JsonWriter.WriteName(property.Name); object value = property.Value; if (value == null) { WriterValidationUtils.ValidateNullPropertyValue(edmProperty, this.MessageWriterSettings.WriterBehavior, this.Model); this.JsonWriter.WriteValue(null); } else { bool isOpenPropertyType = owningType != null && owningType.IsOpen && edmProperty == null; if (isOpenPropertyType) { ValidationUtils.ValidateOpenPropertyValue(property.Name, value); } IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { this.WriteComplexValue( complexValue, propertyTypeReference, isOpenPropertyType, this.CreateDuplicatePropertyNamesChecker(), /*collectionValidator*/ null); } else { ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { ODataVersionChecker.CheckCollectionValueProperties(this.Version, property.Name); this.WriteCollectionValue( collectionValue, propertyTypeReference, isOpenPropertyType); } else { ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue; if (streamReferenceValue != null) { if (!allowStreamProperty) { throw new ODataException(o.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(property.Name)); } Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type."); WriterValidationUtils.ValidateStreamReferenceProperty(property, edmProperty, this.Version, this.WritingResponse); this.WriteStreamReferenceValue((ODataStreamReferenceValue)property.Value); } else { this.WritePrimitiveValue(value, /*collectionValidator*/ null, propertyTypeReference); } } } } }
private void WriteProperty( ODataProperty property, IEdmStructuredType owningType, bool isTopLevel, bool allowStreamProperty, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, ProjectedPropertiesAnnotation projectedProperties) { WriterValidationUtils.ValidatePropertyNotNull(property); string propertyName = property.Name; if (projectedProperties.ShouldSkipProperty(propertyName)) { return; } WriterValidationUtils.ValidatePropertyName(propertyName, bypassValidation); duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); if (property.InstanceAnnotations.Any()) { if (isTopLevel) { this.InstanceAnnotationWriter.WriteInstanceAnnotations(property.InstanceAnnotations); } else { this.InstanceAnnotationWriter.WriteInstanceAnnotations(property.InstanceAnnotations, propertyName); } } IEdmProperty edmProperty = WriterValidationUtils.ValidatePropertyDefined( propertyName, owningType, !this.bypassValidation); IEdmTypeReference propertyTypeReference = edmProperty == null ? null : edmProperty.Type; ODataValue value = property.ODataValue; ODataStreamReferenceValue streamReferenceValue = value as ODataStreamReferenceValue; if (streamReferenceValue != null) { if (!allowStreamProperty) { throw new ODataException(ODataErrorStrings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(propertyName)); } Debug.Assert(owningType == null || owningType.IsODataEntityTypeKind(), "The metadata should not allow named stream properties to be defined on a non-entity type."); Debug.Assert(!isTopLevel, "Stream properties are not allowed at the top level."); WriterValidationUtils.ValidateStreamReferenceProperty(property, edmProperty, this.WritingResponse, this.bypassValidation); this.WriteStreamReferenceProperty(propertyName, streamReferenceValue); return; } string wirePropertyName = isTopLevel ? JsonLightConstants.ODataValuePropertyName : propertyName; if (value is ODataNullValue || value == null) { WriterValidationUtils.ValidateNullPropertyValue(propertyTypeReference, propertyName, this.MessageWriterSettings.WriterBehavior, this.Model, this.bypassValidation); if (isTopLevel) { // Write the special null marker for top-level null properties. this.JsonWriter.WriteInstanceAnnotationName(ODataAnnotationNames.ODataNull); this.JsonWriter.WriteValue(true); } else { this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WriteNullValue(); } return; } bool isOpenPropertyType = this.IsOpenProperty(property, owningType, edmProperty); if (isOpenPropertyType && this.JsonLightOutputContext.MessageWriterSettings.EnableFullValidation) { ValidationUtils.ValidateOpenPropertyValue(propertyName, value); } ODataComplexValue complexValue = value as ODataComplexValue; if (complexValue != null) { if (!isTopLevel) { this.JsonWriter.WriteName(wirePropertyName); } this.JsonLightValueSerializer.WriteComplexValue(complexValue, propertyTypeReference, isTopLevel, isOpenPropertyType, this.CreateDuplicatePropertyNamesChecker()); return; } IEdmTypeReference typeFromValue = TypeNameOracle.ResolveAndValidateTypeNameForValue(this.Model, propertyTypeReference, value, isOpenPropertyType); ODataEnumValue enumValue = value as ODataEnumValue; if (enumValue != null) { // This is a work around, needTypeOnWire always = true for client side: // ClientEdmModel's reflection can't know a property is open type even if it is, so here // make client side always write 'odata.type' for enum. bool needTypeOnWire = string.Equals(this.JsonLightOutputContext.Model.GetType().Name, "ClientEdmModel", StringComparison.OrdinalIgnoreCase); string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting( enumValue, propertyTypeReference, typeFromValue, needTypeOnWire ? true /* leverage this flag to write 'odata.type' */ : isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel); this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WriteEnumValue(enumValue, propertyTypeReference); return; } ODataCollectionValue collectionValue = value as ODataCollectionValue; if (collectionValue != null) { string collectionTypeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(collectionValue, propertyTypeReference, typeFromValue, isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, collectionTypeNameToWrite, isTopLevel); this.JsonWriter.WriteName(wirePropertyName); // passing false for 'isTopLevel' because the outer wrapping object has already been written. this.JsonLightValueSerializer.WriteCollectionValue(collectionValue, propertyTypeReference, isTopLevel, false /*isInUri*/, isOpenPropertyType); } else { ODataPrimitiveValue primitiveValue = value as ODataPrimitiveValue; Debug.Assert(primitiveValue != null, "primitiveValue != null"); string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(primitiveValue, propertyTypeReference, typeFromValue, isOpenPropertyType); this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel); this.JsonWriter.WriteName(wirePropertyName); this.JsonLightValueSerializer.WritePrimitiveValue(primitiveValue.Value, propertyTypeReference); } }